@theia/ai-chat-ui 1.71.0-next.64 → 1.71.0-next.72
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/lib/browser/chat-input-widget.d.ts +42 -2
- package/lib/browser/chat-input-widget.d.ts.map +1 -1
- package/lib/browser/chat-input-widget.js +286 -7
- package/lib/browser/chat-input-widget.js.map +1 -1
- package/lib/browser/chat-token-usage-indicator-util.d.ts +28 -2
- package/lib/browser/chat-token-usage-indicator-util.d.ts.map +1 -1
- package/lib/browser/chat-token-usage-indicator-util.js +42 -10
- package/lib/browser/chat-token-usage-indicator-util.js.map +1 -1
- package/lib/browser/chat-token-usage-indicator-util.spec.js +62 -12
- package/lib/browser/chat-token-usage-indicator-util.spec.js.map +1 -1
- package/lib/browser/chat-tree-view/chat-view-tree-input-widget.d.ts +6 -1
- package/lib/browser/chat-tree-view/chat-view-tree-input-widget.d.ts.map +1 -1
- package/lib/browser/chat-tree-view/chat-view-tree-input-widget.js +7 -0
- package/lib/browser/chat-tree-view/chat-view-tree-input-widget.js.map +1 -1
- package/lib/browser/chat-view-preferences.d.ts +5 -0
- package/lib/browser/chat-view-preferences.d.ts.map +1 -1
- package/lib/browser/chat-view-preferences.js +21 -1
- package/lib/browser/chat-view-preferences.js.map +1 -1
- package/lib/browser/session-settings-dialog.d.ts +2 -5
- package/lib/browser/session-settings-dialog.d.ts.map +1 -1
- package/lib/browser/session-settings-dialog.js +6 -32
- package/lib/browser/session-settings-dialog.js.map +1 -1
- package/package.json +11 -11
- package/src/browser/chat-input-widget.tsx +372 -11
- package/src/browser/chat-token-usage-indicator-util.spec.ts +73 -14
- package/src/browser/chat-token-usage-indicator-util.ts +55 -12
- package/src/browser/chat-tree-view/chat-view-tree-input-widget.tsx +9 -1
- package/src/browser/chat-view-preferences.ts +29 -0
- package/src/browser/session-settings-dialog.tsx +6 -96
- package/src/browser/style/index.css +84 -41
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { ChatAgent, ChatHierarchyBranch, ChatModel, ChatRequestModel, ChatService, ChatRequestParser, ChatMode, ChatSession } from '@theia/ai-chat';
|
|
2
2
|
import { ChatAgentService } from '@theia/ai-chat/lib/common/chat-agent-service';
|
|
3
3
|
import { ParsedChatRequest } from '@theia/ai-chat/lib/common/parsed-chat-request';
|
|
4
|
-
import { GenericCapabilitySelections, AIVariableResolutionRequest, ParsedCapability } from '@theia/ai-core';
|
|
4
|
+
import { GenericCapabilitySelections, AIVariableResolutionRequest, ParsedCapability, FrontendLanguageModelRegistry, ReasoningLevel, ReasoningSettings, ReasoningSupport } from '@theia/ai-core';
|
|
5
5
|
import { ChangeSetDecoratorService } from '@theia/ai-chat/lib/browser/change-set-decorator-service';
|
|
6
6
|
import { ImageContextVariable } from '@theia/ai-chat/lib/common/image-context-variable';
|
|
7
7
|
import { AgentCompletionNotificationService, FrontendVariableService, AIActivationService } from '@theia/ai-core/lib/browser';
|
|
8
8
|
import { AISettingsService, PromptService } from '@theia/ai-core/lib/common';
|
|
9
9
|
import { ApplicationShell } from '@theia/core/lib/browser/shell/application-shell';
|
|
10
|
-
import { DisposableCollection, Emitter, InMemoryResources, URI, Disposable } from '@theia/core';
|
|
10
|
+
import { CommandService, DisposableCollection, Emitter, InMemoryResources, MessageService, URI, Disposable } from '@theia/core';
|
|
11
11
|
import { ContextMenuRenderer, HoverService, LabelProvider, Message, OpenerService, ReactWidget } from '@theia/core/lib/browser';
|
|
12
12
|
import { ContextKey, ContextKeyService } from '@theia/core/lib/browser/context-key-service';
|
|
13
13
|
import { KeybindingRegistry } from '@theia/core/lib/browser/keybinding';
|
|
@@ -70,8 +70,13 @@ export declare class AIChatInputWidget extends ReactWidget {
|
|
|
70
70
|
protected readonly chatInputFocusService: ChatInputFocusService;
|
|
71
71
|
protected readonly aiSettingsService: AISettingsService;
|
|
72
72
|
protected readonly promptService: PromptService;
|
|
73
|
+
protected readonly languageModelRegistry: FrontendLanguageModelRegistry;
|
|
73
74
|
protected readonly preferenceService: PreferenceService | undefined;
|
|
75
|
+
protected readonly messageService: MessageService;
|
|
76
|
+
protected readonly commandService: CommandService;
|
|
74
77
|
protected tokenUsageEnabled: boolean;
|
|
78
|
+
/** Sessions we have already notified for the current warning cycle (re-armed when usage drops below the threshold). */
|
|
79
|
+
protected readonly notifiedSessions: Set<string>;
|
|
75
80
|
protected navigationState: ChatInputNavigationState;
|
|
76
81
|
protected editorRef: SimpleMonacoEditor | undefined;
|
|
77
82
|
protected readonly editorReady: Deferred<void>;
|
|
@@ -85,10 +90,28 @@ export declare class AIChatInputWidget extends ReactWidget {
|
|
|
85
90
|
protected getModeKeybindingHint(): string | undefined;
|
|
86
91
|
cycleMode(): void;
|
|
87
92
|
protected handleModeChange: (mode: string) => Promise<void>;
|
|
93
|
+
/** Reasoning capability of the model the receiving agent would currently use; undefined hides the selector. */
|
|
94
|
+
protected currentReasoningSupport?: ReasoningSupport;
|
|
95
|
+
/** Id (`provider/model`) of the model that backs {@link currentReasoningSupport}; used to resolve preference defaults. */
|
|
96
|
+
protected currentLanguageModelId?: string;
|
|
97
|
+
/** Saved reasoning selection for the receiving agent (loaded from {@link AISettingsService}); kept in sync with the persisted value. */
|
|
98
|
+
protected savedReasoning?: ReasoningSettings;
|
|
99
|
+
protected handleReasoningChange: (level: ReasoningLevel) => Promise<void>;
|
|
100
|
+
/**
|
|
101
|
+
* Resolves the reasoning level to display in the selector. Priority: session override →
|
|
102
|
+
* persisted per-agent selection (from {@link AISettingsService}) →
|
|
103
|
+
* `ai-features.reasoning.defaults` preference entry matching the current model/agent →
|
|
104
|
+
* model's declared default → `'off'`.
|
|
105
|
+
*/
|
|
106
|
+
protected getCurrentReasoningLevel(): ReasoningLevel | undefined;
|
|
107
|
+
protected resolvePreferenceReasoningLevel(): ReasoningLevel | undefined;
|
|
108
|
+
protected updateReasoningSupport(agentId: string | undefined): Promise<void>;
|
|
88
109
|
protected handleCapabilityChange: (fragmentId: string, enabled: boolean) => void;
|
|
89
110
|
protected handleGenericCapabilityChange: (type: keyof GenericCapabilitySelections, ids: string[]) => void;
|
|
90
111
|
protected handleResetGenericCapabilities: () => void;
|
|
91
112
|
protected updateCapabilitiesForAgent(agentId: string, modeId?: string, preserveOverrides?: boolean): Promise<void>;
|
|
113
|
+
/** Updates the active chat session's `commonSettings.reasoning`; pass `undefined` to clear. */
|
|
114
|
+
protected applyReasoningToSession(reasoning: ReasoningSettings | undefined): void;
|
|
92
115
|
protected updateAvailableGenericCapabilities(): Promise<void>;
|
|
93
116
|
/**
|
|
94
117
|
* Extracts capability overrides from the last request in the chat model.
|
|
@@ -124,10 +147,12 @@ export declare class AIChatInputWidget extends ReactWidget {
|
|
|
124
147
|
protected hasGenericCapabilityChangesFromSaved(): boolean;
|
|
125
148
|
/**
|
|
126
149
|
* Checks if there are any unsaved changes (capability overrides or generic selections).
|
|
150
|
+
* Reasoning is auto-persisted in {@link handleReasoningChange} and is intentionally excluded.
|
|
127
151
|
*/
|
|
128
152
|
hasAnyChangesFromSaved(): boolean;
|
|
129
153
|
/**
|
|
130
154
|
* Saves current capability selections to settings.
|
|
155
|
+
* Reasoning is auto-persisted via {@link handleReasoningChange} and is not part of this flow.
|
|
131
156
|
*/
|
|
132
157
|
saveCurrentSelectionsToSettings(): Promise<void>;
|
|
133
158
|
protected chatInputFocusKey: ContextKey<boolean>;
|
|
@@ -210,6 +235,21 @@ export declare class AIChatInputWidget extends ReactWidget {
|
|
|
210
235
|
protected init(): void;
|
|
211
236
|
protected initializeContextKeys(): void;
|
|
212
237
|
updateCursorPositionKeys(): void;
|
|
238
|
+
/**
|
|
239
|
+
* Resolve the configured token usage warning threshold as an absolute token count.
|
|
240
|
+
* The preference is stored as a percentage of the context window; this method
|
|
241
|
+
* converts it using the current assumed context window size.
|
|
242
|
+
*/
|
|
243
|
+
protected getTokenUsageWarningThreshold(): number;
|
|
244
|
+
protected getTokenUsageWarningThresholdPercentage(): number;
|
|
245
|
+
protected isTokenUsageWarningEnabled(): boolean;
|
|
246
|
+
/**
|
|
247
|
+
* Called after a response changes on the currently attached session. Shows a
|
|
248
|
+
* warning the first time the total crosses the threshold, and re-arms when
|
|
249
|
+
* usage drops back below it.
|
|
250
|
+
*/
|
|
251
|
+
protected evaluateTokenUsageWarning(chatModel: ChatModel): void;
|
|
252
|
+
protected showTokenUsageWarning(): Promise<void>;
|
|
213
253
|
protected scheduleUpdateReceivingAgent(): void;
|
|
214
254
|
protected updateReceivingAgent(): Promise<void>;
|
|
215
255
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-input-widget.d.ts","sourceRoot":"","sources":["../../src/browser/chat-input-widget.tsx"],"names":[],"mappings":"AAeA,OAAO,EAC0B,SAAS,EAAmB,mBAAmB,EAC5E,SAAS,EAAE,gBAAgB,EAAE,WAAW,EACxC,iBAAiB,EAAE,QAAQ,EAAE,WAAW,EAC3C,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,8CAA8C,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;AAClF,OAAO,
|
|
1
|
+
{"version":3,"file":"chat-input-widget.d.ts","sourceRoot":"","sources":["../../src/browser/chat-input-widget.tsx"],"names":[],"mappings":"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"}
|
|
@@ -21,6 +21,7 @@ const tslib_1 = require("tslib");
|
|
|
21
21
|
const ai_chat_1 = require("@theia/ai-chat");
|
|
22
22
|
const chat_agent_service_1 = require("@theia/ai-chat/lib/common/chat-agent-service");
|
|
23
23
|
const ai_core_1 = require("@theia/ai-core");
|
|
24
|
+
const frontend_language_model_service_1 = require("@theia/ai-core/lib/browser/frontend-language-model-service");
|
|
24
25
|
const change_set_decorator_service_1 = require("@theia/ai-chat/lib/browser/change-set-decorator-service");
|
|
25
26
|
const image_context_variable_1 = require("@theia/ai-chat/lib/common/image-context-variable");
|
|
26
27
|
const browser_1 = require("@theia/ai-core/lib/browser");
|
|
@@ -52,12 +53,15 @@ const generic_capabilities_section_1 = require("./generic-capabilities-section")
|
|
|
52
53
|
const preferences_1 = require("@theia/core/lib/common/preferences");
|
|
53
54
|
const chat_view_preferences_1 = require("./chat-view-preferences");
|
|
54
55
|
const chat_token_usage_indicator_util_1 = require("./chat-token-usage-indicator-util");
|
|
56
|
+
const chat_view_commands_1 = require("./chat-view-commands");
|
|
55
57
|
exports.AIChatInputConfiguration = Symbol('AIChatInputConfiguration');
|
|
56
58
|
let AIChatInputWidget = class AIChatInputWidget extends browser_2.ReactWidget {
|
|
57
59
|
constructor() {
|
|
58
60
|
super(...arguments);
|
|
59
61
|
this.fileValidationState = new Map();
|
|
60
62
|
this.tokenUsageEnabled = false;
|
|
63
|
+
/** Sessions we have already notified for the current warning cycle (re-armed when usage drops below the threshold). */
|
|
64
|
+
this.notifiedSessions = new Set();
|
|
61
65
|
this.editorRef = undefined;
|
|
62
66
|
this.editorReady = new promise_util_1.Deferred();
|
|
63
67
|
this.handleModeChange = async (mode) => {
|
|
@@ -66,6 +70,35 @@ let AIChatInputWidget = class AIChatInputWidget extends browser_2.ReactWidget {
|
|
|
66
70
|
await this.updateCapabilitiesForAgent(this.receivingAgent.agentId, mode);
|
|
67
71
|
}
|
|
68
72
|
};
|
|
73
|
+
this.handleReasoningChange = async (level) => {
|
|
74
|
+
const session = this.chatService.getSessions().find(s => s.model.id === this._chatModel?.id);
|
|
75
|
+
if (!session) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const currentSettings = session.model.settings ?? {};
|
|
79
|
+
const newSettings = {
|
|
80
|
+
...currentSettings,
|
|
81
|
+
commonSettings: {
|
|
82
|
+
...currentSettings.commonSettings,
|
|
83
|
+
reasoning: { level }
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
session.model.setSettings(newSettings);
|
|
87
|
+
// Auto-persist the reasoning selection per-agent so it is restored on the next session
|
|
88
|
+
// and the capabilities indicator does not light up for an unrelated configuration concern.
|
|
89
|
+
if (this.receivingAgent) {
|
|
90
|
+
try {
|
|
91
|
+
await this.aiSettingsService.updateAgentSettings(this.receivingAgent.agentId, {
|
|
92
|
+
reasoning: { level }
|
|
93
|
+
});
|
|
94
|
+
this.savedReasoning = { level };
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
console.error('Failed to persist reasoning selection:', error);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
this.update();
|
|
101
|
+
};
|
|
69
102
|
this.handleCapabilityChange = (fragmentId, enabled) => {
|
|
70
103
|
const defaultCapability = this.capabilityDefaults.find(c => c.fragmentId === fragmentId);
|
|
71
104
|
const sessionOverrides = new Map(this.userCapabilityOverrides);
|
|
@@ -186,6 +219,61 @@ let AIChatInputWidget = class AIChatInputWidget extends browser_2.ReactWidget {
|
|
|
186
219
|
const nextModeId = this.receivingAgent.modes[nextIndex].id;
|
|
187
220
|
this.handleModeChange(nextModeId);
|
|
188
221
|
}
|
|
222
|
+
/**
|
|
223
|
+
* Resolves the reasoning level to display in the selector. Priority: session override →
|
|
224
|
+
* persisted per-agent selection (from {@link AISettingsService}) →
|
|
225
|
+
* `ai-features.reasoning.defaults` preference entry matching the current model/agent →
|
|
226
|
+
* model's declared default → `'off'`.
|
|
227
|
+
*/
|
|
228
|
+
getCurrentReasoningLevel() {
|
|
229
|
+
if (!this.currentReasoningSupport) {
|
|
230
|
+
return undefined;
|
|
231
|
+
}
|
|
232
|
+
const session = this.chatService.getSessions().find(s => s.model.id === this._chatModel?.id);
|
|
233
|
+
const sessionLevel = session?.model.settings?.commonSettings?.reasoning?.level;
|
|
234
|
+
if (sessionLevel) {
|
|
235
|
+
return sessionLevel;
|
|
236
|
+
}
|
|
237
|
+
if (this.savedReasoning?.level) {
|
|
238
|
+
return this.savedReasoning.level;
|
|
239
|
+
}
|
|
240
|
+
return this.resolvePreferenceReasoningLevel() ?? this.currentReasoningSupport.defaultLevel ?? 'off';
|
|
241
|
+
}
|
|
242
|
+
resolvePreferenceReasoningLevel() {
|
|
243
|
+
if (!this.preferenceService || !this.currentLanguageModelId) {
|
|
244
|
+
return undefined;
|
|
245
|
+
}
|
|
246
|
+
const entries = this.preferenceService.get(ai_core_1.PREFERENCE_NAME_REASONING, []);
|
|
247
|
+
const [providerId, modelId] = this.currentLanguageModelId.split('/');
|
|
248
|
+
return (0, frontend_language_model_service_1.mergeReasoningSettings)(entries, modelId, providerId, this.receivingAgent?.agentId)?.reasoning?.level;
|
|
249
|
+
}
|
|
250
|
+
async updateReasoningSupport(agentId) {
|
|
251
|
+
let support;
|
|
252
|
+
let modelId;
|
|
253
|
+
if (agentId) {
|
|
254
|
+
const agent = this.chatAgentService.getAgent(agentId);
|
|
255
|
+
if (agent) {
|
|
256
|
+
for (const requirement of agent.languageModelRequirements ?? []) {
|
|
257
|
+
try {
|
|
258
|
+
const model = await this.languageModelRegistry.selectLanguageModel({ agent: agent.id, ...requirement });
|
|
259
|
+
if (model?.reasoningSupport) {
|
|
260
|
+
support = model.reasoningSupport;
|
|
261
|
+
modelId = model.id;
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
console.warn('Failed to resolve language model for reasoning support:', error);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
if (support !== this.currentReasoningSupport || modelId !== this.currentLanguageModelId) {
|
|
272
|
+
this.currentReasoningSupport = support;
|
|
273
|
+
this.currentLanguageModelId = modelId;
|
|
274
|
+
this.update();
|
|
275
|
+
}
|
|
276
|
+
}
|
|
189
277
|
async updateCapabilitiesForAgent(agentId, modeId, preserveOverrides) {
|
|
190
278
|
const capabilities = await this.capabilitiesService.getCapabilitiesForAgent(agentId, modeId);
|
|
191
279
|
this.capabilityDefaults = capabilities;
|
|
@@ -194,19 +282,44 @@ let AIChatInputWidget = class AIChatInputWidget extends browser_2.ReactWidget {
|
|
|
194
282
|
const agentSettings = await this.aiSettingsService.getAgentSettings(agentId);
|
|
195
283
|
const savedOverrides = agentSettings?.capabilityOverrides;
|
|
196
284
|
const savedGenericSelections = agentSettings?.genericCapabilitySelections;
|
|
285
|
+
const savedReasoning = agentSettings?.reasoning;
|
|
197
286
|
// Store saved state for comparison
|
|
198
287
|
this.savedCapabilityOverrides = savedOverrides ? { ...savedOverrides } : undefined;
|
|
199
288
|
this.savedGenericCapabilitySelections = savedGenericSelections ? { ...savedGenericSelections } : undefined;
|
|
289
|
+
this.savedReasoning = savedReasoning ? { ...savedReasoning } : undefined;
|
|
200
290
|
// Initialize from saved settings, or empty if none
|
|
201
291
|
this.userCapabilityOverrides = savedOverrides
|
|
202
292
|
? new Map(Object.entries(savedOverrides))
|
|
203
293
|
: new Map();
|
|
204
294
|
this.genericCapabilitySelections = savedGenericSelections ?? {};
|
|
295
|
+
// Mirror the saved per-agent reasoning into the chat session so the selector reflects it
|
|
296
|
+
// immediately on session/agent switch.
|
|
297
|
+
this.applyReasoningToSession(savedReasoning);
|
|
205
298
|
}
|
|
206
299
|
// Update disabled generic capabilities (already used in agent prompt)
|
|
207
300
|
this.disabledGenericCapabilities = await this.capabilitiesService.getUsedGenericCapabilitiesForAgent(agentId, modeId);
|
|
208
301
|
this.update();
|
|
209
302
|
}
|
|
303
|
+
/** Updates the active chat session's `commonSettings.reasoning`; pass `undefined` to clear. */
|
|
304
|
+
applyReasoningToSession(reasoning) {
|
|
305
|
+
const session = this.chatService.getSessions().find(s => s.model.id === this._chatModel?.id);
|
|
306
|
+
if (!session) {
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
const currentSettings = session.model.settings ?? {};
|
|
310
|
+
const currentCommon = currentSettings.commonSettings ?? {};
|
|
311
|
+
if ((currentCommon.reasoning?.level ?? undefined) === (reasoning?.level ?? undefined)) {
|
|
312
|
+
return; // no-op when already in sync
|
|
313
|
+
}
|
|
314
|
+
const newCommon = { ...currentCommon };
|
|
315
|
+
if (reasoning) {
|
|
316
|
+
newCommon.reasoning = { ...reasoning };
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
delete newCommon.reasoning;
|
|
320
|
+
}
|
|
321
|
+
session.model.setSettings({ ...currentSettings, commonSettings: newCommon });
|
|
322
|
+
}
|
|
210
323
|
async updateAvailableGenericCapabilities() {
|
|
211
324
|
if (!this.genericCapabilitiesService) {
|
|
212
325
|
return;
|
|
@@ -320,12 +433,18 @@ let AIChatInputWidget = class AIChatInputWidget extends browser_2.ReactWidget {
|
|
|
320
433
|
}
|
|
321
434
|
/**
|
|
322
435
|
* Checks if there are any unsaved changes (capability overrides or generic selections).
|
|
436
|
+
* Reasoning is auto-persisted in {@link handleReasoningChange} and is intentionally excluded.
|
|
323
437
|
*/
|
|
324
438
|
hasAnyChangesFromSaved() {
|
|
325
|
-
|
|
439
|
+
if (this.receivingAgent === undefined) {
|
|
440
|
+
return false;
|
|
441
|
+
}
|
|
442
|
+
return this.hasCapabilityChangesFromSaved()
|
|
443
|
+
|| this.hasGenericCapabilityChangesFromSaved();
|
|
326
444
|
}
|
|
327
445
|
/**
|
|
328
446
|
* Saves current capability selections to settings.
|
|
447
|
+
* Reasoning is auto-persisted via {@link handleReasoningChange} and is not part of this flow.
|
|
329
448
|
*/
|
|
330
449
|
async saveCurrentSelectionsToSettings() {
|
|
331
450
|
if (!this.receivingAgent) {
|
|
@@ -404,6 +523,9 @@ let AIChatInputWidget = class AIChatInputWidget extends browser_2.ReactWidget {
|
|
|
404
523
|
this.userCapabilityOverrides = this.getLastCapabilityOverridesFromModel(chatModel);
|
|
405
524
|
this.genericCapabilitySelections = this.getLastGenericCapabilitySelectionsFromModel(chatModel);
|
|
406
525
|
this.onDisposeForChatModel.push(chatModel.onDidChange(event => {
|
|
526
|
+
if (event.kind === 'responseChanged') {
|
|
527
|
+
this.evaluateTokenUsageWarning(chatModel);
|
|
528
|
+
}
|
|
407
529
|
if (event.kind === 'addVariable') {
|
|
408
530
|
// Validate files added via any path (including LLM tool calls)
|
|
409
531
|
// Get the current variables and validate any new file variables
|
|
@@ -428,6 +550,16 @@ let AIChatInputWidget = class AIChatInputWidget extends browser_2.ReactWidget {
|
|
|
428
550
|
}
|
|
429
551
|
}));
|
|
430
552
|
this._chatModel = chatModel;
|
|
553
|
+
// Evaluate the warning on attach. `notifiedSessions` lives on this widget
|
|
554
|
+
// instance, so the warning fires at most once per (widget lifetime × session):
|
|
555
|
+
// - Within the same widget, switching between sessions that have already been
|
|
556
|
+
// notified does not re-notify.
|
|
557
|
+
// - Closing and reopening the chat view creates a fresh widget with an empty
|
|
558
|
+
// Set, so sessions still above the threshold will be warned about again the
|
|
559
|
+
// first time they are shown after reopen — once per session. Accepted as a
|
|
560
|
+
// rare corner case; promoting the state to the ChatSession would avoid it
|
|
561
|
+
// but isn't worth the coupling today.
|
|
562
|
+
this.evaluateTokenUsageWarning(chatModel);
|
|
431
563
|
this.scheduleUpdateReceivingAgent();
|
|
432
564
|
this.update();
|
|
433
565
|
}
|
|
@@ -465,12 +597,40 @@ let AIChatInputWidget = class AIChatInputWidget extends browser_2.ReactWidget {
|
|
|
465
597
|
this.tokenUsageEnabled = this.preferenceService?.get(chat_view_preferences_1.CHAT_VIEW_TOKEN_USAGE_ENABLED, false) ?? false;
|
|
466
598
|
this.update();
|
|
467
599
|
}
|
|
600
|
+
else if (change.preferenceName === ai_core_1.PREFERENCE_NAME_REASONING) {
|
|
601
|
+
// Refresh the reasoning selector display when the default preference changes.
|
|
602
|
+
this.update();
|
|
603
|
+
}
|
|
604
|
+
else if (change.preferenceName === chat_view_preferences_1.CHAT_VIEW_TOKEN_USAGE_WARNING_THRESHOLD_PERCENTAGE) {
|
|
605
|
+
// Threshold changed: clear notified sessions so users are warned again
|
|
606
|
+
// at the new threshold (e.g. after raising it from the warning's
|
|
607
|
+
// "Open Settings" action), and re-evaluate the current session so the
|
|
608
|
+
// warning appears immediately if it's still above the new threshold.
|
|
609
|
+
this.notifiedSessions.clear();
|
|
610
|
+
if (this._chatModel) {
|
|
611
|
+
this.evaluateTokenUsageWarning(this._chatModel);
|
|
612
|
+
}
|
|
613
|
+
// Re-render so the indicator's color bands reflect the new threshold.
|
|
614
|
+
this.update();
|
|
615
|
+
}
|
|
616
|
+
else if (change.preferenceName === chat_view_preferences_1.CHAT_VIEW_TOKEN_USAGE_WARNING_ENABLED && this._chatModel) {
|
|
617
|
+
// If the user just enabled warnings for a session already above threshold,
|
|
618
|
+
// evaluate now so they get an immediate notification instead of waiting for
|
|
619
|
+
// the next response.
|
|
620
|
+
this.evaluateTokenUsageWarning(this._chatModel);
|
|
621
|
+
}
|
|
468
622
|
}));
|
|
469
623
|
}
|
|
470
624
|
// Listen for prompt fragment changes to refresh capabilities
|
|
471
625
|
this.toDispose.push(this.capabilitiesService.onDidChangeCapabilities(() => {
|
|
472
626
|
this.refreshCapabilities();
|
|
473
627
|
}));
|
|
628
|
+
// Refresh reasoning capability if the language model registry changes (model added/removed/alias re-resolved).
|
|
629
|
+
this.toDispose.push(this.languageModelRegistry.onChange(() => {
|
|
630
|
+
if (this.receivingAgent) {
|
|
631
|
+
this.updateReasoningSupport(this.receivingAgent.agentId);
|
|
632
|
+
}
|
|
633
|
+
}));
|
|
474
634
|
// When the default mode changes externally (e.g. via AI Configuration),
|
|
475
635
|
// sync the mode selector. Deferred via queueMicrotask so the prompt service's
|
|
476
636
|
// internal state is fully updated before we read agent.modes.
|
|
@@ -521,6 +681,79 @@ let AIChatInputWidget = class AIChatInputWidget extends browser_2.ReactWidget {
|
|
|
521
681
|
this.chatInputFirstLineKey.set(isFirstVisualOverall);
|
|
522
682
|
this.chatInputLastLineKey.set(isLastVisualOverall);
|
|
523
683
|
}
|
|
684
|
+
/**
|
|
685
|
+
* Resolve the configured token usage warning threshold as an absolute token count.
|
|
686
|
+
* The preference is stored as a percentage of the context window; this method
|
|
687
|
+
* converts it using the current assumed context window size.
|
|
688
|
+
*/
|
|
689
|
+
getTokenUsageWarningThreshold() {
|
|
690
|
+
const percentage = this.getTokenUsageWarningThresholdPercentage();
|
|
691
|
+
return Math.round((percentage / 100) * chat_token_usage_indicator_util_1.CHAT_CONTEXT_WINDOW_SIZE);
|
|
692
|
+
}
|
|
693
|
+
getTokenUsageWarningThresholdPercentage() {
|
|
694
|
+
const value = this.preferenceService?.get(chat_view_preferences_1.CHAT_VIEW_TOKEN_USAGE_WARNING_THRESHOLD_PERCENTAGE, chat_view_preferences_1.CHAT_VIEW_TOKEN_USAGE_WARNING_THRESHOLD_PERCENTAGE_DEFAULT);
|
|
695
|
+
if (typeof value !== 'number' || !Number.isFinite(value) || value < 1 || value > 100) {
|
|
696
|
+
return chat_view_preferences_1.CHAT_VIEW_TOKEN_USAGE_WARNING_THRESHOLD_PERCENTAGE_DEFAULT;
|
|
697
|
+
}
|
|
698
|
+
return value;
|
|
699
|
+
}
|
|
700
|
+
isTokenUsageWarningEnabled() {
|
|
701
|
+
return this.preferenceService?.get(chat_view_preferences_1.CHAT_VIEW_TOKEN_USAGE_WARNING_ENABLED, false) ?? false;
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* Called after a response changes on the currently attached session. Shows a
|
|
705
|
+
* warning the first time the total crosses the threshold, and re-arms when
|
|
706
|
+
* usage drops back below it.
|
|
707
|
+
*/
|
|
708
|
+
evaluateTokenUsageWarning(chatModel) {
|
|
709
|
+
// No point doing any work if the feature is off.
|
|
710
|
+
if (!this.isTokenUsageWarningEnabled()) {
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
// `responseChanged` fires on every streaming tick, but providers typically
|
|
714
|
+
// only set `tokenUsage` at completion. Skip in-progress responses so we do
|
|
715
|
+
// the walk + decision once per response rather than per chunk.
|
|
716
|
+
const lastRequest = chatModel.getRequests().at(-1);
|
|
717
|
+
if (lastRequest && !lastRequest.response.isComplete) {
|
|
718
|
+
return;
|
|
719
|
+
}
|
|
720
|
+
const decision = (0, chat_token_usage_indicator_util_1.decideTokenUsageWarning)({
|
|
721
|
+
totalTokens: (0, chat_token_usage_indicator_util_1.computeSessionTokenUsage)(chatModel),
|
|
722
|
+
threshold: this.getTokenUsageWarningThreshold(),
|
|
723
|
+
alreadyNotified: this.notifiedSessions.has(chatModel.id)
|
|
724
|
+
});
|
|
725
|
+
if (decision === 'reset') {
|
|
726
|
+
this.notifiedSessions.delete(chatModel.id);
|
|
727
|
+
}
|
|
728
|
+
else if (decision === 'notify') {
|
|
729
|
+
this.notifiedSessions.add(chatModel.id);
|
|
730
|
+
this.showTokenUsageWarning();
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
async showTokenUsageWarning() {
|
|
734
|
+
const percentage = this.getTokenUsageWarningThresholdPercentage();
|
|
735
|
+
const message = core_1.nls.localize('theia/ai/chat-ui/tokenUsageWarningMessage', 'Chat session token usage has reached {0}% of the context window. ' +
|
|
736
|
+
'Consider summarizing this session or starting a new one to avoid hitting the limit.', percentage);
|
|
737
|
+
const summarizeAction = core_1.nls.localize('theia/ai/chat-ui/tokenUsageWarningSummarizeAction', 'Summarize Current Session');
|
|
738
|
+
const newSessionAction = core_1.nls.localize('theia/ai/chat-ui/tokenUsageWarningNewSessionAction', 'Start New Chat');
|
|
739
|
+
const openSettingsAction = core_1.nls.localizeByDefault('Open Settings');
|
|
740
|
+
const selected = await this.messageService.warn(message, summarizeAction, newSessionAction, openSettingsAction);
|
|
741
|
+
if (selected === summarizeAction) {
|
|
742
|
+
this.commandService.executeCommand(chat_view_commands_1.ChatCommands.AI_CHAT_NEW_WITH_TASK_CONTEXT.id).catch(error => {
|
|
743
|
+
console.error(`Failed to execute '${chat_view_commands_1.ChatCommands.AI_CHAT_NEW_WITH_TASK_CONTEXT.id}' from token usage warning`, error);
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
else if (selected === newSessionAction) {
|
|
747
|
+
this.commandService.executeCommand(chat_view_commands_1.AI_CHAT_NEW_CHAT_WINDOW_COMMAND.id).catch(error => {
|
|
748
|
+
console.error(`Failed to execute '${chat_view_commands_1.AI_CHAT_NEW_CHAT_WINDOW_COMMAND.id}' from token usage warning`, error);
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
else if (selected === openSettingsAction) {
|
|
752
|
+
this.commandService.executeCommand(browser_2.CommonCommands.OPEN_PREFERENCES.id, chat_view_preferences_1.CHAT_VIEW_TOKEN_USAGE_WARNING_THRESHOLD_PERCENTAGE).catch(error => {
|
|
753
|
+
console.error(`Failed to execute '${browser_2.CommonCommands.OPEN_PREFERENCES.id}' from token usage warning`, error);
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
}
|
|
524
757
|
scheduleUpdateReceivingAgent() {
|
|
525
758
|
if (this.queryInFlight) {
|
|
526
759
|
// Don't update capabilities while a query is being sent — the editor is being
|
|
@@ -616,12 +849,14 @@ let AIChatInputWidget = class AIChatInputWidget extends browser_2.ReactWidget {
|
|
|
616
849
|
// Only preserve overrides on forced refresh if the session has previous requests
|
|
617
850
|
const shouldPreserveOverrides = needsRefresh && hasPreviousRequests;
|
|
618
851
|
await this.updateCapabilitiesForAgent(agentId, initialModeId, shouldPreserveOverrides);
|
|
852
|
+
this.updateReasoningSupport(agentId);
|
|
619
853
|
}
|
|
620
854
|
else if (!agent && this.receivingAgent !== undefined) {
|
|
621
855
|
this.receivingAgent = undefined;
|
|
622
856
|
this.capabilityDefaults = [];
|
|
623
857
|
this.userCapabilityOverrides = new Map();
|
|
624
858
|
this.chatInputHasModesKey.set(false);
|
|
859
|
+
this.currentReasoningSupport = undefined;
|
|
625
860
|
this.update();
|
|
626
861
|
}
|
|
627
862
|
}
|
|
@@ -755,6 +990,10 @@ let AIChatInputWidget = class AIChatInputWidget extends browser_2.ReactWidget {
|
|
|
755
990
|
currentMode: this.receivingAgent?.currentModeId,
|
|
756
991
|
onModeChange: this.handleModeChange,
|
|
757
992
|
keybindingHint: this.getModeKeybindingHint(),
|
|
993
|
+
}, reasoningSelectorProps: {
|
|
994
|
+
reasoningSupport: this.currentReasoningSupport,
|
|
995
|
+
currentLevel: this.getCurrentReasoningLevel(),
|
|
996
|
+
onReasoningChange: this.handleReasoningChange,
|
|
758
997
|
}, capabilitiesProps: {
|
|
759
998
|
capabilities: this.capabilityDefaults,
|
|
760
999
|
overrides: this.userCapabilityOverrides,
|
|
@@ -771,7 +1010,7 @@ let AIChatInputWidget = class AIChatInputWidget extends browser_2.ReactWidget {
|
|
|
771
1010
|
availableCapabilities: this.availableGenericCapabilities,
|
|
772
1011
|
disabledCapabilities: this.disabledGenericCapabilities,
|
|
773
1012
|
hoverService: this.hoverService,
|
|
774
|
-
}, tokenUsageEnabled: this.tokenUsageEnabled }));
|
|
1013
|
+
}, tokenUsageEnabled: this.tokenUsageEnabled, tokenUsageWarningThreshold: this.getTokenUsageWarningThreshold() }));
|
|
775
1014
|
}
|
|
776
1015
|
onDragOver(event) {
|
|
777
1016
|
event.preventDefault();
|
|
@@ -1112,11 +1351,23 @@ tslib_1.__decorate([
|
|
|
1112
1351
|
(0, inversify_1.inject)(common_1.PromptService),
|
|
1113
1352
|
tslib_1.__metadata("design:type", Object)
|
|
1114
1353
|
], AIChatInputWidget.prototype, "promptService", void 0);
|
|
1354
|
+
tslib_1.__decorate([
|
|
1355
|
+
(0, inversify_1.inject)(ai_core_1.FrontendLanguageModelRegistry),
|
|
1356
|
+
tslib_1.__metadata("design:type", Object)
|
|
1357
|
+
], AIChatInputWidget.prototype, "languageModelRegistry", void 0);
|
|
1115
1358
|
tslib_1.__decorate([
|
|
1116
1359
|
(0, inversify_1.inject)(preferences_1.PreferenceService),
|
|
1117
1360
|
(0, inversify_1.optional)(),
|
|
1118
1361
|
tslib_1.__metadata("design:type", Object)
|
|
1119
1362
|
], AIChatInputWidget.prototype, "preferenceService", void 0);
|
|
1363
|
+
tslib_1.__decorate([
|
|
1364
|
+
(0, inversify_1.inject)(core_1.MessageService),
|
|
1365
|
+
tslib_1.__metadata("design:type", core_1.MessageService)
|
|
1366
|
+
], AIChatInputWidget.prototype, "messageService", void 0);
|
|
1367
|
+
tslib_1.__decorate([
|
|
1368
|
+
(0, inversify_1.inject)(core_1.CommandService),
|
|
1369
|
+
tslib_1.__metadata("design:type", Object)
|
|
1370
|
+
], AIChatInputWidget.prototype, "commandService", void 0);
|
|
1120
1371
|
tslib_1.__decorate([
|
|
1121
1372
|
(0, inversify_1.postConstruct)(),
|
|
1122
1373
|
tslib_1.__metadata("design:type", Function),
|
|
@@ -1479,12 +1730,12 @@ const ChatInput = (props) => {
|
|
|
1479
1730
|
const contextUI = buildContextUI(props.context, props.labelProvider, props.onDeleteContextElement, props.onOpenContextElement, props.fileValidationState);
|
|
1480
1731
|
// Show mode selector if agent has multiple modes
|
|
1481
1732
|
const showModeSelector = (props.modeSelectorProps.receivingAgentModes?.length ?? 0) > 1;
|
|
1482
|
-
// Token usage computation
|
|
1733
|
+
// Token usage computation (cheap pure function walking the model's request list)
|
|
1483
1734
|
const totalTokens = props.tokenUsageEnabled ? (0, chat_token_usage_indicator_util_1.computeSessionTokenUsage)(props.chatModel) : 0;
|
|
1484
1735
|
const showTokenUsage = props.tokenUsageEnabled && totalTokens > 0;
|
|
1485
|
-
const tokenColorClass = showTokenUsage ? (0, chat_token_usage_indicator_util_1.getUsageColorClass)(totalTokens) : '';
|
|
1736
|
+
const tokenColorClass = showTokenUsage ? (0, chat_token_usage_indicator_util_1.getUsageColorClass)(totalTokens, props.tokenUsageWarningThreshold) : '';
|
|
1486
1737
|
const tokenIsWarningOrError = tokenColorClass === 'token-usage-yellow' || tokenColorClass === 'token-usage-red';
|
|
1487
|
-
const tokenTooltip = showTokenUsage ? (0, chat_token_usage_indicator_util_1.buildBarTooltip)((0, chat_token_usage_indicator_util_1.getLatestTokenUsage)(props.chatModel), totalTokens) : undefined;
|
|
1738
|
+
const tokenTooltip = showTokenUsage ? (0, chat_token_usage_indicator_util_1.buildBarTooltip)((0, chat_token_usage_indicator_util_1.getLatestTokenUsage)(props.chatModel), totalTokens, props.tokenUsageWarningThreshold) : undefined;
|
|
1488
1739
|
return (React.createElement("div", { className: "theia-ChatInput", "data-ai-disabled": !props.isEnabled, onDragOver: props.onDragOver, onDrop: props.onDrop, ref: containerRef },
|
|
1489
1740
|
props.showSuggestions !== false && React.createElement(chat_input_agent_suggestions_1.ChatInputAgentSuggestions, { suggestions: props.suggestions, opener: props.openerService }),
|
|
1490
1741
|
props.showChangeSet && changeSetUI?.elements &&
|
|
@@ -1505,6 +1756,11 @@ const ChatInput = (props) => {
|
|
|
1505
1756
|
currentMode: props.modeSelectorProps.currentMode,
|
|
1506
1757
|
onModeChange: props.modeSelectorProps.onModeChange,
|
|
1507
1758
|
keybindingHint: props.modeSelectorProps.keybindingHint,
|
|
1759
|
+
}, reasoningSelectorProps: {
|
|
1760
|
+
show: !!props.reasoningSelectorProps.reasoningSupport,
|
|
1761
|
+
reasoningSupport: props.reasoningSelectorProps.reasoningSupport,
|
|
1762
|
+
currentLevel: props.reasoningSelectorProps.currentLevel,
|
|
1763
|
+
onReasoningChange: props.reasoningSelectorProps.onReasoningChange,
|
|
1508
1764
|
}, capabilitiesToggle: {
|
|
1509
1765
|
show: props.showCapabilities !== false,
|
|
1510
1766
|
isOpen: props.capabilitiesProps.isOpen,
|
|
@@ -1527,7 +1783,7 @@ function hoverHandler(hoverService, content, position = 'bottom') {
|
|
|
1527
1783
|
});
|
|
1528
1784
|
};
|
|
1529
1785
|
}
|
|
1530
|
-
const ChatInputOptions = ({ leftOptions, rightOptions, isEnabled, hoverService, tokenUsage, modeSelectorProps, capabilitiesToggle }) => {
|
|
1786
|
+
const ChatInputOptions = ({ leftOptions, rightOptions, isEnabled, hoverService, tokenUsage, modeSelectorProps, reasoningSelectorProps, capabilitiesToggle }) => {
|
|
1531
1787
|
const capabilitiesLabel = core_1.nls.localize('theia/ai/chat-ui/toggleCapabilitiesConfig', 'Toggle Capabilities Configuration');
|
|
1532
1788
|
const capabilitiesTitle = capabilitiesToggle.keybindingHint
|
|
1533
1789
|
? `${capabilitiesLabel} (${capabilitiesToggle.keybindingHint})`
|
|
@@ -1567,7 +1823,8 @@ const ChatInputOptions = ({ leftOptions, rightOptions, isEnabled, hoverService,
|
|
|
1567
1823
|
}
|
|
1568
1824
|
} },
|
|
1569
1825
|
React.createElement("span", { className: "codicon codicon-tools" }),
|
|
1570
|
-
capabilitiesToggle.hasUnsavedChanges && (React.createElement("span", { className: "theia-capabilities-unsaved-indicator" }))))
|
|
1826
|
+
capabilitiesToggle.hasUnsavedChanges && (React.createElement("span", { className: "theia-capabilities-unsaved-indicator" })))),
|
|
1827
|
+
reasoningSelectorProps.show && reasoningSelectorProps.reasoningSupport && (React.createElement(ReasoningSelector, { reasoningSupport: reasoningSelectorProps.reasoningSupport, currentLevel: reasoningSelectorProps.currentLevel, onReasoningChange: reasoningSelectorProps.onReasoningChange, disabled: !isEnabled, hoverService: hoverService })))));
|
|
1571
1828
|
};
|
|
1572
1829
|
/**
|
|
1573
1830
|
* Combined capabilities bar that shows:
|
|
@@ -1612,6 +1869,28 @@ const ChatModeSelector = React.memo(({ modes, currentMode, onModeChange, disable
|
|
|
1612
1869
|
return (React.createElement("span", { onMouseEnter: hoverHandler(hoverService, title) },
|
|
1613
1870
|
React.createElement(select_component_1.SelectComponent, { className: `theia-ChatInput-ModeSelector${disabled ? ' disabled' : ''}`, options: options, defaultValue: currentMode ?? modes[0]?.id ?? '', onChange: handleChange })));
|
|
1614
1871
|
});
|
|
1872
|
+
const reasoningLevelLabel = (level) => {
|
|
1873
|
+
switch (level) {
|
|
1874
|
+
case 'off': return core_1.nls.localizeByDefault('Off');
|
|
1875
|
+
case 'minimal': return core_1.nls.localize('theia/ai/chat-ui/reasoning/minimal', 'Minimal');
|
|
1876
|
+
case 'low': return core_1.nls.localize('theia/ai/chat-ui/reasoning/low', 'Low');
|
|
1877
|
+
case 'medium': return core_1.nls.localize('theia/ai/chat-ui/reasoning/medium', 'Medium');
|
|
1878
|
+
case 'high': return core_1.nls.localize('theia/ai/chat-ui/reasoning/high', 'High');
|
|
1879
|
+
case 'auto': return core_1.nls.localizeByDefault('Auto');
|
|
1880
|
+
}
|
|
1881
|
+
};
|
|
1882
|
+
const ReasoningSelector = React.memo(({ reasoningSupport, currentLevel, onReasoningChange, disabled, hoverService }) => {
|
|
1883
|
+
const options = React.useMemo(() => reasoningSupport.supportedLevels.map(level => ({ value: level, label: reasoningLevelLabel(level) })), [reasoningSupport]);
|
|
1884
|
+
const handleChange = React.useCallback((option) => {
|
|
1885
|
+
if (option.value) {
|
|
1886
|
+
onReasoningChange(option.value);
|
|
1887
|
+
}
|
|
1888
|
+
}, [onReasoningChange]);
|
|
1889
|
+
const title = core_1.nls.localizeByDefault('Reasoning');
|
|
1890
|
+
const effectiveLevel = currentLevel ?? reasoningSupport.defaultLevel ?? reasoningSupport.supportedLevels[0] ?? 'off';
|
|
1891
|
+
return (React.createElement("span", { onMouseEnter: hoverHandler(hoverService, title) },
|
|
1892
|
+
React.createElement(select_component_1.SelectComponent, { className: `theia-ChatInput-ReasoningSelector reasoning-level-${effectiveLevel}${disabled ? ' disabled' : ''}`, options: options, defaultValue: effectiveLevel, onChange: handleChange })));
|
|
1893
|
+
});
|
|
1615
1894
|
const noPropagation = (handler) => (e) => {
|
|
1616
1895
|
handler();
|
|
1617
1896
|
e.stopPropagation();
|