@theia/ai-chat-ui 1.71.0-next.8 → 1.71.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/lib/browser/ai-chat-ui-contribution.d.ts.map +1 -1
  2. package/lib/browser/ai-chat-ui-contribution.js +10 -9
  3. package/lib/browser/ai-chat-ui-contribution.js.map +1 -1
  4. package/lib/browser/ai-chat-ui-frontend-module.d.ts +1 -0
  5. package/lib/browser/ai-chat-ui-frontend-module.d.ts.map +1 -1
  6. package/lib/browser/ai-chat-ui-frontend-module.js +3 -0
  7. package/lib/browser/ai-chat-ui-frontend-module.js.map +1 -1
  8. package/lib/browser/chat-input-mode-contribution.js +1 -1
  9. package/lib/browser/chat-input-mode-contribution.js.map +1 -1
  10. package/lib/browser/chat-input-widget.d.ts +57 -3
  11. package/lib/browser/chat-input-widget.d.ts.map +1 -1
  12. package/lib/browser/chat-input-widget.js +382 -21
  13. package/lib/browser/chat-input-widget.js.map +1 -1
  14. package/lib/browser/chat-response-part-renderer.d.ts +6 -0
  15. package/lib/browser/chat-response-part-renderer.d.ts.map +1 -1
  16. package/lib/browser/chat-response-renderer/delegation-tool-renderer.d.ts +2 -0
  17. package/lib/browser/chat-response-renderer/delegation-tool-renderer.d.ts.map +1 -1
  18. package/lib/browser/chat-response-renderer/delegation-tool-renderer.js +76 -5
  19. package/lib/browser/chat-response-renderer/delegation-tool-renderer.js.map +1 -1
  20. package/lib/browser/chat-response-renderer/index.d.ts +1 -0
  21. package/lib/browser/chat-response-renderer/index.d.ts.map +1 -1
  22. package/lib/browser/chat-response-renderer/index.js +1 -0
  23. package/lib/browser/chat-response-renderer/index.js.map +1 -1
  24. package/lib/browser/chat-response-renderer/question-part-renderer.d.ts +3 -0
  25. package/lib/browser/chat-response-renderer/question-part-renderer.d.ts.map +1 -1
  26. package/lib/browser/chat-response-renderer/question-part-renderer.js +19 -6
  27. package/lib/browser/chat-response-renderer/question-part-renderer.js.map +1 -1
  28. package/lib/browser/chat-response-renderer/tool-call-rendering.d.ts +21 -0
  29. package/lib/browser/chat-response-renderer/tool-call-rendering.d.ts.map +1 -0
  30. package/lib/browser/chat-response-renderer/tool-call-rendering.js +53 -0
  31. package/lib/browser/chat-response-renderer/tool-call-rendering.js.map +1 -0
  32. package/lib/browser/chat-response-renderer/tool-confirmation.d.ts +4 -0
  33. package/lib/browser/chat-response-renderer/tool-confirmation.d.ts.map +1 -1
  34. package/lib/browser/chat-response-renderer/tool-confirmation.js +22 -0
  35. package/lib/browser/chat-response-renderer/tool-confirmation.js.map +1 -1
  36. package/lib/browser/chat-response-renderer/toolcall-part-renderer.d.ts +1 -0
  37. package/lib/browser/chat-response-renderer/toolcall-part-renderer.d.ts.map +1 -1
  38. package/lib/browser/chat-response-renderer/toolcall-part-renderer.js +7 -18
  39. package/lib/browser/chat-response-renderer/toolcall-part-renderer.js.map +1 -1
  40. package/lib/browser/chat-response-renderer/toolcall-utils.d.ts +1 -0
  41. package/lib/browser/chat-response-renderer/toolcall-utils.d.ts.map +1 -1
  42. package/lib/browser/chat-response-renderer/toolcall-utils.js +3 -0
  43. package/lib/browser/chat-response-renderer/toolcall-utils.js.map +1 -1
  44. package/lib/browser/chat-token-usage-indicator-util.d.ts +35 -0
  45. package/lib/browser/chat-token-usage-indicator-util.d.ts.map +1 -0
  46. package/lib/browser/chat-token-usage-indicator-util.js +138 -0
  47. package/lib/browser/chat-token-usage-indicator-util.js.map +1 -0
  48. package/lib/browser/chat-token-usage-indicator-util.spec.d.ts +2 -0
  49. package/lib/browser/chat-token-usage-indicator-util.spec.d.ts.map +1 -0
  50. package/lib/browser/chat-token-usage-indicator-util.spec.js +226 -0
  51. package/lib/browser/chat-token-usage-indicator-util.spec.js.map +1 -0
  52. package/lib/browser/chat-tree-view/chat-view-tree-input-widget.d.ts +6 -1
  53. package/lib/browser/chat-tree-view/chat-view-tree-input-widget.d.ts.map +1 -1
  54. package/lib/browser/chat-tree-view/chat-view-tree-input-widget.js +7 -0
  55. package/lib/browser/chat-tree-view/chat-view-tree-input-widget.js.map +1 -1
  56. package/lib/browser/chat-tree-view/chat-view-tree-widget.d.ts.map +1 -1
  57. package/lib/browser/chat-tree-view/chat-view-tree-widget.js +20 -3
  58. package/lib/browser/chat-tree-view/chat-view-tree-widget.js.map +1 -1
  59. package/lib/browser/chat-view-preferences.d.ts +18 -0
  60. package/lib/browser/chat-view-preferences.d.ts.map +1 -0
  61. package/lib/browser/chat-view-preferences.js +69 -0
  62. package/lib/browser/chat-view-preferences.js.map +1 -0
  63. package/lib/browser/chat-view-widget-toolbar-contribution.d.ts.map +1 -1
  64. package/lib/browser/chat-view-widget-toolbar-contribution.js +3 -2
  65. package/lib/browser/chat-view-widget-toolbar-contribution.js.map +1 -1
  66. package/lib/browser/chat-view-widget.d.ts +1 -2
  67. package/lib/browser/chat-view-widget.d.ts.map +1 -1
  68. package/lib/browser/chat-view-widget.js +3 -7
  69. package/lib/browser/chat-view-widget.js.map +1 -1
  70. package/lib/browser/session-settings-dialog.d.ts +2 -5
  71. package/lib/browser/session-settings-dialog.d.ts.map +1 -1
  72. package/lib/browser/session-settings-dialog.js +15 -33
  73. package/lib/browser/session-settings-dialog.js.map +1 -1
  74. package/lib/common/toolcall-utils.d.ts +6 -0
  75. package/lib/common/toolcall-utils.d.ts.map +1 -0
  76. package/lib/common/toolcall-utils.js +40 -0
  77. package/lib/common/toolcall-utils.js.map +1 -0
  78. package/lib/common/toolcall-utils.spec.d.ts +2 -0
  79. package/lib/common/toolcall-utils.spec.d.ts.map +1 -0
  80. package/lib/common/toolcall-utils.spec.js +102 -0
  81. package/lib/common/toolcall-utils.spec.js.map +1 -0
  82. package/package.json +12 -12
  83. package/src/browser/ai-chat-ui-contribution.ts +10 -9
  84. package/src/browser/ai-chat-ui-frontend-module.ts +4 -0
  85. package/src/browser/chat-input-mode-contribution.ts +1 -1
  86. package/src/browser/chat-input-widget.tsx +481 -14
  87. package/src/browser/chat-response-part-renderer.ts +6 -0
  88. package/src/browser/chat-response-renderer/delegation-tool-renderer.tsx +105 -7
  89. package/src/browser/chat-response-renderer/index.ts +1 -0
  90. package/src/browser/chat-response-renderer/question-part-renderer.tsx +24 -8
  91. package/src/browser/chat-response-renderer/tool-call-rendering.tsx +89 -0
  92. package/src/browser/chat-response-renderer/tool-confirmation.tsx +26 -0
  93. package/src/browser/chat-response-renderer/toolcall-part-renderer.tsx +21 -18
  94. package/src/browser/chat-response-renderer/toolcall-utils.ts +2 -0
  95. package/src/browser/chat-token-usage-indicator-util.spec.ts +262 -0
  96. package/src/browser/chat-token-usage-indicator-util.ts +151 -0
  97. package/src/browser/chat-tree-view/chat-view-tree-input-widget.tsx +9 -1
  98. package/src/browser/chat-tree-view/chat-view-tree-widget.tsx +22 -3
  99. package/src/browser/chat-view-preferences.ts +87 -0
  100. package/src/browser/chat-view-widget-toolbar-contribution.tsx +3 -2
  101. package/src/browser/chat-view-widget.tsx +4 -7
  102. package/src/browser/session-settings-dialog.tsx +15 -97
  103. package/src/browser/style/index.css +164 -54
  104. package/src/browser/style/tool-call-rendering.css +327 -0
  105. package/src/common/toolcall-utils.spec.ts +118 -0
  106. package/src/common/toolcall-utils.ts +36 -0
@@ -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");
@@ -49,11 +50,18 @@ const chat_capabilities_panel_1 = require("./chat-capabilities-panel");
49
50
  const chat_input_focus_service_1 = require("./chat-input-focus-service");
50
51
  const generic_capabilities_service_1 = require("./generic-capabilities-service");
51
52
  const generic_capabilities_section_1 = require("./generic-capabilities-section");
53
+ const preferences_1 = require("@theia/core/lib/common/preferences");
54
+ const chat_view_preferences_1 = require("./chat-view-preferences");
55
+ const chat_token_usage_indicator_util_1 = require("./chat-token-usage-indicator-util");
56
+ const chat_view_commands_1 = require("./chat-view-commands");
52
57
  exports.AIChatInputConfiguration = Symbol('AIChatInputConfiguration');
53
58
  let AIChatInputWidget = class AIChatInputWidget extends browser_2.ReactWidget {
54
59
  constructor() {
55
60
  super(...arguments);
56
61
  this.fileValidationState = new Map();
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();
57
65
  this.editorRef = undefined;
58
66
  this.editorReady = new promise_util_1.Deferred();
59
67
  this.handleModeChange = async (mode) => {
@@ -62,6 +70,35 @@ let AIChatInputWidget = class AIChatInputWidget extends browser_2.ReactWidget {
62
70
  await this.updateCapabilitiesForAgent(this.receivingAgent.agentId, mode);
63
71
  }
64
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
+ };
65
102
  this.handleCapabilityChange = (fragmentId, enabled) => {
66
103
  const defaultCapability = this.capabilityDefaults.find(c => c.fragmentId === fragmentId);
67
104
  const sessionOverrides = new Map(this.userCapabilityOverrides);
@@ -182,6 +219,61 @@ let AIChatInputWidget = class AIChatInputWidget extends browser_2.ReactWidget {
182
219
  const nextModeId = this.receivingAgent.modes[nextIndex].id;
183
220
  this.handleModeChange(nextModeId);
184
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
+ }
185
277
  async updateCapabilitiesForAgent(agentId, modeId, preserveOverrides) {
186
278
  const capabilities = await this.capabilitiesService.getCapabilitiesForAgent(agentId, modeId);
187
279
  this.capabilityDefaults = capabilities;
@@ -190,19 +282,44 @@ let AIChatInputWidget = class AIChatInputWidget extends browser_2.ReactWidget {
190
282
  const agentSettings = await this.aiSettingsService.getAgentSettings(agentId);
191
283
  const savedOverrides = agentSettings?.capabilityOverrides;
192
284
  const savedGenericSelections = agentSettings?.genericCapabilitySelections;
285
+ const savedReasoning = agentSettings?.reasoning;
193
286
  // Store saved state for comparison
194
287
  this.savedCapabilityOverrides = savedOverrides ? { ...savedOverrides } : undefined;
195
288
  this.savedGenericCapabilitySelections = savedGenericSelections ? { ...savedGenericSelections } : undefined;
289
+ this.savedReasoning = savedReasoning ? { ...savedReasoning } : undefined;
196
290
  // Initialize from saved settings, or empty if none
197
291
  this.userCapabilityOverrides = savedOverrides
198
292
  ? new Map(Object.entries(savedOverrides))
199
293
  : new Map();
200
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);
201
298
  }
202
299
  // Update disabled generic capabilities (already used in agent prompt)
203
300
  this.disabledGenericCapabilities = await this.capabilitiesService.getUsedGenericCapabilitiesForAgent(agentId, modeId);
204
301
  this.update();
205
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
+ }
206
323
  async updateAvailableGenericCapabilities() {
207
324
  if (!this.genericCapabilitiesService) {
208
325
  return;
@@ -234,6 +351,18 @@ let AIChatInputWidget = class AIChatInputWidget extends browser_2.ReactWidget {
234
351
  }
235
352
  return new Map(Object.entries(overrides));
236
353
  }
354
+ /**
355
+ * Extracts the mode ID from the last request in the chat model.
356
+ * Used to restore the user's selected mode when switching sessions or on reload.
357
+ */
358
+ getLastModeIdFromModel(chatModel) {
359
+ const requests = chatModel.getRequests();
360
+ if (requests.length === 0) {
361
+ return undefined;
362
+ }
363
+ const lastRequest = requests[requests.length - 1];
364
+ return lastRequest.request.modeId;
365
+ }
237
366
  /**
238
367
  * Extracts generic capability selections from the last request in the chat model.
239
368
  * Used to restore user's selections when switching sessions or on reload.
@@ -304,12 +433,18 @@ let AIChatInputWidget = class AIChatInputWidget extends browser_2.ReactWidget {
304
433
  }
305
434
  /**
306
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.
307
437
  */
308
438
  hasAnyChangesFromSaved() {
309
- return (this.hasCapabilityChangesFromSaved() || this.hasGenericCapabilityChangesFromSaved()) && this.receivingAgent !== undefined;
439
+ if (this.receivingAgent === undefined) {
440
+ return false;
441
+ }
442
+ return this.hasCapabilityChangesFromSaved()
443
+ || this.hasGenericCapabilityChangesFromSaved();
310
444
  }
311
445
  /**
312
446
  * Saves current capability selections to settings.
447
+ * Reasoning is auto-persisted via {@link handleReasoningChange} and is not part of this flow.
313
448
  */
314
449
  async saveCurrentSelectionsToSettings() {
315
450
  if (!this.receivingAgent) {
@@ -388,6 +523,9 @@ let AIChatInputWidget = class AIChatInputWidget extends browser_2.ReactWidget {
388
523
  this.userCapabilityOverrides = this.getLastCapabilityOverridesFromModel(chatModel);
389
524
  this.genericCapabilitySelections = this.getLastGenericCapabilitySelectionsFromModel(chatModel);
390
525
  this.onDisposeForChatModel.push(chatModel.onDidChange(event => {
526
+ if (event.kind === 'responseChanged') {
527
+ this.evaluateTokenUsageWarning(chatModel);
528
+ }
391
529
  if (event.kind === 'addVariable') {
392
530
  // Validate files added via any path (including LLM tool calls)
393
531
  // Get the current variables and validate any new file variables
@@ -412,6 +550,16 @@ let AIChatInputWidget = class AIChatInputWidget extends browser_2.ReactWidget {
412
550
  }
413
551
  }));
414
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);
415
563
  this.scheduleUpdateReceivingAgent();
416
564
  this.update();
417
565
  }
@@ -424,8 +572,8 @@ let AIChatInputWidget = class AIChatInputWidget extends browser_2.ReactWidget {
424
572
  this.id = AIChatInputWidget_1.ID;
425
573
  this.title.closable = false;
426
574
  this.toDispose.push(this.resources.add(this.getResourceUri(), ''));
427
- this.toDispose.push(this.aiActivationService.onDidChangeActiveStatus(() => {
428
- this.setEnabled(this.aiActivationService.isActive);
575
+ this.toDispose.push(this.aiActivationService.onDidChangeCanRun(() => {
576
+ this.setEnabled(this.aiActivationService.canRun);
429
577
  }));
430
578
  this.toDispose.push(this.chatAgentService.onDefaultAgentChanged(() => {
431
579
  this.scheduleUpdateReceivingAgent();
@@ -437,15 +585,58 @@ let AIChatInputWidget = class AIChatInputWidget extends browser_2.ReactWidget {
437
585
  this.updateReceivingAgentTimeout = undefined;
438
586
  }
439
587
  }));
440
- this.setEnabled(this.aiActivationService.isActive);
588
+ this.setEnabled(this.aiActivationService.canRun);
441
589
  this.historyService.init().then(() => {
442
590
  this.navigationState = new chat_input_history_1.ChatInputNavigationState(this.historyService);
443
591
  });
444
592
  this.initializeContextKeys();
593
+ this.tokenUsageEnabled = this.preferenceService?.get(chat_view_preferences_1.CHAT_VIEW_TOKEN_USAGE_ENABLED, false) ?? false;
594
+ if (this.preferenceService) {
595
+ this.toDispose.push(this.preferenceService.onPreferenceChanged(change => {
596
+ if (change.preferenceName === chat_view_preferences_1.CHAT_VIEW_TOKEN_USAGE_ENABLED) {
597
+ this.tokenUsageEnabled = this.preferenceService?.get(chat_view_preferences_1.CHAT_VIEW_TOKEN_USAGE_ENABLED, false) ?? false;
598
+ this.update();
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
+ }
622
+ }));
623
+ }
445
624
  // Listen for prompt fragment changes to refresh capabilities
446
625
  this.toDispose.push(this.capabilitiesService.onDidChangeCapabilities(() => {
447
626
  this.refreshCapabilities();
448
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
+ }));
634
+ // When the default mode changes externally (e.g. via AI Configuration),
635
+ // sync the mode selector. Deferred via queueMicrotask so the prompt service's
636
+ // internal state is fully updated before we read agent.modes.
637
+ this.toDispose.push(this.promptService.onSelectedVariantChange(() => {
638
+ queueMicrotask(() => this.syncSelectedModeWithDefault());
639
+ }));
449
640
  // Listen for generic capabilities changes
450
641
  if (this.genericCapabilitiesService) {
451
642
  this.updateAvailableGenericCapabilities();
@@ -490,6 +681,79 @@ let AIChatInputWidget = class AIChatInputWidget extends browser_2.ReactWidget {
490
681
  this.chatInputFirstLineKey.set(isFirstVisualOverall);
491
682
  this.chatInputLastLineKey.set(isLastVisualOverall);
492
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
+ }
493
757
  scheduleUpdateReceivingAgent() {
494
758
  if (this.queryInFlight) {
495
759
  // Don't update capabilities while a query is being sent — the editor is being
@@ -571,7 +835,11 @@ let AIChatInputWidget = class AIChatInputWidget extends browser_2.ReactWidget {
571
835
  if (agent && (agentId !== previousAgentId || needsRefresh)) {
572
836
  const modes = agent.modes ?? [];
573
837
  const defaultMode = modes.find(m => m.isDefault);
574
- const initialModeId = defaultMode?.id;
838
+ const hasPreviousRequests = this._chatModel.getRequests().length > 0;
839
+ const restoredModeId = needsRefresh && hasPreviousRequests
840
+ ? this.getLastModeIdFromModel(this._chatModel)
841
+ : undefined;
842
+ const initialModeId = restoredModeId ?? defaultMode?.id;
575
843
  this.receivingAgent = {
576
844
  agentId: agentId,
577
845
  modes,
@@ -579,15 +847,39 @@ let AIChatInputWidget = class AIChatInputWidget extends browser_2.ReactWidget {
579
847
  };
580
848
  this.chatInputHasModesKey.set(modes.length > 1);
581
849
  // Only preserve overrides on forced refresh if the session has previous requests
582
- const hasPreviousRequests = this._chatModel.getRequests().length > 0;
583
850
  const shouldPreserveOverrides = needsRefresh && hasPreviousRequests;
584
851
  await this.updateCapabilitiesForAgent(agentId, initialModeId, shouldPreserveOverrides);
852
+ this.updateReasoningSupport(agentId);
585
853
  }
586
854
  else if (!agent && this.receivingAgent !== undefined) {
587
855
  this.receivingAgent = undefined;
588
856
  this.capabilityDefaults = [];
589
857
  this.userCapabilityOverrides = new Map();
590
858
  this.chatInputHasModesKey.set(false);
859
+ this.currentReasoningSupport = undefined;
860
+ this.update();
861
+ }
862
+ }
863
+ /**
864
+ * Syncs the selected mode in the UI with the agent's current default mode.
865
+ * Called when the default mode changes externally (e.g. via AI Configuration).
866
+ */
867
+ syncSelectedModeWithDefault() {
868
+ if (!this.receivingAgent) {
869
+ return;
870
+ }
871
+ const agent = this.chatAgentService.getAgent(this.receivingAgent.agentId);
872
+ if (!agent?.modes) {
873
+ return;
874
+ }
875
+ const updatedModes = agent.modes;
876
+ const newDefault = updatedModes.find(m => m.isDefault);
877
+ if (newDefault && newDefault.id !== this.receivingAgent.currentModeId) {
878
+ this.receivingAgent = {
879
+ ...this.receivingAgent,
880
+ modes: updatedModes,
881
+ currentModeId: newDefault.id
882
+ };
591
883
  this.update();
592
884
  }
593
885
  }
@@ -698,6 +990,10 @@ let AIChatInputWidget = class AIChatInputWidget extends browser_2.ReactWidget {
698
990
  currentMode: this.receivingAgent?.currentModeId,
699
991
  onModeChange: this.handleModeChange,
700
992
  keybindingHint: this.getModeKeybindingHint(),
993
+ }, reasoningSelectorProps: {
994
+ reasoningSupport: this.currentReasoningSupport,
995
+ currentLevel: this.getCurrentReasoningLevel(),
996
+ onReasoningChange: this.handleReasoningChange,
701
997
  }, capabilitiesProps: {
702
998
  capabilities: this.capabilityDefaults,
703
999
  overrides: this.userCapabilityOverrides,
@@ -714,7 +1010,7 @@ let AIChatInputWidget = class AIChatInputWidget extends browser_2.ReactWidget {
714
1010
  availableCapabilities: this.availableGenericCapabilities,
715
1011
  disabledCapabilities: this.disabledGenericCapabilities,
716
1012
  hoverService: this.hoverService,
717
- } }));
1013
+ }, tokenUsageEnabled: this.tokenUsageEnabled, tokenUsageWarningThreshold: this.getTokenUsageWarningThreshold() }));
718
1014
  }
719
1015
  onDragOver(event) {
720
1016
  event.preventDefault();
@@ -1051,6 +1347,27 @@ tslib_1.__decorate([
1051
1347
  (0, inversify_1.inject)(common_1.AISettingsService),
1052
1348
  tslib_1.__metadata("design:type", Object)
1053
1349
  ], AIChatInputWidget.prototype, "aiSettingsService", void 0);
1350
+ tslib_1.__decorate([
1351
+ (0, inversify_1.inject)(common_1.PromptService),
1352
+ tslib_1.__metadata("design:type", Object)
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);
1358
+ tslib_1.__decorate([
1359
+ (0, inversify_1.inject)(preferences_1.PreferenceService),
1360
+ (0, inversify_1.optional)(),
1361
+ tslib_1.__metadata("design:type", Object)
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);
1054
1371
  tslib_1.__decorate([
1055
1372
  (0, inversify_1.postConstruct)(),
1056
1373
  tslib_1.__metadata("design:type", Function),
@@ -1413,22 +1730,37 @@ const ChatInput = (props) => {
1413
1730
  const contextUI = buildContextUI(props.context, props.labelProvider, props.onDeleteContextElement, props.onOpenContextElement, props.fileValidationState);
1414
1731
  // Show mode selector if agent has multiple modes
1415
1732
  const showModeSelector = (props.modeSelectorProps.receivingAgentModes?.length ?? 0) > 1;
1733
+ // Token usage computation (cheap pure function walking the model's request list)
1734
+ const totalTokens = props.tokenUsageEnabled ? (0, chat_token_usage_indicator_util_1.computeSessionTokenUsage)(props.chatModel) : 0;
1735
+ const showTokenUsage = props.tokenUsageEnabled && totalTokens > 0;
1736
+ const tokenColorClass = showTokenUsage ? (0, chat_token_usage_indicator_util_1.getUsageColorClass)(totalTokens, props.tokenUsageWarningThreshold) : '';
1737
+ const tokenIsWarningOrError = tokenColorClass === 'token-usage-yellow' || tokenColorClass === 'token-usage-red';
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;
1416
1739
  return (React.createElement("div", { className: "theia-ChatInput", "data-ai-disabled": !props.isEnabled, onDragOver: props.onDragOver, onDrop: props.onDrop, ref: containerRef },
1417
1740
  props.showSuggestions !== false && React.createElement(chat_input_agent_suggestions_1.ChatInputAgentSuggestions, { suggestions: props.suggestions, opener: props.openerService }),
1418
1741
  props.showChangeSet && changeSetUI?.elements &&
1419
1742
  React.createElement(ChangeSetBox, { changeSet: changeSetUI }),
1420
- React.createElement("div", { className: 'theia-ChatInput-Editor-Box' },
1743
+ React.createElement("div", { className: `theia-ChatInput-Editor-Box${tokenIsWarningOrError ? ` token-usage-border-${tokenColorClass}` : ''}` },
1421
1744
  props.showCapabilities !== false && (React.createElement(CapabilitiesBar, { isOpen: props.capabilitiesProps.isOpen, capabilities: props.capabilitiesProps.capabilities, overrides: props.capabilitiesProps.overrides, onCapabilityChange: props.capabilitiesProps.onCapabilityChange, genericCapabilities: props.genericCapabilitiesProps.genericCapabilities, onGenericCapabilityChange: props.genericCapabilitiesProps.onGenericCapabilityChange, onResetGenericCapabilities: props.genericCapabilitiesProps.onResetGenericCapabilities, availableCapabilities: props.genericCapabilitiesProps.availableCapabilities, disabledCapabilities: props.genericCapabilitiesProps.disabledCapabilities, disabled: !props.isEnabled, hoverService: props.hoverService, hasUnsavedChanges: props.capabilitiesProps.hasUnsavedChanges, onSaveToSettings: props.capabilitiesProps.onSaveToSettings })),
1422
1745
  React.createElement("div", { className: 'theia-ChatInput-Editor', ref: editorContainerRef, onKeyDown: onKeyDown, onFocus: handleInputFocus, onBlur: handleInputBlur },
1423
1746
  React.createElement("div", { ref: placeholderRef, className: 'theia-ChatInput-Editor-Placeholder' }, placeholderText)),
1424
1747
  props.context && props.context.length > 0 &&
1425
1748
  React.createElement(ChatContext, { context: contextUI.context }),
1426
- React.createElement(ChatInputOptions, { leftOptions: leftOptions, rightOptions: rightOptions, isEnabled: props.isEnabled, hoverService: props.hoverService, modeSelectorProps: {
1749
+ React.createElement(ChatInputOptions, { leftOptions: leftOptions, rightOptions: rightOptions, isEnabled: props.isEnabled, hoverService: props.hoverService, tokenUsage: showTokenUsage ? {
1750
+ percent: Math.min((totalTokens / chat_token_usage_indicator_util_1.CHAT_CONTEXT_WINDOW_SIZE) * 100, 100),
1751
+ colorClass: tokenColorClass,
1752
+ tooltip: tokenTooltip,
1753
+ } : undefined, modeSelectorProps: {
1427
1754
  show: showModeSelector,
1428
1755
  modes: props.modeSelectorProps.receivingAgentModes,
1429
1756
  currentMode: props.modeSelectorProps.currentMode,
1430
1757
  onModeChange: props.modeSelectorProps.onModeChange,
1431
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,
1432
1764
  }, capabilitiesToggle: {
1433
1765
  show: props.showCapabilities !== false,
1434
1766
  isOpen: props.capabilitiesProps.isOpen,
@@ -1442,16 +1774,16 @@ const ChatInput = (props) => {
1442
1774
  /**
1443
1775
  * Returns an onMouseEnter handler that shows a hover tooltip via HoverService.
1444
1776
  */
1445
- function hoverHandler(hoverService, content) {
1777
+ function hoverHandler(hoverService, content, position = 'bottom') {
1446
1778
  return (e) => {
1447
1779
  hoverService.requestHover({
1448
1780
  content,
1449
1781
  target: e.currentTarget,
1450
- position: 'bottom'
1782
+ position
1451
1783
  });
1452
1784
  };
1453
1785
  }
1454
- const ChatInputOptions = ({ leftOptions, rightOptions, isEnabled, hoverService, modeSelectorProps, capabilitiesToggle }) => {
1786
+ const ChatInputOptions = ({ leftOptions, rightOptions, isEnabled, hoverService, tokenUsage, modeSelectorProps, reasoningSelectorProps, capabilitiesToggle }) => {
1455
1787
  const capabilitiesLabel = core_1.nls.localize('theia/ai/chat-ui/toggleCapabilitiesConfig', 'Toggle Capabilities Configuration');
1456
1788
  const capabilitiesTitle = capabilitiesToggle.keybindingHint
1457
1789
  ? `${capabilitiesLabel} (${capabilitiesToggle.keybindingHint})`
@@ -1460,14 +1792,20 @@ const ChatInputOptions = ({ leftOptions, rightOptions, isEnabled, hoverService,
1460
1792
  // Right options are rendered first in DOM for tab order (send button first when enabled)
1461
1793
  // CSS order property positions them visually (left on left, right on right)
1462
1794
  React.createElement("div", { className: "theia-ChatInputOptions" },
1463
- React.createElement("div", { className: "theia-ChatInputOptions-right" }, rightOptions.map((option, index) => (React.createElement("span", { key: index, className: `option${option.disabled ? ' disabled' : ''}${option.text?.align === 'right' ? ' reverse' : ''}`, "aria-label": option.title, role: 'button', tabIndex: option.disabled ? -1 : 0, onClick: option.handler, onMouseEnter: hoverHandler(hoverService, option.title), onKeyDown: e => {
1464
- if (e.key === 'Enter' || e.key === ' ') {
1465
- e.preventDefault();
1466
- option.handler();
1467
- }
1468
- } },
1469
- React.createElement("span", null, option.text?.content),
1470
- React.createElement("span", { className: `codicon ${option.className}` }))))),
1795
+ React.createElement("div", { className: "theia-ChatInputOptions-right" },
1796
+ tokenUsage && (React.createElement("span", { className: `token-usage-badge ${tokenUsage.colorClass}`, ...(tokenUsage.tooltip && { onMouseEnter: hoverHandler(hoverService, tokenUsage.tooltip, 'top') }) },
1797
+ React.createElement("span", { className: 'token-usage-ring', style: {
1798
+ background: `conic-gradient(var(--token-usage-fill) ${tokenUsage.percent}%, var(--token-usage-track) ${tokenUsage.percent}%)`
1799
+ } },
1800
+ React.createElement("span", { className: 'token-usage-ring-inner' })))),
1801
+ rightOptions.map((option, index) => (React.createElement("span", { key: index, className: `option${option.disabled ? ' disabled' : ''}${option.text?.align === 'right' ? ' reverse' : ''}`, "aria-label": option.title, role: 'button', tabIndex: option.disabled ? -1 : 0, onClick: option.handler, onMouseEnter: hoverHandler(hoverService, option.title), onKeyDown: e => {
1802
+ if (e.key === 'Enter' || e.key === ' ') {
1803
+ e.preventDefault();
1804
+ option.handler();
1805
+ }
1806
+ } },
1807
+ React.createElement("span", null, option.text?.content),
1808
+ React.createElement("span", { className: `codicon ${option.className}` }))))),
1471
1809
  React.createElement("div", { className: "theia-ChatInputOptions-left" },
1472
1810
  leftOptions.map((option, index) => (React.createElement("span", { key: index, className: `option${option.disabled ? ' disabled' : ''}${option.text?.align === 'right' ? ' reverse' : ''}`, "aria-label": option.title, role: 'button', tabIndex: option.disabled ? -1 : 0, onClick: option.handler, onMouseEnter: hoverHandler(hoverService, option.title), onKeyDown: e => {
1473
1811
  if (e.key === 'Enter' || e.key === ' ') {
@@ -1485,7 +1823,8 @@ const ChatInputOptions = ({ leftOptions, rightOptions, isEnabled, hoverService,
1485
1823
  }
1486
1824
  } },
1487
1825
  React.createElement("span", { className: "codicon codicon-tools" }),
1488
- 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 })))));
1489
1828
  };
1490
1829
  /**
1491
1830
  * Combined capabilities bar that shows:
@@ -1530,6 +1869,28 @@ const ChatModeSelector = React.memo(({ modes, currentMode, onModeChange, disable
1530
1869
  return (React.createElement("span", { onMouseEnter: hoverHandler(hoverService, title) },
1531
1870
  React.createElement(select_component_1.SelectComponent, { className: `theia-ChatInput-ModeSelector${disabled ? ' disabled' : ''}`, options: options, defaultValue: currentMode ?? modes[0]?.id ?? '', onChange: handleChange })));
1532
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
+ });
1533
1894
  const noPropagation = (handler) => (e) => {
1534
1895
  handler();
1535
1896
  e.stopPropagation();