7a0da7932b
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
140 lines
5.1 KiB
JavaScript
140 lines
5.1 KiB
JavaScript
/**
|
|
* Tests for the agent-thinking panel renderer in components/progress.js
|
|
* (the `updateAgentThinking` function).
|
|
*
|
|
* Regression coverage for the "Using web_search" display bug
|
|
* (PR #4470 / fix/display-actual-engine-name):
|
|
*
|
|
* The LangGraph strategy puts the friendly engine name in the progress
|
|
* event's `data.message` (e.g. `🔍 Searching DuckDuckGo: "..."`) while
|
|
* keeping the stable tool id in `data.tool` ("web_search"). The renderer
|
|
* must surface the friendly message, not "Using web_search".
|
|
*
|
|
* The MCP strategy puts the friendly label in `data.message`
|
|
* (`ACTION: Using DuckDuckGo - "..."`) AND also supplies `data.arguments`.
|
|
* The renderer must show the message verbatim without duplicating the
|
|
* query that's already embedded in it.
|
|
*
|
|
* When no message is supplied, the renderer falls back to
|
|
* `Using ${data.tool}` (+ args), so the panel never renders blank.
|
|
*/
|
|
|
|
let progressComponent;
|
|
|
|
beforeAll(async () => {
|
|
// progress.js is an IIFE; importing it runs the module and exposes
|
|
// window.progressComponent (which now includes updateAgentThinking).
|
|
await import('@js/components/progress.js');
|
|
progressComponent = window.progressComponent;
|
|
});
|
|
|
|
beforeEach(() => {
|
|
// updateAgentThinking queries these two ids and appends step nodes.
|
|
document.body.innerHTML = `
|
|
<div id="agent-thinking-panel" style="display: none;">
|
|
<div id="agent-thinking-content"></div>
|
|
</div>
|
|
`;
|
|
});
|
|
|
|
function renderToolCall(data) {
|
|
progressComponent.updateAgentThinking({ phase: 'tool_call', ...data });
|
|
const step = document
|
|
.getElementById('agent-thinking-content')
|
|
.querySelector('.ldr-agent-step-content');
|
|
return step ? step.textContent : null;
|
|
}
|
|
|
|
describe('updateAgentThinking - tool_call rendering', () => {
|
|
it('shows the LangGraph friendly message instead of "Using web_search"', () => {
|
|
const content = renderToolCall({
|
|
tool: 'web_search', // stable id, must NOT be the display source
|
|
message: '🔍 Searching DuckDuckGo: "climate policy"',
|
|
iteration: 1,
|
|
});
|
|
|
|
expect(content).toBe('🔍 Searching DuckDuckGo: "climate policy"');
|
|
expect(content).not.toContain('web_search');
|
|
expect(content).not.toContain('Using ');
|
|
});
|
|
|
|
it('shows the MCP friendly message without duplicating the query', () => {
|
|
const content = renderToolCall({
|
|
tool: 'DuckDuckGo',
|
|
message: 'ACTION: Using DuckDuckGo - "climate policy"',
|
|
arguments: { query: 'climate policy' },
|
|
});
|
|
|
|
expect(content).toBe('ACTION: Using DuckDuckGo - "climate policy"');
|
|
// The query is embedded in the message; it must appear exactly once
|
|
// (no extra `\nQuery: "..."` appended from data.arguments).
|
|
const occurrences = content.split('climate policy').length - 1;
|
|
expect(occurrences).toBe(1);
|
|
expect(content).not.toContain('Query:');
|
|
});
|
|
|
|
it('falls back to "Using <tool>" with query when no message is present', () => {
|
|
const content = renderToolCall({
|
|
tool: 'web_search',
|
|
arguments: { query: 'climate policy' },
|
|
});
|
|
|
|
expect(content).toBe('Using web_search\nQuery: "climate policy"');
|
|
});
|
|
|
|
it('falls back to "Using unknown" when neither message nor tool is present', () => {
|
|
const content = renderToolCall({});
|
|
|
|
expect(content).toBe('Using unknown');
|
|
});
|
|
});
|
|
|
|
function renderObservation(data) {
|
|
progressComponent.updateAgentThinking({ phase: 'observation', ...data });
|
|
const step = document
|
|
.getElementById('agent-thinking-content')
|
|
.querySelector('.ldr-agent-step-content');
|
|
return step ? step.textContent : null;
|
|
}
|
|
|
|
describe('updateAgentThinking - observation rendering', () => {
|
|
it('keeps the "From {engine}" attribution and appends data.content beneath it', () => {
|
|
const content = renderObservation({
|
|
message: '📄 From the web (SearXNG): [1] Some Title (http://a.com) Snip',
|
|
content: '[1] Some Title (http://a.com)\nThe full snippet body.',
|
|
});
|
|
|
|
expect(content).toBe(
|
|
'📄 From the web (SearXNG): [1] Some Title (http://a.com) Snip\n'
|
|
+ '[1] Some Title (http://a.com)\nThe full snippet body.'
|
|
);
|
|
});
|
|
|
|
it('shows the message alone when no content is attached (short outputs)', () => {
|
|
const content = renderObservation({
|
|
message: '📄 From PubMed: No results.',
|
|
});
|
|
|
|
expect(content).toBe('📄 From PubMed: No results.');
|
|
});
|
|
|
|
it('falls back to content when no message is present', () => {
|
|
const content = renderObservation({
|
|
content: 'raw tool output only',
|
|
});
|
|
|
|
expect(content).toBe('raw tool output only');
|
|
});
|
|
|
|
it('truncates the composed result to 800 chars', () => {
|
|
const content = renderObservation({
|
|
message: '📄 From arXiv: long',
|
|
content: 'z'.repeat(1000),
|
|
});
|
|
|
|
expect(content.length).toBe(803); // 800 + '...'
|
|
expect(content.endsWith('...')).toBe(true);
|
|
expect(content.startsWith('📄 From arXiv: long\n')).toBe(true);
|
|
});
|
|
});
|