mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-19 09:33:53 +00:00
feat(core): Migrate MockTools to declarative pattern. (#6197)
This commit is contained in:
@@ -24,7 +24,9 @@ import {
|
||||
Status as ToolCallStatusType,
|
||||
ApprovalMode,
|
||||
Kind,
|
||||
BaseTool,
|
||||
BaseDeclarativeTool,
|
||||
BaseToolInvocation,
|
||||
ToolInvocation,
|
||||
AnyDeclarativeTool,
|
||||
AnyToolInvocation,
|
||||
} from '@google/gemini-cli-core';
|
||||
@@ -62,7 +64,41 @@ const mockConfig = {
|
||||
getDebugMode: () => false,
|
||||
};
|
||||
|
||||
class MockTool extends BaseTool<object, ToolResult> {
|
||||
class MockToolInvocation extends BaseToolInvocation<object, ToolResult> {
|
||||
constructor(
|
||||
private readonly tool: MockTool,
|
||||
params: object,
|
||||
) {
|
||||
super(params);
|
||||
}
|
||||
|
||||
getDescription(): string {
|
||||
return JSON.stringify(this.params);
|
||||
}
|
||||
|
||||
override shouldConfirmExecute(
|
||||
abortSignal: AbortSignal,
|
||||
): Promise<ToolCallConfirmationDetails | false> {
|
||||
return this.tool.shouldConfirmExecute(this.params, abortSignal);
|
||||
}
|
||||
|
||||
execute(
|
||||
signal: AbortSignal,
|
||||
updateOutput?: (output: string) => void,
|
||||
terminalColumns?: number,
|
||||
terminalRows?: number,
|
||||
): Promise<ToolResult> {
|
||||
return this.tool.execute(
|
||||
this.params,
|
||||
signal,
|
||||
updateOutput,
|
||||
terminalColumns,
|
||||
terminalRows,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MockTool extends BaseDeclarativeTool<object, ToolResult> {
|
||||
constructor(
|
||||
name: string,
|
||||
displayName: string,
|
||||
@@ -80,11 +116,12 @@ class MockTool extends BaseTool<object, ToolResult> {
|
||||
canUpdateOutput,
|
||||
);
|
||||
if (shouldConfirm) {
|
||||
this.shouldConfirmExecute = vi.fn(
|
||||
this.shouldConfirmExecute.mockImplementation(
|
||||
async (): Promise<ToolCallConfirmationDetails | false> => ({
|
||||
type: 'edit',
|
||||
title: 'Mock Tool Requires Confirmation',
|
||||
onConfirm: mockOnUserConfirmForToolConfirmation,
|
||||
filePath: 'mock',
|
||||
fileName: 'mockToolRequiresConfirmation.ts',
|
||||
fileDiff: 'Mock tool requires confirmation',
|
||||
originalContent: 'Original content',
|
||||
@@ -96,6 +133,12 @@ class MockTool extends BaseTool<object, ToolResult> {
|
||||
|
||||
execute = vi.fn();
|
||||
shouldConfirmExecute = vi.fn();
|
||||
|
||||
protected createInvocation(
|
||||
params: object,
|
||||
): ToolInvocation<object, ToolResult> {
|
||||
return new MockToolInvocation(this, params);
|
||||
}
|
||||
}
|
||||
|
||||
const mockTool = new MockTool('mockTool', 'Mock Tool');
|
||||
@@ -142,6 +185,8 @@ describe('useReactToolScheduler in YOLO Mode', () => {
|
||||
onComplete,
|
||||
mockConfig as unknown as Config,
|
||||
setPendingHistoryItem,
|
||||
() => undefined,
|
||||
() => {},
|
||||
),
|
||||
);
|
||||
|
||||
@@ -160,7 +205,7 @@ describe('useReactToolScheduler in YOLO Mode', () => {
|
||||
callId: 'yoloCall',
|
||||
name: 'mockToolRequiresConfirmation',
|
||||
args: { data: 'any data' },
|
||||
};
|
||||
} as any;
|
||||
|
||||
act(() => {
|
||||
schedule(request, new AbortController().signal);
|
||||
@@ -270,13 +315,14 @@ describe('useReactToolScheduler', () => {
|
||||
(
|
||||
mockToolRequiresConfirmation.shouldConfirmExecute as Mock
|
||||
).mockImplementation(
|
||||
async (): Promise<ToolCallConfirmationDetails | null> => ({
|
||||
onConfirm: mockOnUserConfirmForToolConfirmation,
|
||||
fileName: 'mockToolRequiresConfirmation.ts',
|
||||
fileDiff: 'Mock tool requires confirmation',
|
||||
type: 'edit',
|
||||
title: 'Mock Tool Requires Confirmation',
|
||||
}),
|
||||
async (): Promise<ToolCallConfirmationDetails | null> =>
|
||||
({
|
||||
onConfirm: mockOnUserConfirmForToolConfirmation,
|
||||
fileName: 'mockToolRequiresConfirmation.ts',
|
||||
fileDiff: 'Mock tool requires confirmation',
|
||||
type: 'edit',
|
||||
title: 'Mock Tool Requires Confirmation',
|
||||
}) as any,
|
||||
);
|
||||
|
||||
vi.useFakeTimers();
|
||||
@@ -293,6 +339,8 @@ describe('useReactToolScheduler', () => {
|
||||
onComplete,
|
||||
mockConfig as unknown as Config,
|
||||
setPendingHistoryItem,
|
||||
() => undefined,
|
||||
() => {},
|
||||
),
|
||||
);
|
||||
|
||||
@@ -316,7 +364,7 @@ describe('useReactToolScheduler', () => {
|
||||
callId: 'call1',
|
||||
name: 'mockTool',
|
||||
args: { param: 'value' },
|
||||
};
|
||||
} as any;
|
||||
|
||||
act(() => {
|
||||
schedule(request, new AbortController().signal);
|
||||
@@ -365,7 +413,7 @@ describe('useReactToolScheduler', () => {
|
||||
callId: 'call1',
|
||||
name: 'nonexistentTool',
|
||||
args: {},
|
||||
};
|
||||
} as any;
|
||||
|
||||
act(() => {
|
||||
schedule(request, new AbortController().signal);
|
||||
@@ -402,7 +450,7 @@ describe('useReactToolScheduler', () => {
|
||||
callId: 'call1',
|
||||
name: 'mockTool',
|
||||
args: {},
|
||||
};
|
||||
} as any;
|
||||
|
||||
act(() => {
|
||||
schedule(request, new AbortController().signal);
|
||||
@@ -438,7 +486,7 @@ describe('useReactToolScheduler', () => {
|
||||
callId: 'call1',
|
||||
name: 'mockTool',
|
||||
args: {},
|
||||
};
|
||||
} as any;
|
||||
|
||||
act(() => {
|
||||
schedule(request, new AbortController().signal);
|
||||
@@ -480,7 +528,7 @@ describe('useReactToolScheduler', () => {
|
||||
callId: 'callConfirm',
|
||||
name: 'mockToolRequiresConfirmation',
|
||||
args: { data: 'sensitive' },
|
||||
};
|
||||
} as any;
|
||||
|
||||
act(() => {
|
||||
schedule(request, new AbortController().signal);
|
||||
@@ -536,7 +584,7 @@ describe('useReactToolScheduler', () => {
|
||||
callId: 'callConfirmCancel',
|
||||
name: 'mockToolRequiresConfirmation',
|
||||
args: {},
|
||||
};
|
||||
} as any;
|
||||
|
||||
act(() => {
|
||||
schedule(request, new AbortController().signal);
|
||||
@@ -608,7 +656,7 @@ describe('useReactToolScheduler', () => {
|
||||
callId: 'liveCall',
|
||||
name: 'mockToolWithLiveOutput',
|
||||
args: {},
|
||||
};
|
||||
} as any;
|
||||
|
||||
act(() => {
|
||||
schedule(request, new AbortController().signal);
|
||||
@@ -693,8 +741,8 @@ describe('useReactToolScheduler', () => {
|
||||
const { result } = renderScheduler();
|
||||
const schedule = result.current[1];
|
||||
const requests: ToolCallRequestInfo[] = [
|
||||
{ callId: 'multi1', name: 'tool1', args: { p: 1 } },
|
||||
{ callId: 'multi2', name: 'tool2', args: { p: 2 } },
|
||||
{ callId: 'multi1', name: 'tool1', args: { p: 1 } } as any,
|
||||
{ callId: 'multi2', name: 'tool2', args: { p: 2 } } as any,
|
||||
];
|
||||
|
||||
act(() => {
|
||||
@@ -777,12 +825,12 @@ describe('useReactToolScheduler', () => {
|
||||
callId: 'run1',
|
||||
name: 'mockTool',
|
||||
args: {},
|
||||
};
|
||||
} as any;
|
||||
const request2: ToolCallRequestInfo = {
|
||||
callId: 'run2',
|
||||
name: 'mockTool',
|
||||
args: {},
|
||||
};
|
||||
} as any;
|
||||
|
||||
act(() => {
|
||||
schedule(request1, new AbortController().signal);
|
||||
@@ -818,7 +866,7 @@ describe('mapToDisplay', () => {
|
||||
callId: 'testCallId',
|
||||
name: 'testTool',
|
||||
args: { foo: 'bar' },
|
||||
};
|
||||
} as any;
|
||||
|
||||
const baseTool = new MockTool('testTool', 'Test Tool Display');
|
||||
|
||||
@@ -834,9 +882,8 @@ describe('mapToDisplay', () => {
|
||||
} as PartUnion,
|
||||
],
|
||||
resultDisplay: 'Test display output',
|
||||
summary: 'Test summary',
|
||||
error: undefined,
|
||||
};
|
||||
} as any;
|
||||
|
||||
// Define a more specific type for extraProps for these tests
|
||||
// This helps ensure that tool and confirmationDetails are only accessed when they are expected to exist.
|
||||
@@ -882,7 +929,7 @@ describe('mapToDisplay', () => {
|
||||
extraProps: { tool: baseTool, invocation: baseInvocation },
|
||||
expectedStatus: ToolCallStatus.Executing,
|
||||
expectedName: baseTool.displayName,
|
||||
expectedDescription: baseTool.getDescription(baseRequest.args),
|
||||
expectedDescription: baseInvocation.getDescription(),
|
||||
},
|
||||
{
|
||||
name: 'awaiting_approval',
|
||||
@@ -897,6 +944,7 @@ describe('mapToDisplay', () => {
|
||||
serverName: 'testTool',
|
||||
toolName: 'testTool',
|
||||
toolDisplayName: 'Test Tool Display',
|
||||
filePath: 'mock',
|
||||
fileName: 'test.ts',
|
||||
fileDiff: 'Test diff',
|
||||
originalContent: 'Original content',
|
||||
@@ -905,7 +953,7 @@ describe('mapToDisplay', () => {
|
||||
},
|
||||
expectedStatus: ToolCallStatus.Confirming,
|
||||
expectedName: baseTool.displayName,
|
||||
expectedDescription: baseTool.getDescription(baseRequest.args),
|
||||
expectedDescription: baseInvocation.getDescription(),
|
||||
},
|
||||
{
|
||||
name: 'scheduled',
|
||||
@@ -913,7 +961,7 @@ describe('mapToDisplay', () => {
|
||||
extraProps: { tool: baseTool, invocation: baseInvocation },
|
||||
expectedStatus: ToolCallStatus.Pending,
|
||||
expectedName: baseTool.displayName,
|
||||
expectedDescription: baseTool.getDescription(baseRequest.args),
|
||||
expectedDescription: baseInvocation.getDescription(),
|
||||
},
|
||||
{
|
||||
name: 'executing no live output',
|
||||
@@ -921,7 +969,7 @@ describe('mapToDisplay', () => {
|
||||
extraProps: { tool: baseTool, invocation: baseInvocation },
|
||||
expectedStatus: ToolCallStatus.Executing,
|
||||
expectedName: baseTool.displayName,
|
||||
expectedDescription: baseTool.getDescription(baseRequest.args),
|
||||
expectedDescription: baseInvocation.getDescription(),
|
||||
},
|
||||
{
|
||||
name: 'executing with live output',
|
||||
@@ -934,7 +982,7 @@ describe('mapToDisplay', () => {
|
||||
expectedStatus: ToolCallStatus.Executing,
|
||||
expectedResultDisplay: 'Live test output',
|
||||
expectedName: baseTool.displayName,
|
||||
expectedDescription: baseTool.getDescription(baseRequest.args),
|
||||
expectedDescription: baseInvocation.getDescription(),
|
||||
},
|
||||
{
|
||||
name: 'success',
|
||||
@@ -947,7 +995,7 @@ describe('mapToDisplay', () => {
|
||||
expectedStatus: ToolCallStatus.Success,
|
||||
expectedResultDisplay: baseResponse.resultDisplay as any,
|
||||
expectedName: baseTool.displayName,
|
||||
expectedDescription: baseTool.getDescription(baseRequest.args),
|
||||
expectedDescription: baseInvocation.getDescription(),
|
||||
},
|
||||
{
|
||||
name: 'error tool not found',
|
||||
@@ -978,7 +1026,7 @@ describe('mapToDisplay', () => {
|
||||
expectedStatus: ToolCallStatus.Error,
|
||||
expectedResultDisplay: 'Execution failed display',
|
||||
expectedName: baseTool.displayName, // Changed from baseTool.name
|
||||
expectedDescription: baseTool.getDescription(baseRequest.args),
|
||||
expectedDescription: baseInvocation.getDescription(),
|
||||
},
|
||||
{
|
||||
name: 'cancelled',
|
||||
@@ -994,7 +1042,7 @@ describe('mapToDisplay', () => {
|
||||
expectedStatus: ToolCallStatus.Canceled,
|
||||
expectedResultDisplay: 'Cancelled display',
|
||||
expectedName: baseTool.displayName,
|
||||
expectedDescription: baseTool.getDescription(baseRequest.args),
|
||||
expectedDescription: baseInvocation.getDescription(),
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user