@vybestack/llxprt-code-core 0.4.8 → 0.5.0-nightly.251102.e5b51aa3
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/prompt-config/defaults/default-prompts.json +4 -17
- package/dist/src/auth/precedence.d.ts +69 -9
- package/dist/src/auth/precedence.js +467 -69
- package/dist/src/auth/precedence.js.map +1 -1
- package/dist/src/auth/types.d.ts +2 -2
- package/dist/src/config/config.d.ts +15 -1
- package/dist/src/config/config.js +118 -6
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/index.d.ts +6 -0
- package/dist/src/config/index.js +5 -0
- package/dist/src/config/index.js.map +1 -1
- package/dist/src/config/profileManager.d.ts +23 -3
- package/dist/src/config/profileManager.js +54 -7
- package/dist/src/config/profileManager.js.map +1 -1
- package/dist/src/config/subagentManager.d.ts +96 -0
- package/dist/src/config/subagentManager.js +371 -0
- package/dist/src/config/subagentManager.js.map +1 -0
- package/dist/src/config/types.d.ts +18 -0
- package/dist/src/config/types.js +3 -0
- package/dist/src/config/types.js.map +1 -0
- package/dist/src/core/client.d.ts +27 -7
- package/dist/src/core/client.js +231 -55
- package/dist/src/core/client.js.map +1 -1
- package/dist/src/core/contentGenerator.d.ts +3 -1
- package/dist/src/core/contentGenerator.js +3 -0
- package/dist/src/core/contentGenerator.js.map +1 -1
- package/dist/src/core/coreToolScheduler.d.ts +1 -5
- package/dist/src/core/coreToolScheduler.js +95 -23
- package/dist/src/core/coreToolScheduler.js.map +1 -1
- package/dist/src/core/geminiChat.d.ts +42 -12
- package/dist/src/core/geminiChat.js +405 -205
- package/dist/src/core/geminiChat.js.map +1 -1
- package/dist/src/core/nonInteractiveToolExecutor.d.ts +3 -2
- package/dist/src/core/nonInteractiveToolExecutor.js +94 -10
- package/dist/src/core/nonInteractiveToolExecutor.js.map +1 -1
- package/dist/src/core/subagent.d.ts +86 -7
- package/dist/src/core/subagent.js +809 -79
- package/dist/src/core/subagent.js.map +1 -1
- package/dist/src/core/subagentOrchestrator.d.ts +73 -0
- package/dist/src/core/subagentOrchestrator.js +387 -0
- package/dist/src/core/subagentOrchestrator.js.map +1 -0
- package/dist/src/core/subagentScheduler.d.ts +16 -0
- package/dist/src/core/subagentScheduler.js +7 -0
- package/dist/src/core/subagentScheduler.js.map +1 -0
- package/dist/src/core/turn.d.ts +5 -1
- package/dist/src/core/turn.js +5 -1
- package/dist/src/core/turn.js.map +1 -1
- package/dist/src/hooks/tool-render-suppression-hook.js +6 -1
- package/dist/src/hooks/tool-render-suppression-hook.js.map +1 -1
- package/dist/src/ide/ideContext.d.ts +32 -32
- package/dist/src/index.d.ts +19 -1
- package/dist/src/index.js +15 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/interfaces/index.d.ts +1 -0
- package/dist/src/interfaces/index.js +4 -0
- package/dist/src/interfaces/index.js.map +1 -0
- package/dist/src/interfaces/nodejs-error.interface.d.ts +4 -0
- package/dist/src/interfaces/nodejs-error.interface.js +2 -0
- package/dist/src/interfaces/nodejs-error.interface.js.map +1 -0
- package/dist/src/parsers/TextToolCallParser.d.ts +17 -1
- package/dist/src/parsers/TextToolCallParser.js +542 -148
- package/dist/src/parsers/TextToolCallParser.js.map +1 -1
- package/dist/src/prompt-config/defaults/core.md +15 -0
- package/dist/src/prompt-config/defaults/providers/gemini/core.md +203 -119
- package/dist/src/prompt-config/defaults/tool-defaults.js +2 -0
- package/dist/src/prompt-config/defaults/tool-defaults.js.map +1 -1
- package/dist/src/prompt-config/defaults/tools/list-subagents.md +7 -0
- package/dist/src/prompt-config/defaults/tools/task.md +8 -0
- package/dist/src/providers/BaseProvider.d.ts +115 -30
- package/dist/src/providers/BaseProvider.js +445 -109
- package/dist/src/providers/BaseProvider.js.map +1 -1
- package/dist/src/providers/IProvider.d.ts +50 -18
- package/dist/src/providers/LoggingProviderWrapper.d.ts +60 -16
- package/dist/src/providers/LoggingProviderWrapper.js +213 -60
- package/dist/src/providers/LoggingProviderWrapper.js.map +1 -1
- package/dist/src/providers/ProviderManager.d.ts +73 -2
- package/dist/src/providers/ProviderManager.js +492 -40
- package/dist/src/providers/ProviderManager.js.map +1 -1
- package/dist/src/providers/anthropic/AnthropicProvider.d.ts +35 -38
- package/dist/src/providers/anthropic/AnthropicProvider.js +222 -227
- package/dist/src/providers/anthropic/AnthropicProvider.js.map +1 -1
- package/dist/src/providers/errors.d.ts +86 -0
- package/dist/src/providers/errors.js +89 -0
- package/dist/src/providers/errors.js.map +1 -1
- package/dist/src/providers/gemini/GeminiProvider.d.ts +101 -41
- package/dist/src/providers/gemini/GeminiProvider.js +386 -311
- package/dist/src/providers/gemini/GeminiProvider.js.map +1 -1
- package/dist/src/providers/openai/ConversationCache.d.ts +5 -3
- package/dist/src/providers/openai/ConversationCache.js +93 -32
- package/dist/src/providers/openai/ConversationCache.js.map +1 -1
- package/dist/src/providers/openai/OpenAIProvider.d.ts +82 -42
- package/dist/src/providers/openai/OpenAIProvider.js +391 -536
- package/dist/src/providers/openai/OpenAIProvider.js.map +1 -1
- package/dist/src/providers/openai/getOpenAIProviderInfo.d.ts +1 -1
- package/dist/src/providers/openai/getOpenAIProviderInfo.js +52 -22
- package/dist/src/providers/openai/getOpenAIProviderInfo.js.map +1 -1
- package/dist/src/providers/openai/openaiRequestParams.d.ts +7 -0
- package/dist/src/providers/openai/openaiRequestParams.js +66 -0
- package/dist/src/providers/openai/openaiRequestParams.js.map +1 -0
- package/dist/src/providers/openai-responses/OpenAIResponsesProvider.d.ts +6 -33
- package/dist/src/providers/openai-responses/OpenAIResponsesProvider.js +84 -183
- package/dist/src/providers/openai-responses/OpenAIResponsesProvider.js.map +1 -1
- package/dist/src/providers/types/providerRuntime.d.ts +17 -0
- package/dist/src/providers/types/providerRuntime.js +7 -0
- package/dist/src/providers/types/providerRuntime.js.map +1 -0
- package/dist/src/providers/utils/authToken.d.ts +12 -0
- package/dist/src/providers/utils/authToken.js +17 -0
- package/dist/src/providers/utils/authToken.js.map +1 -0
- package/dist/src/providers/utils/userMemory.d.ts +8 -0
- package/dist/src/providers/utils/userMemory.js +34 -0
- package/dist/src/providers/utils/userMemory.js.map +1 -0
- package/dist/src/runtime/AgentRuntimeContext.d.ts +213 -0
- package/dist/src/runtime/AgentRuntimeContext.js +17 -0
- package/dist/src/runtime/AgentRuntimeContext.js.map +1 -0
- package/dist/src/runtime/AgentRuntimeLoader.d.ts +47 -0
- package/dist/src/runtime/AgentRuntimeLoader.js +122 -0
- package/dist/src/runtime/AgentRuntimeLoader.js.map +1 -0
- package/dist/src/runtime/AgentRuntimeState.d.ts +232 -0
- package/dist/src/runtime/AgentRuntimeState.js +439 -0
- package/dist/src/runtime/AgentRuntimeState.js.map +1 -0
- package/dist/src/runtime/RuntimeInvocationContext.d.ts +51 -0
- package/dist/src/runtime/RuntimeInvocationContext.js +52 -0
- package/dist/src/runtime/RuntimeInvocationContext.js.map +1 -0
- package/dist/src/runtime/createAgentRuntimeContext.d.ts +7 -0
- package/dist/src/runtime/createAgentRuntimeContext.js +65 -0
- package/dist/src/runtime/createAgentRuntimeContext.js.map +1 -0
- package/dist/src/runtime/index.d.ts +13 -0
- package/dist/src/runtime/index.js +14 -0
- package/dist/src/runtime/index.js.map +1 -0
- package/dist/src/runtime/providerRuntimeContext.d.ts +30 -0
- package/dist/src/runtime/providerRuntimeContext.js +70 -0
- package/dist/src/runtime/providerRuntimeContext.js.map +1 -0
- package/dist/src/runtime/runtimeAdapters.d.ts +22 -0
- package/dist/src/runtime/runtimeAdapters.js +81 -0
- package/dist/src/runtime/runtimeAdapters.js.map +1 -0
- package/dist/src/runtime/runtimeStateFactory.d.ts +21 -0
- package/dist/src/runtime/runtimeStateFactory.js +104 -0
- package/dist/src/runtime/runtimeStateFactory.js.map +1 -0
- package/dist/src/services/todo-context-tracker.d.ts +10 -8
- package/dist/src/services/todo-context-tracker.js +26 -10
- package/dist/src/services/todo-context-tracker.js.map +1 -1
- package/dist/src/services/tool-call-tracker-service.d.ts +11 -7
- package/dist/src/services/tool-call-tracker-service.js +89 -29
- package/dist/src/services/tool-call-tracker-service.js.map +1 -1
- package/dist/src/settings/SettingsService.d.ts +4 -0
- package/dist/src/settings/SettingsService.js +65 -2
- package/dist/src/settings/SettingsService.js.map +1 -1
- package/dist/src/settings/settingsServiceInstance.d.ts +6 -1
- package/dist/src/settings/settingsServiceInstance.js +28 -8
- package/dist/src/settings/settingsServiceInstance.js.map +1 -1
- package/dist/src/telemetry/loggers.d.ts +5 -1
- package/dist/src/telemetry/loggers.js.map +1 -1
- package/dist/src/telemetry/loggers.test.circular.js +4 -0
- package/dist/src/telemetry/loggers.test.circular.js.map +1 -1
- package/dist/src/telemetry/metrics.d.ts +3 -1
- package/dist/src/telemetry/metrics.js.map +1 -1
- package/dist/src/telemetry/types.d.ts +1 -0
- package/dist/src/telemetry/types.js +3 -0
- package/dist/src/telemetry/types.js.map +1 -1
- package/dist/src/test-utils/index.d.ts +2 -0
- package/dist/src/test-utils/index.js +2 -0
- package/dist/src/test-utils/index.js.map +1 -1
- package/dist/src/test-utils/mockWorkspaceContext.d.ts +0 -3
- package/dist/src/test-utils/mockWorkspaceContext.js +3 -4
- package/dist/src/test-utils/mockWorkspaceContext.js.map +1 -1
- package/dist/src/test-utils/providerCallOptions.d.ts +43 -0
- package/dist/src/test-utils/providerCallOptions.js +137 -0
- package/dist/src/test-utils/providerCallOptions.js.map +1 -0
- package/dist/src/test-utils/runtime.d.ts +92 -0
- package/dist/src/test-utils/runtime.js +226 -0
- package/dist/src/test-utils/runtime.js.map +1 -0
- package/dist/src/test-utils/tools.d.ts +4 -4
- package/dist/src/test-utils/tools.js +20 -10
- package/dist/src/test-utils/tools.js.map +1 -1
- package/dist/src/tools/list-subagents.d.ts +31 -0
- package/dist/src/tools/list-subagents.js +109 -0
- package/dist/src/tools/list-subagents.js.map +1 -0
- package/dist/src/tools/task.d.ts +87 -0
- package/dist/src/tools/task.js +427 -0
- package/dist/src/tools/task.js.map +1 -0
- package/dist/src/tools/todo-read.js +1 -1
- package/dist/src/tools/todo-read.js.map +1 -1
- package/dist/src/tools/todo-store.js +4 -2
- package/dist/src/tools/todo-store.js.map +1 -1
- package/dist/src/tools/todo-write.js +4 -2
- package/dist/src/tools/todo-write.js.map +1 -1
- package/dist/src/tools/tool-error.d.ts +1 -0
- package/dist/src/tools/tool-error.js +1 -0
- package/dist/src/tools/tool-error.js.map +1 -1
- package/dist/src/tools/tool-registry.d.ts +2 -0
- package/dist/src/tools/tool-registry.js +46 -21
- package/dist/src/tools/tool-registry.js.map +1 -1
- package/dist/src/types/modelParams.d.ts +4 -0
- package/dist/src/utils/editor.js +10 -8
- package/dist/src/utils/editor.js.map +1 -1
- package/dist/src/utils/gitIgnoreParser.js +15 -3
- package/dist/src/utils/gitIgnoreParser.js.map +1 -1
- package/package.json +1 -1
- package/dist/src/prompt-config/defaults/providers/anthropic/core.md +0 -97
- package/dist/src/prompt-config/defaults/providers/anthropic/tools/glob.md +0 -34
- package/dist/src/prompt-config/defaults/providers/anthropic/tools/list-directory.md +0 -11
- package/dist/src/prompt-config/defaults/providers/anthropic/tools/read-file.md +0 -14
- package/dist/src/prompt-config/defaults/providers/anthropic/tools/read-many-files.md +0 -31
- package/dist/src/prompt-config/defaults/providers/anthropic/tools/replace.md +0 -41
- package/dist/src/prompt-config/defaults/providers/anthropic/tools/run-shell-command.md +0 -32
- package/dist/src/prompt-config/defaults/providers/anthropic/tools/save-memory.md +0 -35
- package/dist/src/prompt-config/defaults/providers/anthropic/tools/search-file-content.md +0 -44
- package/dist/src/prompt-config/defaults/providers/anthropic/tools/todo-write.md +0 -45
- package/dist/src/prompt-config/defaults/providers/anthropic/tools/write-file.md +0 -11
- package/dist/src/prompt-config/defaults/providers/openai/core.md +0 -97
- package/dist/src/prompt-config/defaults/providers/openai/tools/todo-pause.md +0 -28
- package/dist/src/prompt-config/defaults/providers/openai/tools/todo-read.md +0 -5
- package/dist/src/prompt-config/defaults/providers/openai/tools/todo-write.md +0 -45
package/dist/src/core/client.js
CHANGED
|
@@ -4,18 +4,20 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
import { getDirectoryContextString, getEnvironmentContext, } from '../utils/environmentContext.js';
|
|
7
|
-
import { Turn, GeminiEventType } from './turn.js';
|
|
7
|
+
import { Turn, GeminiEventType, DEFAULT_AGENT_ID, } from './turn.js';
|
|
8
8
|
import { CompressionStatus } from './turn.js';
|
|
9
|
-
import { getCoreSystemPromptAsync, getCompressionPrompt
|
|
9
|
+
import { getCoreSystemPromptAsync, getCompressionPrompt } from './prompts.js';
|
|
10
10
|
import { getResponseText } from '../utils/generateContentResponseUtilities.js';
|
|
11
11
|
import { reportError } from '../utils/errorReporting.js';
|
|
12
12
|
import { GeminiChat } from './geminiChat.js';
|
|
13
13
|
import { DebugLogger } from '../debug/index.js';
|
|
14
14
|
import { HistoryService } from '../services/history/HistoryService.js';
|
|
15
15
|
import { ContentConverters } from '../services/history/ContentConverters.js';
|
|
16
|
+
import { createProviderRuntimeContext } from '../runtime/providerRuntimeContext.js';
|
|
17
|
+
import { loadAgentRuntime } from '../runtime/AgentRuntimeLoader.js';
|
|
16
18
|
import { retryWithBackoff } from '../utils/retry.js';
|
|
17
19
|
import { getErrorMessage } from '../utils/errors.js';
|
|
18
|
-
import { createContentGenerator, } from './contentGenerator.js';
|
|
20
|
+
import { AuthType, createContentGenerator, } from './contentGenerator.js';
|
|
19
21
|
import { ProxyAgent, setGlobalDispatcher } from 'undici';
|
|
20
22
|
import { tokenLimit } from './tokenLimits.js';
|
|
21
23
|
import { COMPRESSION_TOKEN_THRESHOLD, COMPRESSION_PRESERVE_THRESHOLD, } from './compression-config.js';
|
|
@@ -25,10 +27,11 @@ import { ComplexityAnalyzer, } from '../services/complexity-analyzer.js';
|
|
|
25
27
|
import { TodoReminderService } from '../services/todo-reminder-service.js';
|
|
26
28
|
import { isFunctionResponse } from '../utils/messageInspectors.js';
|
|
27
29
|
import { estimateTokens as estimateTextTokens } from '../utils/toolOutputLimiter.js';
|
|
30
|
+
import { subscribeToAgentRuntimeState } from '../runtime/AgentRuntimeState.js';
|
|
28
31
|
const COMPLEXITY_ESCALATION_TURN_THRESHOLD = 3;
|
|
29
|
-
const TODO_PROMPT_SUFFIX = '
|
|
30
|
-
const TOOL_BASE_TODO_MESSAGE = '
|
|
31
|
-
const TOOL_ESCALATED_TODO_MESSAGE = '
|
|
32
|
+
const TODO_PROMPT_SUFFIX = 'Use TODO List to organize this effort.';
|
|
33
|
+
const TOOL_BASE_TODO_MESSAGE = 'After this next tool call I need to call todo_write and create a todo list to organize this effort.';
|
|
34
|
+
const TOOL_ESCALATED_TODO_MESSAGE = 'I have already made several tool calls without a todo list. Immediately call todo_write after this next tool call to organize the work.';
|
|
32
35
|
function isThinkingSupported(model) {
|
|
33
36
|
if (model.startsWith('gemini-2.5'))
|
|
34
37
|
return true;
|
|
@@ -88,6 +91,7 @@ export class GeminiClient {
|
|
|
88
91
|
lastPromptId;
|
|
89
92
|
complexityAnalyzer;
|
|
90
93
|
todoReminderService;
|
|
94
|
+
todoToolsAvailable = false;
|
|
91
95
|
lastComplexitySuggestionTime = 0;
|
|
92
96
|
complexitySuggestionCooldown;
|
|
93
97
|
lastSentIdeContext;
|
|
@@ -97,21 +101,61 @@ export class GeminiClient {
|
|
|
97
101
|
lastComplexitySuggestionTurn;
|
|
98
102
|
toolActivityCount = 0;
|
|
99
103
|
toolCallReminderLevel = 'none';
|
|
100
|
-
pendingInstallerNotices = [];
|
|
101
104
|
/**
|
|
102
105
|
* At any point in this conversation, was compression triggered without
|
|
103
106
|
* being forced and did it fail?
|
|
104
107
|
*/
|
|
105
108
|
hasFailedCompressionAttempt = false;
|
|
106
|
-
|
|
109
|
+
/**
|
|
110
|
+
* Runtime state for stateless operation (Phase 5)
|
|
111
|
+
* @plan PLAN-20251027-STATELESS5.P10
|
|
112
|
+
* @requirement REQ-STAT5-003.1
|
|
113
|
+
* @pseudocode gemini-runtime.md lines 21-42
|
|
114
|
+
*/
|
|
115
|
+
runtimeState;
|
|
116
|
+
_historyService;
|
|
117
|
+
_unsubscribe;
|
|
118
|
+
/**
|
|
119
|
+
* @plan PLAN-20251027-STATELESS5.P10
|
|
120
|
+
* @requirement REQ-STAT5-003.1
|
|
121
|
+
* @pseudocode gemini-runtime.md lines 11-66
|
|
122
|
+
*
|
|
123
|
+
* Phase 5 constructor: Accept optional AgentRuntimeState and HistoryService
|
|
124
|
+
* When provided, client operates in stateless mode using runtime state
|
|
125
|
+
* Otherwise falls back to Config-based operation (backward compatibility)
|
|
126
|
+
*/
|
|
127
|
+
constructor(config, runtimeState, historyService) {
|
|
107
128
|
this.config = config;
|
|
108
|
-
if (
|
|
109
|
-
|
|
129
|
+
if (!runtimeState.provider || runtimeState.provider === '') {
|
|
130
|
+
throw new Error('AgentRuntimeState must have a valid provider');
|
|
131
|
+
}
|
|
132
|
+
if (!runtimeState.model || runtimeState.model === '') {
|
|
133
|
+
throw new Error('AgentRuntimeState must have a valid model');
|
|
134
|
+
}
|
|
135
|
+
if (runtimeState.authType === AuthType.API_KEY &&
|
|
136
|
+
!runtimeState.authPayload?.apiKey) {
|
|
137
|
+
throw new Error('AgentRuntimeState must include apiKey when authType is API_KEY');
|
|
138
|
+
}
|
|
139
|
+
if (runtimeState.authType === AuthType.OAUTH &&
|
|
140
|
+
!runtimeState.authPayload?.token) {
|
|
141
|
+
throw new Error('AgentRuntimeState must include token when authType is OAUTH');
|
|
110
142
|
}
|
|
143
|
+
this.runtimeState = runtimeState;
|
|
144
|
+
this._historyService = historyService;
|
|
111
145
|
this.logger = new DebugLogger('llxprt:core:client');
|
|
112
|
-
this.
|
|
146
|
+
this._unsubscribe = subscribeToAgentRuntimeState(runtimeState.runtimeId, (event) => {
|
|
147
|
+
this.logger.debug('Runtime state changed', event);
|
|
148
|
+
});
|
|
149
|
+
void this._historyService;
|
|
150
|
+
void this._unsubscribe;
|
|
151
|
+
const proxyUrl = runtimeState.proxyUrl;
|
|
152
|
+
if (proxyUrl) {
|
|
153
|
+
setGlobalDispatcher(new ProxyAgent(proxyUrl));
|
|
154
|
+
}
|
|
155
|
+
const embeddingModel = config.getEmbeddingModel();
|
|
156
|
+
this.embeddingModel = embeddingModel || runtimeState.model;
|
|
113
157
|
this.loopDetector = new LoopDetectionService(config);
|
|
114
|
-
this.lastPromptId =
|
|
158
|
+
this.lastPromptId = runtimeState.sessionId;
|
|
115
159
|
// Initialize complexity analyzer with config settings
|
|
116
160
|
const complexitySettings = config.getComplexityAnalyzerSettings();
|
|
117
161
|
this.complexityAnalyzer = new ComplexityAnalyzer({
|
|
@@ -121,7 +165,6 @@ export class GeminiClient {
|
|
|
121
165
|
this.complexitySuggestionCooldown =
|
|
122
166
|
complexitySettings.suggestionCooldownMs ?? 300000;
|
|
123
167
|
this.todoReminderService = new TodoReminderService();
|
|
124
|
-
this.pendingInstallerNotices = [];
|
|
125
168
|
}
|
|
126
169
|
async initialize(contentGeneratorConfig) {
|
|
127
170
|
// Preserve chat history before resetting, but only if we don't already have stored history
|
|
@@ -162,6 +205,10 @@ export class GeminiClient {
|
|
|
162
205
|
return this.contentGenerator?.userTier;
|
|
163
206
|
}
|
|
164
207
|
processComplexityAnalysis(analysis) {
|
|
208
|
+
if (!this.todoToolsAvailable) {
|
|
209
|
+
this.consecutiveComplexTurns = 0;
|
|
210
|
+
return undefined;
|
|
211
|
+
}
|
|
165
212
|
if (!analysis.isComplex || !analysis.shouldSuggestTodos) {
|
|
166
213
|
this.consecutiveComplexTurns = 0;
|
|
167
214
|
return undefined;
|
|
@@ -213,25 +260,22 @@ export class GeminiClient {
|
|
|
213
260
|
return request;
|
|
214
261
|
}
|
|
215
262
|
recordModelActivity(event) {
|
|
263
|
+
if (!this.todoToolsAvailable) {
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
216
266
|
if (event.type !== GeminiEventType.Content &&
|
|
217
267
|
event.type !== GeminiEventType.ToolCallRequest) {
|
|
218
268
|
return;
|
|
219
269
|
}
|
|
220
270
|
this.toolActivityCount += 1;
|
|
221
|
-
|
|
222
|
-
// regardless of complexity - this is the core safety feature
|
|
223
|
-
if (this.toolActivityCount > 5) {
|
|
271
|
+
if (this.toolActivityCount > 4) {
|
|
224
272
|
this.toolCallReminderLevel = 'escalated';
|
|
225
273
|
}
|
|
226
|
-
else if (this.toolActivityCount ===
|
|
274
|
+
else if (this.toolActivityCount === 4 &&
|
|
227
275
|
this.toolCallReminderLevel === 'none') {
|
|
228
276
|
this.toolCallReminderLevel = 'base';
|
|
229
277
|
}
|
|
230
278
|
}
|
|
231
|
-
/**
|
|
232
|
-
* Analyzes the current user request to determine if it's complex enough
|
|
233
|
-
* to warrant todo reminders
|
|
234
|
-
*/
|
|
235
279
|
async addHistory(content) {
|
|
236
280
|
// Ensure chat is initialized before adding history
|
|
237
281
|
if (!this.hasChatInitialized()) {
|
|
@@ -331,7 +375,16 @@ export class GeminiClient {
|
|
|
331
375
|
}
|
|
332
376
|
async setTools() {
|
|
333
377
|
const toolRegistry = this.config.getToolRegistry();
|
|
334
|
-
|
|
378
|
+
if (!toolRegistry) {
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
const toolsView = typeof this.chat?.getToolsView === 'function'
|
|
382
|
+
? this.chat.getToolsView()
|
|
383
|
+
: undefined;
|
|
384
|
+
const toolDeclarations = toolsView
|
|
385
|
+
? this.buildToolDeclarationsFromView(toolRegistry, toolsView)
|
|
386
|
+
: toolRegistry.getFunctionDeclarations();
|
|
387
|
+
this.updateTodoToolAvailabilityFromDeclarations(toolDeclarations);
|
|
335
388
|
// Debug log for intermittent tool issues
|
|
336
389
|
const logger = new DebugLogger('llxprt:client:setTools');
|
|
337
390
|
logger.debug(() => `setTools called, declarations count: ${toolDeclarations.length}`);
|
|
@@ -378,6 +431,13 @@ export class GeminiClient {
|
|
|
378
431
|
parts: [{ text: await getDirectoryContextString(this.config) }],
|
|
379
432
|
});
|
|
380
433
|
}
|
|
434
|
+
async generateDirectMessage(params, promptId) {
|
|
435
|
+
await this.lazyInitialize();
|
|
436
|
+
if (!this.chat) {
|
|
437
|
+
this.chat = await this.startChat([]);
|
|
438
|
+
}
|
|
439
|
+
return this.getChat().generateDirectMessage(params, promptId);
|
|
440
|
+
}
|
|
381
441
|
async startChat(extraHistory) {
|
|
382
442
|
this.forceFullIdeContext = true;
|
|
383
443
|
this.hasFailedCompressionAttempt = false;
|
|
@@ -385,8 +445,6 @@ export class GeminiClient {
|
|
|
385
445
|
await this.lazyInitialize();
|
|
386
446
|
const envParts = await getEnvironmentContext(this.config);
|
|
387
447
|
const toolRegistry = this.config.getToolRegistry();
|
|
388
|
-
const toolDeclarations = toolRegistry.getFunctionDeclarations();
|
|
389
|
-
const tools = [{ functionDeclarations: toolDeclarations }];
|
|
390
448
|
const enabledToolNames = this.getEnabledToolNamesForPrompt();
|
|
391
449
|
// CRITICAL: Reuse stored HistoryService if available to preserve UI conversation display
|
|
392
450
|
// This is essential for maintaining conversation history across provider switches
|
|
@@ -403,21 +461,22 @@ export class GeminiClient {
|
|
|
403
461
|
}
|
|
404
462
|
// Add extraHistory if provided
|
|
405
463
|
if (extraHistory && extraHistory.length > 0) {
|
|
406
|
-
|
|
464
|
+
// @plan PLAN-20251027-STATELESS5.P10
|
|
465
|
+
// @requirement REQ-STAT5-003.1
|
|
466
|
+
const currentModel = this.runtimeState.model;
|
|
407
467
|
for (const content of extraHistory) {
|
|
408
468
|
historyService.add(ContentConverters.toIContent(content), currentModel);
|
|
409
469
|
}
|
|
410
470
|
}
|
|
411
471
|
try {
|
|
412
472
|
const userMemory = this.config.getUserMemory();
|
|
413
|
-
|
|
473
|
+
// @plan PLAN-20251027-STATELESS5.P10
|
|
474
|
+
// @requirement REQ-STAT5-003.1
|
|
475
|
+
const model = this.runtimeState.model;
|
|
476
|
+
// Provider name removed from prompt call signature
|
|
414
477
|
const logger = new DebugLogger('llxprt:client:start');
|
|
415
478
|
logger.debug(() => `DEBUG [client.startChat]: Model from config: ${model}`);
|
|
416
479
|
let systemInstruction = await getCoreSystemPromptAsync(userMemory, model, enabledToolNames);
|
|
417
|
-
const installerNotices = await drainPromptInstallerNotices();
|
|
418
|
-
if (installerNotices.length > 0) {
|
|
419
|
-
this.pendingInstallerNotices.push(...installerNotices);
|
|
420
|
-
}
|
|
421
480
|
// Add environment context to system instruction
|
|
422
481
|
const envContextText = envParts
|
|
423
482
|
.map((part) => ('text' in part ? part.text : ''))
|
|
@@ -435,7 +494,9 @@ export class GeminiClient {
|
|
|
435
494
|
}
|
|
436
495
|
historyService.setBaseTokenOffset(systemPromptTokens);
|
|
437
496
|
logger.debug(() => `DEBUG [client.startChat]: System instruction includes Flash instructions: ${systemInstruction.includes('IMPORTANT: You MUST use the provided tools')}`);
|
|
438
|
-
|
|
497
|
+
// @plan PLAN-20251027-STATELESS5.P10
|
|
498
|
+
// @requirement REQ-STAT5-003.1
|
|
499
|
+
const generateContentConfigWithThinking = isThinkingSupported(this.runtimeState.model)
|
|
439
500
|
? {
|
|
440
501
|
...this.generateContentConfig,
|
|
441
502
|
thinkingConfig: {
|
|
@@ -444,12 +505,62 @@ export class GeminiClient {
|
|
|
444
505
|
},
|
|
445
506
|
}
|
|
446
507
|
: this.generateContentConfig;
|
|
447
|
-
|
|
508
|
+
// @plan PLAN-20251028-STATELESS6.P10
|
|
509
|
+
// @requirement REQ-STAT6-001.2
|
|
510
|
+
// Create runtime context from config (foreground agent)
|
|
511
|
+
const rawCompressionThreshold = this.config.getEphemeralSetting('compression-threshold');
|
|
512
|
+
const compressionThreshold = typeof rawCompressionThreshold === 'number'
|
|
513
|
+
? rawCompressionThreshold
|
|
514
|
+
: undefined;
|
|
515
|
+
const rawContextLimit = this.config.getEphemeralSetting('context-limit');
|
|
516
|
+
const contextLimit = typeof rawContextLimit === 'number' &&
|
|
517
|
+
Number.isFinite(rawContextLimit) &&
|
|
518
|
+
rawContextLimit > 0
|
|
519
|
+
? rawContextLimit
|
|
520
|
+
: undefined;
|
|
521
|
+
const rawPreserveThreshold = this.config.getEphemeralSetting('compression-preserve-threshold');
|
|
522
|
+
const preserveThreshold = typeof rawPreserveThreshold === 'number'
|
|
523
|
+
? rawPreserveThreshold
|
|
524
|
+
: undefined;
|
|
525
|
+
const settings = {
|
|
526
|
+
compressionThreshold: compressionThreshold ?? 0.8,
|
|
527
|
+
contextLimit,
|
|
528
|
+
preserveThreshold: preserveThreshold ?? 0.2,
|
|
529
|
+
telemetry: {
|
|
530
|
+
enabled: true,
|
|
531
|
+
target: null,
|
|
532
|
+
},
|
|
533
|
+
tools: this.getToolGovernanceEphemerals(),
|
|
534
|
+
};
|
|
535
|
+
const providerRuntime = createProviderRuntimeContext({
|
|
536
|
+
settingsService: this.config.getSettingsService(),
|
|
537
|
+
config: this.config,
|
|
538
|
+
runtimeId: this.runtimeState.runtimeId,
|
|
539
|
+
metadata: { source: 'GeminiClient.startChat' },
|
|
540
|
+
});
|
|
541
|
+
const runtimeBundle = await loadAgentRuntime({
|
|
542
|
+
profile: {
|
|
543
|
+
config: this.config,
|
|
544
|
+
state: this.runtimeState,
|
|
545
|
+
settings,
|
|
546
|
+
providerRuntime,
|
|
547
|
+
contentGeneratorConfig: this.config.getContentGeneratorConfig(),
|
|
548
|
+
toolRegistry,
|
|
549
|
+
providerManager: this.config.getProviderManager?.(),
|
|
550
|
+
},
|
|
551
|
+
overrides: {
|
|
552
|
+
historyService,
|
|
553
|
+
contentGenerator: this.getContentGenerator(),
|
|
554
|
+
},
|
|
555
|
+
});
|
|
556
|
+
const filteredDeclarations = this.buildToolDeclarationsFromView(toolRegistry, runtimeBundle.toolsView);
|
|
557
|
+
this.updateTodoToolAvailabilityFromDeclarations(filteredDeclarations);
|
|
558
|
+
const tools = [{ functionDeclarations: filteredDeclarations }];
|
|
559
|
+
return new GeminiChat(runtimeBundle.runtimeContext, runtimeBundle.contentGenerator, {
|
|
448
560
|
systemInstruction,
|
|
449
561
|
...generateContentConfigWithThinking,
|
|
450
562
|
tools,
|
|
451
|
-
}, []
|
|
452
|
-
historyService);
|
|
563
|
+
}, []);
|
|
453
564
|
}
|
|
454
565
|
catch (error) {
|
|
455
566
|
await reportError(error, 'Error initializing chat session.', extraHistory ?? [], 'startChat');
|
|
@@ -624,13 +735,6 @@ export class GeminiClient {
|
|
|
624
735
|
this.chat = await this.startChat();
|
|
625
736
|
}
|
|
626
737
|
}
|
|
627
|
-
if (this.pendingInstallerNotices.length > 0) {
|
|
628
|
-
const notices = [...this.pendingInstallerNotices];
|
|
629
|
-
this.pendingInstallerNotices = [];
|
|
630
|
-
for (const notice of notices) {
|
|
631
|
-
yield { type: GeminiEventType.SystemNotice, value: notice };
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
738
|
if (this.lastPromptId !== prompt_id) {
|
|
635
739
|
this.loopDetector.reset(prompt_id);
|
|
636
740
|
this.lastPromptId = prompt_id;
|
|
@@ -644,7 +748,7 @@ export class GeminiClient {
|
|
|
644
748
|
const contentGenConfig = this.config.getContentGeneratorConfig();
|
|
645
749
|
const providerManager = contentGenConfig?.providerManager;
|
|
646
750
|
const providerName = providerManager?.getActiveProviderName() || 'backend';
|
|
647
|
-
return new Turn(this.getChat(), prompt_id, providerName);
|
|
751
|
+
return new Turn(this.getChat(), prompt_id, DEFAULT_AGENT_ID, providerName);
|
|
648
752
|
}
|
|
649
753
|
// Ensure turns never exceeds MAX_TURNS to prevent infinite loops
|
|
650
754
|
const boundedTurns = Math.min(turns, this.MAX_TURNS);
|
|
@@ -652,16 +756,15 @@ export class GeminiClient {
|
|
|
652
756
|
const contentGenConfig = this.config.getContentGeneratorConfig();
|
|
653
757
|
const providerManager = contentGenConfig?.providerManager;
|
|
654
758
|
const providerName = providerManager?.getActiveProviderName() || 'backend';
|
|
655
|
-
return new Turn(this.getChat(), prompt_id, providerName);
|
|
759
|
+
return new Turn(this.getChat(), prompt_id, DEFAULT_AGENT_ID, providerName);
|
|
656
760
|
}
|
|
657
761
|
// Track the original model from the first call to detect model switching
|
|
658
|
-
|
|
659
|
-
//
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
}
|
|
762
|
+
// @plan PLAN-20251027-STATELESS5.P10
|
|
763
|
+
// @requirement REQ-STAT5-003.1
|
|
764
|
+
const initialModel = originalModel || this.runtimeState.model;
|
|
765
|
+
const compressed = await this.tryCompressChat(prompt_id);
|
|
766
|
+
if (compressed.compressionStatus === CompressionStatus.COMPRESSED) {
|
|
767
|
+
yield { type: GeminiEventType.ChatCompressed, value: compressed };
|
|
665
768
|
}
|
|
666
769
|
// Prevent context updates from being sent while a tool call is
|
|
667
770
|
// waiting for a response. The Gemini API requires that a functionResponse
|
|
@@ -712,7 +815,7 @@ export class GeminiClient {
|
|
|
712
815
|
const contentGenConfig = this.config.getContentGeneratorConfig();
|
|
713
816
|
const providerManager = contentGenConfig?.providerManager;
|
|
714
817
|
const providerName = providerManager?.getActiveProviderName() || 'backend';
|
|
715
|
-
const turn = new Turn(this.getChat(), prompt_id, providerName);
|
|
818
|
+
const turn = new Turn(this.getChat(), prompt_id, DEFAULT_AGENT_ID, providerName);
|
|
716
819
|
const loopDetected = await this.loopDetector.turnStarted(signal);
|
|
717
820
|
if (loopDetected) {
|
|
718
821
|
yield { type: GeminiEventType.LoopDetected };
|
|
@@ -735,7 +838,7 @@ export class GeminiClient {
|
|
|
735
838
|
return turn;
|
|
736
839
|
}
|
|
737
840
|
}
|
|
738
|
-
if (this.toolCallReminderLevel !== 'none') {
|
|
841
|
+
if (this.todoToolsAvailable && this.toolCallReminderLevel !== 'none') {
|
|
739
842
|
const reminderText = this.toolCallReminderLevel === 'escalated'
|
|
740
843
|
? TOOL_ESCALATED_TODO_MESSAGE
|
|
741
844
|
: TOOL_BASE_TODO_MESSAGE;
|
|
@@ -752,7 +855,9 @@ export class GeminiClient {
|
|
|
752
855
|
}
|
|
753
856
|
if (!turn.pendingToolCalls.length && signal && !signal.aborted) {
|
|
754
857
|
// Check if model was switched during the call (likely due to quota error)
|
|
755
|
-
|
|
858
|
+
// @plan PLAN-20251027-STATELESS5.P10
|
|
859
|
+
// @requirement REQ-STAT5-003.1
|
|
860
|
+
const currentModel = this.runtimeState.model;
|
|
756
861
|
if (currentModel !== initialModel) {
|
|
757
862
|
// Model was switched (likely due to quota error fallback)
|
|
758
863
|
// Don't continue with recursive call to prevent unwanted Flash execution
|
|
@@ -768,6 +873,7 @@ export class GeminiClient {
|
|
|
768
873
|
const modelToUse = model;
|
|
769
874
|
try {
|
|
770
875
|
const userMemory = this.config.getUserMemory();
|
|
876
|
+
// Provider name removed from prompt call signature
|
|
771
877
|
const systemInstruction = await getCoreSystemPromptAsync(userMemory, modelToUse, this.getEnabledToolNamesForPrompt());
|
|
772
878
|
const requestConfig = {
|
|
773
879
|
abortSignal,
|
|
@@ -846,6 +952,7 @@ export class GeminiClient {
|
|
|
846
952
|
};
|
|
847
953
|
try {
|
|
848
954
|
const userMemory = this.config.getUserMemory();
|
|
955
|
+
// Provider name removed from prompt call signature
|
|
849
956
|
const systemInstruction = await getCoreSystemPromptAsync(userMemory, modelToUse, this.getEnabledToolNamesForPrompt());
|
|
850
957
|
const requestConfig = {
|
|
851
958
|
abortSignal,
|
|
@@ -920,7 +1027,9 @@ export class GeminiClient {
|
|
|
920
1027
|
};
|
|
921
1028
|
}
|
|
922
1029
|
// Note: chat variable used later in method
|
|
923
|
-
|
|
1030
|
+
// @plan PLAN-20251027-STATELESS5.P10
|
|
1031
|
+
// @requirement REQ-STAT5-003.1
|
|
1032
|
+
const model = this.runtimeState.model;
|
|
924
1033
|
// Get the ACTUAL token count from the history service, not the curated subset
|
|
925
1034
|
const historyService = this.getChat().getHistoryService();
|
|
926
1035
|
const originalTokenCount = historyService
|
|
@@ -1017,10 +1126,12 @@ export class GeminiClient {
|
|
|
1017
1126
|
const historyService = compressedChat.getHistoryService();
|
|
1018
1127
|
if (historyService) {
|
|
1019
1128
|
const userContextLimit = this.config.getEphemeralSetting('context-limit');
|
|
1129
|
+
// @plan PLAN-20251027-STATELESS5.P10
|
|
1130
|
+
// @requirement REQ-STAT5-003.1
|
|
1020
1131
|
historyService.emit('tokensUpdated', {
|
|
1021
1132
|
totalTokens: newTokenCount,
|
|
1022
1133
|
addedTokens: newTokenCount - originalTokenCount,
|
|
1023
|
-
tokenLimit: tokenLimit(this.
|
|
1134
|
+
tokenLimit: tokenLimit(this.runtimeState.model, userContextLimit),
|
|
1024
1135
|
});
|
|
1025
1136
|
}
|
|
1026
1137
|
}
|
|
@@ -1031,6 +1142,63 @@ export class GeminiClient {
|
|
|
1031
1142
|
compressionStatus: CompressionStatus.COMPRESSED,
|
|
1032
1143
|
};
|
|
1033
1144
|
}
|
|
1145
|
+
getToolGovernanceEphemerals() {
|
|
1146
|
+
const allowedList = this.readToolList(this.config.getEphemeralSetting('tools.allowed'));
|
|
1147
|
+
const disabledList = this.readToolList(this.config.getEphemeralSetting('tools.disabled') ??
|
|
1148
|
+
this.config.getEphemeralSetting('disabled-tools'));
|
|
1149
|
+
const hasAllowed = allowedList.length > 0;
|
|
1150
|
+
const hasDisabled = disabledList.length > 0;
|
|
1151
|
+
if (!hasAllowed && !hasDisabled) {
|
|
1152
|
+
return undefined;
|
|
1153
|
+
}
|
|
1154
|
+
return {
|
|
1155
|
+
allowed: hasAllowed ? allowedList : undefined,
|
|
1156
|
+
disabled: hasDisabled ? disabledList : undefined,
|
|
1157
|
+
};
|
|
1158
|
+
}
|
|
1159
|
+
readToolList(value) {
|
|
1160
|
+
if (!Array.isArray(value)) {
|
|
1161
|
+
return [];
|
|
1162
|
+
}
|
|
1163
|
+
const filtered = value.filter((entry) => typeof entry === 'string' && entry.trim().length > 0);
|
|
1164
|
+
return filtered.length > 0 ? [...filtered] : [];
|
|
1165
|
+
}
|
|
1166
|
+
buildToolDeclarationsFromView(toolRegistry, view) {
|
|
1167
|
+
if (!toolRegistry) {
|
|
1168
|
+
return [];
|
|
1169
|
+
}
|
|
1170
|
+
const allowedNames = view.listToolNames();
|
|
1171
|
+
if (allowedNames.length === 0) {
|
|
1172
|
+
return [];
|
|
1173
|
+
}
|
|
1174
|
+
const declarations = [];
|
|
1175
|
+
if (typeof toolRegistry.getAllTools === 'function') {
|
|
1176
|
+
const toolsByName = new Map(toolRegistry.getAllTools().map((tool) => [tool.name, tool]));
|
|
1177
|
+
for (const name of allowedNames) {
|
|
1178
|
+
const tool = toolsByName.get(name);
|
|
1179
|
+
if (!tool) {
|
|
1180
|
+
continue;
|
|
1181
|
+
}
|
|
1182
|
+
const schema = tool.schema;
|
|
1183
|
+
if (schema) {
|
|
1184
|
+
declarations.push(schema);
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
return declarations;
|
|
1188
|
+
}
|
|
1189
|
+
if (typeof toolRegistry.getFunctionDeclarations === 'function') {
|
|
1190
|
+
const declarationsByName = new Map(toolRegistry
|
|
1191
|
+
.getFunctionDeclarations()
|
|
1192
|
+
.map((decl) => [decl.name, decl]));
|
|
1193
|
+
for (const name of allowedNames) {
|
|
1194
|
+
const declaration = declarationsByName.get(name);
|
|
1195
|
+
if (declaration) {
|
|
1196
|
+
declarations.push(declaration);
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
return declarations;
|
|
1201
|
+
}
|
|
1034
1202
|
getEnabledToolNamesForPrompt() {
|
|
1035
1203
|
const toolRegistry = this.config.getToolRegistry();
|
|
1036
1204
|
if (!toolRegistry ||
|
|
@@ -1043,5 +1211,13 @@ export class GeminiClient {
|
|
|
1043
1211
|
.map((tool) => tool.name)
|
|
1044
1212
|
.filter(Boolean)));
|
|
1045
1213
|
}
|
|
1214
|
+
updateTodoToolAvailabilityFromDeclarations(declarations) {
|
|
1215
|
+
const normalizedNames = new Set(declarations
|
|
1216
|
+
.map((decl) => decl?.name)
|
|
1217
|
+
.filter((name) => typeof name === 'string')
|
|
1218
|
+
.map((name) => name.toLowerCase()));
|
|
1219
|
+
this.todoToolsAvailable =
|
|
1220
|
+
normalizedNames.has('todo_write') && normalizedNames.has('todo_read');
|
|
1221
|
+
}
|
|
1046
1222
|
}
|
|
1047
1223
|
//# sourceMappingURL=client.js.map
|