summaryrefslogtreecommitdiff
path: root/packages/core/src
diff options
context:
space:
mode:
authorLeeroy Ding <[email protected]>2025-07-27 22:42:26 +0100
committerGitHub <[email protected]>2025-07-27 21:42:26 +0000
commit9ca48c00a6bfbf8fd25bebfb703ef299c0e38ae2 (patch)
treef04c1f455e814680a504d8351432dbde32713af3 /packages/core/src
parent0b5cc9636243574c4212e969621ea65f03e7e88a (diff)
fix: yolo mode not respected (#4972)
Diffstat (limited to 'packages/core/src')
-rw-r--r--packages/core/src/core/coreToolScheduler.test.ts86
-rw-r--r--packages/core/src/core/coreToolScheduler.ts5
2 files changed, 87 insertions, 4 deletions
diff --git a/packages/core/src/core/coreToolScheduler.test.ts b/packages/core/src/core/coreToolScheduler.test.ts
index 7b6a130c..80651a14 100644
--- a/packages/core/src/core/coreToolScheduler.test.ts
+++ b/packages/core/src/core/coreToolScheduler.test.ts
@@ -20,6 +20,7 @@ import {
ToolResult,
Config,
Icon,
+ ApprovalMode,
} from '../index.js';
import { Part, PartListUnion } from '@google/genai';
@@ -126,6 +127,7 @@ describe('CoreToolScheduler', () => {
getSessionId: () => 'test-session-id',
getUsageStatisticsEnabled: () => true,
getDebugMode: () => false,
+ getApprovalMode: () => ApprovalMode.DEFAULT,
} as unknown as Config;
const scheduler = new CoreToolScheduler({
@@ -194,6 +196,7 @@ describe('CoreToolScheduler with payload', () => {
getSessionId: () => 'test-session-id',
getUsageStatisticsEnabled: () => true,
getDebugMode: () => false,
+ getApprovalMode: () => ApprovalMode.DEFAULT,
} as unknown as Config;
const scheduler = new CoreToolScheduler({
@@ -470,6 +473,7 @@ describe('CoreToolScheduler edit cancellation', () => {
getSessionId: () => 'test-session-id',
getUsageStatisticsEnabled: () => true,
getDebugMode: () => false,
+ getApprovalMode: () => ApprovalMode.DEFAULT,
} as unknown as Config;
const scheduler = new CoreToolScheduler({
@@ -527,3 +531,85 @@ describe('CoreToolScheduler edit cancellation', () => {
expect(cancelledCall.response.resultDisplay.fileName).toBe('test.txt');
});
});
+
+describe('CoreToolScheduler YOLO mode', () => {
+ it('should execute tool requiring confirmation directly without waiting', async () => {
+ // Arrange
+ const mockTool = new MockTool();
+ // This tool would normally require confirmation.
+ mockTool.shouldConfirm = true;
+
+ const toolRegistry = {
+ getTool: () => mockTool,
+ getToolByName: () => mockTool,
+ // Other properties are not needed for this test but are included for type consistency.
+ getFunctionDeclarations: () => [],
+ tools: new Map(),
+ discovery: {} as any,
+ registerTool: () => {},
+ getToolByDisplayName: () => mockTool,
+ getTools: () => [],
+ discoverTools: async () => {},
+ getAllTools: () => [],
+ getToolsByServer: () => [],
+ };
+
+ const onAllToolCallsComplete = vi.fn();
+ const onToolCallsUpdate = vi.fn();
+
+ // Configure the scheduler for YOLO mode.
+ const mockConfig = {
+ getSessionId: () => 'test-session-id',
+ getUsageStatisticsEnabled: () => true,
+ getDebugMode: () => false,
+ getApprovalMode: () => ApprovalMode.YOLO,
+ } as unknown as Config;
+
+ const scheduler = new CoreToolScheduler({
+ config: mockConfig,
+ toolRegistry: Promise.resolve(toolRegistry as any),
+ onAllToolCallsComplete,
+ onToolCallsUpdate,
+ getPreferredEditor: () => 'vscode',
+ });
+
+ const abortController = new AbortController();
+ const request = {
+ callId: '1',
+ name: 'mockTool',
+ args: { param: 'value' },
+ isClientInitiated: false,
+ prompt_id: 'prompt-id-yolo',
+ };
+
+ // Act
+ await scheduler.schedule([request], abortController.signal);
+
+ // Assert
+ // 1. The tool's execute method was called directly.
+ expect(mockTool.executeFn).toHaveBeenCalledWith({ param: 'value' });
+
+ // 2. The tool call status never entered 'awaiting_approval'.
+ const statusUpdates = onToolCallsUpdate.mock.calls
+ .map((call) => (call[0][0] as ToolCall)?.status)
+ .filter(Boolean);
+ expect(statusUpdates).not.toContain('awaiting_approval');
+ expect(statusUpdates).toEqual([
+ 'validating',
+ 'scheduled',
+ 'executing',
+ 'success',
+ ]);
+
+ // 3. The final callback indicates the tool call was successful.
+ expect(onAllToolCallsComplete).toHaveBeenCalled();
+ const completedCalls = onAllToolCallsComplete.mock
+ .calls[0][0] as ToolCall[];
+ expect(completedCalls).toHaveLength(1);
+ const completedCall = completedCalls[0];
+ expect(completedCall.status).toBe('success');
+ if (completedCall.status === 'success') {
+ expect(completedCall.response.resultDisplay).toBe('Tool executed');
+ }
+ });
+});
diff --git a/packages/core/src/core/coreToolScheduler.ts b/packages/core/src/core/coreToolScheduler.ts
index 0d7d5923..af078faa 100644
--- a/packages/core/src/core/coreToolScheduler.ts
+++ b/packages/core/src/core/coreToolScheduler.ts
@@ -219,7 +219,6 @@ interface CoreToolSchedulerOptions {
outputUpdateHandler?: OutputUpdateHandler;
onAllToolCallsComplete?: AllToolCallsCompleteHandler;
onToolCallsUpdate?: ToolCallsUpdateHandler;
- approvalMode?: ApprovalMode;
getPreferredEditor: () => EditorType | undefined;
config: Config;
}
@@ -230,7 +229,6 @@ export class CoreToolScheduler {
private outputUpdateHandler?: OutputUpdateHandler;
private onAllToolCallsComplete?: AllToolCallsCompleteHandler;
private onToolCallsUpdate?: ToolCallsUpdateHandler;
- private approvalMode: ApprovalMode;
private getPreferredEditor: () => EditorType | undefined;
private config: Config;
@@ -240,7 +238,6 @@ export class CoreToolScheduler {
this.outputUpdateHandler = options.outputUpdateHandler;
this.onAllToolCallsComplete = options.onAllToolCallsComplete;
this.onToolCallsUpdate = options.onToolCallsUpdate;
- this.approvalMode = options.approvalMode ?? ApprovalMode.DEFAULT;
this.getPreferredEditor = options.getPreferredEditor;
}
@@ -462,7 +459,7 @@ export class CoreToolScheduler {
const { request: reqInfo, tool: toolInstance } = toolCall;
try {
- if (this.approvalMode === ApprovalMode.YOLO) {
+ if (this.config.getApprovalMode() === ApprovalMode.YOLO) {
this.setStatusInternal(reqInfo.callId, 'scheduled');
} else {
const confirmationDetails = await toolInstance.shouldConfirmExecute(