@google/gemini-cli-core 0.23.0-preview.4 → 0.24.0-nightly.20251231.05049b5ab
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/dist/docs/cli/settings.md +7 -6
- package/dist/docs/get-started/configuration.md +79 -8
- package/dist/google-gemini-cli-core-0.24.0-nightly.20251227.37be16243.tgz +0 -0
- package/dist/src/agents/a2a-client-manager.d.ts +73 -0
- package/dist/src/agents/a2a-client-manager.js +165 -0
- package/dist/src/agents/a2a-client-manager.js.map +1 -0
- package/dist/src/agents/a2a-client-manager.test.d.ts +6 -0
- package/dist/src/agents/a2a-client-manager.test.js +211 -0
- package/dist/src/agents/a2a-client-manager.test.js.map +1 -0
- package/dist/src/agents/local-executor.js +1 -0
- package/dist/src/agents/local-executor.js.map +1 -1
- package/dist/src/agents/registry.d.ts +9 -1
- package/dist/src/agents/registry.js +74 -34
- package/dist/src/agents/registry.js.map +1 -1
- package/dist/src/agents/registry.test.js +79 -30
- package/dist/src/agents/registry.test.js.map +1 -1
- package/dist/src/agents/toml-loader.d.ts +14 -5
- package/dist/src/agents/toml-loader.js +98 -26
- package/dist/src/agents/toml-loader.js.map +1 -1
- package/dist/src/agents/toml-loader.test.js +121 -2
- package/dist/src/agents/toml-loader.test.js.map +1 -1
- package/dist/src/availability/policyHelpers.js +0 -2
- package/dist/src/availability/policyHelpers.js.map +1 -1
- package/dist/src/code_assist/server.js +7 -2
- package/dist/src/code_assist/server.js.map +1 -1
- package/dist/src/code_assist/server.test.js +3 -0
- package/dist/src/code_assist/server.test.js.map +1 -1
- package/dist/src/config/config.d.ts +47 -7
- package/dist/src/config/config.js +59 -28
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/config.test.js +20 -1
- package/dist/src/config/config.test.js.map +1 -1
- package/dist/src/config/models.d.ts +1 -9
- package/dist/src/config/models.js +1 -11
- package/dist/src/config/models.js.map +1 -1
- package/dist/src/config/models.test.js +16 -16
- package/dist/src/config/models.test.js.map +1 -1
- package/dist/src/config/storage.d.ts +2 -0
- package/dist/src/config/storage.js +6 -0
- package/dist/src/config/storage.js.map +1 -1
- package/dist/src/config/storage.test.js +8 -0
- package/dist/src/config/storage.test.js.map +1 -1
- package/dist/src/confirmation-bus/message-bus.js +2 -1
- package/dist/src/confirmation-bus/message-bus.js.map +1 -1
- package/dist/src/core/client.d.ts +5 -1
- package/dist/src/core/client.js +159 -73
- package/dist/src/core/client.js.map +1 -1
- package/dist/src/core/client.test.js +110 -5
- package/dist/src/core/client.test.js.map +1 -1
- package/dist/src/core/contentGenerator.js +2 -2
- package/dist/src/core/contentGenerator.js.map +1 -1
- package/dist/src/core/coreToolHookTriggers.d.ts +2 -2
- package/dist/src/core/coreToolHookTriggers.js +74 -14
- package/dist/src/core/coreToolHookTriggers.js.map +1 -1
- package/dist/src/core/coreToolHookTriggers.test.d.ts +6 -0
- package/dist/src/core/coreToolHookTriggers.test.js +189 -0
- package/dist/src/core/coreToolHookTriggers.test.js.map +1 -0
- package/dist/src/core/coreToolScheduler.d.ts +5 -85
- package/dist/src/core/coreToolScheduler.js +33 -206
- package/dist/src/core/coreToolScheduler.js.map +1 -1
- package/dist/src/core/coreToolScheduler.test.js +19 -367
- package/dist/src/core/coreToolScheduler.test.js.map +1 -1
- package/dist/src/core/nonInteractiveToolExecutor.test.js +0 -1
- package/dist/src/core/nonInteractiveToolExecutor.test.js.map +1 -1
- package/dist/src/core/turn.d.ts +3 -21
- package/dist/src/core/turn.js +1 -0
- package/dist/src/core/turn.js.map +1 -1
- package/dist/src/fallback/handler.js +0 -6
- 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/hooks/hookAggregator.js +7 -0
- package/dist/src/hooks/hookAggregator.js.map +1 -1
- package/dist/src/hooks/hookPlanner.d.ts +1 -5
- package/dist/src/hooks/hookPlanner.js +2 -9
- package/dist/src/hooks/hookPlanner.js.map +1 -1
- package/dist/src/hooks/hookPlanner.test.js +1 -2
- package/dist/src/hooks/hookPlanner.test.js.map +1 -1
- package/dist/src/hooks/hookRegistry.d.ts +5 -10
- package/dist/src/hooks/hookRegistry.js +39 -12
- package/dist/src/hooks/hookRegistry.js.map +1 -1
- package/dist/src/hooks/hookRegistry.test.js +93 -2
- package/dist/src/hooks/hookRegistry.test.js.map +1 -1
- package/dist/src/hooks/hookRunner.d.ts +3 -1
- package/dist/src/hooks/hookRunner.js +31 -3
- package/dist/src/hooks/hookRunner.js.map +1 -1
- package/dist/src/hooks/hookRunner.test.js +58 -2
- package/dist/src/hooks/hookRunner.test.js.map +1 -1
- package/dist/src/hooks/hookSystem.js +1 -1
- package/dist/src/hooks/hookSystem.js.map +1 -1
- package/dist/src/hooks/index.d.ts +1 -1
- package/dist/src/hooks/index.js +1 -1
- package/dist/src/hooks/index.js.map +1 -1
- package/dist/src/hooks/trustedHooks.d.ts +28 -0
- package/dist/src/hooks/trustedHooks.js +90 -0
- package/dist/src/hooks/trustedHooks.js.map +1 -0
- package/dist/src/hooks/trustedHooks.test.d.ts +6 -0
- package/dist/src/hooks/trustedHooks.test.js +154 -0
- package/dist/src/hooks/trustedHooks.test.js.map +1 -0
- package/dist/src/hooks/types.d.ts +18 -9
- package/dist/src/hooks/types.js +31 -26
- package/dist/src/hooks/types.js.map +1 -1
- package/dist/src/hooks/types.test.js +5 -24
- package/dist/src/hooks/types.test.js.map +1 -1
- package/dist/src/ide/ide-client.js +4 -1
- package/dist/src/ide/ide-client.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp/oauth-utils.js +1 -1
- package/dist/src/mcp/oauth-utils.js.map +1 -1
- package/dist/src/mcp/token-storage/keychain-token-storage.js +1 -1
- package/dist/src/mcp/token-storage/keychain-token-storage.js.map +1 -1
- package/dist/src/policy/config.js +4 -2
- package/dist/src/policy/config.js.map +1 -1
- package/dist/src/policy/persistence.test.js +6 -1
- package/dist/src/policy/persistence.test.js.map +1 -1
- package/dist/src/policy/policy-engine.d.ts +10 -1
- package/dist/src/policy/policy-engine.js +24 -4
- package/dist/src/policy/policy-engine.js.map +1 -1
- package/dist/src/policy/policy-engine.test.js +26 -2
- package/dist/src/policy/policy-engine.test.js.map +1 -1
- package/dist/src/policy/shell-safety.test.js +2 -1
- package/dist/src/policy/shell-safety.test.js.map +1 -1
- package/dist/src/policy/toml-loader.d.ts +3 -5
- package/dist/src/policy/toml-loader.js +35 -20
- package/dist/src/policy/toml-loader.js.map +1 -1
- package/dist/src/policy/toml-loader.test.js +28 -7
- package/dist/src/policy/toml-loader.test.js.map +1 -1
- package/dist/src/policy/types.d.ts +15 -0
- package/dist/src/routing/strategies/compositeStrategy.js +4 -2
- package/dist/src/routing/strategies/compositeStrategy.js.map +1 -1
- package/dist/src/routing/strategies/compositeStrategy.test.js +11 -10
- package/dist/src/routing/strategies/compositeStrategy.test.js.map +1 -1
- package/dist/src/routing/strategies/overrideStrategy.js +2 -2
- package/dist/src/routing/strategies/overrideStrategy.js.map +1 -1
- package/dist/src/scheduler/types.d.ts +95 -0
- package/dist/src/scheduler/types.js +7 -0
- package/dist/src/scheduler/types.js.map +1 -0
- package/dist/src/services/environmentSanitization.d.ts +15 -0
- package/dist/src/services/environmentSanitization.js +141 -0
- package/dist/src/services/environmentSanitization.js.map +1 -0
- package/dist/src/services/environmentSanitization.test.d.ts +6 -0
- package/dist/src/services/environmentSanitization.test.js +284 -0
- package/dist/src/services/environmentSanitization.test.js.map +1 -0
- package/dist/src/services/gitService.js +10 -1
- package/dist/src/services/gitService.js.map +1 -1
- package/dist/src/services/gitService.test.js +18 -0
- package/dist/src/services/gitService.test.js.map +1 -1
- package/dist/src/services/shellExecutionService.d.ts +2 -0
- package/dist/src/services/shellExecutionService.js +5 -65
- package/dist/src/services/shellExecutionService.js.map +1 -1
- package/dist/src/services/shellExecutionService.test.js +26 -3
- package/dist/src/services/shellExecutionService.test.js.map +1 -1
- package/dist/src/services/skillManager.d.ts +61 -0
- package/dist/src/services/skillManager.js +157 -0
- package/dist/src/services/skillManager.js.map +1 -0
- package/dist/src/services/skillManager.test.d.ts +6 -0
- package/dist/src/services/skillManager.test.js +169 -0
- package/dist/src/services/skillManager.test.js.map +1 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +4 -6
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
- package/dist/src/telemetry/loggers.test.circular.js +1 -0
- package/dist/src/telemetry/loggers.test.circular.js.map +1 -1
- package/dist/src/telemetry/sdk.js +3 -4
- package/dist/src/telemetry/sdk.js.map +1 -1
- package/dist/src/tools/edit.test.js +1 -1
- package/dist/src/tools/edit.test.js.map +1 -1
- package/dist/src/tools/mcp-client.d.ts +3 -2
- package/dist/src/tools/mcp-client.js +7 -6
- package/dist/src/tools/mcp-client.js.map +1 -1
- package/dist/src/tools/mcp-client.test.js +47 -42
- package/dist/src/tools/mcp-client.test.js.map +1 -1
- package/dist/src/tools/memoryTool.js +0 -2
- package/dist/src/tools/memoryTool.js.map +1 -1
- package/dist/src/tools/shell.js +6 -1
- package/dist/src/tools/shell.js.map +1 -1
- package/dist/src/tools/smart-edit.test.js +1 -1
- package/dist/src/tools/smart-edit.test.js.map +1 -1
- package/dist/src/tools/tool-error.d.ts +2 -1
- package/dist/src/tools/tool-error.js +2 -0
- package/dist/src/tools/tool-error.js.map +1 -1
- package/dist/src/tools/tool-registry.js +1 -1
- package/dist/src/tools/tool-registry.js.map +1 -1
- package/dist/src/tools/tools.d.ts +1 -1
- package/dist/src/tools/tools.js +1 -1
- package/dist/src/tools/web-search.js +2 -1
- package/dist/src/tools/web-search.js.map +1 -1
- package/dist/src/tools/write-file.js +2 -1
- package/dist/src/tools/write-file.js.map +1 -1
- package/dist/src/utils/checkpointUtils.d.ts +1 -1
- package/dist/src/utils/debugLogger.js +1 -0
- package/dist/src/utils/debugLogger.js.map +1 -1
- package/dist/src/utils/editCorrector.js +5 -4
- package/dist/src/utils/editCorrector.js.map +1 -1
- package/dist/src/utils/errorReporting.d.ts +1 -1
- package/dist/src/utils/errorReporting.js +13 -12
- package/dist/src/utils/errorReporting.js.map +1 -1
- package/dist/src/utils/errorReporting.test.js +17 -14
- package/dist/src/utils/errorReporting.test.js.map +1 -1
- package/dist/src/utils/fileUtils.d.ts +4 -0
- package/dist/src/utils/fileUtils.js +53 -0
- package/dist/src/utils/fileUtils.js.map +1 -1
- package/dist/src/utils/fileUtils.test.js +112 -1
- package/dist/src/utils/fileUtils.test.js.map +1 -1
- package/dist/src/utils/generateContentResponseUtilities.d.ts +2 -1
- package/dist/src/utils/generateContentResponseUtilities.js +96 -0
- package/dist/src/utils/generateContentResponseUtilities.js.map +1 -1
- package/dist/src/utils/generateContentResponseUtilities.test.js +221 -1
- package/dist/src/utils/generateContentResponseUtilities.test.js.map +1 -1
- package/dist/src/utils/getFolderStructure.js +1 -1
- package/dist/src/utils/getFolderStructure.js.map +1 -1
- package/dist/src/utils/memoryDiscovery.js +1 -1
- package/dist/src/utils/memoryDiscovery.js.map +1 -1
- package/dist/src/utils/retry.js +3 -3
- package/dist/src/utils/retry.js.map +1 -1
- package/dist/src/utils/summarizer.test.js +3 -2
- package/dist/src/utils/summarizer.test.js.map +1 -1
- package/dist/src/utils/terminal.d.ts +2 -0
- package/dist/src/utils/terminal.js +6 -0
- package/dist/src/utils/terminal.js.map +1 -1
- package/dist/src/utils/tool-utils.d.ts +9 -0
- package/dist/src/utils/tool-utils.js +29 -0
- package/dist/src/utils/tool-utils.js.map +1 -1
- package/dist/src/utils/tool-utils.test.js +15 -1
- package/dist/src/utils/tool-utils.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -1
- package/dist/google-gemini-cli-core-0.23.0-preview.3.tgz +0 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
7
|
+
import { executeToolWithHooks } from './coreToolHookTriggers.js';
|
|
8
|
+
import { ToolErrorType } from '../tools/tool-error.js';
|
|
9
|
+
import { BaseToolInvocation, } from '../tools/tools.js';
|
|
10
|
+
import { MessageBusType, } from '../confirmation-bus/types.js';
|
|
11
|
+
class MockInvocation extends BaseToolInvocation {
|
|
12
|
+
constructor(params) {
|
|
13
|
+
super(params);
|
|
14
|
+
}
|
|
15
|
+
getDescription() {
|
|
16
|
+
return 'mock';
|
|
17
|
+
}
|
|
18
|
+
async execute() {
|
|
19
|
+
return {
|
|
20
|
+
llmContent: this.params.key ? `key: ${this.params.key}` : 'success',
|
|
21
|
+
returnDisplay: this.params.key
|
|
22
|
+
? `key: ${this.params.key}`
|
|
23
|
+
: 'success display',
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
describe('executeToolWithHooks', () => {
|
|
28
|
+
let messageBus;
|
|
29
|
+
let mockTool;
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
messageBus = {
|
|
32
|
+
request: vi.fn(),
|
|
33
|
+
publish: vi.fn(),
|
|
34
|
+
subscribe: vi.fn(),
|
|
35
|
+
unsubscribe: vi.fn(),
|
|
36
|
+
};
|
|
37
|
+
mockTool = {
|
|
38
|
+
build: vi.fn().mockImplementation((params) => new MockInvocation(params)),
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
it('should prioritize continue: false over decision: block in BeforeTool', async () => {
|
|
42
|
+
const invocation = new MockInvocation({});
|
|
43
|
+
const abortSignal = new AbortController().signal;
|
|
44
|
+
vi.mocked(messageBus.request).mockResolvedValue({
|
|
45
|
+
type: MessageBusType.HOOK_EXECUTION_RESPONSE,
|
|
46
|
+
correlationId: 'test-id',
|
|
47
|
+
success: true,
|
|
48
|
+
output: {
|
|
49
|
+
continue: false,
|
|
50
|
+
stopReason: 'Stop immediately',
|
|
51
|
+
decision: 'block',
|
|
52
|
+
reason: 'Should be ignored because continue is false',
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
const result = await executeToolWithHooks(invocation, 'test_tool', abortSignal, messageBus, true, mockTool);
|
|
56
|
+
expect(result.error?.type).toBe(ToolErrorType.STOP_EXECUTION);
|
|
57
|
+
expect(result.error?.message).toBe('Stop immediately');
|
|
58
|
+
});
|
|
59
|
+
it('should block execution in BeforeTool if decision is block', async () => {
|
|
60
|
+
const invocation = new MockInvocation({});
|
|
61
|
+
const abortSignal = new AbortController().signal;
|
|
62
|
+
vi.mocked(messageBus.request).mockResolvedValue({
|
|
63
|
+
type: MessageBusType.HOOK_EXECUTION_RESPONSE,
|
|
64
|
+
correlationId: 'test-id',
|
|
65
|
+
success: true,
|
|
66
|
+
output: {
|
|
67
|
+
decision: 'block',
|
|
68
|
+
reason: 'Execution blocked',
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
const result = await executeToolWithHooks(invocation, 'test_tool', abortSignal, messageBus, true, mockTool);
|
|
72
|
+
expect(result.error?.type).toBe(ToolErrorType.EXECUTION_FAILED);
|
|
73
|
+
expect(result.error?.message).toBe('Execution blocked');
|
|
74
|
+
});
|
|
75
|
+
it('should handle continue: false in AfterTool', async () => {
|
|
76
|
+
const invocation = new MockInvocation({});
|
|
77
|
+
const abortSignal = new AbortController().signal;
|
|
78
|
+
const spy = vi.spyOn(invocation, 'execute');
|
|
79
|
+
// BeforeTool allow
|
|
80
|
+
vi.mocked(messageBus.request)
|
|
81
|
+
.mockResolvedValueOnce({
|
|
82
|
+
type: MessageBusType.HOOK_EXECUTION_RESPONSE,
|
|
83
|
+
correlationId: 'test-id',
|
|
84
|
+
success: true,
|
|
85
|
+
output: { decision: 'allow' },
|
|
86
|
+
})
|
|
87
|
+
// AfterTool stop
|
|
88
|
+
.mockResolvedValueOnce({
|
|
89
|
+
type: MessageBusType.HOOK_EXECUTION_RESPONSE,
|
|
90
|
+
correlationId: 'test-id',
|
|
91
|
+
success: true,
|
|
92
|
+
output: {
|
|
93
|
+
continue: false,
|
|
94
|
+
stopReason: 'Stop after execution',
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
const result = await executeToolWithHooks(invocation, 'test_tool', abortSignal, messageBus, true, mockTool);
|
|
98
|
+
expect(result.error?.type).toBe(ToolErrorType.STOP_EXECUTION);
|
|
99
|
+
expect(result.error?.message).toBe('Stop after execution');
|
|
100
|
+
expect(spy).toHaveBeenCalled();
|
|
101
|
+
});
|
|
102
|
+
it('should block result in AfterTool if decision is deny', async () => {
|
|
103
|
+
const invocation = new MockInvocation({});
|
|
104
|
+
const abortSignal = new AbortController().signal;
|
|
105
|
+
// BeforeTool allow
|
|
106
|
+
vi.mocked(messageBus.request)
|
|
107
|
+
.mockResolvedValueOnce({
|
|
108
|
+
type: MessageBusType.HOOK_EXECUTION_RESPONSE,
|
|
109
|
+
correlationId: 'test-id',
|
|
110
|
+
success: true,
|
|
111
|
+
output: { decision: 'allow' },
|
|
112
|
+
})
|
|
113
|
+
// AfterTool deny
|
|
114
|
+
.mockResolvedValueOnce({
|
|
115
|
+
type: MessageBusType.HOOK_EXECUTION_RESPONSE,
|
|
116
|
+
correlationId: 'test-id',
|
|
117
|
+
success: true,
|
|
118
|
+
output: {
|
|
119
|
+
decision: 'deny',
|
|
120
|
+
reason: 'Result denied',
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
const result = await executeToolWithHooks(invocation, 'test_tool', abortSignal, messageBus, true, mockTool);
|
|
124
|
+
expect(result.error?.type).toBe(ToolErrorType.EXECUTION_FAILED);
|
|
125
|
+
expect(result.error?.message).toBe('Result denied');
|
|
126
|
+
});
|
|
127
|
+
it('should apply modified tool input from BeforeTool hook', async () => {
|
|
128
|
+
const params = { key: 'original' };
|
|
129
|
+
const invocation = new MockInvocation(params);
|
|
130
|
+
const toolName = 'test-tool';
|
|
131
|
+
const abortSignal = new AbortController().signal;
|
|
132
|
+
// Capture arguments to verify what was passed before modification
|
|
133
|
+
const requestSpy = vi.fn().mockImplementation(async (request) => {
|
|
134
|
+
if (request.eventName === 'BeforeTool') {
|
|
135
|
+
// Verify input is original before we return modification instruction
|
|
136
|
+
expect(request.input.tool_input.key).toBe('original');
|
|
137
|
+
return {
|
|
138
|
+
type: MessageBusType.HOOK_EXECUTION_RESPONSE,
|
|
139
|
+
correlationId: 'test-id',
|
|
140
|
+
success: true,
|
|
141
|
+
output: {
|
|
142
|
+
hookSpecificOutput: {
|
|
143
|
+
hookEventName: 'BeforeTool',
|
|
144
|
+
tool_input: { key: 'modified' },
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
type: MessageBusType.HOOK_EXECUTION_RESPONSE,
|
|
151
|
+
correlationId: 'test-id',
|
|
152
|
+
success: true,
|
|
153
|
+
output: {},
|
|
154
|
+
};
|
|
155
|
+
});
|
|
156
|
+
messageBus.request = requestSpy;
|
|
157
|
+
const result = await executeToolWithHooks(invocation, toolName, abortSignal, messageBus, true, // hooksEnabled
|
|
158
|
+
mockTool);
|
|
159
|
+
// Verify result reflects modified input
|
|
160
|
+
expect(result.llmContent).toBe('key: modified\n\n[System] Tool input parameters (key) were modified by a hook before execution.');
|
|
161
|
+
// Verify params object was modified in place
|
|
162
|
+
expect(invocation.params.key).toBe('modified');
|
|
163
|
+
expect(requestSpy).toHaveBeenCalled();
|
|
164
|
+
expect(mockTool.build).toHaveBeenCalledWith({ key: 'modified' });
|
|
165
|
+
});
|
|
166
|
+
it('should not modify input if hook does not provide tool_input', async () => {
|
|
167
|
+
const params = { key: 'original' };
|
|
168
|
+
const invocation = new MockInvocation(params);
|
|
169
|
+
const toolName = 'test-tool';
|
|
170
|
+
const abortSignal = new AbortController().signal;
|
|
171
|
+
vi.mocked(messageBus.request).mockResolvedValue({
|
|
172
|
+
type: MessageBusType.HOOK_EXECUTION_RESPONSE,
|
|
173
|
+
correlationId: 'test-id',
|
|
174
|
+
success: true,
|
|
175
|
+
output: {
|
|
176
|
+
hookSpecificOutput: {
|
|
177
|
+
hookEventName: 'BeforeTool',
|
|
178
|
+
// No tool_input
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
const result = await executeToolWithHooks(invocation, toolName, abortSignal, messageBus, true, // hooksEnabled
|
|
183
|
+
mockTool);
|
|
184
|
+
expect(result.llmContent).toBe('key: original');
|
|
185
|
+
expect(invocation.params.key).toBe('original');
|
|
186
|
+
expect(mockTool.build).not.toHaveBeenCalled();
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
//# sourceMappingURL=coreToolHookTriggers.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coreToolHookTriggers.test.js","sourceRoot":"","sources":["../../../src/core/coreToolHookTriggers.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,82 +3,11 @@
|
|
|
3
3
|
* Copyright 2025 Google LLC
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
import type {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
request: ToolCallRequestInfo;
|
|
12
|
-
tool: AnyDeclarativeTool;
|
|
13
|
-
invocation: AnyToolInvocation;
|
|
14
|
-
startTime?: number;
|
|
15
|
-
outcome?: ToolConfirmationOutcome;
|
|
16
|
-
};
|
|
17
|
-
export type ScheduledToolCall = {
|
|
18
|
-
status: 'scheduled';
|
|
19
|
-
request: ToolCallRequestInfo;
|
|
20
|
-
tool: AnyDeclarativeTool;
|
|
21
|
-
invocation: AnyToolInvocation;
|
|
22
|
-
startTime?: number;
|
|
23
|
-
outcome?: ToolConfirmationOutcome;
|
|
24
|
-
};
|
|
25
|
-
export type ErroredToolCall = {
|
|
26
|
-
status: 'error';
|
|
27
|
-
request: ToolCallRequestInfo;
|
|
28
|
-
response: ToolCallResponseInfo;
|
|
29
|
-
tool?: AnyDeclarativeTool;
|
|
30
|
-
durationMs?: number;
|
|
31
|
-
outcome?: ToolConfirmationOutcome;
|
|
32
|
-
};
|
|
33
|
-
export type SuccessfulToolCall = {
|
|
34
|
-
status: 'success';
|
|
35
|
-
request: ToolCallRequestInfo;
|
|
36
|
-
tool: AnyDeclarativeTool;
|
|
37
|
-
response: ToolCallResponseInfo;
|
|
38
|
-
invocation: AnyToolInvocation;
|
|
39
|
-
durationMs?: number;
|
|
40
|
-
outcome?: ToolConfirmationOutcome;
|
|
41
|
-
};
|
|
42
|
-
export type ExecutingToolCall = {
|
|
43
|
-
status: 'executing';
|
|
44
|
-
request: ToolCallRequestInfo;
|
|
45
|
-
tool: AnyDeclarativeTool;
|
|
46
|
-
invocation: AnyToolInvocation;
|
|
47
|
-
liveOutput?: string | AnsiOutput;
|
|
48
|
-
startTime?: number;
|
|
49
|
-
outcome?: ToolConfirmationOutcome;
|
|
50
|
-
pid?: number;
|
|
51
|
-
};
|
|
52
|
-
export type CancelledToolCall = {
|
|
53
|
-
status: 'cancelled';
|
|
54
|
-
request: ToolCallRequestInfo;
|
|
55
|
-
response: ToolCallResponseInfo;
|
|
56
|
-
tool: AnyDeclarativeTool;
|
|
57
|
-
invocation: AnyToolInvocation;
|
|
58
|
-
durationMs?: number;
|
|
59
|
-
outcome?: ToolConfirmationOutcome;
|
|
60
|
-
};
|
|
61
|
-
export type WaitingToolCall = {
|
|
62
|
-
status: 'awaiting_approval';
|
|
63
|
-
request: ToolCallRequestInfo;
|
|
64
|
-
tool: AnyDeclarativeTool;
|
|
65
|
-
invocation: AnyToolInvocation;
|
|
66
|
-
confirmationDetails: ToolCallConfirmationDetails;
|
|
67
|
-
startTime?: number;
|
|
68
|
-
outcome?: ToolConfirmationOutcome;
|
|
69
|
-
};
|
|
70
|
-
export type Status = ToolCall['status'];
|
|
71
|
-
export type ToolCall = ValidatingToolCall | ScheduledToolCall | ErroredToolCall | SuccessfulToolCall | ExecutingToolCall | CancelledToolCall | WaitingToolCall;
|
|
72
|
-
export type CompletedToolCall = SuccessfulToolCall | CancelledToolCall | ErroredToolCall;
|
|
73
|
-
export type ConfirmHandler = (toolCall: WaitingToolCall) => Promise<ToolConfirmationOutcome>;
|
|
74
|
-
export type OutputUpdateHandler = (toolCallId: string, outputChunk: string | AnsiOutput) => void;
|
|
75
|
-
export type AllToolCallsCompleteHandler = (completedToolCalls: CompletedToolCall[]) => Promise<void>;
|
|
76
|
-
export type ToolCallsUpdateHandler = (toolCalls: ToolCall[]) => void;
|
|
77
|
-
export declare function convertToFunctionResponse(toolName: string, callId: string, llmContent: PartListUnion, model: string): Part[];
|
|
78
|
-
export declare function truncateAndSaveToFile(content: string, callId: string, projectTempDir: string, threshold: number, truncateLines: number): Promise<{
|
|
79
|
-
content: string;
|
|
80
|
-
outputFile?: string;
|
|
81
|
-
}>;
|
|
6
|
+
import { type ToolConfirmationPayload, ToolConfirmationOutcome } from '../tools/tools.js';
|
|
7
|
+
import type { EditorType } from '../utils/editor.js';
|
|
8
|
+
import type { Config } from '../config/config.js';
|
|
9
|
+
import { type ToolCall, type ValidatingToolCall, type ScheduledToolCall, type ErroredToolCall, type SuccessfulToolCall, type ExecutingToolCall, type CancelledToolCall, type WaitingToolCall, type Status, type CompletedToolCall, type ConfirmHandler, type OutputUpdateHandler, type AllToolCallsCompleteHandler, type ToolCallsUpdateHandler, type ToolCallRequestInfo, type ToolCallResponseInfo } from '../scheduler/types.js';
|
|
10
|
+
export type { ToolCall, ValidatingToolCall, ScheduledToolCall, ErroredToolCall, SuccessfulToolCall, ExecutingToolCall, CancelledToolCall, WaitingToolCall, Status, CompletedToolCall, ConfirmHandler, OutputUpdateHandler, AllToolCallsCompleteHandler, ToolCallsUpdateHandler, ToolCallRequestInfo, ToolCallResponseInfo, };
|
|
82
11
|
interface CoreToolSchedulerOptions {
|
|
83
12
|
config: Config;
|
|
84
13
|
outputUpdateHandler?: OutputUpdateHandler;
|
|
@@ -105,14 +34,6 @@ export declare class CoreToolScheduler {
|
|
|
105
34
|
private setArgsInternal;
|
|
106
35
|
private isRunning;
|
|
107
36
|
private buildInvocation;
|
|
108
|
-
/**
|
|
109
|
-
* Generates a suggestion string for a tool name that was not found in the registry.
|
|
110
|
-
* It finds the closest matches based on Levenshtein distance.
|
|
111
|
-
* @param unknownToolName The tool name that was not found.
|
|
112
|
-
* @param topN The number of suggestions to return. Defaults to 3.
|
|
113
|
-
* @returns A suggestion string like " Did you mean 'tool'?" or " Did you mean one of: 'tool1', 'tool2'?", or an empty string if no suggestions are found.
|
|
114
|
-
*/
|
|
115
|
-
private getToolSuggestion;
|
|
116
37
|
schedule(request: ToolCallRequestInfo | ToolCallRequestInfo[], signal: AbortSignal): Promise<void>;
|
|
117
38
|
cancelAll(signal: AbortSignal): void;
|
|
118
39
|
private _schedule;
|
|
@@ -132,4 +53,3 @@ export declare class CoreToolScheduler {
|
|
|
132
53
|
private setToolCallOutcome;
|
|
133
54
|
private isAutoApproved;
|
|
134
55
|
}
|
|
135
|
-
export {};
|
|
@@ -3,115 +3,24 @@
|
|
|
3
3
|
* Copyright 2025 Google LLC
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
-
import { ToolConfirmationOutcome,
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
6
|
+
import { ToolConfirmationOutcome, } from '../tools/tools.js';
|
|
7
|
+
import { ApprovalMode } from '../policy/types.js';
|
|
8
|
+
import { logToolCall, logToolOutputTruncated } from '../telemetry/loggers.js';
|
|
9
|
+
import { ToolErrorType } from '../tools/tool-error.js';
|
|
10
|
+
import { ToolCallEvent, ToolOutputTruncatedEvent } from '../telemetry/types.js';
|
|
11
|
+
import { runInDevTraceSpan } from '../telemetry/trace.js';
|
|
12
|
+
import { SHELL_TOOL_NAME } from '../tools/tool-names.js';
|
|
9
13
|
import { isModifiableDeclarativeTool, modifyWithEditor, } from '../tools/modifiable-tool.js';
|
|
10
14
|
import * as Diff from 'diff';
|
|
11
|
-
import * as fs from 'node:fs/promises';
|
|
12
|
-
import * as path from 'node:path';
|
|
13
15
|
import { SHELL_TOOL_NAMES } from '../utils/shell-utils.js';
|
|
14
|
-
import { doesToolInvocationMatch } from '../utils/tool-utils.js';
|
|
16
|
+
import { doesToolInvocationMatch, getToolSuggestion, } from '../utils/tool-utils.js';
|
|
15
17
|
import { isShellInvocationAllowlisted } from '../utils/shell-permissions.js';
|
|
16
|
-
import levenshtein from 'fast-levenshtein';
|
|
17
18
|
import { ShellToolInvocation } from '../tools/shell.js';
|
|
18
19
|
import { MessageBusType } from '../confirmation-bus/types.js';
|
|
19
20
|
import { fireToolNotificationHook, executeToolWithHooks, } from './coreToolHookTriggers.js';
|
|
20
|
-
import {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
*/
|
|
24
|
-
function createFunctionResponsePart(callId, toolName, output) {
|
|
25
|
-
return {
|
|
26
|
-
functionResponse: {
|
|
27
|
-
id: callId,
|
|
28
|
-
name: toolName,
|
|
29
|
-
response: { output },
|
|
30
|
-
},
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
export function convertToFunctionResponse(toolName, callId, llmContent, model) {
|
|
34
|
-
if (typeof llmContent === 'string') {
|
|
35
|
-
return [createFunctionResponsePart(callId, toolName, llmContent)];
|
|
36
|
-
}
|
|
37
|
-
const parts = toParts(llmContent);
|
|
38
|
-
// Separate text from binary types
|
|
39
|
-
const textParts = [];
|
|
40
|
-
const inlineDataParts = [];
|
|
41
|
-
const fileDataParts = [];
|
|
42
|
-
for (const part of parts) {
|
|
43
|
-
if (part.text !== undefined) {
|
|
44
|
-
textParts.push(part.text);
|
|
45
|
-
}
|
|
46
|
-
else if (part.inlineData) {
|
|
47
|
-
inlineDataParts.push(part);
|
|
48
|
-
}
|
|
49
|
-
else if (part.fileData) {
|
|
50
|
-
fileDataParts.push(part);
|
|
51
|
-
}
|
|
52
|
-
else if (part.functionResponse) {
|
|
53
|
-
if (parts.length > 1) {
|
|
54
|
-
debugLogger.warn('convertToFunctionResponse received multiple parts with a functionResponse. Only the functionResponse will be used, other parts will be ignored');
|
|
55
|
-
}
|
|
56
|
-
// Handle passthrough case
|
|
57
|
-
return [
|
|
58
|
-
{
|
|
59
|
-
functionResponse: {
|
|
60
|
-
id: callId,
|
|
61
|
-
name: toolName,
|
|
62
|
-
response: part.functionResponse.response,
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
];
|
|
66
|
-
}
|
|
67
|
-
// Ignore other part types
|
|
68
|
-
}
|
|
69
|
-
// Build the primary response part
|
|
70
|
-
const part = {
|
|
71
|
-
functionResponse: {
|
|
72
|
-
id: callId,
|
|
73
|
-
name: toolName,
|
|
74
|
-
response: textParts.length > 0 ? { output: textParts.join('\n') } : {},
|
|
75
|
-
},
|
|
76
|
-
};
|
|
77
|
-
const isMultimodalFRSupported = supportsMultimodalFunctionResponse(model);
|
|
78
|
-
const siblingParts = [...fileDataParts];
|
|
79
|
-
if (inlineDataParts.length > 0) {
|
|
80
|
-
if (isMultimodalFRSupported) {
|
|
81
|
-
// Nest inlineData if supported by the model
|
|
82
|
-
part.functionResponse.parts =
|
|
83
|
-
inlineDataParts;
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
// Otherwise treat as siblings
|
|
87
|
-
siblingParts.push(...inlineDataParts);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
// Add descriptive text if the response object is empty but we have binary content
|
|
91
|
-
if (textParts.length === 0 &&
|
|
92
|
-
(inlineDataParts.length > 0 || fileDataParts.length > 0)) {
|
|
93
|
-
const totalBinaryItems = inlineDataParts.length + fileDataParts.length;
|
|
94
|
-
part.functionResponse.response = {
|
|
95
|
-
output: `Binary content provided (${totalBinaryItems} item(s)).`,
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
if (siblingParts.length > 0) {
|
|
99
|
-
return [part, ...siblingParts];
|
|
100
|
-
}
|
|
101
|
-
return [part];
|
|
102
|
-
}
|
|
103
|
-
function toParts(input) {
|
|
104
|
-
const parts = [];
|
|
105
|
-
for (const part of Array.isArray(input) ? input : [input]) {
|
|
106
|
-
if (typeof part === 'string') {
|
|
107
|
-
parts.push({ text: part });
|
|
108
|
-
}
|
|
109
|
-
else if (part) {
|
|
110
|
-
parts.push(part);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
return parts;
|
|
114
|
-
}
|
|
21
|
+
import {} from '../scheduler/types.js';
|
|
22
|
+
import { saveTruncatedContent } from '../utils/fileUtils.js';
|
|
23
|
+
import { convertToFunctionResponse } from '../utils/generateContentResponseUtilities.js';
|
|
115
24
|
const createErrorResponse = (request, error, errorType) => ({
|
|
116
25
|
callId: request.callId,
|
|
117
26
|
error,
|
|
@@ -128,58 +37,6 @@ const createErrorResponse = (request, error, errorType) => ({
|
|
|
128
37
|
errorType,
|
|
129
38
|
contentLength: error.message.length,
|
|
130
39
|
});
|
|
131
|
-
export async function truncateAndSaveToFile(content, callId, projectTempDir, threshold, truncateLines) {
|
|
132
|
-
if (content.length <= threshold) {
|
|
133
|
-
return { content };
|
|
134
|
-
}
|
|
135
|
-
let lines = content.split('\n');
|
|
136
|
-
let fileContent = content;
|
|
137
|
-
// If the content is long but has few lines, wrap it to enable line-based truncation.
|
|
138
|
-
if (lines.length <= truncateLines) {
|
|
139
|
-
const wrapWidth = 120; // A reasonable width for wrapping.
|
|
140
|
-
const wrappedLines = [];
|
|
141
|
-
for (const line of lines) {
|
|
142
|
-
if (line.length > wrapWidth) {
|
|
143
|
-
for (let i = 0; i < line.length; i += wrapWidth) {
|
|
144
|
-
wrappedLines.push(line.substring(i, i + wrapWidth));
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
else {
|
|
148
|
-
wrappedLines.push(line);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
lines = wrappedLines;
|
|
152
|
-
fileContent = lines.join('\n');
|
|
153
|
-
}
|
|
154
|
-
const head = Math.floor(truncateLines / 5);
|
|
155
|
-
const beginning = lines.slice(0, head);
|
|
156
|
-
const end = lines.slice(-(truncateLines - head));
|
|
157
|
-
const truncatedContent = beginning.join('\n') + '\n... [CONTENT TRUNCATED] ...\n' + end.join('\n');
|
|
158
|
-
// Sanitize callId to prevent path traversal.
|
|
159
|
-
const safeFileName = `${path.basename(callId)}.output`;
|
|
160
|
-
const outputFile = path.join(projectTempDir, safeFileName);
|
|
161
|
-
try {
|
|
162
|
-
await fs.writeFile(outputFile, fileContent);
|
|
163
|
-
return {
|
|
164
|
-
content: `Tool output was too large and has been truncated.
|
|
165
|
-
The full output has been saved to: ${outputFile}
|
|
166
|
-
To read the complete output, use the ${READ_FILE_TOOL_NAME} tool with the absolute file path above. For large files, you can use the offset and limit parameters to read specific sections:
|
|
167
|
-
- ${READ_FILE_TOOL_NAME} tool with offset=0, limit=100 to see the first 100 lines
|
|
168
|
-
- ${READ_FILE_TOOL_NAME} tool with offset=N to skip N lines from the beginning
|
|
169
|
-
- ${READ_FILE_TOOL_NAME} tool with limit=M to read only M lines at a time
|
|
170
|
-
The truncated output below shows the beginning and end of the content. The marker '... [CONTENT TRUNCATED] ...' indicates where content was removed.
|
|
171
|
-
This allows you to efficiently examine different parts of the output without loading the entire file.
|
|
172
|
-
Truncated part of the output:
|
|
173
|
-
${truncatedContent}`,
|
|
174
|
-
outputFile,
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
catch (_error) {
|
|
178
|
-
return {
|
|
179
|
-
content: truncatedContent + `\n[Note: Could not save full output to file]`,
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
40
|
export class CoreToolScheduler {
|
|
184
41
|
// Static WeakMap to track which MessageBus instances already have a handler subscribed
|
|
185
42
|
// This prevents duplicate subscriptions when multiple CoreToolScheduler instances are created
|
|
@@ -206,26 +63,24 @@ export class CoreToolScheduler {
|
|
|
206
63
|
// Use a static WeakMap to ensure we only subscribe ONCE per MessageBus instance
|
|
207
64
|
// This prevents memory leaks when multiple CoreToolScheduler instances are created
|
|
208
65
|
// (e.g., on every React render, or for each non-interactive tool call)
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
CoreToolScheduler.subscribedMessageBuses.set(messageBus, sharedHandler);
|
|
228
|
-
}
|
|
66
|
+
const messageBus = this.config.getMessageBus();
|
|
67
|
+
// Check if we've already subscribed a handler to this message bus
|
|
68
|
+
if (!CoreToolScheduler.subscribedMessageBuses.has(messageBus)) {
|
|
69
|
+
// Create a shared handler that will be used for this message bus
|
|
70
|
+
const sharedHandler = (request) => {
|
|
71
|
+
// When ASK_USER policy decision is made, respond with requiresUserConfirmation=true
|
|
72
|
+
// to tell tools to use their legacy confirmation flow
|
|
73
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
74
|
+
messageBus.publish({
|
|
75
|
+
type: MessageBusType.TOOL_CONFIRMATION_RESPONSE,
|
|
76
|
+
correlationId: request.correlationId,
|
|
77
|
+
confirmed: false,
|
|
78
|
+
requiresUserConfirmation: true,
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
messageBus.subscribe(MessageBusType.TOOL_CONFIRMATION_REQUEST, sharedHandler);
|
|
82
|
+
// Store the handler in the WeakMap so we don't subscribe again
|
|
83
|
+
CoreToolScheduler.subscribedMessageBuses.set(messageBus, sharedHandler);
|
|
229
84
|
}
|
|
230
85
|
}
|
|
231
86
|
setStatusInternal(targetCallId, newStatus, signal, auxiliaryData) {
|
|
@@ -398,34 +253,6 @@ export class CoreToolScheduler {
|
|
|
398
253
|
return new Error(String(e));
|
|
399
254
|
}
|
|
400
255
|
}
|
|
401
|
-
/**
|
|
402
|
-
* Generates a suggestion string for a tool name that was not found in the registry.
|
|
403
|
-
* It finds the closest matches based on Levenshtein distance.
|
|
404
|
-
* @param unknownToolName The tool name that was not found.
|
|
405
|
-
* @param topN The number of suggestions to return. Defaults to 3.
|
|
406
|
-
* @returns A suggestion string like " Did you mean 'tool'?" or " Did you mean one of: 'tool1', 'tool2'?", or an empty string if no suggestions are found.
|
|
407
|
-
*/
|
|
408
|
-
getToolSuggestion(unknownToolName, topN = 3) {
|
|
409
|
-
const allToolNames = this.config.getToolRegistry().getAllToolNames();
|
|
410
|
-
const matches = allToolNames.map((toolName) => ({
|
|
411
|
-
name: toolName,
|
|
412
|
-
distance: levenshtein.get(unknownToolName, toolName),
|
|
413
|
-
}));
|
|
414
|
-
matches.sort((a, b) => a.distance - b.distance);
|
|
415
|
-
const topNResults = matches.slice(0, topN);
|
|
416
|
-
if (topNResults.length === 0) {
|
|
417
|
-
return '';
|
|
418
|
-
}
|
|
419
|
-
const suggestedNames = topNResults
|
|
420
|
-
.map((match) => `"${match.name}"`)
|
|
421
|
-
.join(', ');
|
|
422
|
-
if (topNResults.length > 1) {
|
|
423
|
-
return ` Did you mean one of: ${suggestedNames}?`;
|
|
424
|
-
}
|
|
425
|
-
else {
|
|
426
|
-
return ` Did you mean ${suggestedNames}?`;
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
256
|
schedule(request, signal) {
|
|
430
257
|
return runInDevTraceSpan({ name: 'schedule' }, async ({ metadata: spanMetadata }) => {
|
|
431
258
|
spanMetadata.input = request;
|
|
@@ -492,7 +319,7 @@ export class CoreToolScheduler {
|
|
|
492
319
|
.getToolRegistry()
|
|
493
320
|
.getTool(reqInfo.name);
|
|
494
321
|
if (!toolInstance) {
|
|
495
|
-
const suggestion =
|
|
322
|
+
const suggestion = getToolSuggestion(reqInfo.name, this.config.getToolRegistry().getAllToolNames());
|
|
496
323
|
const errorMessage = `Tool "${reqInfo.name}" not found in registry. Tools must use the exact names that are registered.${suggestion}`;
|
|
497
324
|
return {
|
|
498
325
|
status: 'error',
|
|
@@ -731,10 +558,10 @@ export class CoreToolScheduler {
|
|
|
731
558
|
: tc);
|
|
732
559
|
this.notifyToolCallsUpdate();
|
|
733
560
|
};
|
|
734
|
-
promise = executeToolWithHooks(invocation, toolName, signal, messageBus, hooksEnabled, liveOutputCallback, shellExecutionConfig, setPidCallback);
|
|
561
|
+
promise = executeToolWithHooks(invocation, toolName, signal, messageBus, hooksEnabled, toolCall.tool, liveOutputCallback, shellExecutionConfig, setPidCallback);
|
|
735
562
|
}
|
|
736
563
|
else {
|
|
737
|
-
promise = executeToolWithHooks(invocation, toolName, signal, messageBus, hooksEnabled, liveOutputCallback, shellExecutionConfig);
|
|
564
|
+
promise = executeToolWithHooks(invocation, toolName, signal, messageBus, hooksEnabled, toolCall.tool, liveOutputCallback, shellExecutionConfig);
|
|
738
565
|
}
|
|
739
566
|
try {
|
|
740
567
|
const toolResult = await promise;
|
|
@@ -754,7 +581,7 @@ export class CoreToolScheduler {
|
|
|
754
581
|
const originalContentLength = content.length;
|
|
755
582
|
const threshold = this.config.getTruncateToolOutputThreshold();
|
|
756
583
|
const lines = this.config.getTruncateToolOutputLines();
|
|
757
|
-
const truncatedResult = await
|
|
584
|
+
const truncatedResult = await saveTruncatedContent(content, callId, this.config.storage.getProjectTempDir(), threshold, lines);
|
|
758
585
|
content = truncatedResult.content;
|
|
759
586
|
outputFile = truncatedResult.outputFile;
|
|
760
587
|
if (outputFile) {
|