diff options
| author | joshualitt <[email protected]> | 2025-08-18 13:28:15 -0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-08-18 20:28:15 +0000 |
| commit | d66ddcd82e09d7b6fbc0226e31d73d38db5cff2a (patch) | |
| tree | d78d3437feffc7eb3620f5e02f5489453b3766aa /packages/core/src/tools/tools.test.ts | |
| parent | 91cd0db2b3e99f5829dbb6d09696333e9198cc9d (diff) | |
bug(core): Do not throw validation errors when building tools in `nonInteractiveToolExecutor`. (#6363)
Diffstat (limited to 'packages/core/src/tools/tools.test.ts')
| -rw-r--r-- | packages/core/src/tools/tools.test.ts | 115 |
1 files changed, 113 insertions, 2 deletions
diff --git a/packages/core/src/tools/tools.test.ts b/packages/core/src/tools/tools.test.ts index 9942d3a9..a98d1121 100644 --- a/packages/core/src/tools/tools.test.ts +++ b/packages/core/src/tools/tools.test.ts @@ -4,8 +4,119 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { describe, it, expect } from 'vitest'; -import { hasCycleInSchema } from './tools.js'; // Added getStringifiedResultForDisplay +import { describe, it, expect, vi } from 'vitest'; +import { + DeclarativeTool, + hasCycleInSchema, + Kind, + ToolInvocation, + ToolResult, +} from './tools.js'; +import { ToolErrorType } from './tool-error.js'; + +class TestToolInvocation implements ToolInvocation<object, ToolResult> { + constructor( + readonly params: object, + private readonly executeFn: () => Promise<ToolResult>, + ) {} + + getDescription(): string { + return 'A test invocation'; + } + + toolLocations() { + return []; + } + + shouldConfirmExecute(): Promise<false> { + return Promise.resolve(false); + } + + execute(): Promise<ToolResult> { + return this.executeFn(); + } +} + +class TestTool extends DeclarativeTool<object, ToolResult> { + private readonly buildFn: (params: object) => TestToolInvocation; + + constructor(buildFn: (params: object) => TestToolInvocation) { + super('test-tool', 'Test Tool', 'A tool for testing', Kind.Other, {}); + this.buildFn = buildFn; + } + + build(params: object): ToolInvocation<object, ToolResult> { + return this.buildFn(params); + } +} + +describe('DeclarativeTool', () => { + describe('validateBuildAndExecute', () => { + const abortSignal = new AbortController().signal; + + it('should return INVALID_TOOL_PARAMS error if build fails', async () => { + const buildError = new Error('Invalid build parameters'); + const buildFn = vi.fn().mockImplementation(() => { + throw buildError; + }); + const tool = new TestTool(buildFn); + const params = { foo: 'bar' }; + + const result = await tool.validateBuildAndExecute(params, abortSignal); + + expect(buildFn).toHaveBeenCalledWith(params); + expect(result).toEqual({ + llmContent: `Error: Invalid parameters provided. Reason: ${buildError.message}`, + returnDisplay: buildError.message, + error: { + message: buildError.message, + type: ToolErrorType.INVALID_TOOL_PARAMS, + }, + }); + }); + + it('should return EXECUTION_FAILED error if execute fails', async () => { + const executeError = new Error('Execution failed'); + const executeFn = vi.fn().mockRejectedValue(executeError); + const invocation = new TestToolInvocation({}, executeFn); + const buildFn = vi.fn().mockReturnValue(invocation); + const tool = new TestTool(buildFn); + const params = { foo: 'bar' }; + + const result = await tool.validateBuildAndExecute(params, abortSignal); + + expect(buildFn).toHaveBeenCalledWith(params); + expect(executeFn).toHaveBeenCalled(); + expect(result).toEqual({ + llmContent: `Error: Tool call execution failed. Reason: ${executeError.message}`, + returnDisplay: executeError.message, + error: { + message: executeError.message, + type: ToolErrorType.EXECUTION_FAILED, + }, + }); + }); + + it('should return the result of execute on success', async () => { + const successResult: ToolResult = { + llmContent: 'Success!', + returnDisplay: 'Success!', + summary: 'Tool executed successfully', + }; + const executeFn = vi.fn().mockResolvedValue(successResult); + const invocation = new TestToolInvocation({}, executeFn); + const buildFn = vi.fn().mockReturnValue(invocation); + const tool = new TestTool(buildFn); + const params = { foo: 'bar' }; + + const result = await tool.validateBuildAndExecute(params, abortSignal); + + expect(buildFn).toHaveBeenCalledWith(params); + expect(executeFn).toHaveBeenCalled(); + expect(result).toEqual(successResult); + }); + }); +}); describe('hasCycleInSchema', () => { it('should detect a simple direct cycle', () => { |
