diff --git a/integration-tests/sdk-typescript/test-helper.ts b/integration-tests/sdk-typescript/test-helper.ts index 8274398cb00..e2a9c398356 100644 --- a/integration-tests/sdk-typescript/test-helper.ts +++ b/integration-tests/sdk-typescript/test-helper.ts @@ -830,6 +830,30 @@ export function assertToolCalled( } } +/** + * Assert that a specific tool was called and all its results succeeded + */ +export function assertToolSucceeded( + messages: SDKMessage[], + toolName: string, +): void { + const results = findToolResults(messages, toolName); + + if (results.length === 0) { + throw new Error( + `Expected tool '${toolName}' to have at least one result, but found none`, + ); + } + + for (const result of results) { + if (result.isError) { + throw new Error( + `Expected tool '${toolName}' to succeed, but got error: ${result.content}`, + ); + } + } +} + /** * Assert that the conversation completed successfully */ diff --git a/integration-tests/sdk-typescript/tool-control.test.ts b/integration-tests/sdk-typescript/tool-control.test.ts index 5fe5e474712..abc8466266b 100644 --- a/integration-tests/sdk-typescript/tool-control.test.ts +++ b/integration-tests/sdk-typescript/tool-control.test.ts @@ -26,12 +26,13 @@ import { findToolCalls, findToolResults, assertSuccessfulCompletion, + assertToolSucceeded, createSharedTestOptions, createResultWaiter, } from './test-helper.js'; const SHARED_TEST_OPTIONS = createSharedTestOptions(); -const TEST_TIMEOUT = 60000; +const TEST_TIMEOUT = process.env['CI'] ? 120_000 : 60_000; const SANDBOX_MODE = process.env['QWEN_SANDBOX']?.toLowerCase().trim(); const IS_CONTAINER_SANDBOX = SANDBOX_MODE === 'docker' || SANDBOX_MODE === 'podman'; @@ -89,10 +90,9 @@ describe('Tool Control Parameters (E2E)', () => { // Should NOT have list_directory since it's not in coreTools expect(toolNames).not.toContain('list_directory'); - // Verify file was actually modified (content changed from original). - // Don't assert on specific wording — the model may paraphrase. - const content = await helper.readFile('test.txt'); - expect(content).not.toBe('original content'); + // Verify write_file executed successfully (tool-control check, + // not model-content check — the model may echo back the original). + assertToolSucceeded(messages, 'write_file'); } finally { await q.close(); } @@ -584,10 +584,9 @@ describe('Tool Control Parameters (E2E)', () => { // canUseTool should NOT have been called (tools are in allowedTools) expect(canUseToolCalled).toBe(false); - // Verify file was actually modified (content changed from original). - // Don't assert on specific wording — the model may paraphrase. - const content = await helper.readFile('test.txt'); - expect(content).not.toBe('original'); + // Verify write_file executed successfully (tool-control check, + // not model-content check — the model may echo back the original). + assertToolSucceeded(messages, 'write_file'); } finally { await q.close(); } @@ -881,10 +880,9 @@ describe('Tool Control Parameters (E2E)', () => { // Should NOT use tools outside coreTools expect(toolNames).not.toContain('run_shell_command'); - // Verify file was actually modified (content changed from original). - // Don't assert on specific wording — the model may paraphrase. - const content = await helper.readFile('test.txt'); - expect(content).not.toBe('test'); + // Verify write_file executed successfully (tool-control check, + // not model-content check — the model may echo back the original). + assertToolSucceeded(messages, 'write_file'); } finally { await q.close(); } @@ -984,10 +982,9 @@ describe('Tool Control Parameters (E2E)', () => { // canUseTool should be called for core write tools expect(canUseToolCalls).toContain('write_file'); - // Verify file was actually modified (content changed from original). - // Don't assert on specific wording — the model may paraphrase. - const content = await helper.readFile('test.txt'); - expect(content).not.toBe('test'); + // Verify write_file executed successfully (tool-control check, + // not model-content check — the model may echo back the original). + assertToolSucceeded(messages, 'write_file'); } finally { await q.close(); }