@theia/ai-chat-ui 1.56.0 → 1.57.0-next.136

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 (45) hide show
  1. package/README.md +2 -1
  2. package/lib/browser/ai-chat-ui-contribution.d.ts.map +1 -1
  3. package/lib/browser/ai-chat-ui-contribution.js +1 -1
  4. package/lib/browser/ai-chat-ui-contribution.js.map +1 -1
  5. package/lib/browser/ai-chat-ui-frontend-module.d.ts.map +1 -1
  6. package/lib/browser/ai-chat-ui-frontend-module.js +9 -1
  7. package/lib/browser/ai-chat-ui-frontend-module.js.map +1 -1
  8. package/lib/browser/chat-input-widget.d.ts +18 -5
  9. package/lib/browser/chat-input-widget.d.ts.map +1 -1
  10. package/lib/browser/chat-input-widget.js +229 -80
  11. package/lib/browser/chat-input-widget.js.map +1 -1
  12. package/lib/browser/chat-response-renderer/code-part-renderer.d.ts +30 -2
  13. package/lib/browser/chat-response-renderer/code-part-renderer.d.ts.map +1 -1
  14. package/lib/browser/chat-response-renderer/code-part-renderer.js +45 -10
  15. package/lib/browser/chat-response-renderer/code-part-renderer.js.map +1 -1
  16. package/lib/browser/chat-response-renderer/markdown-part-renderer.d.ts +8 -3
  17. package/lib/browser/chat-response-renderer/markdown-part-renderer.d.ts.map +1 -1
  18. package/lib/browser/chat-response-renderer/markdown-part-renderer.js +38 -10
  19. package/lib/browser/chat-response-renderer/markdown-part-renderer.js.map +1 -1
  20. package/lib/browser/chat-response-renderer/toolcall-part-renderer.d.ts.map +1 -1
  21. package/lib/browser/chat-response-renderer/toolcall-part-renderer.js +8 -2
  22. package/lib/browser/chat-response-renderer/toolcall-part-renderer.js.map +1 -1
  23. package/lib/browser/chat-tree-view/chat-view-tree-widget.d.ts +2 -1
  24. package/lib/browser/chat-tree-view/chat-view-tree-widget.d.ts.map +1 -1
  25. package/lib/browser/chat-tree-view/chat-view-tree-widget.js +8 -4
  26. package/lib/browser/chat-tree-view/chat-view-tree-widget.js.map +1 -1
  27. package/lib/browser/chat-view-language-contribution.d.ts +2 -1
  28. package/lib/browser/chat-view-language-contribution.d.ts.map +1 -1
  29. package/lib/browser/chat-view-language-contribution.js +3 -6
  30. package/lib/browser/chat-view-language-contribution.js.map +1 -1
  31. package/lib/browser/chat-view-widget.d.ts +4 -1
  32. package/lib/browser/chat-view-widget.d.ts.map +1 -1
  33. package/lib/browser/chat-view-widget.js +14 -4
  34. package/lib/browser/chat-view-widget.js.map +1 -1
  35. package/package.json +12 -12
  36. package/src/browser/ai-chat-ui-contribution.ts +2 -2
  37. package/src/browser/ai-chat-ui-frontend-module.ts +27 -5
  38. package/src/browser/chat-input-widget.tsx +339 -100
  39. package/src/browser/chat-response-renderer/code-part-renderer.tsx +48 -9
  40. package/src/browser/chat-response-renderer/markdown-part-renderer.tsx +39 -12
  41. package/src/browser/chat-response-renderer/toolcall-part-renderer.tsx +8 -2
  42. package/src/browser/chat-tree-view/chat-view-tree-widget.tsx +10 -4
  43. package/src/browser/chat-view-language-contribution.ts +6 -8
  44. package/src/browser/chat-view-widget.tsx +19 -6
  45. package/src/browser/style/index.css +209 -28
@@ -15,7 +15,7 @@
15
15
  // *****************************************************************************
16
16
 
17
17
  import { ChatResponsePartRenderer } from '../chat-response-part-renderer';
18
- import { injectable } from '@theia/core/shared/inversify';
18
+ import { inject, injectable } from '@theia/core/shared/inversify';
19
19
  import {
20
20
  ChatResponseContent,
21
21
  InformationalChatResponseContent,
@@ -26,9 +26,12 @@ import * as React from '@theia/core/shared/react';
26
26
  import * as markdownit from '@theia/core/shared/markdown-it';
27
27
  import * as DOMPurify from '@theia/core/shared/dompurify';
28
28
  import { MarkdownString } from '@theia/core/lib/common/markdown-rendering';
29
+ import { OpenerService, open } from '@theia/core/lib/browser';
30
+ import { URI } from '@theia/core';
29
31
 
30
32
  @injectable()
31
33
  export class MarkdownPartRenderer implements ChatResponsePartRenderer<MarkdownChatResponseContent | InformationalChatResponseContent> {
34
+ @inject(OpenerService) protected readonly openerService: OpenerService;
32
35
  protected readonly markdownIt = markdownit();
33
36
  canHandle(response: ChatResponseContent): number {
34
37
  if (MarkdownChatResponseContent.is(response)) {
@@ -47,13 +50,12 @@ export class MarkdownPartRenderer implements ChatResponsePartRenderer<MarkdownCh
47
50
  return null;
48
51
  }
49
52
 
50
- return <MarkdownRender response={response} />;
53
+ return <MarkdownRender response={response} openerService={this.openerService} />;
51
54
  }
52
-
53
55
  }
54
56
 
55
- const MarkdownRender = ({ response }: { response: MarkdownChatResponseContent | InformationalChatResponseContent }) => {
56
- const ref = useMarkdownRendering(response.content);
57
+ const MarkdownRender = ({ response, openerService }: { response: MarkdownChatResponseContent | InformationalChatResponseContent; openerService: OpenerService }) => {
58
+ const ref = useMarkdownRendering(response.content, openerService);
57
59
 
58
60
  return <div ref={ref}></div>;
59
61
  };
@@ -62,31 +64,56 @@ const MarkdownRender = ({ response }: { response: MarkdownChatResponseContent |
62
64
  * This hook uses markdown-it directly to render markdown.
63
65
  * The reason to use markdown-it directly is that the MarkdownRenderer is
64
66
  * overridden by theia with a monaco version. This monaco version strips all html
65
- * tags from the markdown with empty content.
66
- * This leads to unexpected behavior when rendering markdown with html tags.
67
+ * tags from the markdown with empty content. This leads to unexpected behavior when
68
+ * rendering markdown with html tags.
69
+ *
70
+ * Moreover, we want to intercept link clicks to use the Theia OpenerService instead of the default browser behavior.
67
71
  *
68
72
  * @param markdown the string to render as markdown
69
73
  * @param skipSurroundingParagraph whether to remove a surrounding paragraph element (default: false)
74
+ * @param openerService the service to handle link opening
70
75
  * @returns the ref to use in an element to render the markdown
71
76
  */
72
- export const useMarkdownRendering = (markdown: string | MarkdownString, skipSurroundingParagraph: boolean = false) => {
77
+ export const useMarkdownRendering = (markdown: string | MarkdownString, openerService: OpenerService, skipSurroundingParagraph: boolean = false) => {
78
+ // null is valid in React
73
79
  // eslint-disable-next-line no-null/no-null
74
80
  const ref = useRef<HTMLDivElement | null>(null);
75
81
  const markdownString = typeof markdown === 'string' ? markdown : markdown.value;
76
82
  useEffect(() => {
77
83
  const markdownIt = markdownit();
78
84
  const host = document.createElement('div');
79
- // markdownIt always puts the content in a paragraph element, so we remove it if we don't want it
85
+
86
+ // markdownIt always puts the content in a paragraph element, so we remove it if we don't want that
80
87
  const html = skipSurroundingParagraph ? markdownIt.render(markdownString).replace(/^<p>|<\/p>|<p><\/p>$/g, '') : markdownIt.render(markdownString);
88
+
81
89
  host.innerHTML = DOMPurify.sanitize(html, {
82
- ALLOW_UNKNOWN_PROTOCOLS: true // DOMPurify usually strips non http(s) links from hrefs
90
+ // DOMPurify usually strips non http(s) links from hrefs
91
+ // but we want to allow them (see handleClick via OpenerService below)
92
+ ALLOW_UNKNOWN_PROTOCOLS: true
83
93
  });
84
94
  while (ref?.current?.firstChild) {
85
95
  ref.current.removeChild(ref.current.firstChild);
86
96
  }
87
-
88
97
  ref?.current?.appendChild(host);
89
- }, [markdownString]);
98
+
99
+ // intercept link clicks to use the Theia OpenerService instead of the default browser behavior
100
+ const handleClick = (event: MouseEvent) => {
101
+ let target = event.target as HTMLElement;
102
+ while (target && target.tagName !== 'A') {
103
+ target = target.parentElement as HTMLElement;
104
+ }
105
+ if (target && target.tagName === 'A') {
106
+ const href = target.getAttribute('href');
107
+ if (href) {
108
+ open(openerService, new URI(href));
109
+ event.preventDefault();
110
+ }
111
+ }
112
+ };
113
+
114
+ ref?.current?.addEventListener('click', handleClick);
115
+ return () => ref.current?.removeEventListener('click', handleClick);
116
+ }, [markdownString, skipSurroundingParagraph, openerService]);
90
117
 
91
118
  return ref;
92
119
  };
@@ -74,10 +74,16 @@ export class ToolCallPartRenderer implements ChatResponsePartRenderer<ToolCallCh
74
74
  private tryPrettyPrintJson(response: ToolCallChatResponseContent): string | undefined {
75
75
  let responseContent = response.result;
76
76
  try {
77
- if (response.result) {
78
- responseContent = JSON.stringify(JSON.parse(response.result), undefined, 2);
77
+ if (responseContent) {
78
+ if (typeof responseContent === 'string') {
79
+ responseContent = JSON.parse(responseContent);
80
+ }
81
+ responseContent = JSON.stringify(responseContent, undefined, 2);
79
82
  }
80
83
  } catch (e) {
84
+ if (typeof responseContent !== 'string') {
85
+ responseContent = `The content could not be converted to string: '${e.message}'. This is the original content: '${responseContent}'.`;
86
+ }
81
87
  // fall through
82
88
  }
83
89
  return responseContent;
@@ -34,6 +34,7 @@ import {
34
34
  Key,
35
35
  KeyCode,
36
36
  NodeProps,
37
+ OpenerService,
37
38
  TreeModel,
38
39
  TreeNode,
39
40
  TreeProps,
@@ -88,6 +89,9 @@ export class ChatViewTreeWidget extends TreeWidget {
88
89
  @inject(CommandRegistry)
89
90
  private commandRegistry: CommandRegistry;
90
91
 
92
+ @inject(OpenerService)
93
+ protected readonly openerService: OpenerService;
94
+
91
95
  @inject(HoverService)
92
96
  private hoverService: HoverService;
93
97
 
@@ -303,7 +307,7 @@ export class ChatViewTreeWidget extends TreeWidget {
303
307
  }}>
304
308
  {this.getAgentLabel(node)}
305
309
  </h3>
306
- {inProgress && <span className='theia-ChatContentInProgress'>Generating</span>}
310
+ {inProgress && !waitingForInput && <span className='theia-ChatContentInProgress'>Generating</span>}
307
311
  {inProgress && waitingForInput && <span className='theia-ChatContentInProgress'>Waiting for input</span>}
308
312
  <div className='theia-ChatNodeToolbar'>
309
313
  {!inProgress &&
@@ -370,6 +374,7 @@ export class ChatViewTreeWidget extends TreeWidget {
370
374
  hoverService={this.hoverService}
371
375
  chatAgentService={this.chatAgentService}
372
376
  variableService={this.variableService}
377
+ openerService={this.openerService}
373
378
  />;
374
379
  }
375
380
 
@@ -432,12 +437,13 @@ export class ChatViewTreeWidget extends TreeWidget {
432
437
 
433
438
  const ChatRequestRender = (
434
439
  {
435
- node, hoverService, chatAgentService, variableService
440
+ node, hoverService, chatAgentService, variableService, openerService
436
441
  }: {
437
442
  node: RequestNode,
438
443
  hoverService: HoverService,
439
444
  chatAgentService: ChatAgentService,
440
- variableService: AIVariableService
445
+ variableService: AIVariableService,
446
+ openerService: OpenerService
441
447
  }) => {
442
448
  const parts = node.request.message.parts;
443
449
  return (
@@ -465,7 +471,7 @@ const ChatRequestRender = (
465
471
  );
466
472
  } else {
467
473
  // maintain the leading and trailing spaces with explicit `&nbsp;`, otherwise they would get trimmed by the markdown renderer
468
- const ref = useMarkdownRendering(part.text.replace(/^\s|\s$/g, '&nbsp;'), true);
474
+ const ref = useMarkdownRendering(part.text.replace(/^\s|\s$/g, '&nbsp;'), openerService, true);
469
475
  return (
470
476
  <span key={index} ref={ref}></span>
471
477
  );
@@ -13,14 +13,14 @@
13
13
  //
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
- import { inject, injectable, named } from '@theia/core/shared/inversify';
16
+ import { inject, injectable } from '@theia/core/shared/inversify';
17
17
  import { FrontendApplication, FrontendApplicationContribution } from '@theia/core/lib/browser';
18
18
  import * as monaco from '@theia/monaco-editor-core';
19
- import { ContributionProvider, MaybePromise } from '@theia/core';
19
+ import { MaybePromise } from '@theia/core';
20
20
  import { ProviderResult } from '@theia/monaco-editor-core/esm/vs/editor/common/languages';
21
21
  import { ChatAgentService } from '@theia/ai-chat';
22
22
  import { AIVariableService } from '@theia/ai-core/lib/common';
23
- import { ToolProvider } from '@theia/ai-core/lib/common/tool-invocation-registry';
23
+ import { ToolInvocationRegistry } from '@theia/ai-core/lib/common/tool-invocation-registry';
24
24
 
25
25
  export const CHAT_VIEW_LANGUAGE_ID = 'theia-ai-chat-view-language';
26
26
  export const CHAT_VIEW_LANGUAGE_EXTENSION = 'aichatviewlanguage';
@@ -34,12 +34,10 @@ export class ChatViewLanguageContribution implements FrontendApplicationContribu
34
34
  @inject(AIVariableService)
35
35
  protected readonly variableService: AIVariableService;
36
36
 
37
- @inject(ContributionProvider)
38
- @named(ToolProvider)
39
- private providers: ContributionProvider<ToolProvider>;
37
+ @inject(ToolInvocationRegistry)
38
+ protected readonly toolInvocationRegistry: ToolInvocationRegistry;
40
39
 
41
40
  onStart(_app: FrontendApplication): MaybePromise<void> {
42
- console.log('ChatViewLanguageContribution started');
43
41
  monaco.languages.register({ id: CHAT_VIEW_LANGUAGE_ID, extensions: [CHAT_VIEW_LANGUAGE_EXTENSION] });
44
42
 
45
43
  monaco.languages.registerCompletionItemProvider(CHAT_VIEW_LANGUAGE_ID, {
@@ -131,7 +129,7 @@ export class ChatViewLanguageContribution implements FrontendApplicationContribu
131
129
  model,
132
130
  position,
133
131
  '~',
134
- this.providers.getContributions().map(provider => provider.getTool()),
132
+ this.toolInvocationRegistry.getAllFunctions(),
135
133
  monaco.languages.CompletionItemKind.Function,
136
134
  tool => tool.id,
137
135
  tool => tool.name,
@@ -14,8 +14,8 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
  import { CommandService, deepClone, Emitter, Event, MessageService } from '@theia/core';
17
- import { ChatRequest, ChatRequestModel, ChatRequestModelImpl, ChatService, ChatSession } from '@theia/ai-chat';
18
- import { BaseWidget, codicon, ExtractableWidget, PanelLayout, PreferenceService, StatefulWidget } from '@theia/core/lib/browser';
17
+ import { ChatRequest, ChatRequestModel, ChatService, ChatSession } from '@theia/ai-chat';
18
+ import { BaseWidget, codicon, ExtractableWidget, Message, PanelLayout, PreferenceService, StatefulWidget } from '@theia/core/lib/browser';
19
19
  import { nls } from '@theia/core/lib/common/nls';
20
20
  import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
21
21
  import { AIChatInputWidget } from './chat-input-widget';
@@ -93,6 +93,8 @@ export class ChatViewWidget extends BaseWidget implements ExtractableWidget, Sta
93
93
  this.inputWidget.onQuery = this.onQuery.bind(this);
94
94
  this.inputWidget.onCancel = this.onCancel.bind(this);
95
95
  this.inputWidget.chatModel = this.chatSession.model;
96
+ this.inputWidget.onDeleteChangeSet = this.onDeleteChangeSet.bind(this);
97
+ this.inputWidget.onDeleteChangeSetElement = this.onDeleteChangeSetElement.bind(this);
96
98
  this.treeWidget.trackChatModel(this.chatSession.model);
97
99
 
98
100
  this.initListeners();
@@ -125,6 +127,11 @@ export class ChatViewWidget extends BaseWidget implements ExtractableWidget, Sta
125
127
  );
126
128
  }
127
129
 
130
+ protected override onActivateRequest(msg: Message): void {
131
+ super.onActivateRequest(msg);
132
+ this.inputWidget.activate();
133
+ }
134
+
128
135
  storeState(): object {
129
136
  return this.state;
130
137
  }
@@ -160,7 +167,7 @@ export class ChatViewWidget extends BaseWidget implements ExtractableWidget, Sta
160
167
  const requestProgress = await this.chatService.sendRequest(this.chatSession.id, chatRequest);
161
168
  requestProgress?.responseCompleted.then(responseModel => {
162
169
  if (responseModel.isError) {
163
- this.messageService.error(responseModel.errorObject?.message ?? 'An error occurred druring chat service invocation.');
170
+ this.messageService.error(responseModel.errorObject?.message ?? 'An error occurred during chat service invocation.');
164
171
  }
165
172
  });
166
173
  if (!requestProgress) {
@@ -171,9 +178,15 @@ export class ChatViewWidget extends BaseWidget implements ExtractableWidget, Sta
171
178
  }
172
179
 
173
180
  protected onCancel(requestModel: ChatRequestModel): void {
174
- // TODO we should pass a cancellation token with the request (or retrieve one from the request invocation) so we can cleanly cancel here
175
- // For now we cancel manually via casting
176
- (requestModel as ChatRequestModelImpl).response.cancel();
181
+ this.chatService.cancelRequest(requestModel.session.id, requestModel.id);
182
+ }
183
+
184
+ protected onDeleteChangeSet(sessionId: string): void {
185
+ this.chatService.deleteChangeSet(sessionId);
186
+ }
187
+
188
+ protected onDeleteChangeSetElement(sessionId: string, index: number): void {
189
+ this.chatService.deleteChangeSetElement(sessionId, index);
177
190
  }
178
191
 
179
192
  lock(): void {
@@ -7,8 +7,8 @@
7
7
  flex: 1;
8
8
  }
9
9
 
10
- .chat-input-widget > .ps__rail-x,
11
- .chat-input-widget > .ps__rail-y {
10
+ .chat-input-widget>.ps__rail-x,
11
+ .chat-input-widget>.ps__rail-y {
12
12
  display: none !important;
13
13
  }
14
14
 
@@ -23,7 +23,7 @@
23
23
  overflow-wrap: break-word;
24
24
  }
25
25
 
26
- div:last-child > .theia-ChatNode {
26
+ div:last-child>.theia-ChatNode {
27
27
  border: none;
28
28
  }
29
29
 
@@ -59,6 +59,7 @@ div:last-child > .theia-ChatNode {
59
59
  }
60
60
 
61
61
  @keyframes dots {
62
+
62
63
  0%,
63
64
  20% {
64
65
  content: "";
@@ -95,15 +96,18 @@ div:last-child > .theia-ChatNode {
95
96
  margin-left: auto;
96
97
  line-height: 18px;
97
98
  }
99
+
98
100
  .theia-ChatNodeToolbar .theia-ChatNodeToolbarAction {
99
101
  display: none;
100
102
  align-items: center;
101
103
  padding: 4px;
102
104
  border-radius: 5px;
103
105
  }
106
+
104
107
  .theia-ChatNode:hover .theia-ChatNodeToolbar .theia-ChatNodeToolbarAction {
105
108
  display: inline-block;
106
109
  }
110
+
107
111
  .theia-ChatNodeToolbar .theia-ChatNodeToolbarAction:hover {
108
112
  cursor: pointer;
109
113
  background-color: var(--theia-toolbar-hoverBackground);
@@ -118,7 +122,7 @@ div:last-child > .theia-ChatNode {
118
122
  padding-inline-start: 1rem;
119
123
  }
120
124
 
121
- .theia-ChatNode li > p {
125
+ .theia-ChatNode li>p {
122
126
  margin-top: 0;
123
127
  margin-bottom: 0;
124
128
  }
@@ -132,7 +136,7 @@ div:last-child > .theia-ChatNode {
132
136
  font-size: var(--theia-code-font-size);
133
137
  }
134
138
 
135
- .theia-RequestNode > p div {
139
+ .theia-RequestNode>p div {
136
140
  display: inline;
137
141
  }
138
142
 
@@ -153,51 +157,196 @@ div:last-child > .theia-ChatNode {
153
157
  }
154
158
 
155
159
  .theia-ChatInput {
160
+ margin-top: 16px;
156
161
  position: relative;
157
162
  width: 100%;
158
163
  box-sizing: border-box;
159
164
  gap: 4px;
160
165
  }
161
166
 
162
- .theia-ChatInput-Editor-Box {
163
- margin-bottom: 2px;
164
- padding: 10px;
167
+ .theia-ChatInput-ChangeSet-Box {
168
+ margin: 0 16px -5px 16px;
169
+ padding: 2px;
170
+ padding-bottom: 12px;
165
171
  height: auto;
172
+ border: var(--theia-border-width) solid var(--theia-dropdown-border);
173
+ border-radius: 4px 4px 0 0;
174
+ background-color: var(--theia-activityBar-background);
166
175
  display: flex;
167
176
  flex-direction: column;
177
+ }
178
+
179
+ .theia-ChatInput-ChangeSet-Header {
180
+ display: flex;
181
+ justify-content: space-between;
182
+ align-items: center;
183
+ margin: 4px;
184
+ }
185
+
186
+ .theia-ChatInput-ChangeSet-Box h3 {
187
+ font-size: 12px;
188
+ color: var(--theia-disabledForeground);
189
+ padding-top: 0;
190
+ margin: 0;
191
+ display: flex;
192
+ }
193
+
194
+ .theia-ChatInput-ChangeSet-Header-Actions button {
195
+ font-size: 12px;
196
+ padding: 2px 4px;
197
+ min-width: 40px;
198
+ margin-left: 6px;
199
+ }
200
+
201
+ .theia-ChatInput-ChangeSet-List ul {
202
+ list-style-type: none;
203
+ padding: 0;
204
+ margin: 4px;
205
+ }
206
+
207
+ .theia-ChatInput-ChangeSet-List ul li {
208
+ display: flex;
209
+ flex-direction: row;
210
+ line-height: 18px;
211
+ padding: 0;
212
+ padding-top: 2px;
213
+ margin: 0 2px 2px 0px;
214
+ border-radius: 4px;
215
+ position: relative;
216
+ }
217
+
218
+ .theia-ChatInput-ChangeSet-List ul li:hover {
219
+ background-color: var(--theia-toolbar-hoverBackground);
220
+ }
221
+
222
+ .theia-ChatInput-ChangeSet-Actions {
223
+ display: none;
224
+ }
225
+
226
+ .theia-ChatInput-ChangeSet-List ul {
227
+ max-height: 150px;
228
+ overflow-y: auto;
229
+ }
230
+
231
+ .theia-ChatInput-ChangeSet-List ul li {
232
+ cursor: pointer;
233
+ }
234
+
235
+ .theia-ChatInput-ChangeSet-List ul li:hover .theia-ChatInput-ChangeSet-Actions {
236
+ display: flex;
168
237
  justify-content: flex-end;
238
+ flex: auto;
239
+ gap: 4px;
240
+ }
241
+
242
+ .theia-ChatInput-ChangeSet-List .theia-ChatInput-ChangeSet-Icon {
243
+ padding-left: 2px;
244
+ padding-right: 4px;
245
+ min-width: var(--theia-icon-size);
246
+ display: flex;
247
+ justify-content: center;
248
+ align-items: center;
249
+ }
250
+
251
+ .theia-ChatInput-ChangeSet-List .theia-ChatInput-ChangeSet-Icon::before {
252
+ text-align: center;
253
+ }
254
+
255
+ .theia-ChatInput-ChangeSet-List .theia-ChatInput-ChangeSet-Icon.codicon::before {
256
+ font-size: var(--theia-ui-font-size1);
257
+ }
258
+
259
+ .theia-ChatInput-ChangeSet-Actions .action {
260
+ width: 16px;
261
+ height: 16px;
262
+ cursor: pointer;
263
+ }
264
+
265
+ .theia-ChatInput-ChangeSet-additionalInfo {
266
+ margin-left: 8px;
267
+ color: var(--theia-disabledForeground);
268
+ }
269
+
270
+ .theia-ChatInput-ChangeSet-labelParts {
169
271
  overflow: hidden;
272
+ text-overflow: ellipsis;
170
273
  }
171
274
 
172
- .theia-ChatInput-Editor {
173
- width: 100%;
275
+ .theia-ChatInput-ChangeSet-title {
276
+ white-space: nowrap;
277
+ overflow: hidden;
278
+ text-overflow: ellipsis;
279
+ }
280
+
281
+ .theia-ChatInput-ChangeSet-Header-Actions,
282
+ .theia-ChatInput-ChangeSet-Box h3,
283
+ .theia-ChatInput-ChangeSet-additionalInfo {
284
+ white-space: nowrap;
285
+ overflow: hidden;
286
+ text-overflow: ellipsis;
287
+ }
288
+
289
+ .theia-ChatInput-ChangeSet-Header-Actions .codicon.action {
290
+ font-size: 18px;
291
+ height: 20px;
292
+ vertical-align: middle;
293
+ margin-left: 4px;
294
+ border-radius: 4px;
295
+ cursor: pointer;
296
+ }
297
+
298
+ .theia-ChatInput-ChangeSet-Header-Actions .codicon.action:hover {
299
+ background-color: var(--theia-toolbar-hoverBackground);
300
+ }
301
+
302
+ .theia-ChatInput-ChangeSet-title.rejected {
303
+ text-decoration: line-through;
304
+ }
305
+
306
+ .theia-ChatInput-ChangeSet-title.add.pending {
307
+ color: var(--theia-charts-green);
308
+ }
309
+
310
+ .theia-ChatInput-ChangeSet-title.modify.pending {
311
+ color: var(--theia-charts-orange);
312
+ }
313
+
314
+ .theia-ChatInput-ChangeSet-title.delete.pending {
315
+ color: var(--theia-charts-red);
316
+ }
317
+
318
+ .theia-ChatInput-Editor-Box {
319
+ margin: 0 16px 16px 16px;
320
+ padding: 2px;
174
321
  height: auto;
175
322
  border: var(--theia-border-width) solid var(--theia-dropdown-border);
176
323
  border-radius: 4px;
324
+ background-color: var(--theia-editor-background);
177
325
  display: flex;
178
- flex-direction: column-reverse;
326
+ flex-direction: column;
327
+ justify-content: flex-end;
179
328
  overflow: hidden;
180
- transition: height 0.05s ease-in-out;
181
329
  }
182
330
 
183
- .theia-ChatInput-Editor:has(.monaco-editor.focused) {
331
+ .theia-ChatInput-Editor-Box:has(.monaco-editor.focused) {
184
332
  border-color: var(--theia-focusBorder);
185
333
  }
186
334
 
187
- .theia-ChatInput-Editor .monaco-editor {
188
- display: flex;
335
+ .theia-ChatInput-Editor {
189
336
  width: 100%;
190
- height: 100%;
337
+ height: auto;
338
+ display: flex;
339
+ flex-direction: column-reverse;
191
340
  overflow: hidden;
341
+ transition: height 0.05s ease-in-out;
192
342
  position: relative;
193
343
  }
194
344
 
195
345
  .theia-ChatInput-Editor-Placeholder {
196
346
  position: absolute;
197
- top: -3px;
198
- left: 19px;
347
+ top: 9px;
348
+ left: 8px;
199
349
  right: 0;
200
- bottom: 0;
201
350
  display: flex;
202
351
  align-items: center;
203
352
  color: var(--theia-descriptionForeground);
@@ -205,10 +354,19 @@ div:last-child > .theia-ChatNode {
205
354
  z-index: 10;
206
355
  text-align: left;
207
356
  }
357
+
208
358
  .theia-ChatInput-Editor-Placeholder.hidden {
209
359
  display: none;
210
360
  }
211
361
 
362
+ .theia-ChatInput-Editor .monaco-editor {
363
+ display: flex;
364
+ width: 100%;
365
+ height: 100%;
366
+ overflow: hidden;
367
+ position: relative;
368
+ }
369
+
212
370
  .theia-ChatInput-Editor .monaco-editor .margin,
213
371
  .theia-ChatInput-Editor .monaco-editor .monaco-editor-background,
214
372
  .theia-ChatInput-Editor .monaco-editor .inputarea.ime-input {
@@ -216,29 +374,46 @@ div:last-child > .theia-ChatNode {
216
374
  }
217
375
 
218
376
  .theia-ChatInputOptions {
219
- position: absolute;
220
- bottom: 31px;
221
- right: 26px;
222
- width: 10px;
223
- height: 10px;
377
+ width: 100%;
378
+ height: 25px;
379
+ padding-left: 6px;
380
+ padding-right: 6px;
381
+ display: flex;
382
+ justify-content: space-between;
383
+ }
384
+
385
+ .theia-ChatInputOptions .theia-ChatInputOptions-left,
386
+ .theia-ChatInputOptions .theia-ChatInputOptions-right {
387
+ display: flex;
388
+ }
389
+
390
+ .theia-ChatInputOptions .theia-ChatInputOptions-right {
391
+ margin-right: 12px;
224
392
  }
225
393
 
226
394
  .theia-ChatInputOptions .option {
227
395
  width: 21px;
228
396
  height: 21px;
229
- margin-top: 2px;
397
+ padding: 2px;
230
398
  display: inline-block;
231
399
  box-sizing: border-box;
232
400
  user-select: none;
233
401
  background-repeat: no-repeat;
234
402
  background-position: center;
403
+ border-radius: 5px;
235
404
  border: var(--theia-border-width) solid transparent;
236
- opacity: 0.7;
237
405
  cursor: pointer;
238
406
  }
239
407
 
408
+ .theia-ChatInputOptions .option.disabled {
409
+ cursor: default;
410
+ opacity: var(--theia-mod-disabled-opacity);
411
+ pointer-events: none;
412
+ }
413
+
240
414
  .theia-ChatInputOptions .option:hover {
241
415
  opacity: 1;
416
+ background-color: var(--theia-toolbar-hoverBackground);
242
417
  }
243
418
 
244
419
  .theia-CodePartRenderer-root {
@@ -269,6 +444,7 @@ div:last-child > .theia-ChatNode {
269
444
  border-radius: 5px;
270
445
  cursor: pointer;
271
446
  }
447
+
272
448
  .theia-CodePartRenderer-right .button:hover {
273
449
  background-color: var(--theia-toolbar-hoverBackground);
274
450
  }
@@ -283,25 +459,28 @@ div:last-child > .theia-ChatNode {
283
459
  display: flex;
284
460
  flex-direction: column;
285
461
  gap: 8px;
286
- border: var(--theia-border-width) solid
287
- var(--theia-sideBarSectionHeader-border);
462
+ border: var(--theia-border-width) solid var(--theia-sideBarSectionHeader-border);
288
463
  padding: 8px 12px 12px;
289
464
  border-radius: 5px;
290
465
  margin: 0 0 8px 0;
291
466
  }
467
+
292
468
  .theia-QuestionPartRenderer-options {
293
469
  display: flex;
294
470
  flex-wrap: wrap;
295
471
  gap: 12px;
296
472
  }
473
+
297
474
  .theia-QuestionPartRenderer-option {
298
475
  min-width: 100px;
299
476
  flex: 1 1 auto;
300
477
  margin: 0;
301
478
  }
479
+
302
480
  .theia-QuestionPartRenderer-option.selected:disabled:hover {
303
481
  background-color: var(--theia-button-disabledBackground);
304
482
  }
483
+
305
484
  .theia-QuestionPartRenderer-option:disabled:not(.selected) {
306
485
  background-color: var(--theia-button-secondaryBackground);
307
486
  }
@@ -355,9 +534,11 @@ details[open].collapsible-arguments .collapsible-arguments-summary {
355
534
  .theia-ResponseNode-ProgressMessage .inProgress {
356
535
  color: var(--theia-progressBar-background);
357
536
  }
537
+
358
538
  .theia-ResponseNode-ProgressMessage .completed {
359
539
  color: var(--theia-successBackground);
360
540
  }
541
+
361
542
  .theia-ResponseNode-ProgressMessage .failed {
362
543
  color: var(--theia-errorForeground);
363
544
  }