@google/gemini-cli-core 0.12.0-nightly.20251023.c4c0c0d1 → 0.12.0-preview.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -5
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/src/agents/subagent-tool-wrapper.test.js +2 -4
- package/dist/src/agents/subagent-tool-wrapper.test.js.map +1 -1
- package/dist/src/code_assist/oauth2.d.ts +2 -2
- package/dist/src/code_assist/oauth2.js +53 -41
- package/dist/src/code_assist/oauth2.js.map +1 -1
- package/dist/src/code_assist/oauth2.test.js +65 -33
- package/dist/src/code_assist/oauth2.test.js.map +1 -1
- package/dist/src/code_assist/server.d.ts +3 -3
- package/dist/src/code_assist/server.js.map +1 -1
- package/dist/src/code_assist/setup.d.ts +2 -2
- package/dist/src/code_assist/setup.js.map +1 -1
- package/dist/src/config/config.d.ts +12 -3
- package/dist/src/config/config.js +35 -9
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/config.test.js +58 -21
- package/dist/src/config/config.test.js.map +1 -1
- package/dist/src/config/storage.d.ts +1 -0
- package/dist/src/config/storage.js +3 -0
- package/dist/src/config/storage.js.map +1 -1
- package/dist/src/core/client.d.ts +1 -11
- package/dist/src/core/client.js +17 -165
- package/dist/src/core/client.js.map +1 -1
- package/dist/src/core/client.test.js +70 -405
- package/dist/src/core/client.test.js.map +1 -1
- package/dist/src/core/contentGenerator.js +39 -28
- package/dist/src/core/contentGenerator.js.map +1 -1
- package/dist/src/core/contentGenerator.test.js +28 -0
- package/dist/src/core/contentGenerator.test.js.map +1 -1
- package/dist/src/core/coreToolScheduler.d.ts +7 -7
- package/dist/src/core/coreToolScheduler.js +312 -183
- package/dist/src/core/coreToolScheduler.js.map +1 -1
- package/dist/src/core/coreToolScheduler.test.js +239 -9
- package/dist/src/core/coreToolScheduler.test.js.map +1 -1
- package/dist/src/core/fakeContentGenerator.d.ts +33 -0
- package/dist/src/core/fakeContentGenerator.js +58 -0
- package/dist/src/core/fakeContentGenerator.js.map +1 -0
- package/dist/src/core/fakeContentGenerator.test.d.ts +6 -0
- package/dist/src/core/fakeContentGenerator.test.js +127 -0
- package/dist/src/core/fakeContentGenerator.test.js.map +1 -0
- package/dist/src/core/loggingContentGenerator.d.ts +1 -0
- package/dist/src/core/loggingContentGenerator.js +113 -33
- package/dist/src/core/loggingContentGenerator.js.map +1 -1
- package/dist/src/core/nonInteractiveToolExecutor.js +5 -4
- package/dist/src/core/nonInteractiveToolExecutor.js.map +1 -1
- package/dist/src/core/prompts.test.js +30 -108
- package/dist/src/core/prompts.test.js.map +1 -1
- package/dist/src/core/recordingContentGenerator.d.ts +18 -0
- package/dist/src/core/recordingContentGenerator.js +77 -0
- package/dist/src/core/recordingContentGenerator.js.map +1 -0
- package/dist/src/core/recordingContentGenerator.test.d.ts +6 -0
- package/dist/src/core/recordingContentGenerator.test.js +101 -0
- package/dist/src/core/recordingContentGenerator.test.js.map +1 -0
- package/dist/src/fallback/handler.js +2 -0
- package/dist/src/fallback/handler.js.map +1 -1
- package/dist/src/generated/git-commit.d.ts +2 -2
- package/dist/src/generated/git-commit.js +2 -2
- package/dist/src/generated/git-commit.js.map +1 -1
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +3 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp/google-auth-provider.d.ts +2 -0
- package/dist/src/mcp/google-auth-provider.js +19 -2
- package/dist/src/mcp/google-auth-provider.js.map +1 -1
- package/dist/src/mcp/google-auth-provider.test.js +42 -9
- package/dist/src/mcp/google-auth-provider.test.js.map +1 -1
- package/dist/src/mcp/oauth-provider.js +2 -2
- package/dist/src/mcp/oauth-provider.js.map +1 -1
- package/dist/src/mcp/oauth-provider.test.js +130 -0
- package/dist/src/mcp/oauth-provider.test.js.map +1 -1
- package/dist/src/mcp/oauth-token-storage.js +5 -4
- package/dist/src/mcp/oauth-token-storage.js.map +1 -1
- package/dist/src/mcp/oauth-token-storage.test.js +17 -11
- package/dist/src/mcp/oauth-token-storage.test.js.map +1 -1
- package/dist/src/mcp/oauth-utils.d.ts +7 -0
- package/dist/src/mcp/oauth-utils.js +19 -0
- package/dist/src/mcp/oauth-utils.js.map +1 -1
- package/dist/src/mcp/oauth-utils.test.js +32 -0
- package/dist/src/mcp/oauth-utils.test.js.map +1 -1
- package/dist/src/mcp/sa-impersonation-provider.d.ts +0 -6
- package/dist/src/mcp/sa-impersonation-provider.js +6 -23
- package/dist/src/mcp/sa-impersonation-provider.js.map +1 -1
- package/dist/src/mcp/token-storage/base-token-storage.test.js +75 -84
- package/dist/src/mcp/token-storage/base-token-storage.test.js.map +1 -1
- package/dist/src/mcp/token-storage/keychain-token-storage.d.ts +6 -2
- package/dist/src/mcp/token-storage/keychain-token-storage.js +62 -6
- package/dist/src/mcp/token-storage/keychain-token-storage.js.map +1 -1
- package/dist/src/mcp/token-storage/keychain-token-storage.test.js +54 -3
- package/dist/src/mcp/token-storage/keychain-token-storage.test.js.map +1 -1
- package/dist/src/mcp/token-storage/types.d.ts +6 -0
- package/dist/src/mcp/token-storage/types.js.map +1 -1
- package/dist/src/policy/policy-engine.js +4 -0
- package/dist/src/policy/policy-engine.js.map +1 -1
- package/dist/src/services/chatCompressionService.d.ts +32 -0
- package/dist/src/services/chatCompressionService.js +164 -0
- package/dist/src/services/chatCompressionService.js.map +1 -0
- package/dist/src/services/chatCompressionService.test.d.ts +6 -0
- package/dist/src/services/chatCompressionService.test.js +211 -0
- package/dist/src/services/chatCompressionService.test.js.map +1 -0
- package/dist/src/services/fileDiscoveryService.d.ts +0 -8
- package/dist/src/services/fileDiscoveryService.js +5 -33
- package/dist/src/services/fileDiscoveryService.js.map +1 -1
- package/dist/src/services/fileDiscoveryService.test.js +11 -11
- package/dist/src/services/fileDiscoveryService.test.js.map +1 -1
- package/dist/src/services/loopDetectionService.js +19 -9
- package/dist/src/services/loopDetectionService.js.map +1 -1
- package/dist/src/services/loopDetectionService.test.js +40 -11
- package/dist/src/services/loopDetectionService.test.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +1 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +40 -33
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js +1 -1
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js.map +1 -1
- package/dist/src/telemetry/index.d.ts +1 -0
- package/dist/src/telemetry/index.js +1 -0
- package/dist/src/telemetry/index.js.map +1 -1
- package/dist/src/telemetry/loggers.js +10 -17
- package/dist/src/telemetry/loggers.js.map +1 -1
- package/dist/src/telemetry/loggers.test.js +173 -30
- package/dist/src/telemetry/loggers.test.js.map +1 -1
- package/dist/src/telemetry/metrics.d.ts +1 -1
- package/dist/src/telemetry/metrics.js +1 -1
- package/dist/src/telemetry/metrics.js.map +1 -1
- package/dist/src/telemetry/metrics.test.js +2 -2
- package/dist/src/telemetry/metrics.test.js.map +1 -1
- package/dist/src/telemetry/semantic.d.ts +82 -0
- package/dist/src/telemetry/semantic.js +269 -0
- package/dist/src/telemetry/semantic.js.map +1 -0
- package/dist/src/telemetry/semantic.test.d.ts +6 -0
- package/dist/src/telemetry/semantic.test.js +387 -0
- package/dist/src/telemetry/semantic.test.js.map +1 -0
- package/dist/src/telemetry/trace.d.ts +46 -0
- package/dist/src/telemetry/trace.js +121 -0
- package/dist/src/telemetry/trace.js.map +1 -0
- package/dist/src/telemetry/types.d.ts +37 -18
- package/dist/src/telemetry/types.js +107 -36
- package/dist/src/telemetry/types.js.map +1 -1
- package/dist/src/telemetry/uiTelemetry.js +6 -6
- package/dist/src/telemetry/uiTelemetry.js.map +1 -1
- package/dist/src/telemetry/uiTelemetry.test.js +88 -66
- package/dist/src/telemetry/uiTelemetry.test.js.map +1 -1
- package/dist/src/tools/edit.d.ts +3 -2
- package/dist/src/tools/edit.js +15 -11
- package/dist/src/tools/edit.js.map +1 -1
- package/dist/src/tools/edit.test.js +19 -0
- package/dist/src/tools/edit.test.js.map +1 -1
- package/dist/src/tools/glob.js +4 -2
- package/dist/src/tools/glob.js.map +1 -1
- package/dist/src/tools/glob.test.js +203 -199
- package/dist/src/tools/glob.test.js.map +1 -1
- package/dist/src/tools/grep.js +2 -2
- package/dist/src/tools/grep.js.map +1 -1
- package/dist/src/tools/ls.js +2 -1
- package/dist/src/tools/ls.js.map +1 -1
- package/dist/src/tools/ls.test.js +0 -7
- package/dist/src/tools/ls.test.js.map +1 -1
- package/dist/src/tools/mcp-client-manager.js +2 -1
- package/dist/src/tools/mcp-client-manager.js.map +1 -1
- package/dist/src/tools/mcp-client.d.ts +4 -1
- package/dist/src/tools/mcp-client.js +71 -92
- package/dist/src/tools/mcp-client.js.map +1 -1
- package/dist/src/tools/mcp-client.test.js +16 -6
- package/dist/src/tools/mcp-client.test.js.map +1 -1
- package/dist/src/tools/mcp-tool.d.ts +3 -2
- package/dist/src/tools/mcp-tool.js +12 -10
- package/dist/src/tools/mcp-tool.js.map +1 -1
- package/dist/src/tools/memoryTool.d.ts +5 -3
- package/dist/src/tools/memoryTool.js +9 -7
- package/dist/src/tools/memoryTool.js.map +1 -1
- package/dist/src/tools/read-file.js +7 -3
- package/dist/src/tools/read-file.js.map +1 -1
- package/dist/src/tools/read-file.test.js +25 -2
- package/dist/src/tools/read-file.test.js.map +1 -1
- package/dist/src/tools/shell.d.ts +6 -4
- package/dist/src/tools/shell.js +18 -12
- package/dist/src/tools/shell.js.map +1 -1
- package/dist/src/tools/shell.test.js +7 -0
- package/dist/src/tools/shell.test.js.map +1 -1
- package/dist/src/tools/smart-edit.d.ts +2 -1
- package/dist/src/tools/smart-edit.js +10 -9
- package/dist/src/tools/smart-edit.js.map +1 -1
- package/dist/src/tools/tool-registry.d.ts +5 -1
- package/dist/src/tools/tool-registry.js +10 -3
- package/dist/src/tools/tool-registry.js.map +1 -1
- package/dist/src/tools/tools.d.ts +6 -0
- package/dist/src/tools/tools.js +29 -17
- package/dist/src/tools/tools.js.map +1 -1
- package/dist/src/tools/web-fetch.js +1 -12
- package/dist/src/tools/web-fetch.js.map +1 -1
- package/dist/src/tools/web-fetch.test.js +2 -2
- package/dist/src/tools/web-fetch.test.js.map +1 -1
- package/dist/src/tools/write-file.d.ts +2 -1
- package/dist/src/tools/write-file.js +6 -6
- package/dist/src/tools/write-file.js.map +1 -1
- package/dist/src/tools/write-todos.d.ts +2 -1
- package/dist/src/tools/write-todos.js +5 -2
- package/dist/src/tools/write-todos.js.map +1 -1
- package/dist/src/utils/environmentContext.d.ts +2 -1
- package/dist/src/utils/environmentContext.js +18 -0
- package/dist/src/utils/environmentContext.js.map +1 -1
- package/dist/src/utils/errorParsing.d.ts +1 -1
- package/dist/src/utils/errorParsing.js +5 -33
- package/dist/src/utils/errorParsing.js.map +1 -1
- package/dist/src/utils/errorParsing.test.js +0 -88
- package/dist/src/utils/errorParsing.test.js.map +1 -1
- package/dist/src/utils/errors.d.ts +3 -0
- package/dist/src/utils/errors.js +6 -0
- package/dist/src/utils/errors.js.map +1 -1
- package/dist/src/utils/events.d.ts +19 -1
- package/dist/src/utils/events.js +9 -0
- package/dist/src/utils/events.js.map +1 -1
- package/dist/src/utils/extensionLoader.d.ts +38 -0
- package/dist/src/utils/extensionLoader.js +20 -0
- package/dist/src/utils/extensionLoader.js.map +1 -0
- package/dist/src/utils/flashFallback.test.js +26 -45
- package/dist/src/utils/flashFallback.test.js.map +1 -1
- package/dist/src/utils/getFolderStructure.js +7 -16
- package/dist/src/utils/getFolderStructure.js.map +1 -1
- package/dist/src/utils/googleErrors.d.ts +104 -0
- package/dist/src/utils/googleErrors.js +152 -0
- package/dist/src/utils/googleErrors.js.map +1 -0
- package/dist/src/utils/googleErrors.test.d.ts +6 -0
- package/dist/src/utils/googleErrors.test.js +301 -0
- package/dist/src/utils/googleErrors.test.js.map +1 -0
- package/dist/src/utils/googleQuotaErrors.d.ts +35 -0
- package/dist/src/utils/googleQuotaErrors.js +131 -0
- package/dist/src/utils/googleQuotaErrors.js.map +1 -0
- package/dist/src/utils/googleQuotaErrors.test.d.ts +6 -0
- package/dist/src/utils/googleQuotaErrors.test.js +281 -0
- package/dist/src/utils/googleQuotaErrors.test.js.map +1 -0
- package/dist/src/utils/ignorePatterns.test.js +26 -30
- package/dist/src/utils/ignorePatterns.test.js.map +1 -1
- package/dist/src/utils/memoryDiscovery.d.ts +2 -2
- package/dist/src/utils/memoryDiscovery.js +3 -2
- package/dist/src/utils/memoryDiscovery.js.map +1 -1
- package/dist/src/utils/memoryDiscovery.test.js +19 -35
- package/dist/src/utils/memoryDiscovery.test.js.map +1 -1
- package/dist/src/utils/paths.js +126 -26
- package/dist/src/utils/paths.js.map +1 -1
- package/dist/src/utils/paths.test.js +200 -68
- package/dist/src/utils/paths.test.js.map +1 -1
- package/dist/src/utils/quotaErrorDetection.d.ts +0 -2
- package/dist/src/utils/quotaErrorDetection.js +0 -46
- package/dist/src/utils/quotaErrorDetection.js.map +1 -1
- package/dist/src/utils/retry.js +41 -145
- package/dist/src/utils/retry.js.map +1 -1
- package/dist/src/utils/retry.test.js +31 -110
- package/dist/src/utils/retry.test.js.map +1 -1
- package/dist/src/utils/shell-utils.test.js +70 -0
- package/dist/src/utils/shell-utils.test.js.map +1 -1
- package/dist/src/utils/workspaceContext.js +1 -1
- package/dist/src/utils/workspaceContext.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/dist/google-gemini-cli-core-0.12.0-nightly.20251022.0542de95.tgz +0 -0
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Copyright 2025 Google LLC
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
-
import { ToolConfirmationOutcome, ApprovalMode, logToolCall, ToolErrorType, ToolCallEvent, logToolOutputTruncated, ToolOutputTruncatedEvent, } from '../index.js';
|
|
6
|
+
import { ToolConfirmationOutcome, ApprovalMode, logToolCall, ToolErrorType, ToolCallEvent, logToolOutputTruncated, ToolOutputTruncatedEvent, runInDevTraceSpan, } from '../index.js';
|
|
7
7
|
import { READ_FILE_TOOL_NAME, SHELL_TOOL_NAME } from '../tools/tool-names.js';
|
|
8
8
|
import { getResponseTextFromParts } from '../utils/generateContentResponseUtilities.js';
|
|
9
9
|
import { isModifiableDeclarativeTool, modifyWithEditor, } from '../tools/modifiable-tool.js';
|
|
@@ -145,6 +145,9 @@ ${truncatedContent}`,
|
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
147
|
export class CoreToolScheduler {
|
|
148
|
+
// Static WeakMap to track which MessageBus instances already have a handler subscribed
|
|
149
|
+
// This prevents duplicate subscriptions when multiple CoreToolScheduler instances are created
|
|
150
|
+
static subscribedMessageBuses = new WeakMap();
|
|
148
151
|
toolCalls = [];
|
|
149
152
|
outputUpdateHandler;
|
|
150
153
|
onAllToolCallsComplete;
|
|
@@ -154,7 +157,10 @@ export class CoreToolScheduler {
|
|
|
154
157
|
onEditorClose;
|
|
155
158
|
isFinalizingToolCalls = false;
|
|
156
159
|
isScheduling = false;
|
|
160
|
+
isCancelling = false;
|
|
157
161
|
requestQueue = [];
|
|
162
|
+
toolCallQueue = [];
|
|
163
|
+
completedToolCallsForBatch = [];
|
|
158
164
|
constructor(options) {
|
|
159
165
|
this.config = options.config;
|
|
160
166
|
this.outputUpdateHandler = options.outputUpdateHandler;
|
|
@@ -163,12 +169,31 @@ export class CoreToolScheduler {
|
|
|
163
169
|
this.getPreferredEditor = options.getPreferredEditor;
|
|
164
170
|
this.onEditorClose = options.onEditorClose;
|
|
165
171
|
// Subscribe to message bus for ASK_USER policy decisions
|
|
172
|
+
// Use a static WeakMap to ensure we only subscribe ONCE per MessageBus instance
|
|
173
|
+
// This prevents memory leaks when multiple CoreToolScheduler instances are created
|
|
174
|
+
// (e.g., on every React render, or for each non-interactive tool call)
|
|
166
175
|
if (this.config.getEnableMessageBusIntegration()) {
|
|
167
176
|
const messageBus = this.config.getMessageBus();
|
|
168
|
-
|
|
177
|
+
// Check if we've already subscribed a handler to this message bus
|
|
178
|
+
if (!CoreToolScheduler.subscribedMessageBuses.has(messageBus)) {
|
|
179
|
+
// Create a shared handler that will be used for this message bus
|
|
180
|
+
const sharedHandler = (request) => {
|
|
181
|
+
// When ASK_USER policy decision is made, respond with requiresUserConfirmation=true
|
|
182
|
+
// to tell tools to use their legacy confirmation flow
|
|
183
|
+
messageBus.publish({
|
|
184
|
+
type: MessageBusType.TOOL_CONFIRMATION_RESPONSE,
|
|
185
|
+
correlationId: request.correlationId,
|
|
186
|
+
confirmed: false,
|
|
187
|
+
requiresUserConfirmation: true,
|
|
188
|
+
});
|
|
189
|
+
};
|
|
190
|
+
messageBus.subscribe(MessageBusType.TOOL_CONFIRMATION_REQUEST, sharedHandler);
|
|
191
|
+
// Store the handler in the WeakMap so we don't subscribe again
|
|
192
|
+
CoreToolScheduler.subscribedMessageBuses.set(messageBus, sharedHandler);
|
|
193
|
+
}
|
|
169
194
|
}
|
|
170
195
|
}
|
|
171
|
-
setStatusInternal(targetCallId, newStatus, auxiliaryData) {
|
|
196
|
+
setStatusInternal(targetCallId, newStatus, signal, auxiliaryData) {
|
|
172
197
|
this.toolCalls = this.toolCalls.map((currentCall) => {
|
|
173
198
|
if (currentCall.request.callId !== targetCallId ||
|
|
174
199
|
currentCall.status === 'success' ||
|
|
@@ -298,7 +323,6 @@ export class CoreToolScheduler {
|
|
|
298
323
|
}
|
|
299
324
|
});
|
|
300
325
|
this.notifyToolCallsUpdate();
|
|
301
|
-
this.checkAndNotifyCompletion();
|
|
302
326
|
}
|
|
303
327
|
setArgsInternal(targetCallId, args) {
|
|
304
328
|
this.toolCalls = this.toolCalls.map((call) => {
|
|
@@ -368,40 +392,66 @@ export class CoreToolScheduler {
|
|
|
368
392
|
}
|
|
369
393
|
}
|
|
370
394
|
schedule(request, signal) {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
const
|
|
376
|
-
|
|
377
|
-
this.requestQueue.
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
signal
|
|
387
|
-
resolve()
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
reject(reason)
|
|
392
|
-
|
|
395
|
+
return runInDevTraceSpan({ name: 'schedule' }, async ({ metadata: spanMetadata }) => {
|
|
396
|
+
spanMetadata.input = request;
|
|
397
|
+
if (this.isRunning() || this.isScheduling) {
|
|
398
|
+
return new Promise((resolve, reject) => {
|
|
399
|
+
const abortHandler = () => {
|
|
400
|
+
// Find and remove the request from the queue
|
|
401
|
+
const index = this.requestQueue.findIndex((item) => item.request === request);
|
|
402
|
+
if (index > -1) {
|
|
403
|
+
this.requestQueue.splice(index, 1);
|
|
404
|
+
reject(new Error('Tool call cancelled while in queue.'));
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
signal.addEventListener('abort', abortHandler, { once: true });
|
|
408
|
+
this.requestQueue.push({
|
|
409
|
+
request,
|
|
410
|
+
signal,
|
|
411
|
+
resolve: () => {
|
|
412
|
+
signal.removeEventListener('abort', abortHandler);
|
|
413
|
+
resolve();
|
|
414
|
+
},
|
|
415
|
+
reject: (reason) => {
|
|
416
|
+
signal.removeEventListener('abort', abortHandler);
|
|
417
|
+
reject(reason);
|
|
418
|
+
},
|
|
419
|
+
});
|
|
393
420
|
});
|
|
394
|
-
}
|
|
421
|
+
}
|
|
422
|
+
return this._schedule(request, signal);
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
cancelAll(signal) {
|
|
426
|
+
if (this.isCancelling) {
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
this.isCancelling = true;
|
|
430
|
+
// Cancel the currently active tool call, if there is one.
|
|
431
|
+
if (this.toolCalls.length > 0) {
|
|
432
|
+
const activeCall = this.toolCalls[0];
|
|
433
|
+
// Only cancel if it's in a cancellable state.
|
|
434
|
+
if (activeCall.status === 'awaiting_approval' ||
|
|
435
|
+
activeCall.status === 'executing' ||
|
|
436
|
+
activeCall.status === 'scheduled' ||
|
|
437
|
+
activeCall.status === 'validating') {
|
|
438
|
+
this.setStatusInternal(activeCall.request.callId, 'cancelled', signal, 'User cancelled the operation.');
|
|
439
|
+
}
|
|
395
440
|
}
|
|
396
|
-
|
|
441
|
+
// Clear the queue and mark all queued items as cancelled for completion reporting.
|
|
442
|
+
this._cancelAllQueuedCalls();
|
|
443
|
+
// Finalize the batch immediately.
|
|
444
|
+
void this.checkAndNotifyCompletion(signal);
|
|
397
445
|
}
|
|
398
446
|
async _schedule(request, signal) {
|
|
399
447
|
this.isScheduling = true;
|
|
448
|
+
this.isCancelling = false;
|
|
400
449
|
try {
|
|
401
450
|
if (this.isRunning()) {
|
|
402
451
|
throw new Error('Cannot schedule new tool calls while other tool calls are actively running (executing or awaiting approval).');
|
|
403
452
|
}
|
|
404
453
|
const requestsToProcess = Array.isArray(request) ? request : [request];
|
|
454
|
+
this.completedToolCallsForBatch = [];
|
|
405
455
|
const newToolCalls = requestsToProcess.map((reqInfo) => {
|
|
406
456
|
const toolInstance = this.config
|
|
407
457
|
.getToolRegistry()
|
|
@@ -434,28 +484,55 @@ export class CoreToolScheduler {
|
|
|
434
484
|
startTime: Date.now(),
|
|
435
485
|
};
|
|
436
486
|
});
|
|
437
|
-
this.
|
|
438
|
-
this.
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
487
|
+
this.toolCallQueue.push(...newToolCalls);
|
|
488
|
+
await this._processNextInQueue(signal);
|
|
489
|
+
}
|
|
490
|
+
finally {
|
|
491
|
+
this.isScheduling = false;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
async _processNextInQueue(signal) {
|
|
495
|
+
// If there's already a tool being processed, or the queue is empty, stop.
|
|
496
|
+
if (this.toolCalls.length > 0 || this.toolCallQueue.length === 0) {
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
// If cancellation happened between steps, handle it.
|
|
500
|
+
if (signal.aborted) {
|
|
501
|
+
this._cancelAllQueuedCalls();
|
|
502
|
+
// Finalize the batch.
|
|
503
|
+
await this.checkAndNotifyCompletion(signal);
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
const toolCall = this.toolCallQueue.shift();
|
|
507
|
+
// This is now the single active tool call.
|
|
508
|
+
this.toolCalls = [toolCall];
|
|
509
|
+
this.notifyToolCallsUpdate();
|
|
510
|
+
// Handle tools that were already errored during creation.
|
|
511
|
+
if (toolCall.status === 'error') {
|
|
512
|
+
// An error during validation means this "active" tool is already complete.
|
|
513
|
+
// We need to check for batch completion to either finish or process the next in queue.
|
|
514
|
+
await this.checkAndNotifyCompletion(signal);
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
// This logic is moved from the old `for` loop in `_schedule`.
|
|
518
|
+
if (toolCall.status === 'validating') {
|
|
519
|
+
const { request: reqInfo, invocation } = toolCall;
|
|
520
|
+
try {
|
|
521
|
+
if (signal.aborted) {
|
|
522
|
+
this.setStatusInternal(reqInfo.callId, 'cancelled', signal, 'Tool call cancelled by user.');
|
|
523
|
+
// The completion check will handle the cascade.
|
|
524
|
+
await this.checkAndNotifyCompletion(signal);
|
|
525
|
+
return;
|
|
442
526
|
}
|
|
443
|
-
const
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
const confirmationDetails = await invocation.shouldConfirmExecute(signal);
|
|
451
|
-
if (!confirmationDetails) {
|
|
452
|
-
this.setToolCallOutcome(reqInfo.callId, ToolConfirmationOutcome.ProceedAlways);
|
|
453
|
-
this.setStatusInternal(reqInfo.callId, 'scheduled');
|
|
454
|
-
continue;
|
|
455
|
-
}
|
|
456
|
-
if (this.isAutoApproved(validatingCall)) {
|
|
527
|
+
const confirmationDetails = await invocation.shouldConfirmExecute(signal);
|
|
528
|
+
if (!confirmationDetails) {
|
|
529
|
+
this.setToolCallOutcome(reqInfo.callId, ToolConfirmationOutcome.ProceedAlways);
|
|
530
|
+
this.setStatusInternal(reqInfo.callId, 'scheduled', signal);
|
|
531
|
+
}
|
|
532
|
+
else {
|
|
533
|
+
if (this.isAutoApproved(toolCall)) {
|
|
457
534
|
this.setToolCallOutcome(reqInfo.callId, ToolConfirmationOutcome.ProceedAlways);
|
|
458
|
-
this.setStatusInternal(reqInfo.callId, 'scheduled');
|
|
535
|
+
this.setStatusInternal(reqInfo.callId, 'scheduled', signal);
|
|
459
536
|
}
|
|
460
537
|
else {
|
|
461
538
|
// Allow IDE to resolve confirmation
|
|
@@ -475,35 +552,33 @@ export class CoreToolScheduler {
|
|
|
475
552
|
...confirmationDetails,
|
|
476
553
|
onConfirm: (outcome, payload) => this.handleConfirmationResponse(reqInfo.callId, originalOnConfirm, outcome, signal, payload),
|
|
477
554
|
};
|
|
478
|
-
this.setStatusInternal(reqInfo.callId, 'awaiting_approval', wrappedConfirmationDetails);
|
|
555
|
+
this.setStatusInternal(reqInfo.callId, 'awaiting_approval', signal, wrappedConfirmationDetails);
|
|
479
556
|
}
|
|
480
557
|
}
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
558
|
+
}
|
|
559
|
+
catch (error) {
|
|
560
|
+
if (signal.aborted) {
|
|
561
|
+
this.setStatusInternal(reqInfo.callId, 'cancelled', signal, 'Tool call cancelled by user.');
|
|
562
|
+
await this.checkAndNotifyCompletion(signal);
|
|
563
|
+
}
|
|
564
|
+
else {
|
|
565
|
+
this.setStatusInternal(reqInfo.callId, 'error', signal, createErrorResponse(reqInfo, error instanceof Error ? error : new Error(String(error)), ToolErrorType.UNHANDLED_EXCEPTION));
|
|
566
|
+
await this.checkAndNotifyCompletion(signal);
|
|
487
567
|
}
|
|
488
568
|
}
|
|
489
|
-
await this.attemptExecutionOfScheduledCalls(signal);
|
|
490
|
-
void this.checkAndNotifyCompletion();
|
|
491
|
-
}
|
|
492
|
-
finally {
|
|
493
|
-
this.isScheduling = false;
|
|
494
569
|
}
|
|
570
|
+
await this.attemptExecutionOfScheduledCalls(signal);
|
|
495
571
|
}
|
|
496
572
|
async handleConfirmationResponse(callId, originalOnConfirm, outcome, signal, payload) {
|
|
497
573
|
const toolCall = this.toolCalls.find((c) => c.request.callId === callId && c.status === 'awaiting_approval');
|
|
498
574
|
if (toolCall && toolCall.status === 'awaiting_approval') {
|
|
499
575
|
await originalOnConfirm(outcome);
|
|
500
576
|
}
|
|
501
|
-
if (outcome === ToolConfirmationOutcome.ProceedAlways) {
|
|
502
|
-
await this.autoApproveCompatiblePendingTools(signal, callId);
|
|
503
|
-
}
|
|
504
577
|
this.setToolCallOutcome(callId, outcome);
|
|
505
578
|
if (outcome === ToolConfirmationOutcome.Cancel || signal.aborted) {
|
|
506
|
-
|
|
579
|
+
// Instead of just cancelling one tool, trigger the full cancel cascade.
|
|
580
|
+
this.cancelAll(signal);
|
|
581
|
+
return; // `cancelAll` calls `checkAndNotifyCompletion`, so we can exit here.
|
|
507
582
|
}
|
|
508
583
|
else if (outcome === ToolConfirmationOutcome.ModifyWithEditor) {
|
|
509
584
|
const waitingToolCall = toolCall;
|
|
@@ -513,13 +588,13 @@ export class CoreToolScheduler {
|
|
|
513
588
|
if (!editorType) {
|
|
514
589
|
return;
|
|
515
590
|
}
|
|
516
|
-
this.setStatusInternal(callId, 'awaiting_approval', {
|
|
591
|
+
this.setStatusInternal(callId, 'awaiting_approval', signal, {
|
|
517
592
|
...waitingToolCall.confirmationDetails,
|
|
518
593
|
isModifying: true,
|
|
519
594
|
});
|
|
520
595
|
const { updatedParams, updatedDiff } = await modifyWithEditor(waitingToolCall.request.args, modifyContext, editorType, signal, this.onEditorClose);
|
|
521
596
|
this.setArgsInternal(callId, updatedParams);
|
|
522
|
-
this.setStatusInternal(callId, 'awaiting_approval', {
|
|
597
|
+
this.setStatusInternal(callId, 'awaiting_approval', signal, {
|
|
523
598
|
...waitingToolCall.confirmationDetails,
|
|
524
599
|
fileDiff: updatedDiff,
|
|
525
600
|
isModifying: false,
|
|
@@ -531,7 +606,7 @@ export class CoreToolScheduler {
|
|
|
531
606
|
if (payload?.newContent && toolCall) {
|
|
532
607
|
await this._applyInlineModify(toolCall, payload, signal);
|
|
533
608
|
}
|
|
534
|
-
this.setStatusInternal(callId, 'scheduled');
|
|
609
|
+
this.setStatusInternal(callId, 'scheduled', signal);
|
|
535
610
|
}
|
|
536
611
|
await this.attemptExecutionOfScheduledCalls(signal);
|
|
537
612
|
}
|
|
@@ -551,7 +626,7 @@ export class CoreToolScheduler {
|
|
|
551
626
|
const updatedParams = modifyContext.createUpdatedParams(currentContent, payload.newContent, toolCall.request.args);
|
|
552
627
|
const updatedDiff = Diff.createPatch(modifyContext.getFilePath(toolCall.request.args), currentContent, payload.newContent, 'Current', 'Proposed');
|
|
553
628
|
this.setArgsInternal(toolCall.request.callId, updatedParams);
|
|
554
|
-
this.setStatusInternal(toolCall.request.callId, 'awaiting_approval', {
|
|
629
|
+
this.setStatusInternal(toolCall.request.callId, 'awaiting_approval', signal, {
|
|
555
630
|
...toolCall.confirmationDetails,
|
|
556
631
|
fileDiff: updatedDiff,
|
|
557
632
|
});
|
|
@@ -569,7 +644,7 @@ export class CoreToolScheduler {
|
|
|
569
644
|
const scheduledCall = toolCall;
|
|
570
645
|
const { callId, name: toolName } = scheduledCall.request;
|
|
571
646
|
const invocation = scheduledCall.invocation;
|
|
572
|
-
this.setStatusInternal(callId, 'executing');
|
|
647
|
+
this.setStatusInternal(callId, 'executing', signal);
|
|
573
648
|
const liveOutputCallback = scheduledCall.tool.canUpdateOutput && this.outputUpdateHandler
|
|
574
649
|
? (outputChunk) => {
|
|
575
650
|
if (this.outputUpdateHandler) {
|
|
@@ -582,103 +657,142 @@ export class CoreToolScheduler {
|
|
|
582
657
|
}
|
|
583
658
|
: undefined;
|
|
584
659
|
const shellExecutionConfig = this.config.getShellExecutionConfig();
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
const setPidCallback = (pid) => {
|
|
592
|
-
this.toolCalls = this.toolCalls.map((tc) => tc.request.callId === callId && tc.status === 'executing'
|
|
593
|
-
? { ...tc, pid }
|
|
594
|
-
: tc);
|
|
595
|
-
this.notifyToolCallsUpdate();
|
|
660
|
+
await runInDevTraceSpan({
|
|
661
|
+
name: toolCall.tool.name,
|
|
662
|
+
attributes: { type: 'tool-call' },
|
|
663
|
+
}, async ({ metadata: spanMetadata }) => {
|
|
664
|
+
spanMetadata.input = {
|
|
665
|
+
request: toolCall.request,
|
|
596
666
|
};
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
if (toolResult.error === undefined) {
|
|
609
|
-
let content = toolResult.llmContent;
|
|
610
|
-
let outputFile = undefined;
|
|
611
|
-
const contentLength = typeof content === 'string' ? content.length : undefined;
|
|
612
|
-
if (typeof content === 'string' &&
|
|
613
|
-
toolName === SHELL_TOOL_NAME &&
|
|
614
|
-
this.config.getEnableToolOutputTruncation() &&
|
|
615
|
-
this.config.getTruncateToolOutputThreshold() > 0 &&
|
|
616
|
-
this.config.getTruncateToolOutputLines() > 0) {
|
|
617
|
-
const originalContentLength = content.length;
|
|
618
|
-
const threshold = this.config.getTruncateToolOutputThreshold();
|
|
619
|
-
const lines = this.config.getTruncateToolOutputLines();
|
|
620
|
-
const truncatedResult = await truncateAndSaveToFile(content, callId, this.config.storage.getProjectTempDir(), threshold, lines);
|
|
621
|
-
content = truncatedResult.content;
|
|
622
|
-
outputFile = truncatedResult.outputFile;
|
|
623
|
-
if (outputFile) {
|
|
624
|
-
logToolOutputTruncated(this.config, new ToolOutputTruncatedEvent(scheduledCall.request.prompt_id, {
|
|
625
|
-
toolName,
|
|
626
|
-
originalContentLength,
|
|
627
|
-
truncatedContentLength: content.length,
|
|
628
|
-
threshold,
|
|
629
|
-
lines,
|
|
630
|
-
}));
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
const response = convertToFunctionResponse(toolName, callId, content);
|
|
634
|
-
const successResponse = {
|
|
635
|
-
callId,
|
|
636
|
-
responseParts: response,
|
|
637
|
-
resultDisplay: toolResult.returnDisplay,
|
|
638
|
-
error: undefined,
|
|
639
|
-
errorType: undefined,
|
|
640
|
-
outputFile,
|
|
641
|
-
contentLength,
|
|
667
|
+
// TODO: Refactor to remove special casing for ShellToolInvocation.
|
|
668
|
+
// Introduce a generic callbacks object for the execute method to handle
|
|
669
|
+
// things like `onPid` and `onLiveOutput`. This will make the scheduler
|
|
670
|
+
// agnostic to the invocation type.
|
|
671
|
+
let promise;
|
|
672
|
+
if (invocation instanceof ShellToolInvocation) {
|
|
673
|
+
const setPidCallback = (pid) => {
|
|
674
|
+
this.toolCalls = this.toolCalls.map((tc) => tc.request.callId === callId && tc.status === 'executing'
|
|
675
|
+
? { ...tc, pid }
|
|
676
|
+
: tc);
|
|
677
|
+
this.notifyToolCallsUpdate();
|
|
642
678
|
};
|
|
643
|
-
|
|
679
|
+
promise = invocation.execute(signal, liveOutputCallback, shellExecutionConfig, setPidCallback);
|
|
644
680
|
}
|
|
645
681
|
else {
|
|
646
|
-
|
|
647
|
-
const error = new Error(toolResult.error.message);
|
|
648
|
-
const errorResponse = createErrorResponse(scheduledCall.request, error, toolResult.error.type);
|
|
649
|
-
this.setStatusInternal(callId, 'error', errorResponse);
|
|
682
|
+
promise = invocation.execute(signal, liveOutputCallback, shellExecutionConfig);
|
|
650
683
|
}
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
684
|
+
try {
|
|
685
|
+
const toolResult = await promise;
|
|
686
|
+
spanMetadata.output = toolResult;
|
|
687
|
+
if (signal.aborted) {
|
|
688
|
+
this.setStatusInternal(callId, 'cancelled', signal, 'User cancelled tool execution.');
|
|
689
|
+
}
|
|
690
|
+
else if (toolResult.error === undefined) {
|
|
691
|
+
let content = toolResult.llmContent;
|
|
692
|
+
let outputFile = undefined;
|
|
693
|
+
const contentLength = typeof content === 'string' ? content.length : undefined;
|
|
694
|
+
if (typeof content === 'string' &&
|
|
695
|
+
toolName === SHELL_TOOL_NAME &&
|
|
696
|
+
this.config.getEnableToolOutputTruncation() &&
|
|
697
|
+
this.config.getTruncateToolOutputThreshold() > 0 &&
|
|
698
|
+
this.config.getTruncateToolOutputLines() > 0) {
|
|
699
|
+
const originalContentLength = content.length;
|
|
700
|
+
const threshold = this.config.getTruncateToolOutputThreshold();
|
|
701
|
+
const lines = this.config.getTruncateToolOutputLines();
|
|
702
|
+
const truncatedResult = await truncateAndSaveToFile(content, callId, this.config.storage.getProjectTempDir(), threshold, lines);
|
|
703
|
+
content = truncatedResult.content;
|
|
704
|
+
outputFile = truncatedResult.outputFile;
|
|
705
|
+
if (outputFile) {
|
|
706
|
+
logToolOutputTruncated(this.config, new ToolOutputTruncatedEvent(scheduledCall.request.prompt_id, {
|
|
707
|
+
toolName,
|
|
708
|
+
originalContentLength,
|
|
709
|
+
truncatedContentLength: content.length,
|
|
710
|
+
threshold,
|
|
711
|
+
lines,
|
|
712
|
+
}));
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
const response = convertToFunctionResponse(toolName, callId, content);
|
|
716
|
+
const successResponse = {
|
|
717
|
+
callId,
|
|
718
|
+
responseParts: response,
|
|
719
|
+
resultDisplay: toolResult.returnDisplay,
|
|
720
|
+
error: undefined,
|
|
721
|
+
errorType: undefined,
|
|
722
|
+
outputFile,
|
|
723
|
+
contentLength,
|
|
724
|
+
};
|
|
725
|
+
this.setStatusInternal(callId, 'success', signal, successResponse);
|
|
726
|
+
}
|
|
727
|
+
else {
|
|
728
|
+
// It is a failure
|
|
729
|
+
const error = new Error(toolResult.error.message);
|
|
730
|
+
const errorResponse = createErrorResponse(scheduledCall.request, error, toolResult.error.type);
|
|
731
|
+
this.setStatusInternal(callId, 'error', signal, errorResponse);
|
|
732
|
+
}
|
|
655
733
|
}
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
734
|
+
catch (executionError) {
|
|
735
|
+
spanMetadata.error = executionError;
|
|
736
|
+
if (signal.aborted) {
|
|
737
|
+
this.setStatusInternal(callId, 'cancelled', signal, 'User cancelled tool execution.');
|
|
738
|
+
}
|
|
739
|
+
else {
|
|
740
|
+
this.setStatusInternal(callId, 'error', signal, createErrorResponse(scheduledCall.request, executionError instanceof Error
|
|
741
|
+
? executionError
|
|
742
|
+
: new Error(String(executionError)), ToolErrorType.UNHANDLED_EXCEPTION));
|
|
743
|
+
}
|
|
660
744
|
}
|
|
661
|
-
|
|
745
|
+
await this.checkAndNotifyCompletion(signal);
|
|
746
|
+
});
|
|
662
747
|
}
|
|
663
748
|
}
|
|
664
749
|
}
|
|
665
|
-
async checkAndNotifyCompletion() {
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
750
|
+
async checkAndNotifyCompletion(signal) {
|
|
751
|
+
// This method is now only concerned with the single active tool call.
|
|
752
|
+
if (this.toolCalls.length === 0) {
|
|
753
|
+
// It's possible to be called when a batch is cancelled before any tool has started.
|
|
754
|
+
if (signal.aborted && this.toolCallQueue.length > 0) {
|
|
755
|
+
this._cancelAllQueuedCalls();
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
else {
|
|
759
|
+
const activeCall = this.toolCalls[0];
|
|
760
|
+
const isTerminal = activeCall.status === 'success' ||
|
|
761
|
+
activeCall.status === 'error' ||
|
|
762
|
+
activeCall.status === 'cancelled';
|
|
763
|
+
// If the active tool is not in a terminal state (e.g., it's 'executing' or 'awaiting_approval'),
|
|
764
|
+
// then the scheduler is still busy or paused. We should not proceed.
|
|
765
|
+
if (!isTerminal) {
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
// The active tool is finished. Move it to the completed batch.
|
|
769
|
+
const completedCall = activeCall;
|
|
770
|
+
this.completedToolCallsForBatch.push(completedCall);
|
|
771
|
+
logToolCall(this.config, new ToolCallEvent(completedCall));
|
|
772
|
+
// Clear the active tool slot. This is crucial for the sequential processing.
|
|
671
773
|
this.toolCalls = [];
|
|
672
|
-
|
|
673
|
-
|
|
774
|
+
}
|
|
775
|
+
// Now, check if the entire batch is complete.
|
|
776
|
+
// The batch is complete if the queue is empty or the operation was cancelled.
|
|
777
|
+
if (this.toolCallQueue.length === 0 || signal.aborted) {
|
|
778
|
+
if (signal.aborted) {
|
|
779
|
+
this._cancelAllQueuedCalls();
|
|
780
|
+
}
|
|
781
|
+
// If there's nothing to report and we weren't cancelled, we can stop.
|
|
782
|
+
// But if we were cancelled, we must proceed to potentially start the next queued request.
|
|
783
|
+
if (this.completedToolCallsForBatch.length === 0 && !signal.aborted) {
|
|
784
|
+
return;
|
|
674
785
|
}
|
|
675
786
|
if (this.onAllToolCallsComplete) {
|
|
676
787
|
this.isFinalizingToolCalls = true;
|
|
677
|
-
|
|
788
|
+
// Use the batch array, not the (now empty) active array.
|
|
789
|
+
await this.onAllToolCallsComplete(this.completedToolCallsForBatch);
|
|
790
|
+
this.completedToolCallsForBatch = []; // Clear after reporting.
|
|
678
791
|
this.isFinalizingToolCalls = false;
|
|
679
792
|
}
|
|
793
|
+
this.isCancelling = false;
|
|
680
794
|
this.notifyToolCallsUpdate();
|
|
681
|
-
// After completion, process the next item in the queue.
|
|
795
|
+
// After completion of the entire batch, process the next item in the main request queue.
|
|
682
796
|
if (this.requestQueue.length > 0) {
|
|
683
797
|
const next = this.requestQueue.shift();
|
|
684
798
|
this._schedule(next.request, next.signal)
|
|
@@ -686,10 +800,58 @@ export class CoreToolScheduler {
|
|
|
686
800
|
.catch(next.reject);
|
|
687
801
|
}
|
|
688
802
|
}
|
|
803
|
+
else {
|
|
804
|
+
// The batch is not yet complete, so continue processing the current batch sequence.
|
|
805
|
+
await this._processNextInQueue(signal);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
_cancelAllQueuedCalls() {
|
|
809
|
+
while (this.toolCallQueue.length > 0) {
|
|
810
|
+
const queuedCall = this.toolCallQueue.shift();
|
|
811
|
+
// Don't cancel tools that already errored during validation.
|
|
812
|
+
if (queuedCall.status === 'error') {
|
|
813
|
+
this.completedToolCallsForBatch.push(queuedCall);
|
|
814
|
+
continue;
|
|
815
|
+
}
|
|
816
|
+
const durationMs = 'startTime' in queuedCall && queuedCall.startTime
|
|
817
|
+
? Date.now() - queuedCall.startTime
|
|
818
|
+
: undefined;
|
|
819
|
+
const errorMessage = '[Operation Cancelled] User cancelled the operation.';
|
|
820
|
+
this.completedToolCallsForBatch.push({
|
|
821
|
+
request: queuedCall.request,
|
|
822
|
+
tool: queuedCall.tool,
|
|
823
|
+
invocation: queuedCall.invocation,
|
|
824
|
+
status: 'cancelled',
|
|
825
|
+
response: {
|
|
826
|
+
callId: queuedCall.request.callId,
|
|
827
|
+
responseParts: [
|
|
828
|
+
{
|
|
829
|
+
functionResponse: {
|
|
830
|
+
id: queuedCall.request.callId,
|
|
831
|
+
name: queuedCall.request.name,
|
|
832
|
+
response: {
|
|
833
|
+
error: errorMessage,
|
|
834
|
+
},
|
|
835
|
+
},
|
|
836
|
+
},
|
|
837
|
+
],
|
|
838
|
+
resultDisplay: undefined,
|
|
839
|
+
error: undefined,
|
|
840
|
+
errorType: undefined,
|
|
841
|
+
contentLength: errorMessage.length,
|
|
842
|
+
},
|
|
843
|
+
durationMs,
|
|
844
|
+
outcome: ToolConfirmationOutcome.Cancel,
|
|
845
|
+
});
|
|
846
|
+
}
|
|
689
847
|
}
|
|
690
848
|
notifyToolCallsUpdate() {
|
|
691
849
|
if (this.onToolCallsUpdate) {
|
|
692
|
-
this.onToolCallsUpdate([
|
|
850
|
+
this.onToolCallsUpdate([
|
|
851
|
+
...this.completedToolCallsForBatch,
|
|
852
|
+
...this.toolCalls,
|
|
853
|
+
...this.toolCallQueue,
|
|
854
|
+
]);
|
|
693
855
|
}
|
|
694
856
|
}
|
|
695
857
|
setToolCallOutcome(callId, outcome) {
|
|
@@ -702,23 +864,6 @@ export class CoreToolScheduler {
|
|
|
702
864
|
};
|
|
703
865
|
});
|
|
704
866
|
}
|
|
705
|
-
/**
|
|
706
|
-
* Handle tool confirmation requests from the message bus when policy decision is ASK_USER.
|
|
707
|
-
* This publishes a response with requiresUserConfirmation=true to signal the tool
|
|
708
|
-
* that it should fall back to its legacy confirmation UI.
|
|
709
|
-
*/
|
|
710
|
-
handleToolConfirmationRequest(request) {
|
|
711
|
-
// When ASK_USER policy decision is made, the message bus emits the request here.
|
|
712
|
-
// We respond with requiresUserConfirmation=true to tell the tool to use its
|
|
713
|
-
// legacy confirmation flow (which will show diffs, URLs, etc in the UI).
|
|
714
|
-
const messageBus = this.config.getMessageBus();
|
|
715
|
-
messageBus.publish({
|
|
716
|
-
type: MessageBusType.TOOL_CONFIRMATION_RESPONSE,
|
|
717
|
-
correlationId: request.correlationId,
|
|
718
|
-
confirmed: false, // Not auto-approved
|
|
719
|
-
requiresUserConfirmation: true, // Use legacy UI confirmation
|
|
720
|
-
});
|
|
721
|
-
}
|
|
722
867
|
isAutoApproved(toolCall) {
|
|
723
868
|
if (this.config.getApprovalMode() === ApprovalMode.YOLO) {
|
|
724
869
|
return true;
|
|
@@ -731,21 +876,5 @@ export class CoreToolScheduler {
|
|
|
731
876
|
}
|
|
732
877
|
return doesToolInvocationMatch(tool, invocation, allowedTools);
|
|
733
878
|
}
|
|
734
|
-
async autoApproveCompatiblePendingTools(signal, triggeringCallId) {
|
|
735
|
-
const pendingTools = this.toolCalls.filter((call) => call.status === 'awaiting_approval' &&
|
|
736
|
-
call.request.callId !== triggeringCallId);
|
|
737
|
-
for (const pendingTool of pendingTools) {
|
|
738
|
-
try {
|
|
739
|
-
const stillNeedsConfirmation = await pendingTool.invocation.shouldConfirmExecute(signal);
|
|
740
|
-
if (!stillNeedsConfirmation) {
|
|
741
|
-
this.setToolCallOutcome(pendingTool.request.callId, ToolConfirmationOutcome.ProceedAlways);
|
|
742
|
-
this.setStatusInternal(pendingTool.request.callId, 'scheduled');
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
catch (error) {
|
|
746
|
-
console.error(`Error checking confirmation for tool ${pendingTool.request.callId}:`, error);
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
}
|
|
750
879
|
}
|
|
751
880
|
//# sourceMappingURL=coreToolScheduler.js.map
|