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

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
@@ -18,6 +18,7 @@ import { ChatSessionSettings, CommonChatSessionSettings } from '@theia/ai-chat';
18
18
  import { InMemoryResources, URI, nls } from '@theia/core';
19
19
  import { AbstractDialog, Message } from '@theia/core/lib/browser';
20
20
  import * as React from '@theia/core/shared/react';
21
+ import { flushSync } from '@theia/core/shared/react-dom';
21
22
  import { createRoot, Root } from '@theia/core/shared/react-dom/client';
22
23
  import { MonacoEditor } from '@theia/monaco/lib/browser/monaco-editor';
23
24
  import { MonacoEditorProvider } from '@theia/monaco/lib/browser/monaco-editor-provider';
@@ -26,59 +27,6 @@ export interface SessionSettingsDialogProps {
26
27
  initialSettings: ChatSessionSettings | undefined;
27
28
  }
28
29
 
29
- interface ThinkingModeSectionProps {
30
- enabled: boolean;
31
- budgetTokens: number;
32
- onEnabledChange: (enabled: boolean) => void;
33
- onBudgetChange: (budget: number) => void;
34
- }
35
-
36
- const ThinkingModeSection: React.FC<ThinkingModeSectionProps> = ({
37
- enabled,
38
- budgetTokens,
39
- onEnabledChange,
40
- onBudgetChange
41
- }) => (
42
- <div className="session-settings-thinking-mode">
43
- <div className="session-settings-section-header">
44
- {nls.localize('theia/ai/session-settings-dialog/thinkingMode', 'Thinking Mode')}
45
- </div>
46
- <div className="session-settings-section-note">
47
- {nls.localize('theia/ai/session-settings-dialog/thinkingModeNote', 'Some models may ignore this setting.')}
48
- </div>
49
- <div className="session-settings-checkbox-container">
50
- <input
51
- type="checkbox"
52
- id="thinking-enabled"
53
- checked={enabled}
54
- onChange={e => onEnabledChange(e.target.checked)}
55
- />
56
- <label htmlFor="thinking-enabled">
57
- {nls.localize('theia/ai/session-settings-dialog/enableThinking', 'Enable extended thinking')}
58
- </label>
59
- </div>
60
- <div className="session-settings-budget-container">
61
- <label
62
- htmlFor="thinking-budget"
63
- className={!enabled ? 'disabled' : ''}
64
- >
65
- {nls.localize('theia/ai/session-settings-dialog/budgetTokens', 'Budget tokens:')}
66
- </label>
67
- <input
68
- type="number"
69
- id="thinking-budget"
70
- min={1000}
71
- max={100000}
72
- step={1000}
73
- value={budgetTokens}
74
- placeholder="10000"
75
- disabled={!enabled}
76
- onChange={e => onBudgetChange(parseInt(e.target.value, 10))}
77
- />
78
- </div>
79
- </div>
80
- );
81
-
82
30
  interface ConfirmationTimeoutSectionProps {
83
31
  enabled: boolean;
84
32
  timeoutSeconds: number;
@@ -155,35 +103,21 @@ const ErrorMessage: React.FC<ErrorMessageProps> = ({ message }) => (
155
103
  );
156
104
 
157
105
  interface DialogContentProps {
158
- thinkingEnabled: boolean;
159
- thinkingBudget: number;
160
106
  confirmationTimeoutEnabled: boolean;
161
107
  confirmationTimeoutSeconds: number;
162
108
  errorMessage: string;
163
- onThinkingEnabledChange: (enabled: boolean) => void;
164
- onThinkingBudgetChange: (budget: number) => void;
165
109
  onConfirmationTimeoutEnabledChange: (enabled: boolean) => void;
166
110
  onConfirmationTimeoutSecondsChange: (seconds: number) => void;
167
111
  }
168
112
 
169
113
  const DialogContent: React.FC<DialogContentProps> = ({
170
- thinkingEnabled,
171
- thinkingBudget,
172
114
  confirmationTimeoutEnabled,
173
115
  confirmationTimeoutSeconds,
174
116
  errorMessage,
175
- onThinkingEnabledChange,
176
- onThinkingBudgetChange,
177
117
  onConfirmationTimeoutEnabledChange,
178
118
  onConfirmationTimeoutSecondsChange
179
119
  }) => (
180
120
  <div className="session-settings-container">
181
- <ThinkingModeSection
182
- enabled={thinkingEnabled}
183
- budgetTokens={thinkingBudget}
184
- onEnabledChange={onThinkingEnabledChange}
185
- onBudgetChange={onThinkingBudgetChange}
186
- />
187
121
  <ConfirmationTimeoutSection
188
122
  enabled={confirmationTimeoutEnabled}
189
123
  timeoutSeconds={confirmationTimeoutSeconds}
@@ -203,12 +137,11 @@ export class SessionSettingsDialog extends AbstractDialog<ChatSessionSettings> {
203
137
  protected initialAdvancedSettingsString: string;
204
138
  protected errorMessage: string = '';
205
139
 
206
- protected thinkingEnabled: boolean;
207
- protected thinkingBudget: number;
208
-
209
140
  protected confirmationTimeoutEnabled: boolean;
210
141
  protected confirmationTimeoutSeconds: number;
211
142
 
143
+ protected preservedReasoning: CommonChatSessionSettings['reasoning'];
144
+
212
145
  protected contentRoot: Root;
213
146
  protected editorContainerNode: HTMLDivElement;
214
147
 
@@ -225,9 +158,8 @@ export class SessionSettingsDialog extends AbstractDialog<ChatSessionSettings> {
225
158
  const initialSettings = options.initialSettings;
226
159
  this.settings = initialSettings ? { ...initialSettings } : {};
227
160
 
228
- // Extract thinking mode settings from commonSettings
229
- this.thinkingEnabled = this.settings.commonSettings?.thinkingMode?.enabled ?? false;
230
- this.thinkingBudget = this.settings.commonSettings?.thinkingMode?.budgetTokens ?? 10000;
161
+ // Reasoning is edited in the chat input; preserve it across this dialog.
162
+ this.preservedReasoning = this.settings.commonSettings?.reasoning;
231
163
 
232
164
  // Extract confirmation timeout settings from commonSettings
233
165
  const savedTimeout = this.settings.commonSettings?.confirmationTimeout;
@@ -253,7 +185,14 @@ export class SessionSettingsDialog extends AbstractDialog<ChatSessionSettings> {
253
185
 
254
186
  protected override onAfterAttach(msg: Message): void {
255
187
  super.onAfterAttach(msg);
256
- this.render();
188
+ // flushSync ensures React commits the render synchronously so that
189
+ // attachEditorContainer can query the DOM immediately afterwards.
190
+ // Without this, React 18 may defer the commit when invoked outside a
191
+ // browser event handler (e.g. from an Electron IPC callback from an
192
+ // Electron-rendered native menu), causing attachEditorContainer to
193
+ // find no .session-settings-advanced element and the Monaco editor
194
+ // to initialize inside a detached, zero-size node.
195
+ flushSync(() => this.render());
257
196
  this.attachEditorContainer();
258
197
  this.createJsonEditor();
259
198
  }
@@ -273,13 +212,9 @@ export class SessionSettingsDialog extends AbstractDialog<ChatSessionSettings> {
273
212
  protected render(): void {
274
213
  this.contentRoot.render(
275
214
  <DialogContent
276
- thinkingEnabled={this.thinkingEnabled}
277
- thinkingBudget={this.thinkingBudget}
278
215
  confirmationTimeoutEnabled={this.confirmationTimeoutEnabled}
279
216
  confirmationTimeoutSeconds={this.confirmationTimeoutSeconds}
280
217
  errorMessage={this.errorMessage}
281
- onThinkingEnabledChange={this.handleThinkingEnabledChange}
282
- onThinkingBudgetChange={this.handleThinkingBudgetChange}
283
218
  onConfirmationTimeoutEnabledChange={this.handleConfirmationTimeoutEnabledChange}
284
219
  onConfirmationTimeoutSecondsChange={this.handleConfirmationTimeoutSecondsChange}
285
220
  />
@@ -379,20 +314,6 @@ export class SessionSettingsDialog extends AbstractDialog<ChatSessionSettings> {
379
314
  }
380
315
  }
381
316
 
382
- protected handleThinkingEnabledChange = (enabled: boolean): void => {
383
- this.thinkingEnabled = enabled;
384
- this.updateSettingsFromCommonSettings();
385
- this.render();
386
- this.attachEditorContainer();
387
- };
388
-
389
- protected handleThinkingBudgetChange = (budget: number): void => {
390
- this.thinkingBudget = budget;
391
- this.updateSettingsFromCommonSettings();
392
- this.render();
393
- this.attachEditorContainer();
394
- };
395
-
396
317
  protected handleConfirmationTimeoutEnabledChange = (enabled: boolean): void => {
397
318
  this.confirmationTimeoutEnabled = enabled;
398
319
  this.updateSettingsFromCommonSettings();
@@ -409,11 +330,8 @@ export class SessionSettingsDialog extends AbstractDialog<ChatSessionSettings> {
409
330
 
410
331
  protected updateSettingsFromCommonSettings(): void {
411
332
  const commonSettings: CommonChatSessionSettings = {};
412
- if (this.thinkingEnabled) {
413
- commonSettings.thinkingMode = {
414
- enabled: true,
415
- budgetTokens: isNaN(this.thinkingBudget) ? undefined : this.thinkingBudget
416
- };
333
+ if (this.preservedReasoning) {
334
+ commonSettings.reasoning = this.preservedReasoning;
417
335
  }
418
336
  if (this.confirmationTimeoutEnabled && !isNaN(this.confirmationTimeoutSeconds) && this.confirmationTimeoutSeconds > 0) {
419
337
  commonSettings.confirmationTimeout = this.confirmationTimeoutSeconds;
@@ -713,8 +713,9 @@ div:last-child>.theia-ChatNode {
713
713
  flex-direction: row-reverse;
714
714
  }
715
715
 
716
- /* Mode selector - compact SelectComponent inside toolbar */
717
- .theia-ChatInput-ModeSelector.theia-select-component {
716
+ /* Mode and reasoning selectors - compact SelectComponents inside toolbar */
717
+ .theia-ChatInput-ModeSelector.theia-select-component,
718
+ .theia-ChatInput-ReasoningSelector.theia-select-component {
718
719
  min-width: unset;
719
720
  min-height: unset;
720
721
  height: calc(var(--theia-icon-size) + var(--theia-ui-padding) - 1px);
@@ -729,26 +730,103 @@ div:last-child>.theia-ChatNode {
729
730
  outline: none;
730
731
  }
731
732
 
732
- .theia-ChatInput-ModeSelector .theia-select-component-chevron {
733
+ /* Anchor for the off-level slash overlay drawn via ::after. */
734
+ .theia-ChatInput-ReasoningSelector.theia-select-component {
735
+ position: relative;
736
+ }
737
+
738
+ .theia-ChatInput-ModeSelector .theia-select-component-chevron,
739
+ .theia-ChatInput-ReasoningSelector .theia-select-component-chevron {
733
740
  font-size: var(--theia-ui-font-size1);
734
741
  margin-left: calc(var(--theia-ui-padding) / 3);
735
742
  }
736
743
 
737
- .theia-ChatInput-ModeSelector.theia-select-component:hover {
744
+ .theia-ChatInput-ModeSelector.theia-select-component:hover,
745
+ .theia-ChatInput-ReasoningSelector.theia-select-component:hover {
738
746
  background-color: var(--theia-toolbar-hoverBackground);
739
747
  }
740
748
 
741
- .theia-ChatInput-ModeSelector.theia-select-component:focus-visible {
749
+ .theia-ChatInput-ModeSelector.theia-select-component:focus-visible,
750
+ .theia-ChatInput-ReasoningSelector.theia-select-component:focus-visible {
742
751
  outline: 1px solid var(--theia-focusBorder);
743
752
  outline-offset: -1px;
744
753
  }
745
754
 
746
- .theia-ChatInput-ModeSelector.disabled {
755
+ .theia-ChatInput-ModeSelector.disabled,
756
+ .theia-ChatInput-ReasoningSelector.disabled {
747
757
  opacity: var(--theia-mod-disabled-opacity);
748
758
  cursor: default;
749
759
  pointer-events: none;
750
760
  }
751
761
 
762
+ /* Inject a leading lightbulb icon inside the reasoning selector so it shares the dropdown's
763
+ click area, hover/focus styles, and visual bounds (no DOM gap, single control). Sized to match
764
+ the toolbar's other codicons (e.g. capabilities wrench) rather than the small chevron.
765
+ The base glyph is the filled lightbulb (\ea61); per-level overrides below swap glyph, opacity
766
+ or color to give a visual cue that scales with the chosen reasoning intensity. */
767
+ .theia-ChatInput-ReasoningSelector.theia-select-component::before {
768
+ font-family: codicon;
769
+ content: '\ea61';
770
+ /* codicon-lightbulb (filled) — default for low/medium/high */
771
+ font-size: var(--theia-icon-size);
772
+ line-height: 1;
773
+ margin-right: calc(var(--theia-ui-padding) / 3);
774
+ display: inline-flex;
775
+ align-items: center;
776
+ }
777
+
778
+ /* Off: empty bulb glyph + CSS-drawn diagonal slash overlay (mimics MDI's lightbulb-off). */
779
+ .theia-ChatInput-ReasoningSelector.reasoning-level-off::before {
780
+ content: '\ec40';
781
+ /* codicon-lightbulb-empty */
782
+ opacity: 0.85;
783
+ }
784
+
785
+ .theia-ChatInput-ReasoningSelector.reasoning-level-off::after {
786
+ content: '';
787
+ position: absolute;
788
+ /* Center over the ::before icon area: padding-left + half icon width. */
789
+ left: calc(var(--theia-ui-padding) * 2 / 3 + var(--theia-icon-size) / 2);
790
+ top: 50%;
791
+ width: calc(var(--theia-icon-size) * 0.95);
792
+ height: 1.5px;
793
+ background-color: currentColor;
794
+ border-radius: 1px;
795
+ transform: translate(-50%, -50%) rotate(-45deg);
796
+ pointer-events: none;
797
+ opacity: 0.85;
798
+ }
799
+
800
+ /* Minimal: empty (outline only) bulb at low opacity — "on, but barely".
801
+ Lower opacity than `low` so the brightness order matches the level order:
802
+ the crisper outline at full opacity would otherwise read brighter than a filled bulb at 0.55. */
803
+ .theia-ChatInput-ReasoningSelector.reasoning-level-minimal::before {
804
+ content: '\ec40';
805
+ /* codicon-lightbulb-empty */
806
+ opacity: 0.5;
807
+ }
808
+
809
+ /* Low: filled bulb, perceptibly more present than minimal. */
810
+ .theia-ChatInput-ReasoningSelector.reasoning-level-low::before {
811
+ opacity: 0.7;
812
+ }
813
+
814
+ /* Medium: filled bulb, moderately bright. */
815
+ .theia-ChatInput-ReasoningSelector.reasoning-level-medium::before {
816
+ opacity: 0.9;
817
+ }
818
+
819
+ /* High: filled bulb at full opacity, tinted with the warning foreground (warm/yellow). */
820
+ .theia-ChatInput-ReasoningSelector.reasoning-level-high::before {
821
+ color: var(--theia-editorWarning-foreground);
822
+ }
823
+
824
+ /* Auto: lightbulb-sparkle — "the model decides automatically". */
825
+ .theia-ChatInput-ReasoningSelector.reasoning-level-auto::before {
826
+ content: '\ec1f';
827
+ /* codicon-lightbulb-sparkle */
828
+ }
829
+
752
830
  .theia-CodePartRenderer-root {
753
831
  display: flex;
754
832
  flex-direction: column;
@@ -1208,12 +1286,6 @@ div:last-child>.theia-ChatNode {
1208
1286
  outline-color: var(--theia-editor-background);
1209
1287
  }
1210
1288
 
1211
- .session-settings-thinking-mode {
1212
- padding: 8px 0;
1213
- border-bottom: 1px solid var(--theia-sideBarSectionHeader-border);
1214
- margin-bottom: 8px;
1215
- }
1216
-
1217
1289
  .session-settings-section-header {
1218
1290
  font-weight: 600;
1219
1291
  font-size: 13px;
@@ -1243,35 +1315,6 @@ div:last-child>.theia-ChatNode {
1243
1315
  user-select: none;
1244
1316
  }
1245
1317
 
1246
- .session-settings-budget-container {
1247
- display: flex;
1248
- align-items: center;
1249
- gap: 8px;
1250
- margin-left: 22px;
1251
- }
1252
-
1253
- .session-settings-budget-container label {
1254
- white-space: nowrap;
1255
- }
1256
-
1257
- .session-settings-budget-container label.disabled {
1258
- color: var(--theia-disabledForeground);
1259
- }
1260
-
1261
- .session-settings-budget-container input[type="number"] {
1262
- width: 100px;
1263
- padding: 4px 8px;
1264
- border: 1px solid var(--theia-input-border);
1265
- border-radius: 4px;
1266
- background-color: var(--theia-input-background);
1267
- color: var(--theia-input-foreground);
1268
- }
1269
-
1270
- .session-settings-budget-container input[type="number"]:disabled {
1271
- opacity: var(--theia-mod-disabled-opacity);
1272
- cursor: not-allowed;
1273
- }
1274
-
1275
1318
  .session-settings-confirmation-timeout {
1276
1319
  padding: 8px 0;
1277
1320
  border-bottom: 1px solid var(--theia-sideBarSectionHeader-border);
@@ -1354,21 +1397,23 @@ div:last-child>.theia-ChatNode {
1354
1397
  background-color: var(--theia-toolbar-hoverBackground);
1355
1398
  }
1356
1399
 
1357
- .delegation-summary::before {
1400
+ .delegation-toggle-arrow::before {
1358
1401
  content: "\25BC";
1359
- /* Down arrow */
1360
- position: absolute;
1361
- right: var(--theia-ui-padding);
1362
- top: 50%;
1363
- transform: translateY(-50%);
1364
1402
  transition: transform 0.2s ease;
1365
- color: var(--theia-descriptionForeground);
1366
- font-size: var(--theia-ui-font-size1);
1403
+ display: inline-block;
1404
+ transform: rotate(-90deg);
1367
1405
  }
1368
1406
 
1369
- .delegation-response-details:not([open]) .delegation-summary::before {
1370
- transform: translateY(-50%) rotate(-90deg);
1371
- /* Right arrow when closed */
1407
+ .delegation-toggle-arrow.open::before {
1408
+ transform: rotate(0deg);
1409
+ }
1410
+
1411
+ .delegation-toggle-arrow {
1412
+ color: var(--theia-descriptionForeground);
1413
+ font-size: var(--theia-ui-font-size1);
1414
+ flex-shrink: 0;
1415
+ display: flex;
1416
+ align-items: center;
1372
1417
  }
1373
1418
 
1374
1419
  .delegation-response-details:not([open]) .delegation-summary {
@@ -1407,8 +1452,6 @@ div:last-child>.theia-ChatNode {
1407
1452
  align-items: center;
1408
1453
  gap: var(--theia-ui-padding);
1409
1454
  font-size: var(--theia-ui-font-size1);
1410
- /* Leave space for the arrow */
1411
- margin-right: calc(var(--theia-ui-padding) * 3);
1412
1455
  }
1413
1456
 
1414
1457
  .delegation-status-icon {
@@ -1467,6 +1510,27 @@ div:last-child>.theia-ChatNode {
1467
1510
  color: var(--theia-foreground);
1468
1511
  }
1469
1512
 
1513
+ .delegation-interaction-badge {
1514
+ color: var(--theia-editorWarning-foreground);
1515
+ display: flex;
1516
+ align-items: center;
1517
+ }
1518
+
1519
+ .delegation-pending-confirmations {
1520
+ margin-top: var(--theia-ui-padding);
1521
+ padding-top: var(--theia-ui-padding);
1522
+ border-top: var(--theia-border-width) solid var(--theia-sideBarSectionHeader-border);
1523
+ }
1524
+
1525
+ .delegation-pending-confirmations .theia-tool-confirmation {
1526
+ margin: 0;
1527
+ margin-bottom: var(--theia-ui-padding);
1528
+ }
1529
+
1530
+ .delegation-pending-confirmations .theia-tool-confirmation:last-child {
1531
+ margin-bottom: 0;
1532
+ }
1533
+
1470
1534
  .delegation-response-placeholder {
1471
1535
  margin-top: var(--theia-ui-padding);
1472
1536
  min-height: calc(var(--theia-ui-padding) * 6);
@@ -2015,3 +2079,49 @@ div:last-child>.theia-ChatNode {
2015
2079
  .theia-capabilities-collapsed-scrollbar::-webkit-scrollbar-thumb:hover {
2016
2080
  background-color: var(--theia-scrollbarSlider-hoverBackground);
2017
2081
  }
2082
+
2083
+ /* Token usage: border tinting on warning/error (repeated with :has for focus specificity) */
2084
+ .theia-ChatInput-Editor-Box.token-usage-border-token-usage-yellow,
2085
+ .theia-ChatInput-Editor-Box.token-usage-border-token-usage-yellow:has(.monaco-editor.focused) {
2086
+ border-color: var(--theia-warningBackground);
2087
+ }
2088
+
2089
+ .theia-ChatInput-Editor-Box.token-usage-border-token-usage-red,
2090
+ .theia-ChatInput-Editor-Box.token-usage-border-token-usage-red:has(.monaco-editor.focused) {
2091
+ border-color: var(--theia-errorBackground);
2092
+ }
2093
+
2094
+ /* Token usage badge next to send button */
2095
+ .token-usage-badge {
2096
+ cursor: default;
2097
+ display: flex;
2098
+ align-items: center;
2099
+ margin-right: calc(var(--theia-ui-padding) / 2);
2100
+ --token-usage-fill: var(--theia-descriptionForeground);
2101
+ --token-usage-track: color-mix(in srgb, var(--theia-foreground) 12%, transparent);
2102
+ }
2103
+
2104
+ .token-usage-badge.token-usage-yellow {
2105
+ --token-usage-fill: var(--theia-warningBackground);
2106
+ }
2107
+
2108
+ .token-usage-badge.token-usage-red {
2109
+ --token-usage-fill: var(--theia-errorBackground);
2110
+ }
2111
+
2112
+ /* Circular progress ring */
2113
+ .token-usage-ring {
2114
+ width: var(--theia-icon-size);
2115
+ height: var(--theia-icon-size);
2116
+ border-radius: 50%;
2117
+ display: flex;
2118
+ align-items: center;
2119
+ justify-content: center;
2120
+ }
2121
+
2122
+ .token-usage-ring-inner {
2123
+ width: 75%;
2124
+ height: 75%;
2125
+ border-radius: 50%;
2126
+ background: var(--theia-editor-background);
2127
+ }