@vybestack/llxprt-code 0.1.19-gamma → 0.1.20
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 +9 -0
- package/dist/package.json +5 -5
- package/dist/src/auth/oauth-manager.d.ts +1 -0
- package/dist/src/auth/oauth-manager.js +24 -13
- package/dist/src/auth/oauth-manager.js.map +1 -1
- package/dist/src/auth/oauth-manager.spec.js +4 -4
- package/dist/src/auth/oauth-manager.spec.js.map +1 -1
- package/dist/src/commands/mcp/list.js +1 -1
- package/dist/src/commands/mcp/list.js.map +1 -1
- package/dist/src/config/config.d.ts +2 -1
- package/dist/src/config/config.js +183 -25
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/keyBindings.js +4 -0
- package/dist/src/config/keyBindings.js.map +1 -1
- package/dist/src/config/settingsSchema.d.ts +18 -9
- package/dist/src/config/settingsSchema.js +18 -9
- package/dist/src/config/settingsSchema.js.map +1 -1
- package/dist/src/config/trustedFolders.d.ts +36 -0
- package/dist/src/config/trustedFolders.js +112 -0
- package/dist/src/config/trustedFolders.js.map +1 -0
- package/dist/src/gemini.js +28 -18
- package/dist/src/gemini.js.map +1 -1
- package/dist/src/generated/git-commit.d.ts +1 -1
- package/dist/src/generated/git-commit.js +1 -1
- package/dist/src/nonInteractiveCli.js +3 -4
- package/dist/src/nonInteractiveCli.js.map +1 -1
- package/dist/src/providers/logging/git-stats.js +0 -1
- package/dist/src/providers/logging/git-stats.js.map +1 -1
- package/dist/src/providers/providerConfigUtils.js +1 -1
- package/dist/src/providers/providerConfigUtils.js.map +1 -1
- package/dist/src/services/BuiltinCommandLoader.js +2 -0
- package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
- package/dist/src/services/todo-continuation/todoContinuationService.d.ts +0 -1
- package/dist/src/services/todo-continuation/todoContinuationService.js +2 -1
- package/dist/src/services/todo-continuation/todoContinuationService.js.map +1 -1
- package/dist/src/ui/App.js +50 -34
- package/dist/src/ui/App.js.map +1 -1
- package/dist/src/ui/IdeIntegrationNudge.d.ts +7 -4
- package/dist/src/ui/IdeIntegrationNudge.js +31 -10
- package/dist/src/ui/IdeIntegrationNudge.js.map +1 -1
- package/dist/src/ui/commands/authCommand.js +16 -8
- package/dist/src/ui/commands/authCommand.js.map +1 -1
- package/dist/src/ui/commands/directoryCommand.js +2 -4
- package/dist/src/ui/commands/directoryCommand.js.map +1 -1
- package/dist/src/ui/commands/ideCommand.js +11 -8
- package/dist/src/ui/commands/ideCommand.js.map +1 -1
- package/dist/src/ui/commands/keyCommand.js +1 -1
- package/dist/src/ui/commands/keyCommand.js.map +1 -1
- package/dist/src/ui/commands/keyfileCommand.js +1 -1
- package/dist/src/ui/commands/keyfileCommand.js.map +1 -1
- package/dist/src/ui/commands/mcpCommand.js +10 -6
- package/dist/src/ui/commands/mcpCommand.js.map +1 -1
- package/dist/src/ui/commands/setCommand.js +43 -3
- package/dist/src/ui/commands/setCommand.js.map +1 -1
- package/dist/src/ui/commands/setupGithubCommand.js +5 -16
- package/dist/src/ui/commands/setupGithubCommand.js.map +1 -1
- package/dist/src/ui/commands/terminalSetupCommand.d.ts +13 -0
- package/dist/src/ui/commands/terminalSetupCommand.js +41 -0
- package/dist/src/ui/commands/terminalSetupCommand.js.map +1 -0
- package/dist/src/ui/commands/types.d.ts +1 -0
- package/dist/src/ui/commands/types.js.map +1 -1
- package/dist/src/ui/components/AuthDialog.js +56 -29
- package/dist/src/ui/components/AuthDialog.js.map +1 -1
- package/dist/src/ui/components/AuthInProgress.js +5 -4
- package/dist/src/ui/components/AuthInProgress.js.map +1 -1
- package/dist/src/ui/components/DebugProfiler.js +5 -4
- package/dist/src/ui/components/DebugProfiler.js.map +1 -1
- package/dist/src/ui/components/DetailedMessagesDisplay.js +4 -4
- package/dist/src/ui/components/DetailedMessagesDisplay.js.map +1 -1
- package/dist/src/ui/components/EditorSettingsDialog.js +6 -5
- package/dist/src/ui/components/EditorSettingsDialog.js.map +1 -1
- package/dist/src/ui/components/ErrorBoundary.js +2 -2
- package/dist/src/ui/components/ErrorBoundary.js.map +1 -1
- package/dist/src/ui/components/FolderTrustDialog.js +5 -4
- package/dist/src/ui/components/FolderTrustDialog.js.map +1 -1
- package/dist/src/ui/components/InputPrompt.js +7 -1
- package/dist/src/ui/components/InputPrompt.js.map +1 -1
- package/dist/src/ui/components/LoggingDialog.js +5 -1
- package/dist/src/ui/components/LoggingDialog.js.map +1 -1
- package/dist/src/ui/components/OAuthCodeDialog.js +12 -14
- package/dist/src/ui/components/OAuthCodeDialog.js.map +1 -1
- package/dist/src/ui/components/SettingsDialog.js +12 -10
- package/dist/src/ui/components/SettingsDialog.js.map +1 -1
- package/dist/src/ui/components/ShellConfirmationDialog.js +5 -4
- package/dist/src/ui/components/ShellConfirmationDialog.js.map +1 -1
- package/dist/src/ui/components/ThemeDialog.js +6 -5
- package/dist/src/ui/components/ThemeDialog.js.map +1 -1
- package/dist/src/ui/components/TodoPanel.js +2 -2
- package/dist/src/ui/components/TodoPanel.js.map +1 -1
- package/dist/src/ui/components/messages/InfoMessage.js +1 -1
- package/dist/src/ui/components/messages/InfoMessage.js.map +1 -1
- package/dist/src/ui/components/messages/ToolConfirmationMessage.js +8 -7
- package/dist/src/ui/components/messages/ToolConfirmationMessage.js.map +1 -1
- package/dist/src/ui/components/shared/RadioButtonSelect.js +11 -9
- package/dist/src/ui/components/shared/RadioButtonSelect.js.map +1 -1
- package/dist/src/ui/components/shared/text-buffer.d.ts +17 -4
- package/dist/src/ui/components/shared/text-buffer.js +256 -80
- package/dist/src/ui/components/shared/text-buffer.js.map +1 -1
- package/dist/src/ui/components/shared/vim-buffer-actions.js +139 -152
- package/dist/src/ui/components/shared/vim-buffer-actions.js.map +1 -1
- package/dist/src/ui/containers/SessionController.js +23 -23
- package/dist/src/ui/containers/SessionController.js.map +1 -1
- package/dist/src/ui/hooks/atCommandProcessor.js +1 -1
- package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/slashCommandProcessor.js +7 -1
- package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/useAuthCommand.js +8 -60
- package/dist/src/ui/hooks/useAuthCommand.js.map +1 -1
- package/dist/src/ui/hooks/useAutoAcceptIndicator.js +5 -5
- package/dist/src/ui/hooks/useAutoAcceptIndicator.js.map +1 -1
- package/dist/src/ui/hooks/useFocus.d.ts +4 -0
- package/dist/src/ui/hooks/useFocus.js +4 -4
- package/dist/src/ui/hooks/useFocus.js.map +1 -1
- package/dist/src/ui/hooks/useFolderTrust.d.ts +3 -2
- package/dist/src/ui/hooks/useFolderTrust.js +24 -9
- package/dist/src/ui/hooks/useFolderTrust.js.map +1 -1
- package/dist/src/ui/hooks/useGeminiStream.d.ts +1 -0
- package/dist/src/ui/hooks/useGeminiStream.js +126 -40
- package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
- package/dist/src/ui/hooks/useKeypress.d.ts +9 -1
- package/dist/src/ui/hooks/useKeypress.js +191 -8
- package/dist/src/ui/hooks/useKeypress.js.map +1 -1
- package/dist/src/ui/hooks/useKittyKeyboardProtocol.d.ts +15 -0
- package/dist/src/ui/hooks/useKittyKeyboardProtocol.js +20 -0
- package/dist/src/ui/hooks/useKittyKeyboardProtocol.js.map +1 -0
- package/dist/src/ui/privacy/CloudFreePrivacyNotice.js +5 -4
- package/dist/src/ui/privacy/CloudFreePrivacyNotice.js.map +1 -1
- package/dist/src/ui/privacy/CloudPaidPrivacyNotice.js +5 -4
- package/dist/src/ui/privacy/CloudPaidPrivacyNotice.js.map +1 -1
- package/dist/src/ui/privacy/GeminiPrivacyNotice.js +5 -4
- package/dist/src/ui/privacy/GeminiPrivacyNotice.js.map +1 -1
- package/dist/src/ui/reducers/sessionReducer.js +1 -0
- package/dist/src/ui/reducers/sessionReducer.js.map +1 -1
- package/dist/src/ui/utils/kittyProtocolDetector.d.ts +13 -0
- package/dist/src/ui/utils/kittyProtocolDetector.js +88 -0
- package/dist/src/ui/utils/kittyProtocolDetector.js.map +1 -0
- package/dist/src/ui/utils/platformConstants.d.ts +38 -0
- package/dist/src/ui/utils/platformConstants.js +39 -0
- package/dist/src/ui/utils/platformConstants.js.map +1 -0
- package/dist/src/ui/utils/renderLoopDetector.js +3 -3
- package/dist/src/ui/utils/renderLoopDetector.js.map +1 -1
- package/dist/src/ui/utils/terminalSetup.d.ts +30 -0
- package/dist/src/ui/utils/terminalSetup.js +281 -0
- package/dist/src/ui/utils/terminalSetup.js.map +1 -0
- package/dist/src/utils/checks.d.ts +19 -0
- package/dist/src/utils/checks.js +24 -0
- package/dist/src/utils/checks.js.map +1 -0
- package/dist/src/utils/privacy/ConversationDataRedactor.d.ts +0 -2
- package/dist/src/utils/privacy/ConversationDataRedactor.js +4 -37
- package/dist/src/utils/privacy/ConversationDataRedactor.js.map +1 -1
- package/dist/src/zed-integration/acp.d.ts +63 -0
- package/dist/src/{acp → zed-integration}/acp.js +76 -44
- package/dist/src/zed-integration/acp.js.map +1 -0
- package/dist/src/zed-integration/schema.d.ts +11679 -0
- package/dist/src/zed-integration/schema.js +305 -0
- package/dist/src/zed-integration/schema.js.map +1 -0
- package/dist/src/zed-integration/zedIntegration.d.ts +10 -0
- package/dist/src/{acp/acpPeer.js → zed-integration/zedIntegration.js} +333 -188
- package/dist/src/zed-integration/zedIntegration.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/dist/src/acp/acp.d.ts +0 -208
- package/dist/src/acp/acp.js.map +0 -1
- package/dist/src/acp/acpPeer.d.ts +0 -8
- package/dist/src/acp/acpPeer.js.map +0 -1
- package/dist/src/ui/utils/errorParsing.d.ts +0 -7
- package/dist/src/ui/utils/errorParsing.js +0 -106
- package/dist/src/ui/utils/errorParsing.js.map +0 -1
@@ -3,13 +3,16 @@
|
|
3
3
|
* Copyright 2025 Google LLC
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
5
5
|
*/
|
6
|
-
import { AuthType, logToolCall, convertToFunctionResponse, ToolConfirmationOutcome, clearCachedCredentialFile, isNodeError, getErrorMessage, isWithinRoot, getErrorStatus, } from '@vybestack/llxprt-code-core';
|
6
|
+
import { AuthType, logToolCall, convertToFunctionResponse, ToolConfirmationOutcome, clearCachedCredentialFile, isNodeError, getErrorMessage, isWithinRoot, getErrorStatus, MCPServerConfig, } from '@vybestack/llxprt-code-core';
|
7
7
|
import * as acp from './acp.js';
|
8
8
|
import { Readable, Writable } from 'node:stream';
|
9
9
|
import { SettingScope } from '../config/settings.js';
|
10
10
|
import * as fs from 'fs/promises';
|
11
11
|
import * as path from 'path';
|
12
|
-
|
12
|
+
import { z } from 'zod';
|
13
|
+
import { randomUUID } from 'crypto';
|
14
|
+
import { loadCliConfig } from '../config/config.js';
|
15
|
+
export async function runZedIntegration(config, settings, extensions, argv) {
|
13
16
|
const stdout = Writable.toWeb(process.stdout);
|
14
17
|
const stdin = Readable.toWeb(process.stdin);
|
15
18
|
// Stdout is used to send messages to the client, so console.log/console.info
|
@@ -17,61 +20,138 @@ export async function runAcpPeer(config, settings) {
|
|
17
20
|
console.log = console.error;
|
18
21
|
console.info = console.error;
|
19
22
|
console.debug = console.error;
|
20
|
-
new acp.
|
23
|
+
new acp.AgentSideConnection((client) => new GeminiAgent(config, settings, extensions, argv, client), stdout, stdin);
|
21
24
|
}
|
22
25
|
class GeminiAgent {
|
23
26
|
config;
|
24
27
|
settings;
|
28
|
+
extensions;
|
29
|
+
argv;
|
25
30
|
client;
|
26
|
-
|
27
|
-
|
28
|
-
constructor(config, settings, client) {
|
31
|
+
sessions = new Map();
|
32
|
+
constructor(config, settings, extensions, argv, client) {
|
29
33
|
this.config = config;
|
30
34
|
this.settings = settings;
|
35
|
+
this.extensions = extensions;
|
36
|
+
this.argv = argv;
|
31
37
|
this.client = client;
|
32
38
|
}
|
33
|
-
async initialize(
|
39
|
+
async initialize(_args) {
|
40
|
+
const authMethods = [
|
41
|
+
{
|
42
|
+
id: AuthType.LOGIN_WITH_GOOGLE,
|
43
|
+
name: 'Log in with Google',
|
44
|
+
description: null,
|
45
|
+
},
|
46
|
+
{
|
47
|
+
id: AuthType.USE_GEMINI,
|
48
|
+
name: 'Use Gemini API key',
|
49
|
+
description: 'Requires setting the `GEMINI_API_KEY` environment variable',
|
50
|
+
},
|
51
|
+
{
|
52
|
+
id: AuthType.USE_VERTEX_AI,
|
53
|
+
name: 'Vertex AI',
|
54
|
+
description: null,
|
55
|
+
},
|
56
|
+
];
|
57
|
+
return {
|
58
|
+
protocolVersion: acp.PROTOCOL_VERSION,
|
59
|
+
authMethods,
|
60
|
+
agentCapabilities: {
|
61
|
+
loadSession: false,
|
62
|
+
},
|
63
|
+
};
|
64
|
+
}
|
65
|
+
async authenticate({ methodId }) {
|
66
|
+
const method = z.nativeEnum(AuthType).parse(methodId);
|
67
|
+
await clearCachedCredentialFile();
|
68
|
+
await this.config.refreshAuth(method);
|
69
|
+
this.settings.setValue(SettingScope.User, 'selectedAuthType', method);
|
70
|
+
}
|
71
|
+
async newSession({ cwd, mcpServers, }) {
|
72
|
+
const sessionId = randomUUID();
|
73
|
+
const config = await this.newSessionConfig(sessionId, cwd, mcpServers);
|
34
74
|
let isAuthenticated = false;
|
35
75
|
if (this.settings.merged.selectedAuthType) {
|
36
76
|
try {
|
37
|
-
await
|
77
|
+
await config.refreshAuth(this.settings.merged.selectedAuthType);
|
38
78
|
isAuthenticated = true;
|
39
79
|
}
|
40
|
-
catch (
|
41
|
-
console.error(
|
80
|
+
catch (e) {
|
81
|
+
console.error(`Authentication failed: ${e}`);
|
42
82
|
}
|
43
83
|
}
|
44
|
-
|
84
|
+
if (!isAuthenticated) {
|
85
|
+
throw acp.RequestError.authRequired();
|
86
|
+
}
|
87
|
+
const geminiClient = config.getGeminiClient();
|
88
|
+
const chat = await geminiClient.startChat();
|
89
|
+
const session = new Session(sessionId, chat, config, this.client);
|
90
|
+
this.sessions.set(sessionId, session);
|
91
|
+
return {
|
92
|
+
sessionId,
|
93
|
+
};
|
45
94
|
}
|
46
|
-
async
|
47
|
-
|
48
|
-
|
49
|
-
|
95
|
+
async newSessionConfig(sessionId, cwd, mcpServers) {
|
96
|
+
const mergedMcpServers = { ...this.settings.merged.mcpServers };
|
97
|
+
for (const { command, args, env: rawEnv, name } of mcpServers) {
|
98
|
+
const env = {};
|
99
|
+
for (const { name: envName, value } of rawEnv) {
|
100
|
+
env[envName] = value;
|
101
|
+
}
|
102
|
+
mergedMcpServers[name] = new MCPServerConfig(command, args, env, cwd);
|
103
|
+
}
|
104
|
+
const settings = { ...this.settings.merged, mcpServers: mergedMcpServers };
|
105
|
+
const config = await loadCliConfig(settings, this.extensions, sessionId, this.argv, cwd);
|
106
|
+
await config.initialize();
|
107
|
+
return config;
|
108
|
+
}
|
109
|
+
async cancel(params) {
|
110
|
+
const session = this.sessions.get(params.sessionId);
|
111
|
+
if (!session) {
|
112
|
+
throw new Error(`Session not found: ${params.sessionId}`);
|
113
|
+
}
|
114
|
+
await session.cancelPendingPrompt();
|
115
|
+
}
|
116
|
+
async prompt(params) {
|
117
|
+
const session = this.sessions.get(params.sessionId);
|
118
|
+
if (!session) {
|
119
|
+
throw new Error(`Session not found: ${params.sessionId}`);
|
120
|
+
}
|
121
|
+
return session.prompt(params);
|
122
|
+
}
|
123
|
+
}
|
124
|
+
class Session {
|
125
|
+
id;
|
126
|
+
chat;
|
127
|
+
config;
|
128
|
+
client;
|
129
|
+
pendingPrompt = null;
|
130
|
+
constructor(id, chat, config, client) {
|
131
|
+
this.id = id;
|
132
|
+
this.chat = chat;
|
133
|
+
this.config = config;
|
134
|
+
this.client = client;
|
50
135
|
}
|
51
|
-
async
|
52
|
-
if (!this.
|
136
|
+
async cancelPendingPrompt() {
|
137
|
+
if (!this.pendingPrompt) {
|
53
138
|
throw new Error('Not currently generating');
|
54
139
|
}
|
55
|
-
this.
|
56
|
-
|
140
|
+
this.pendingPrompt.abort();
|
141
|
+
this.pendingPrompt = null;
|
57
142
|
}
|
58
|
-
async
|
59
|
-
this.
|
143
|
+
async prompt(params) {
|
144
|
+
this.pendingPrompt?.abort();
|
60
145
|
const pendingSend = new AbortController();
|
61
|
-
this.
|
62
|
-
if (!this.chat) {
|
63
|
-
const geminiClient = this.config.getGeminiClient();
|
64
|
-
this.chat = await geminiClient.startChat();
|
65
|
-
}
|
146
|
+
this.pendingPrompt = pendingSend;
|
66
147
|
const promptId = Math.random().toString(16).slice(2);
|
67
148
|
const chat = this.chat;
|
68
|
-
const
|
69
|
-
const parts = await this.#resolveUserMessage(params, pendingSend.signal);
|
149
|
+
const parts = await this.#resolvePrompt(params.prompt, pendingSend.signal);
|
70
150
|
let nextMessage = { role: 'user', parts };
|
71
151
|
while (nextMessage !== null) {
|
72
152
|
if (pendingSend.signal.aborted) {
|
73
153
|
chat.addHistory(nextMessage);
|
74
|
-
return;
|
154
|
+
return { stopReason: 'cancelled' };
|
75
155
|
}
|
76
156
|
const functionCalls = [];
|
77
157
|
try {
|
@@ -79,17 +159,12 @@ class GeminiAgent {
|
|
79
159
|
message: nextMessage?.parts ?? [],
|
80
160
|
config: {
|
81
161
|
abortSignal: pendingSend.signal,
|
82
|
-
tools: [
|
83
|
-
{
|
84
|
-
functionDeclarations: toolRegistry.getFunctionDeclarations(),
|
85
|
-
},
|
86
|
-
],
|
87
162
|
},
|
88
163
|
}, promptId);
|
89
164
|
nextMessage = null;
|
90
165
|
for await (const resp of responseStream) {
|
91
166
|
if (pendingSend.signal.aborted) {
|
92
|
-
return;
|
167
|
+
return { stopReason: 'cancelled' };
|
93
168
|
}
|
94
169
|
if (resp.candidates && resp.candidates.length > 0) {
|
95
170
|
const candidate = resp.candidates[0];
|
@@ -97,10 +172,15 @@ class GeminiAgent {
|
|
97
172
|
if (!part.text) {
|
98
173
|
continue;
|
99
174
|
}
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
175
|
+
const content = {
|
176
|
+
type: 'text',
|
177
|
+
text: part.text,
|
178
|
+
};
|
179
|
+
this.sendUpdate({
|
180
|
+
sessionUpdate: part.thought
|
181
|
+
? 'agent_thought_chunk'
|
182
|
+
: 'agent_message_chunk',
|
183
|
+
content,
|
104
184
|
});
|
105
185
|
}
|
106
186
|
}
|
@@ -118,7 +198,7 @@ class GeminiAgent {
|
|
118
198
|
if (functionCalls.length > 0) {
|
119
199
|
const toolResponseParts = [];
|
120
200
|
for (const fc of functionCalls) {
|
121
|
-
const response = await this
|
201
|
+
const response = await this.runTool(pendingSend.signal, promptId, fc);
|
122
202
|
const parts = Array.isArray(response) ? response : [response];
|
123
203
|
for (const part of parts) {
|
124
204
|
if (typeof part === 'string') {
|
@@ -132,8 +212,16 @@ class GeminiAgent {
|
|
132
212
|
nextMessage = { role: 'user', parts: toolResponseParts };
|
133
213
|
}
|
134
214
|
}
|
215
|
+
return { stopReason: 'end_turn' };
|
216
|
+
}
|
217
|
+
async sendUpdate(update) {
|
218
|
+
const params = {
|
219
|
+
sessionId: this.id,
|
220
|
+
update,
|
221
|
+
};
|
222
|
+
await this.client.sessionUpdate(params);
|
135
223
|
}
|
136
|
-
async
|
224
|
+
async runTool(abortSignal, promptId, fc) {
|
137
225
|
const callId = fc.id ?? `${fc.name}-${Date.now()}`;
|
138
226
|
const args = (fc.args ?? {});
|
139
227
|
const startTime = Date.now();
|
@@ -167,59 +255,71 @@ class GeminiAgent {
|
|
167
255
|
if (!tool) {
|
168
256
|
return errorResponse(new Error(`Tool "${fc.name}" not found in registry.`));
|
169
257
|
}
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
const
|
174
|
-
if (confirmationDetails) {
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
oldText: confirmationDetails.originalContent,
|
181
|
-
newText: confirmationDetails.newContent,
|
182
|
-
};
|
183
|
-
}
|
184
|
-
const result = await this.client.requestToolCallConfirmation({
|
185
|
-
label: invocation.getDescription(),
|
186
|
-
icon: tool.icon,
|
187
|
-
content,
|
188
|
-
confirmation: toAcpToolCallConfirmation(confirmationDetails),
|
189
|
-
locations: invocation.toolLocations(),
|
258
|
+
const invocation = tool.build(args);
|
259
|
+
const confirmationDetails = await invocation.shouldConfirmExecute(abortSignal);
|
260
|
+
if (confirmationDetails) {
|
261
|
+
const content = [];
|
262
|
+
if (confirmationDetails.type === 'edit') {
|
263
|
+
content.push({
|
264
|
+
type: 'diff',
|
265
|
+
path: confirmationDetails.fileName,
|
266
|
+
oldText: confirmationDetails.originalContent,
|
267
|
+
newText: confirmationDetails.newContent,
|
190
268
|
});
|
191
|
-
await confirmationDetails.onConfirm(toToolCallOutcome(result.outcome));
|
192
|
-
switch (result.outcome) {
|
193
|
-
case 'reject':
|
194
|
-
return errorResponse(new Error(`Tool "${fc.name}" not allowed to run by the user.`));
|
195
|
-
case 'cancel':
|
196
|
-
return errorResponse(new Error(`Tool "${fc.name}" was canceled by the user.`));
|
197
|
-
case 'allow':
|
198
|
-
case 'alwaysAllow':
|
199
|
-
case 'alwaysAllowMcpServer':
|
200
|
-
case 'alwaysAllowTool':
|
201
|
-
break;
|
202
|
-
default: {
|
203
|
-
const resultOutcome = result.outcome;
|
204
|
-
throw new Error(`Unexpected: ${resultOutcome}`);
|
205
|
-
}
|
206
|
-
}
|
207
|
-
toolCallId = result.id;
|
208
269
|
}
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
270
|
+
const params = {
|
271
|
+
sessionId: this.id,
|
272
|
+
options: toPermissionOptions(confirmationDetails),
|
273
|
+
toolCall: {
|
274
|
+
toolCallId: callId,
|
275
|
+
status: 'pending',
|
276
|
+
title: invocation.getDescription(),
|
277
|
+
content,
|
213
278
|
locations: invocation.toolLocations(),
|
214
|
-
|
215
|
-
|
279
|
+
kind: tool.kind,
|
280
|
+
},
|
281
|
+
};
|
282
|
+
const output = await this.client.requestPermission(params);
|
283
|
+
const outcome = output.outcome.outcome === 'cancelled'
|
284
|
+
? ToolConfirmationOutcome.Cancel
|
285
|
+
: z
|
286
|
+
.nativeEnum(ToolConfirmationOutcome)
|
287
|
+
.parse(output.outcome.optionId);
|
288
|
+
await confirmationDetails.onConfirm(outcome);
|
289
|
+
switch (outcome) {
|
290
|
+
case ToolConfirmationOutcome.Cancel:
|
291
|
+
return errorResponse(new Error(`Tool "${fc.name}" was canceled by the user.`));
|
292
|
+
case ToolConfirmationOutcome.ProceedOnce:
|
293
|
+
case ToolConfirmationOutcome.ProceedAlways:
|
294
|
+
case ToolConfirmationOutcome.ProceedAlwaysServer:
|
295
|
+
case ToolConfirmationOutcome.ProceedAlwaysTool:
|
296
|
+
case ToolConfirmationOutcome.ModifyWithEditor:
|
297
|
+
break;
|
298
|
+
default: {
|
299
|
+
const resultOutcome = outcome;
|
300
|
+
throw new Error(`Unexpected: ${resultOutcome}`);
|
301
|
+
}
|
216
302
|
}
|
303
|
+
}
|
304
|
+
else {
|
305
|
+
await this.sendUpdate({
|
306
|
+
sessionUpdate: 'tool_call',
|
307
|
+
toolCallId: callId,
|
308
|
+
status: 'in_progress',
|
309
|
+
title: invocation.getDescription(),
|
310
|
+
content: [],
|
311
|
+
locations: invocation.toolLocations(),
|
312
|
+
kind: tool.kind,
|
313
|
+
});
|
314
|
+
}
|
315
|
+
try {
|
217
316
|
const toolResult = await invocation.execute(abortSignal);
|
218
|
-
const
|
219
|
-
await this.
|
220
|
-
|
221
|
-
|
222
|
-
|
317
|
+
const content = toToolCallContent(toolResult);
|
318
|
+
await this.sendUpdate({
|
319
|
+
sessionUpdate: 'tool_call_update',
|
320
|
+
toolCallId: callId,
|
321
|
+
status: 'completed',
|
322
|
+
content: content ? [content] : [],
|
223
323
|
});
|
224
324
|
const durationMs = Date.now() - startTime;
|
225
325
|
logToolCall(this.config, {
|
@@ -235,27 +335,47 @@ class GeminiAgent {
|
|
235
335
|
}
|
236
336
|
catch (e) {
|
237
337
|
const error = e instanceof Error ? e : new Error(String(e));
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
338
|
+
await this.sendUpdate({
|
339
|
+
sessionUpdate: 'tool_call_update',
|
340
|
+
toolCallId: callId,
|
341
|
+
status: 'failed',
|
342
|
+
content: [
|
343
|
+
{ type: 'content', content: { type: 'text', text: error.message } },
|
344
|
+
],
|
345
|
+
});
|
245
346
|
return errorResponse(error);
|
246
347
|
}
|
247
348
|
}
|
248
|
-
async #
|
249
|
-
const
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
349
|
+
async #resolvePrompt(message, abortSignal) {
|
350
|
+
const parts = message.map((part) => {
|
351
|
+
switch (part.type) {
|
352
|
+
case 'text':
|
353
|
+
return { text: part.text };
|
354
|
+
case 'resource_link':
|
355
|
+
return {
|
356
|
+
fileData: {
|
357
|
+
mimeData: part.mimeType,
|
358
|
+
name: part.name,
|
359
|
+
fileUri: part.uri,
|
360
|
+
},
|
361
|
+
};
|
362
|
+
case 'resource': {
|
363
|
+
return {
|
364
|
+
fileData: {
|
365
|
+
mimeData: part.resource.mimeType,
|
366
|
+
name: part.resource.uri,
|
367
|
+
fileUri: part.resource.uri,
|
368
|
+
},
|
369
|
+
};
|
254
370
|
}
|
255
|
-
|
256
|
-
throw new Error(
|
371
|
+
default: {
|
372
|
+
throw new Error(`Unexpected chunk type: '${part.type}'`);
|
257
373
|
}
|
258
|
-
}
|
374
|
+
}
|
375
|
+
});
|
376
|
+
const atPathCommandParts = parts.filter((part) => 'fileData' in part);
|
377
|
+
if (atPathCommandParts.length === 0) {
|
378
|
+
return parts;
|
259
379
|
}
|
260
380
|
// Get centralized file discovery service
|
261
381
|
const fileDiscovery = this.config.getFileService();
|
@@ -271,7 +391,7 @@ class GeminiAgent {
|
|
271
391
|
throw new Error('Error: read_many_files tool not found.');
|
272
392
|
}
|
273
393
|
for (const atPathPart of atPathCommandParts) {
|
274
|
-
const pathName = atPathPart.
|
394
|
+
const pathName = atPathPart.fileData.fileUri;
|
275
395
|
// Check if path should be ignored by git
|
276
396
|
if (fileDiscovery.shouldGitIgnoreFile(pathName)) {
|
277
397
|
ignoredPaths.push(pathName);
|
@@ -291,21 +411,21 @@ class GeminiAgent {
|
|
291
411
|
currentPathSpec = pathName.endsWith('/')
|
292
412
|
? `${pathName}**`
|
293
413
|
: `${pathName}/**`;
|
294
|
-
this
|
414
|
+
this.debug(`Path ${pathName} resolved to directory, using glob: ${currentPathSpec}`);
|
295
415
|
}
|
296
416
|
else {
|
297
|
-
this
|
417
|
+
this.debug(`Path ${pathName} resolved to file: ${currentPathSpec}`);
|
298
418
|
}
|
299
419
|
resolvedSuccessfully = true;
|
300
420
|
}
|
301
421
|
else {
|
302
|
-
this
|
422
|
+
this.debug(`Path ${pathName} is outside the project directory. Skipping.`);
|
303
423
|
}
|
304
424
|
}
|
305
425
|
catch (error) {
|
306
426
|
if (isNodeError(error) && error.code === 'ENOENT') {
|
307
427
|
if (this.config.getEnableRecursiveFileSearch() && globTool) {
|
308
|
-
this
|
428
|
+
this.debug(`Path ${pathName} not found directly, attempting glob search.`);
|
309
429
|
try {
|
310
430
|
const globResult = await globTool.buildAndExecute({
|
311
431
|
pattern: `**/*${pathName}*`,
|
@@ -319,15 +439,15 @@ class GeminiAgent {
|
|
319
439
|
if (lines.length > 1 && lines[1]) {
|
320
440
|
const firstMatchAbsolute = lines[1].trim();
|
321
441
|
currentPathSpec = path.relative(this.config.getTargetDir(), firstMatchAbsolute);
|
322
|
-
this
|
442
|
+
this.debug(`Glob search for ${pathName} found ${firstMatchAbsolute}, using relative path: ${currentPathSpec}`);
|
323
443
|
resolvedSuccessfully = true;
|
324
444
|
}
|
325
445
|
else {
|
326
|
-
this
|
446
|
+
this.debug(`Glob search for '**/*${pathName}*' did not return a usable path. Path ${pathName} will be skipped.`);
|
327
447
|
}
|
328
448
|
}
|
329
449
|
else {
|
330
|
-
this
|
450
|
+
this.debug(`Glob search for '**/*${pathName}*' found no files or an error. Path ${pathName} will be skipped.`);
|
331
451
|
}
|
332
452
|
}
|
333
453
|
catch (globError) {
|
@@ -335,7 +455,7 @@ class GeminiAgent {
|
|
335
455
|
}
|
336
456
|
}
|
337
457
|
else {
|
338
|
-
this
|
458
|
+
this.debug(`Glob tool not found. Path ${pathName} will be skipped.`);
|
339
459
|
}
|
340
460
|
}
|
341
461
|
else {
|
@@ -350,22 +470,23 @@ class GeminiAgent {
|
|
350
470
|
}
|
351
471
|
// Construct the initial part of the query for the LLM
|
352
472
|
let initialQueryText = '';
|
353
|
-
for (let i = 0; i <
|
354
|
-
const chunk =
|
473
|
+
for (let i = 0; i < parts.length; i++) {
|
474
|
+
const chunk = parts[i];
|
355
475
|
if ('text' in chunk) {
|
356
476
|
initialQueryText += chunk.text;
|
357
477
|
}
|
358
478
|
else {
|
359
479
|
// type === 'atPath'
|
360
|
-
const resolvedSpec = atPathToResolvedSpecMap.get(chunk.
|
480
|
+
const resolvedSpec = chunk.fileData && atPathToResolvedSpecMap.get(chunk.fileData.fileUri);
|
361
481
|
if (i > 0 &&
|
362
482
|
initialQueryText.length > 0 &&
|
363
483
|
!initialQueryText.endsWith(' ') &&
|
364
484
|
resolvedSpec) {
|
365
485
|
// Add space if previous part was text and didn't end with space, or if previous was @path
|
366
|
-
const prevPart =
|
486
|
+
const prevPart = parts[i - 1];
|
367
487
|
if ('text' in prevPart ||
|
368
|
-
('
|
488
|
+
('fileData' in prevPart &&
|
489
|
+
atPathToResolvedSpecMap.has(prevPart.fileData.fileUri))) {
|
369
490
|
initialQueryText += ' ';
|
370
491
|
}
|
371
492
|
}
|
@@ -378,10 +499,12 @@ class GeminiAgent {
|
|
378
499
|
if (i > 0 &&
|
379
500
|
initialQueryText.length > 0 &&
|
380
501
|
!initialQueryText.endsWith(' ') &&
|
381
|
-
!chunk.
|
502
|
+
!chunk.fileData?.fileUri.startsWith(' ')) {
|
382
503
|
initialQueryText += ' ';
|
383
504
|
}
|
384
|
-
|
505
|
+
if (chunk.fileData?.fileUri) {
|
506
|
+
initialQueryText += `@${chunk.fileData.fileUri}`;
|
507
|
+
}
|
385
508
|
}
|
386
509
|
}
|
387
510
|
}
|
@@ -389,7 +512,7 @@ class GeminiAgent {
|
|
389
512
|
// Inform user about ignored paths
|
390
513
|
if (ignoredPaths.length > 0) {
|
391
514
|
const ignoreType = respectGitIgnore ? 'git-ignored' : 'custom-ignored';
|
392
|
-
this
|
515
|
+
this.debug(`Ignored ${ignoredPaths.length} ${ignoreType} files: ${ignoredPaths.join(', ')}`);
|
393
516
|
}
|
394
517
|
// Fallback for lone "@" or completely invalid @-commands resulting in empty initialQueryText
|
395
518
|
if (pathSpecsToRead.length === 0) {
|
@@ -401,23 +524,31 @@ class GeminiAgent {
|
|
401
524
|
paths: pathSpecsToRead,
|
402
525
|
respectGitIgnore, // Use configuration setting
|
403
526
|
};
|
404
|
-
|
527
|
+
const callId = `${readManyFilesTool.name}-${Date.now()}`;
|
405
528
|
try {
|
406
529
|
const invocation = readManyFilesTool.build(toolArgs);
|
407
|
-
|
408
|
-
|
409
|
-
|
530
|
+
await this.sendUpdate({
|
531
|
+
sessionUpdate: 'tool_call',
|
532
|
+
toolCallId: callId,
|
533
|
+
status: 'in_progress',
|
534
|
+
title: invocation.getDescription(),
|
535
|
+
content: [],
|
536
|
+
locations: invocation.toolLocations(),
|
537
|
+
kind: readManyFilesTool.kind,
|
410
538
|
});
|
411
|
-
toolCallId = toolCall.id;
|
412
539
|
const result = await invocation.execute(abortSignal);
|
413
540
|
const content = toToolCallContent(result) || {
|
414
|
-
type: '
|
415
|
-
|
541
|
+
type: 'content',
|
542
|
+
content: {
|
543
|
+
type: 'text',
|
544
|
+
text: `Successfully read: ${contentLabelsForDisplay.join(', ')}`,
|
545
|
+
},
|
416
546
|
};
|
417
|
-
await this.
|
418
|
-
|
419
|
-
|
420
|
-
|
547
|
+
await this.sendUpdate({
|
548
|
+
sessionUpdate: 'tool_call_update',
|
549
|
+
toolCallId: callId,
|
550
|
+
status: 'completed',
|
551
|
+
content: content ? [content] : [],
|
421
552
|
});
|
422
553
|
if (Array.isArray(result.llmContent)) {
|
423
554
|
const fileContentRegex = /^--- (.*?) ---\n\n([\s\S]*?)\n\n$/;
|
@@ -452,20 +583,24 @@ class GeminiAgent {
|
|
452
583
|
return processedQueryParts;
|
453
584
|
}
|
454
585
|
catch (error) {
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
586
|
+
await this.sendUpdate({
|
587
|
+
sessionUpdate: 'tool_call_update',
|
588
|
+
toolCallId: callId,
|
589
|
+
status: 'failed',
|
590
|
+
content: [
|
591
|
+
{
|
592
|
+
type: 'content',
|
593
|
+
content: {
|
594
|
+
type: 'text',
|
595
|
+
text: `Error reading files (${contentLabelsForDisplay.join(', ')}): ${getErrorMessage(error)}`,
|
596
|
+
},
|
462
597
|
},
|
463
|
-
|
464
|
-
}
|
598
|
+
],
|
599
|
+
});
|
465
600
|
throw error;
|
466
601
|
}
|
467
602
|
}
|
468
|
-
|
603
|
+
debug(msg) {
|
469
604
|
if (this.config.getDebugMode()) {
|
470
605
|
console.warn(msg);
|
471
606
|
}
|
@@ -475,8 +610,8 @@ function toToolCallContent(toolResult) {
|
|
475
610
|
if (toolResult.returnDisplay) {
|
476
611
|
if (typeof toolResult.returnDisplay === 'string') {
|
477
612
|
return {
|
478
|
-
type: '
|
479
|
-
|
613
|
+
type: 'content',
|
614
|
+
content: { type: 'text', text: toolResult.returnDisplay },
|
480
615
|
};
|
481
616
|
}
|
482
617
|
else {
|
@@ -492,55 +627,65 @@ function toToolCallContent(toolResult) {
|
|
492
627
|
return null;
|
493
628
|
}
|
494
629
|
}
|
495
|
-
|
496
|
-
|
630
|
+
const basicPermissionOptions = [
|
631
|
+
{
|
632
|
+
optionId: ToolConfirmationOutcome.ProceedOnce,
|
633
|
+
name: 'Allow',
|
634
|
+
kind: 'allow_once',
|
635
|
+
},
|
636
|
+
{
|
637
|
+
optionId: ToolConfirmationOutcome.Cancel,
|
638
|
+
name: 'Reject',
|
639
|
+
kind: 'reject_once',
|
640
|
+
},
|
641
|
+
];
|
642
|
+
function toPermissionOptions(confirmation) {
|
643
|
+
switch (confirmation.type) {
|
497
644
|
case 'edit':
|
498
|
-
return
|
645
|
+
return [
|
646
|
+
{
|
647
|
+
optionId: ToolConfirmationOutcome.ProceedAlways,
|
648
|
+
name: 'Allow All Edits',
|
649
|
+
kind: 'allow_always',
|
650
|
+
},
|
651
|
+
...basicPermissionOptions,
|
652
|
+
];
|
499
653
|
case 'exec':
|
500
|
-
return
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
654
|
+
return [
|
655
|
+
{
|
656
|
+
optionId: ToolConfirmationOutcome.ProceedAlways,
|
657
|
+
name: `Always Allow ${confirmation.rootCommand}`,
|
658
|
+
kind: 'allow_always',
|
659
|
+
},
|
660
|
+
...basicPermissionOptions,
|
661
|
+
];
|
505
662
|
case 'mcp':
|
506
|
-
return
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
663
|
+
return [
|
664
|
+
{
|
665
|
+
optionId: ToolConfirmationOutcome.ProceedAlwaysServer,
|
666
|
+
name: `Always Allow ${confirmation.serverName}`,
|
667
|
+
kind: 'allow_always',
|
668
|
+
},
|
669
|
+
{
|
670
|
+
optionId: ToolConfirmationOutcome.ProceedAlwaysTool,
|
671
|
+
name: `Always Allow ${confirmation.toolName}`,
|
672
|
+
kind: 'allow_always',
|
673
|
+
},
|
674
|
+
...basicPermissionOptions,
|
675
|
+
];
|
512
676
|
case 'info':
|
513
|
-
return
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
// Type exhaustiveness check - if this errors, a new type was added
|
522
|
-
const unreachable = confirmationDetails;
|
523
|
-
throw new Error(`Unexpected: ${unreachable}`);
|
524
|
-
}
|
525
|
-
}
|
526
|
-
}
|
527
|
-
function toToolCallOutcome(outcome) {
|
528
|
-
switch (outcome) {
|
529
|
-
case 'allow':
|
530
|
-
return ToolConfirmationOutcome.ProceedOnce;
|
531
|
-
case 'alwaysAllow':
|
532
|
-
return ToolConfirmationOutcome.ProceedAlways;
|
533
|
-
case 'alwaysAllowMcpServer':
|
534
|
-
return ToolConfirmationOutcome.ProceedAlwaysServer;
|
535
|
-
case 'alwaysAllowTool':
|
536
|
-
return ToolConfirmationOutcome.ProceedAlwaysTool;
|
537
|
-
case 'reject':
|
538
|
-
case 'cancel':
|
539
|
-
return ToolConfirmationOutcome.Cancel;
|
677
|
+
return [
|
678
|
+
{
|
679
|
+
optionId: ToolConfirmationOutcome.ProceedAlways,
|
680
|
+
name: `Always Allow`,
|
681
|
+
kind: 'allow_always',
|
682
|
+
},
|
683
|
+
...basicPermissionOptions,
|
684
|
+
];
|
540
685
|
default: {
|
541
|
-
const unreachable =
|
686
|
+
const unreachable = confirmation;
|
542
687
|
throw new Error(`Unexpected: ${unreachable}`);
|
543
688
|
}
|
544
689
|
}
|
545
690
|
}
|
546
|
-
//# sourceMappingURL=
|
691
|
+
//# sourceMappingURL=zedIntegration.js.map
|