@theia/ai-chat-ui 1.65.0-next.19 → 1.65.0-next.28

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 (30) hide show
  1. package/lib/browser/ai-chat-ui-frontend-module.d.ts.map +1 -1
  2. package/lib/browser/ai-chat-ui-frontend-module.js +9 -1
  3. package/lib/browser/ai-chat-ui-frontend-module.js.map +1 -1
  4. package/lib/browser/chat-input-history-contribution.d.ts +16 -0
  5. package/lib/browser/chat-input-history-contribution.d.ts.map +1 -0
  6. package/lib/browser/chat-input-history-contribution.js +143 -0
  7. package/lib/browser/chat-input-history-contribution.js.map +1 -0
  8. package/lib/browser/chat-input-history.d.ts +32 -0
  9. package/lib/browser/chat-input-history.d.ts.map +1 -0
  10. package/lib/browser/chat-input-history.js +125 -0
  11. package/lib/browser/chat-input-history.js.map +1 -0
  12. package/lib/browser/chat-input-widget.d.ts +16 -0
  13. package/lib/browser/chat-input-widget.d.ts.map +1 -1
  14. package/lib/browser/chat-input-widget.js +98 -4
  15. package/lib/browser/chat-input-widget.js.map +1 -1
  16. package/lib/browser/chat-response-renderer/toolcall-part-renderer.d.ts +2 -1
  17. package/lib/browser/chat-response-renderer/toolcall-part-renderer.d.ts.map +1 -1
  18. package/lib/browser/chat-response-renderer/toolcall-part-renderer.js +4 -3
  19. package/lib/browser/chat-response-renderer/toolcall-part-renderer.js.map +1 -1
  20. package/lib/browser/chat-view-widget.d.ts +2 -2
  21. package/lib/browser/chat-view-widget.d.ts.map +1 -1
  22. package/lib/browser/chat-view-widget.js +1 -1
  23. package/lib/browser/chat-view-widget.js.map +1 -1
  24. package/package.json +10 -10
  25. package/src/browser/ai-chat-ui-frontend-module.ts +11 -2
  26. package/src/browser/chat-input-history-contribution.ts +150 -0
  27. package/src/browser/chat-input-history.ts +138 -0
  28. package/src/browser/chat-input-widget.tsx +119 -2
  29. package/src/browser/chat-response-renderer/toolcall-part-renderer.tsx +2 -1
  30. package/src/browser/chat-view-widget.tsx +2 -2
@@ -0,0 +1,150 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2025 STMicroelectronics and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import { Command, CommandContribution, CommandRegistry } from '@theia/core';
18
+ import { ApplicationShell, KeybindingContribution, KeybindingRegistry } from '@theia/core/lib/browser';
19
+ import { inject, injectable } from '@theia/core/shared/inversify';
20
+ import { AIChatInputWidget } from './chat-input-widget';
21
+ import { ChatInputHistoryService } from './chat-input-history';
22
+
23
+ const CHAT_INPUT_PREVIOUS_PROMPT_COMMAND = Command.toDefaultLocalizedCommand({
24
+ id: 'chat-input:previous-prompt',
25
+ label: 'Previous Prompt'
26
+ });
27
+
28
+ const CHAT_INPUT_NEXT_PROMPT_COMMAND = Command.toDefaultLocalizedCommand({
29
+ id: 'chat-input:next-prompt',
30
+ label: 'Next Prompt'
31
+ });
32
+
33
+ const CHAT_INPUT_CLEAR_HISTORY_COMMAND = Command.toDefaultLocalizedCommand({
34
+ id: 'chat-input:clear-history',
35
+ category: 'Chat',
36
+ label: 'Clear Input Prompt History'
37
+ });
38
+
39
+ @injectable()
40
+ export class ChatInputHistoryContribution implements CommandContribution, KeybindingContribution {
41
+
42
+ @inject(ApplicationShell)
43
+ protected readonly shell: ApplicationShell;
44
+
45
+ @inject(ChatInputHistoryService)
46
+ protected readonly historyService: ChatInputHistoryService;
47
+
48
+ registerCommands(commands: CommandRegistry): void {
49
+ commands.registerCommand(CHAT_INPUT_PREVIOUS_PROMPT_COMMAND, {
50
+ execute: () => this.executeNavigatePrevious(),
51
+ isEnabled: () => this.isNavigationEnabled()
52
+ });
53
+
54
+ commands.registerCommand(CHAT_INPUT_NEXT_PROMPT_COMMAND, {
55
+ execute: () => this.executeNavigateNext(),
56
+ isEnabled: () => this.isNavigationEnabled()
57
+ });
58
+
59
+ commands.registerCommand(CHAT_INPUT_CLEAR_HISTORY_COMMAND, {
60
+ execute: () => this.historyService.clearHistory(),
61
+ isEnabled: () => this.historyService.getPrompts().length > 0
62
+ });
63
+ }
64
+
65
+ registerKeybindings(keybindings: KeybindingRegistry): void {
66
+ keybindings.registerKeybinding({
67
+ command: CHAT_INPUT_PREVIOUS_PROMPT_COMMAND.id,
68
+ keybinding: 'up',
69
+ when: 'chatInputFocus && chatInputFirstLine && !suggestWidgetVisible'
70
+ });
71
+
72
+ keybindings.registerKeybinding({
73
+ command: CHAT_INPUT_NEXT_PROMPT_COMMAND.id,
74
+ keybinding: 'down',
75
+ when: 'chatInputFocus && chatInputLastLine && !suggestWidgetVisible'
76
+ });
77
+ }
78
+
79
+ protected executeNavigatePrevious(): void {
80
+ const chatInputWidget = this.findFocusedChatInput();
81
+ if (!chatInputWidget || !chatInputWidget.editor) {
82
+ return;
83
+ }
84
+
85
+ const currentInput = chatInputWidget.editor.getControl().getValue();
86
+ const previousPrompt = chatInputWidget.getPreviousPrompt(currentInput);
87
+
88
+ if (previousPrompt !== undefined) {
89
+ chatInputWidget.editor.getControl().setValue(previousPrompt);
90
+ this.positionCursorAtEnd(chatInputWidget);
91
+ }
92
+ }
93
+
94
+ protected executeNavigateNext(): void {
95
+ const chatInputWidget = this.findFocusedChatInput();
96
+ if (!chatInputWidget || !chatInputWidget.editor) {
97
+ return;
98
+ }
99
+
100
+ const nextPrompt = chatInputWidget.getNextPrompt();
101
+
102
+ if (nextPrompt !== undefined) {
103
+ chatInputWidget.editor.getControl().setValue(nextPrompt);
104
+ this.positionCursorAtEnd(chatInputWidget);
105
+ }
106
+ }
107
+
108
+ protected positionCursorAtEnd(widget: AIChatInputWidget): void {
109
+ const editor = widget.editor?.getControl();
110
+ const model = editor?.getModel();
111
+
112
+ if (editor && model) {
113
+ const lastLine = model.getLineCount();
114
+ const lastColumn = model.getLineContent(lastLine).length + 1;
115
+ editor.setPosition({ lineNumber: lastLine, column: lastColumn });
116
+ editor.focus();
117
+
118
+ setTimeout(() => {
119
+ // Trigger cursor position update after setting value
120
+ if (widget.editor?.getControl().hasWidgetFocus()) {
121
+ widget.updateCursorPositionKeys();
122
+ }
123
+ }, 0);
124
+ }
125
+ }
126
+
127
+ protected findFocusedChatInput(): AIChatInputWidget | undefined {
128
+ const activeElement = document.activeElement;
129
+ if (!(activeElement instanceof HTMLElement)) {
130
+ return;
131
+ }
132
+ const activeWidget = this.shell.findWidgetForElement(activeElement);
133
+ if (!(activeWidget instanceof AIChatInputWidget)) {
134
+ return;
135
+ }
136
+ if (!activeWidget.inputConfiguration?.enablePromptHistory) {
137
+ return;
138
+ }
139
+ if (!activeWidget.editor?.getControl().hasWidgetFocus()) {
140
+ return;
141
+ }
142
+ return activeWidget;
143
+ }
144
+
145
+ protected isNavigationEnabled(): boolean {
146
+ const chatInputWidget = this.findFocusedChatInput();
147
+ return chatInputWidget !== undefined &&
148
+ chatInputWidget.inputConfiguration?.enablePromptHistory !== false;
149
+ }
150
+ }
@@ -0,0 +1,138 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2025 STMicroelectronics and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import { inject, injectable } from '@theia/core/shared/inversify';
18
+ import { StorageService } from '@theia/core/lib/browser';
19
+
20
+ /**
21
+ * Manages navigation state for a single chat input widget.
22
+ * Each widget has its own independent navigation state while sharing the same history.
23
+ */
24
+ export class ChatInputNavigationState {
25
+ private currentIndex: number;
26
+ private preservedInput?: string;
27
+ private isNavigating = false;
28
+
29
+ constructor(private readonly historyService: ChatInputHistoryService) {
30
+ this.currentIndex = historyService.getPrompts().length;
31
+ }
32
+
33
+ getPreviousPrompt(currentInput: string): string | undefined {
34
+ const history = this.historyService.getPrompts();
35
+
36
+ if (history.length === 0) {
37
+ return undefined;
38
+ }
39
+
40
+ if (!this.isNavigating) {
41
+ this.preservedInput = currentInput;
42
+ this.isNavigating = true;
43
+ this.currentIndex = history.length;
44
+ }
45
+
46
+ if (this.currentIndex <= 0) {
47
+ // Already at the oldest prompt
48
+ return undefined;
49
+ }
50
+
51
+ this.currentIndex--;
52
+ return history[this.currentIndex];
53
+ }
54
+
55
+ getNextPrompt(): string | undefined {
56
+ const history = this.historyService.getPrompts();
57
+
58
+ if (!this.isNavigating || this.currentIndex >= history.length) {
59
+ return undefined;
60
+ }
61
+
62
+ this.currentIndex++;
63
+
64
+ if (this.currentIndex >= history.length) {
65
+ // Reached end of history - return to preserved input
66
+ this.isNavigating = false;
67
+ const preserved = this.preservedInput;
68
+ this.preservedInput = undefined;
69
+ this.currentIndex = history.length;
70
+ return preserved || '';
71
+ }
72
+
73
+ return history[this.currentIndex];
74
+ }
75
+
76
+ stopNavigation(): void {
77
+ this.isNavigating = false;
78
+ this.preservedInput = undefined;
79
+ this.currentIndex = this.historyService.getPrompts().length;
80
+ }
81
+
82
+ }
83
+
84
+ const CHAT_PROMPT_HISTORY_STORAGE_KEY = 'ai-chat-prompt-history';
85
+ const MAX_HISTORY_SIZE = 100;
86
+
87
+ /**
88
+ * Manages shared prompt history across all chat input widgets.
89
+ * Each prompt is stored only once and shared between all chat inputs.
90
+ */
91
+ @injectable()
92
+ export class ChatInputHistoryService {
93
+
94
+ @inject(StorageService)
95
+ protected readonly storageService: StorageService;
96
+
97
+ protected history: string[] = [];
98
+
99
+ async init(): Promise<void> {
100
+ const data = await this.storageService.getData<{ prompts: string[] }>(CHAT_PROMPT_HISTORY_STORAGE_KEY, { prompts: [] });
101
+ this.history = data.prompts || [];
102
+ }
103
+
104
+ /**
105
+ * Get read-only access to the current prompt history.
106
+ */
107
+ getPrompts(): readonly string[] {
108
+ return this.history;
109
+ }
110
+
111
+ clearHistory(): void {
112
+ this.history = [];
113
+ this.persistHistory();
114
+ }
115
+
116
+ addToHistory(prompt: string): void {
117
+ const trimmed = prompt.trim();
118
+ if (!trimmed) {
119
+ return;
120
+ }
121
+
122
+ // Remove existing instance and add to end (most recent)
123
+ this.history = this.history
124
+ .filter(item => item !== trimmed)
125
+ .concat(trimmed)
126
+ .slice(-MAX_HISTORY_SIZE);
127
+
128
+ this.persistHistory();
129
+ }
130
+
131
+ protected async persistHistory(): Promise<void> {
132
+ try {
133
+ await this.storageService.setData(CHAT_PROMPT_HISTORY_STORAGE_KEY, { prompts: this.history });
134
+ } catch (error) {
135
+ console.warn('Failed to persist chat prompt history:', error);
136
+ }
137
+ }
138
+ }
@@ -23,6 +23,7 @@ import { AIVariableResolutionRequest } from '@theia/ai-core';
23
23
  import { AgentCompletionNotificationService, FrontendVariableService, AIActivationService } from '@theia/ai-core/lib/browser';
24
24
  import { DisposableCollection, Emitter, InMemoryResources, URI, nls } from '@theia/core';
25
25
  import { ContextMenuRenderer, LabelProvider, Message, OpenerService, ReactWidget } from '@theia/core/lib/browser';
26
+ import { ContextKey, ContextKeyService } from '@theia/core/lib/browser/context-key-service';
26
27
  import { Deferred } from '@theia/core/lib/common/promise-util';
27
28
  import { inject, injectable, optional, postConstruct } from '@theia/core/shared/inversify';
28
29
  import * as React from '@theia/core/shared/react';
@@ -35,6 +36,7 @@ import { CHAT_VIEW_LANGUAGE_EXTENSION } from './chat-view-language-contribution'
35
36
  import { ContextVariablePicker } from './context-variable-picker';
36
37
  import { TASK_CONTEXT_VARIABLE } from '@theia/ai-chat/lib/browser/task-context-variable';
37
38
  import { IModelDeltaDecoration } from '@theia/monaco-editor-core/esm/vs/editor/common/model';
39
+ import { ChatInputHistoryService, ChatInputNavigationState } from './chat-input-history';
38
40
 
39
41
  type Query = (query: string) => Promise<void>;
40
42
  type Unpin = () => void;
@@ -49,6 +51,7 @@ export interface AIChatInputConfiguration {
49
51
  showPinnedAgent?: boolean;
50
52
  showChangeSet?: boolean;
51
53
  showSuggestions?: boolean;
54
+ enablePromptHistory?: boolean;
52
55
  }
53
56
 
54
57
  @injectable()
@@ -95,9 +98,43 @@ export class AIChatInputWidget extends ReactWidget {
95
98
  @inject(AIActivationService)
96
99
  protected readonly aiActivationService: AIActivationService;
97
100
 
101
+ @inject(ChatInputHistoryService)
102
+ protected readonly historyService: ChatInputHistoryService;
103
+
104
+ protected navigationState: ChatInputNavigationState;
105
+
106
+ @inject(ContextKeyService)
107
+ protected readonly contextKeyService: ContextKeyService;
108
+
98
109
  protected editorRef: SimpleMonacoEditor | undefined = undefined;
99
110
  protected readonly editorReady = new Deferred<void>();
100
111
 
112
+ get editor(): SimpleMonacoEditor | undefined {
113
+ return this.editorRef;
114
+ }
115
+
116
+ get inputConfiguration(): AIChatInputConfiguration | undefined {
117
+ return this.configuration;
118
+ }
119
+
120
+ getPreviousPrompt(currentInput: string): string | undefined {
121
+ if (!this.navigationState) {
122
+ return undefined;
123
+ }
124
+ return this.navigationState.getPreviousPrompt(currentInput);
125
+ }
126
+
127
+ getNextPrompt(): string | undefined {
128
+ if (!this.navigationState) {
129
+ return undefined;
130
+ }
131
+ return this.navigationState.getNextPrompt();
132
+ }
133
+
134
+ protected chatInputFocusKey: ContextKey<boolean>;
135
+ protected chatInputFirstLineKey: ContextKey<boolean>;
136
+ protected chatInputLastLineKey: ContextKey<boolean>;
137
+
101
138
  protected isEnabled = false;
102
139
  protected heightInLines = 12;
103
140
 
@@ -111,7 +148,13 @@ export class AIChatInputWidget extends ReactWidget {
111
148
 
112
149
  protected _onQuery: Query;
113
150
  set onQuery(query: Query) {
114
- this._onQuery = query;
151
+ this._onQuery = (prompt: string) => {
152
+ if (this.configuration?.enablePromptHistory !== false && prompt.trim()) {
153
+ this.historyService.addToHistory(prompt);
154
+ this.navigationState.stopNavigation();
155
+ }
156
+ return query(prompt);
157
+ };
115
158
  }
116
159
  protected _onUnpin: Unpin;
117
160
  set onUnpin(unpin: Unpin) {
@@ -167,9 +210,79 @@ export class AIChatInputWidget extends ReactWidget {
167
210
  }));
168
211
  this.toDispose.push(this.onDidResizeEmitter);
169
212
  this.setEnabled(this.aiActivationService.isActive);
213
+ this.historyService.init().then(() => {
214
+ this.navigationState = new ChatInputNavigationState(this.historyService);
215
+ });
216
+ this.initializeContextKeys();
170
217
  this.update();
171
218
  }
172
219
 
220
+ protected initializeContextKeys(): void {
221
+ this.chatInputFocusKey = this.contextKeyService.createKey<boolean>('chatInputFocus', false);
222
+ this.chatInputFirstLineKey = this.contextKeyService.createKey<boolean>('chatInputFirstLine', false);
223
+ this.chatInputLastLineKey = this.contextKeyService.createKey<boolean>('chatInputLastLine', false);
224
+ }
225
+
226
+ updateCursorPositionKeys(): void {
227
+ if (!this.editorRef) {
228
+ this.chatInputFirstLineKey.set(false);
229
+ this.chatInputLastLineKey.set(false);
230
+ return;
231
+ }
232
+
233
+ const editor = this.editorRef.getControl();
234
+ const position = editor.getPosition();
235
+ const model = editor.getModel();
236
+
237
+ if (!position || !model) {
238
+ this.chatInputFirstLineKey.set(false);
239
+ this.chatInputLastLineKey.set(false);
240
+ return;
241
+ }
242
+
243
+ const isFirstLine = position.lineNumber === 1;
244
+ const isLastLine = position.lineNumber === model.getLineCount();
245
+
246
+ this.chatInputFirstLineKey.set(isFirstLine);
247
+ this.chatInputLastLineKey.set(isLastLine);
248
+ }
249
+
250
+ protected setupEditorEventListeners(): void {
251
+ if (!this.editorRef) {
252
+ return;
253
+ }
254
+
255
+ const editor = this.editorRef.getControl();
256
+
257
+ this.toDispose.push(editor.onDidFocusEditorWidget(() => {
258
+ this.chatInputFocusKey.set(true);
259
+ this.updateCursorPositionKeys();
260
+ }));
261
+
262
+ this.toDispose.push(editor.onDidBlurEditorWidget(() => {
263
+ this.chatInputFocusKey.set(false);
264
+ this.chatInputFirstLineKey.set(false);
265
+ this.chatInputLastLineKey.set(false);
266
+ }));
267
+
268
+ this.toDispose.push(editor.onDidChangeCursorPosition(() => {
269
+ if (editor.hasWidgetFocus()) {
270
+ this.updateCursorPositionKeys();
271
+ }
272
+ }));
273
+
274
+ this.toDispose.push(editor.onDidChangeModelContent(() => {
275
+ if (editor.hasWidgetFocus()) {
276
+ this.updateCursorPositionKeys();
277
+ }
278
+ }));
279
+
280
+ if (editor.hasWidgetFocus()) {
281
+ this.chatInputFocusKey.set(true);
282
+ this.updateCursorPositionKeys();
283
+ }
284
+ }
285
+
173
286
  protected override onActivateRequest(msg: Message): void {
174
287
  super.onActivateRequest(msg);
175
288
  this.editorReady.promise.then(() => {
@@ -206,6 +319,7 @@ export class AIChatInputWidget extends ReactWidget {
206
319
  const isEditing = !!(currentRequest && (EditableChatRequestModel.isEditing(currentRequest)));
207
320
  const isPending = () => !!(currentRequest && !isEditing && ChatRequestModel.isInProgress(currentRequest));
208
321
  const pending = isPending();
322
+ const hasPromptHistory = this.configuration?.enablePromptHistory && this.historyService.getPrompts().length > 0;
209
323
 
210
324
  return (
211
325
  <ChatInput
@@ -232,12 +346,14 @@ export class AIChatInputWidget extends ReactWidget {
232
346
  isEnabled={this.isEnabled}
233
347
  setEditorRef={editor => {
234
348
  this.editorRef = editor;
349
+ this.setupEditorEventListeners();
235
350
  this.editorReady.resolve();
236
351
  }}
237
352
  showContext={this.configuration?.showContext}
238
353
  showPinnedAgent={this.configuration?.showPinnedAgent}
239
354
  showChangeSet={this.configuration?.showChangeSet}
240
355
  showSuggestions={this.configuration?.showSuggestions}
356
+ hasPromptHistory={hasPromptHistory}
241
357
  labelProvider={this.labelProvider}
242
358
  actionService={this.changeSetActionService}
243
359
  decoratorService={this.changeSetDecoratorService}
@@ -388,6 +504,7 @@ interface ChatInputProperties {
388
504
  showPinnedAgent?: boolean;
389
505
  showChangeSet?: boolean;
390
506
  showSuggestions?: boolean;
507
+ hasPromptHistory?: boolean;
391
508
  labelProvider: LabelProvider;
392
509
  actionService: ChangeSetActionService;
393
510
  decoratorService: ChangeSetDecoratorService;
@@ -439,7 +556,7 @@ const ChatInput: React.FunctionComponent<ChatInputProperties> = (props: ChatInpu
439
556
  ? nls.localize('theia/ai/chat-ui/aiDisabled', 'AI features are disabled')
440
557
  : shouldUseTaskPlaceholder
441
558
  ? taskPlaceholder
442
- : nls.localizeByDefault('Ask a question');
559
+ : nls.localizeByDefault('Ask a question') + (props.hasPromptHistory ? nls.localizeByDefault(' ({0} for history)', '⇅') : '');
443
560
 
444
561
  // Handle paste events on the container
445
562
  const handlePaste = React.useCallback((event: ClipboardEvent) => {
@@ -22,10 +22,11 @@ import { nls } from '@theia/core/lib/common/nls';
22
22
  import { codicon, OpenerService } from '@theia/core/lib/browser';
23
23
  import * as React from '@theia/core/shared/react';
24
24
  import { ToolConfirmation, ToolConfirmationState } from './tool-confirmation';
25
- import { ToolConfirmationManager, ToolConfirmationMode } from '@theia/ai-chat/lib/browser/chat-tool-preferences';
25
+ import { ToolConfirmationMode } from '@theia/ai-chat/lib/common/chat-tool-preferences';
26
26
  import { ResponseNode } from '../chat-tree-view';
27
27
  import { useMarkdownRendering } from './markdown-part-renderer';
28
28
  import { ToolCallResult } from '@theia/ai-core';
29
+ import { ToolConfirmationManager } from '@theia/ai-chat/lib/browser/chat-tool-preference-bindings';
29
30
 
30
31
  @injectable()
31
32
  export class ToolCallPartRenderer implements ChatResponsePartRenderer<ToolCallChatResponseContent> {
@@ -13,9 +13,9 @@
13
13
  //
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
- import { CommandService, deepClone, Emitter, Event, MessageService, URI } from '@theia/core';
16
+ import { CommandService, deepClone, Emitter, Event, MessageService, PreferenceService, URI } from '@theia/core';
17
17
  import { ChatRequest, ChatRequestModel, ChatService, ChatSession, isActiveSessionChangedEvent, MutableChatModel } from '@theia/ai-chat';
18
- import { BaseWidget, codicon, ExtractableWidget, Message, PanelLayout, PreferenceService, StatefulWidget } from '@theia/core/lib/browser';
18
+ import { BaseWidget, codicon, ExtractableWidget, Message, PanelLayout, 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';