diff options
| author | joshualitt <[email protected]> | 2025-08-06 10:50:02 -0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-08-06 17:50:02 +0000 |
| commit | 6133bea388a2de69c71a6be6f1450707f2ce4dfb (patch) | |
| tree | 367de1d618069ea80e47d7e86c4fb8f82ad032a7 /packages/cli/src/ui/hooks/useToolScheduler.test.ts | |
| parent | 882a97aff998b2f19731e9966d135f1db5a59914 (diff) | |
feat(core): Introduce `DeclarativeTool` and `ToolInvocation`. (#5613)
Diffstat (limited to 'packages/cli/src/ui/hooks/useToolScheduler.test.ts')
| -rw-r--r-- | packages/cli/src/ui/hooks/useToolScheduler.test.ts | 180 |
1 files changed, 97 insertions, 83 deletions
diff --git a/packages/cli/src/ui/hooks/useToolScheduler.test.ts b/packages/cli/src/ui/hooks/useToolScheduler.test.ts index 5395d18a..ee5251d3 100644 --- a/packages/cli/src/ui/hooks/useToolScheduler.test.ts +++ b/packages/cli/src/ui/hooks/useToolScheduler.test.ts @@ -15,7 +15,6 @@ import { PartUnion, FunctionResponse } from '@google/genai'; import { Config, ToolCallRequestInfo, - Tool, ToolRegistry, ToolResult, ToolCallConfirmationDetails, @@ -25,6 +24,9 @@ import { Status as ToolCallStatusType, ApprovalMode, Icon, + BaseTool, + AnyDeclarativeTool, + AnyToolInvocation, } from '@google/gemini-cli-core'; import { HistoryItemWithoutId, @@ -53,46 +55,55 @@ const mockConfig = { getDebugMode: () => false, }; -const mockTool: Tool = { - name: 'mockTool', - displayName: 'Mock Tool', - description: 'A mock tool for testing', - icon: Icon.Hammer, - toolLocations: vi.fn(), - isOutputMarkdown: false, - canUpdateOutput: false, - schema: {}, - validateToolParams: vi.fn(), - execute: vi.fn(), - shouldConfirmExecute: vi.fn(), - getDescription: vi.fn((args) => `Description for ${JSON.stringify(args)}`), -}; +class MockTool extends BaseTool<object, ToolResult> { + constructor( + name: string, + displayName: string, + canUpdateOutput = false, + shouldConfirm = false, + isOutputMarkdown = false, + ) { + super( + name, + displayName, + 'A mock tool for testing', + Icon.Hammer, + {}, + isOutputMarkdown, + canUpdateOutput, + ); + if (shouldConfirm) { + this.shouldConfirmExecute = vi.fn( + async (): Promise<ToolCallConfirmationDetails | false> => ({ + type: 'edit', + title: 'Mock Tool Requires Confirmation', + onConfirm: mockOnUserConfirmForToolConfirmation, + fileName: 'mockToolRequiresConfirmation.ts', + fileDiff: 'Mock tool requires confirmation', + originalContent: 'Original content', + newContent: 'New content', + }), + ); + } + } -const mockToolWithLiveOutput: Tool = { - ...mockTool, - name: 'mockToolWithLiveOutput', - displayName: 'Mock Tool With Live Output', - canUpdateOutput: true, -}; + execute = vi.fn(); + shouldConfirmExecute = vi.fn(); +} +const mockTool = new MockTool('mockTool', 'Mock Tool'); +const mockToolWithLiveOutput = new MockTool( + 'mockToolWithLiveOutput', + 'Mock Tool With Live Output', + true, +); let mockOnUserConfirmForToolConfirmation: Mock; - -const mockToolRequiresConfirmation: Tool = { - ...mockTool, - name: 'mockToolRequiresConfirmation', - displayName: 'Mock Tool Requires Confirmation', - shouldConfirmExecute: vi.fn( - async (): Promise<ToolCallConfirmationDetails | false> => ({ - type: 'edit', - title: 'Mock Tool Requires Confirmation', - onConfirm: mockOnUserConfirmForToolConfirmation, - fileName: 'mockToolRequiresConfirmation.ts', - fileDiff: 'Mock tool requires confirmation', - originalContent: 'Original content', - newContent: 'New content', - }), - ), -}; +const mockToolRequiresConfirmation = new MockTool( + 'mockToolRequiresConfirmation', + 'Mock Tool Requires Confirmation', + false, + true, +); describe('useReactToolScheduler in YOLO Mode', () => { let onComplete: Mock; @@ -646,28 +657,21 @@ describe('useReactToolScheduler', () => { }); it('should schedule and execute multiple tool calls', async () => { - const tool1 = { - ...mockTool, - name: 'tool1', - displayName: 'Tool 1', - execute: vi.fn().mockResolvedValue({ - llmContent: 'Output 1', - returnDisplay: 'Display 1', - summary: 'Summary 1', - } as ToolResult), - shouldConfirmExecute: vi.fn().mockResolvedValue(null), - }; - const tool2 = { - ...mockTool, - name: 'tool2', - displayName: 'Tool 2', - execute: vi.fn().mockResolvedValue({ - llmContent: 'Output 2', - returnDisplay: 'Display 2', - summary: 'Summary 2', - } as ToolResult), - shouldConfirmExecute: vi.fn().mockResolvedValue(null), - }; + const tool1 = new MockTool('tool1', 'Tool 1'); + tool1.execute.mockResolvedValue({ + llmContent: 'Output 1', + returnDisplay: 'Display 1', + summary: 'Summary 1', + } as ToolResult); + tool1.shouldConfirmExecute.mockResolvedValue(null); + + const tool2 = new MockTool('tool2', 'Tool 2'); + tool2.execute.mockResolvedValue({ + llmContent: 'Output 2', + returnDisplay: 'Display 2', + summary: 'Summary 2', + } as ToolResult); + tool2.shouldConfirmExecute.mockResolvedValue(null); mockToolRegistry.getTool.mockImplementation((name) => { if (name === 'tool1') return tool1; @@ -805,20 +809,7 @@ describe('mapToDisplay', () => { args: { foo: 'bar' }, }; - const baseTool: Tool = { - name: 'testTool', - displayName: 'Test Tool Display', - description: 'Test Description', - isOutputMarkdown: false, - canUpdateOutput: false, - schema: {}, - icon: Icon.Hammer, - toolLocations: vi.fn(), - validateToolParams: vi.fn(), - execute: vi.fn(), - shouldConfirmExecute: vi.fn(), - getDescription: vi.fn((args) => `Desc: ${JSON.stringify(args)}`), - }; + const baseTool = new MockTool('testTool', 'Test Tool Display'); const baseResponse: ToolCallResponseInfo = { callId: 'testCallId', @@ -840,13 +831,15 @@ describe('mapToDisplay', () => { // This helps ensure that tool and confirmationDetails are only accessed when they are expected to exist. type MapToDisplayExtraProps = | { - tool?: Tool; + tool?: AnyDeclarativeTool; + invocation?: AnyToolInvocation; liveOutput?: string; response?: ToolCallResponseInfo; confirmationDetails?: ToolCallConfirmationDetails; } | { - tool: Tool; + tool: AnyDeclarativeTool; + invocation?: AnyToolInvocation; response?: ToolCallResponseInfo; confirmationDetails?: ToolCallConfirmationDetails; } @@ -857,10 +850,12 @@ describe('mapToDisplay', () => { } | { confirmationDetails: ToolCallConfirmationDetails; - tool?: Tool; + tool?: AnyDeclarativeTool; + invocation?: AnyToolInvocation; response?: ToolCallResponseInfo; }; + const baseInvocation = baseTool.build(baseRequest.args); const testCases: Array<{ name: string; status: ToolCallStatusType; @@ -873,7 +868,7 @@ describe('mapToDisplay', () => { { name: 'validating', status: 'validating', - extraProps: { tool: baseTool }, + extraProps: { tool: baseTool, invocation: baseInvocation }, expectedStatus: ToolCallStatus.Executing, expectedName: baseTool.displayName, expectedDescription: baseTool.getDescription(baseRequest.args), @@ -883,6 +878,7 @@ describe('mapToDisplay', () => { status: 'awaiting_approval', extraProps: { tool: baseTool, + invocation: baseInvocation, confirmationDetails: { onConfirm: vi.fn(), type: 'edit', @@ -903,7 +899,7 @@ describe('mapToDisplay', () => { { name: 'scheduled', status: 'scheduled', - extraProps: { tool: baseTool }, + extraProps: { tool: baseTool, invocation: baseInvocation }, expectedStatus: ToolCallStatus.Pending, expectedName: baseTool.displayName, expectedDescription: baseTool.getDescription(baseRequest.args), @@ -911,7 +907,7 @@ describe('mapToDisplay', () => { { name: 'executing no live output', status: 'executing', - extraProps: { tool: baseTool }, + extraProps: { tool: baseTool, invocation: baseInvocation }, expectedStatus: ToolCallStatus.Executing, expectedName: baseTool.displayName, expectedDescription: baseTool.getDescription(baseRequest.args), @@ -919,7 +915,11 @@ describe('mapToDisplay', () => { { name: 'executing with live output', status: 'executing', - extraProps: { tool: baseTool, liveOutput: 'Live test output' }, + extraProps: { + tool: baseTool, + invocation: baseInvocation, + liveOutput: 'Live test output', + }, expectedStatus: ToolCallStatus.Executing, expectedResultDisplay: 'Live test output', expectedName: baseTool.displayName, @@ -928,7 +928,11 @@ describe('mapToDisplay', () => { { name: 'success', status: 'success', - extraProps: { tool: baseTool, response: baseResponse }, + extraProps: { + tool: baseTool, + invocation: baseInvocation, + response: baseResponse, + }, expectedStatus: ToolCallStatus.Success, expectedResultDisplay: baseResponse.resultDisplay as any, expectedName: baseTool.displayName, @@ -970,6 +974,7 @@ describe('mapToDisplay', () => { status: 'cancelled', extraProps: { tool: baseTool, + invocation: baseInvocation, response: { ...baseResponse, resultDisplay: 'Cancelled display', @@ -1030,12 +1035,21 @@ describe('mapToDisplay', () => { request: { ...baseRequest, callId: 'call1' }, status: 'success', tool: baseTool, + invocation: baseTool.build(baseRequest.args), response: { ...baseResponse, callId: 'call1' }, } as ToolCall; + const toolForCall2 = new MockTool( + baseTool.name, + baseTool.displayName, + false, + false, + true, + ); const toolCall2: ToolCall = { request: { ...baseRequest, callId: 'call2' }, status: 'executing', - tool: { ...baseTool, isOutputMarkdown: true }, + tool: toolForCall2, + invocation: toolForCall2.build(baseRequest.args), liveOutput: 'markdown output', } as ToolCall; |
