@theia/ai-chat-ui 1.65.0-next.55 → 1.65.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.
@@ -1 +1 @@
1
- {"version":3,"file":"chat-view-commands.d.ts","sourceRoot":"","sources":["../../src/browser/chat-view-commands.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,OAAO,EAAO,MAAM,aAAa,CAAC;AAG3C,yBAAiB,YAAY,CAAC;IAInB,MAAM,kBAAkB,SAIN,CAAC;IAEnB,MAAM,oBAAoB,SAIR,CAAC;IAEnB,MAAM,qBAAqB,SAIW,CAAC;IAEvC,MAAM,6BAA6B,EAAE,OAE3C,CAAC;IAEK,MAAM,0CAA0C,SAIvB,CAAC;IAE1B,MAAM,iCAAiC,SAKd,CAAC;IAE1B,MAAM,wCAAwC,SAKrB,CAAC;CACpC;AAED,eAAO,MAAM,+BAA+B,EAAE,OAG7C,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,OAGxC,CAAC"}
1
+ {"version":3,"file":"chat-view-commands.d.ts","sourceRoot":"","sources":["../../src/browser/chat-view-commands.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,OAAO,EAAO,MAAM,aAAa,CAAC;AAG3C,yBAAiB,YAAY,CAAC;IACnB,MAAM,aAAa,SAAS,CAAC;IAC7B,MAAM,iBAAiB,QAAmC,CAAC;IAE3D,MAAM,kBAAkB,SAKsB,CAAC;IAE/C,MAAM,oBAAoB,SAKsB,CAAC;IAEjD,MAAM,qBAAqB,SAKwB,CAAC;IAEpD,MAAM,6BAA6B,EAAE,OAE3C,CAAC;IAEK,MAAM,0CAA0C,SAIgB,CAAC;IAEjE,MAAM,iCAAiC,SAKqB,CAAC;IAE7D,MAAM,wCAAwC,SAKiB,CAAC;CAC1E;AAED,eAAO,MAAM,+BAA+B,SAK1C,CAAC;AAEH,eAAO,MAAM,0BAA0B,SAKrC,CAAC"}
@@ -20,50 +20,57 @@ const core_1 = require("@theia/core");
20
20
  const browser_1 = require("@theia/core/lib/browser");
21
21
  var ChatCommands;
22
22
  (function (ChatCommands) {
23
- const CHAT_CATEGORY = 'Chat';
24
- const CHAT_CATEGORY_KEY = core_1.nls.getDefaultKey(CHAT_CATEGORY);
23
+ ChatCommands.CHAT_CATEGORY = 'Chat';
24
+ ChatCommands.CHAT_CATEGORY_KEY = core_1.nls.getDefaultKey(ChatCommands.CHAT_CATEGORY);
25
25
  ChatCommands.SCROLL_LOCK_WIDGET = core_1.Command.toLocalizedCommand({
26
26
  id: 'chat:widget:lock',
27
- category: CHAT_CATEGORY,
28
- iconClass: (0, browser_1.codicon)('unlock')
29
- }, '', CHAT_CATEGORY_KEY);
27
+ category: ChatCommands.CHAT_CATEGORY,
28
+ iconClass: (0, browser_1.codicon)('unlock'),
29
+ label: 'Lock Scroll'
30
+ }, 'theia/ai-chat-ui/scroll-lock', ChatCommands.CHAT_CATEGORY_KEY);
30
31
  ChatCommands.SCROLL_UNLOCK_WIDGET = core_1.Command.toLocalizedCommand({
31
32
  id: 'chat:widget:unlock',
32
- category: CHAT_CATEGORY,
33
- iconClass: (0, browser_1.codicon)('lock')
34
- }, '', CHAT_CATEGORY_KEY);
33
+ category: ChatCommands.CHAT_CATEGORY,
34
+ iconClass: (0, browser_1.codicon)('lock'),
35
+ label: 'Unlock Scroll'
36
+ }, 'theia/ai-chat-ui/scroll-unlock', ChatCommands.CHAT_CATEGORY_KEY);
35
37
  ChatCommands.EDIT_SESSION_SETTINGS = core_1.Command.toLocalizedCommand({
36
38
  id: 'chat:widget:session-settings',
37
- category: CHAT_CATEGORY,
38
- iconClass: (0, browser_1.codicon)('bracket')
39
- }, 'Set Session Settings', CHAT_CATEGORY_KEY);
39
+ category: ChatCommands.CHAT_CATEGORY,
40
+ iconClass: (0, browser_1.codicon)('bracket'),
41
+ label: 'Set Session Settings'
42
+ }, 'theia/ai-chat-ui/session-settings', ChatCommands.CHAT_CATEGORY_KEY);
40
43
  ChatCommands.AI_CHAT_NEW_WITH_TASK_CONTEXT = {
41
44
  id: 'ai-chat.new-with-task-context',
42
45
  };
43
46
  ChatCommands.AI_CHAT_INITIATE_SESSION_WITH_TASK_CONTEXT = core_1.Command.toLocalizedCommand({
44
47
  id: 'ai-chat.initiate-session-with-task-context',
45
48
  label: 'Task Context: Initiate Session',
46
- category: CHAT_CATEGORY
47
- }, undefined, CHAT_CATEGORY_KEY);
49
+ category: ChatCommands.CHAT_CATEGORY
50
+ }, 'theia/ai-chat-ui/initiate-session-task-context', ChatCommands.CHAT_CATEGORY_KEY);
48
51
  ChatCommands.AI_CHAT_SUMMARIZE_CURRENT_SESSION = core_1.Command.toLocalizedCommand({
49
52
  id: 'ai-chat-summary-current-session',
50
53
  iconClass: (0, browser_1.codicon)('go-to-editing-session'),
51
54
  label: 'Summarize Current Session',
52
- category: CHAT_CATEGORY
53
- }, undefined, CHAT_CATEGORY_KEY);
55
+ category: ChatCommands.CHAT_CATEGORY
56
+ }, 'theia/ai-chat-ui/summarize-current-session', ChatCommands.CHAT_CATEGORY_KEY);
54
57
  ChatCommands.AI_CHAT_OPEN_SUMMARY_FOR_CURRENT_SESSION = core_1.Command.toLocalizedCommand({
55
58
  id: 'ai-chat-open-current-session-summary',
56
59
  iconClass: (0, browser_1.codicon)('note'),
57
60
  label: 'Open Current Session Summary',
58
- category: CHAT_CATEGORY
59
- }, undefined, CHAT_CATEGORY_KEY);
61
+ category: ChatCommands.CHAT_CATEGORY
62
+ }, 'theia/ai-chat-ui/open-current-session-summary', ChatCommands.CHAT_CATEGORY_KEY);
60
63
  })(ChatCommands || (exports.ChatCommands = ChatCommands = {}));
61
- exports.AI_CHAT_NEW_CHAT_WINDOW_COMMAND = {
64
+ exports.AI_CHAT_NEW_CHAT_WINDOW_COMMAND = core_1.Command.toDefaultLocalizedCommand({
62
65
  id: 'ai-chat-ui.new-chat',
63
- iconClass: (0, browser_1.codicon)('add')
64
- };
65
- exports.AI_CHAT_SHOW_CHATS_COMMAND = {
66
+ iconClass: (0, browser_1.codicon)('add'),
67
+ category: ChatCommands.CHAT_CATEGORY,
68
+ label: 'New Chat'
69
+ });
70
+ exports.AI_CHAT_SHOW_CHATS_COMMAND = core_1.Command.toDefaultLocalizedCommand({
66
71
  id: 'ai-chat-ui.show-chats',
67
- iconClass: (0, browser_1.codicon)('history')
68
- };
72
+ iconClass: (0, browser_1.codicon)('history'),
73
+ category: ChatCommands.CHAT_CATEGORY,
74
+ label: 'Show Chats...'
75
+ });
69
76
  //# sourceMappingURL=chat-view-commands.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"chat-view-commands.js","sourceRoot":"","sources":["../../src/browser/chat-view-commands.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,yCAAyC;AACzC,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;;;AAEhF,sCAA2C;AAC3C,qDAAkD;AAElD,IAAiB,YAAY,CA6C5B;AA7CD,WAAiB,YAAY;IACzB,MAAM,aAAa,GAAG,MAAM,CAAC;IAC7B,MAAM,iBAAiB,GAAG,UAAG,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC;IAE9C,+BAAkB,GAAG,cAAO,CAAC,kBAAkB,CAAC;QACzD,EAAE,EAAE,kBAAkB;QACtB,QAAQ,EAAE,aAAa;QACvB,SAAS,EAAE,IAAA,iBAAO,EAAC,QAAQ,CAAC;KAC/B,EAAE,EAAE,EAAE,iBAAiB,CAAC,CAAC;IAEb,iCAAoB,GAAG,cAAO,CAAC,kBAAkB,CAAC;QAC3D,EAAE,EAAE,oBAAoB;QACxB,QAAQ,EAAE,aAAa;QACvB,SAAS,EAAE,IAAA,iBAAO,EAAC,MAAM,CAAC;KAC7B,EAAE,EAAE,EAAE,iBAAiB,CAAC,CAAC;IAEb,kCAAqB,GAAG,cAAO,CAAC,kBAAkB,CAAC;QAC5D,EAAE,EAAE,8BAA8B;QAClC,QAAQ,EAAE,aAAa;QACvB,SAAS,EAAE,IAAA,iBAAO,EAAC,SAAS,CAAC;KAChC,EAAE,sBAAsB,EAAE,iBAAiB,CAAC,CAAC;IAEjC,0CAA6B,GAAY;QAClD,EAAE,EAAE,+BAA+B;KACtC,CAAC;IAEW,uDAA0C,GAAG,cAAO,CAAC,kBAAkB,CAAC;QACjF,EAAE,EAAE,4CAA4C;QAChD,KAAK,EAAE,gCAAgC;QACvC,QAAQ,EAAE,aAAa;KAC1B,EAAE,SAAS,EAAE,iBAAiB,CAAC,CAAC;IAEpB,8CAAiC,GAAG,cAAO,CAAC,kBAAkB,CAAC;QACxE,EAAE,EAAE,iCAAiC;QACrC,SAAS,EAAE,IAAA,iBAAO,EAAC,uBAAuB,CAAC;QAC3C,KAAK,EAAE,2BAA2B;QAClC,QAAQ,EAAE,aAAa;KAC1B,EAAE,SAAS,EAAE,iBAAiB,CAAC,CAAC;IAEpB,qDAAwC,GAAG,cAAO,CAAC,kBAAkB,CAAC;QAC/E,EAAE,EAAE,sCAAsC;QAC1C,SAAS,EAAE,IAAA,iBAAO,EAAC,MAAM,CAAC;QAC1B,KAAK,EAAE,8BAA8B;QACrC,QAAQ,EAAE,aAAa;KAC1B,EAAE,SAAS,EAAE,iBAAiB,CAAC,CAAC;AACrC,CAAC,EA7CgB,YAAY,4BAAZ,YAAY,QA6C5B;AAEY,QAAA,+BAA+B,GAAY;IACpD,EAAE,EAAE,qBAAqB;IACzB,SAAS,EAAE,IAAA,iBAAO,EAAC,KAAK,CAAC;CAC5B,CAAC;AAEW,QAAA,0BAA0B,GAAY;IAC/C,EAAE,EAAE,uBAAuB;IAC3B,SAAS,EAAE,IAAA,iBAAO,EAAC,SAAS,CAAC;CAChC,CAAC"}
1
+ {"version":3,"file":"chat-view-commands.js","sourceRoot":"","sources":["../../src/browser/chat-view-commands.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,yCAAyC;AACzC,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;;;AAEhF,sCAA2C;AAC3C,qDAAkD;AAElD,IAAiB,YAAY,CAgD5B;AAhDD,WAAiB,YAAY;IACZ,0BAAa,GAAG,MAAM,CAAC;IACvB,8BAAiB,GAAG,UAAG,CAAC,aAAa,CAAC,aAAA,aAAa,CAAC,CAAC;IAErD,+BAAkB,GAAG,cAAO,CAAC,kBAAkB,CAAC;QACzD,EAAE,EAAE,kBAAkB;QACtB,QAAQ,EAAE,aAAA,aAAa;QACvB,SAAS,EAAE,IAAA,iBAAO,EAAC,QAAQ,CAAC;QAC5B,KAAK,EAAE,aAAa;KACvB,EAAE,8BAA8B,EAAE,aAAA,iBAAiB,CAAC,CAAC;IAEzC,iCAAoB,GAAG,cAAO,CAAC,kBAAkB,CAAC;QAC3D,EAAE,EAAE,oBAAoB;QACxB,QAAQ,EAAE,aAAA,aAAa;QACvB,SAAS,EAAE,IAAA,iBAAO,EAAC,MAAM,CAAC;QAC1B,KAAK,EAAE,eAAe;KACzB,EAAE,gCAAgC,EAAE,aAAA,iBAAiB,CAAC,CAAC;IAE3C,kCAAqB,GAAG,cAAO,CAAC,kBAAkB,CAAC;QAC5D,EAAE,EAAE,8BAA8B;QAClC,QAAQ,EAAE,aAAA,aAAa;QACvB,SAAS,EAAE,IAAA,iBAAO,EAAC,SAAS,CAAC;QAC7B,KAAK,EAAE,sBAAsB;KAChC,EAAE,mCAAmC,EAAE,aAAA,iBAAiB,CAAC,CAAC;IAE9C,0CAA6B,GAAY;QAClD,EAAE,EAAE,+BAA+B;KACtC,CAAC;IAEW,uDAA0C,GAAG,cAAO,CAAC,kBAAkB,CAAC;QACjF,EAAE,EAAE,4CAA4C;QAChD,KAAK,EAAE,gCAAgC;QACvC,QAAQ,EAAE,aAAA,aAAa;KAC1B,EAAE,gDAAgD,EAAE,aAAA,iBAAiB,CAAC,CAAC;IAE3D,8CAAiC,GAAG,cAAO,CAAC,kBAAkB,CAAC;QACxE,EAAE,EAAE,iCAAiC;QACrC,SAAS,EAAE,IAAA,iBAAO,EAAC,uBAAuB,CAAC;QAC3C,KAAK,EAAE,2BAA2B;QAClC,QAAQ,EAAE,aAAA,aAAa;KAC1B,EAAE,4CAA4C,EAAE,aAAA,iBAAiB,CAAC,CAAC;IAEvD,qDAAwC,GAAG,cAAO,CAAC,kBAAkB,CAAC;QAC/E,EAAE,EAAE,sCAAsC;QAC1C,SAAS,EAAE,IAAA,iBAAO,EAAC,MAAM,CAAC;QAC1B,KAAK,EAAE,8BAA8B;QACrC,QAAQ,EAAE,aAAA,aAAa;KAC1B,EAAE,+CAA+C,EAAE,aAAA,iBAAiB,CAAC,CAAC;AAC3E,CAAC,EAhDgB,YAAY,4BAAZ,YAAY,QAgD5B;AAEY,QAAA,+BAA+B,GAAG,cAAO,CAAC,yBAAyB,CAAC;IAC7E,EAAE,EAAE,qBAAqB;IACzB,SAAS,EAAE,IAAA,iBAAO,EAAC,KAAK,CAAC;IACzB,QAAQ,EAAE,YAAY,CAAC,aAAa;IACpC,KAAK,EAAE,UAAU;CACpB,CAAC,CAAC;AAEU,QAAA,0BAA0B,GAAG,cAAO,CAAC,yBAAyB,CAAC;IACxE,EAAE,EAAE,uBAAuB;IAC3B,SAAS,EAAE,IAAA,iBAAO,EAAC,SAAS,CAAC;IAC7B,QAAQ,EAAE,YAAY,CAAC,aAAa;IACpC,KAAK,EAAE,eAAe;CACzB,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,19 +1,18 @@
1
1
  {
2
2
  "name": "@theia/ai-chat-ui",
3
- "version": "1.65.0-next.55+d141c3601",
3
+ "version": "1.65.0",
4
4
  "description": "Theia - AI Chat UI Extension",
5
5
  "dependencies": {
6
- "@theia/ai-chat": "1.65.0-next.55+d141c3601",
7
- "@theia/ai-core": "1.65.0-next.55+d141c3601",
8
- "@theia/core": "1.65.0-next.55+d141c3601",
9
- "@theia/editor": "1.65.0-next.55+d141c3601",
10
- "@theia/editor-preview": "1.65.0-next.55+d141c3601",
11
- "@theia/filesystem": "1.65.0-next.55+d141c3601",
12
- "@theia/monaco": "1.65.0-next.55+d141c3601",
6
+ "@theia/ai-chat": "1.65.0",
7
+ "@theia/ai-core": "1.65.0",
8
+ "@theia/core": "1.65.0",
9
+ "@theia/editor": "1.65.0",
10
+ "@theia/editor-preview": "1.65.0",
11
+ "@theia/filesystem": "1.65.0",
12
+ "@theia/monaco": "1.65.0",
13
13
  "@theia/monaco-editor-core": "1.96.302",
14
- "@theia/workspace": "1.65.0-next.55+d141c3601",
14
+ "@theia/workspace": "1.65.0",
15
15
  "date-fns": "^4.1.0",
16
- "minimatch": "^5.1.0",
17
16
  "tslib": "^2.6.2",
18
17
  "uuid": "^9.0.1"
19
18
  },
@@ -51,10 +50,10 @@
51
50
  "watch": "theiaext watch"
52
51
  },
53
52
  "devDependencies": {
54
- "@theia/ext-scripts": "1.64.0"
53
+ "@theia/ext-scripts": "1.65.0"
55
54
  },
56
55
  "nyc": {
57
56
  "extends": "../../configs/nyc.json"
58
57
  },
59
- "gitHead": "d141c3601e8c3d9cd254468790fed3566aa23305"
58
+ "gitHead": "500dfc80cee94fd2a623b5fb59b22d5a575247c2"
60
59
  }
@@ -229,14 +229,14 @@ export class AIChatContribution extends AbstractViewContribution<ChatViewWidget>
229
229
  registry.registerItem({
230
230
  id: AI_CHAT_NEW_CHAT_WINDOW_COMMAND.id,
231
231
  command: AI_CHAT_NEW_CHAT_WINDOW_COMMAND.id,
232
- tooltip: nls.localizeByDefault('New Chat'),
232
+ tooltip: AI_CHAT_NEW_CHAT_WINDOW_COMMAND.label,
233
233
  isVisible: widget => this.activationService.isActive && this.withWidget(widget),
234
234
  when: ENABLE_AI_CONTEXT_KEY
235
235
  });
236
236
  registry.registerItem({
237
237
  id: AI_CHAT_SHOW_CHATS_COMMAND.id,
238
238
  command: AI_CHAT_SHOW_CHATS_COMMAND.id,
239
- tooltip: nls.localizeByDefault('Show Chats...'),
239
+ tooltip: AI_CHAT_SHOW_CHATS_COMMAND.label,
240
240
  isVisible: widget => this.activationService.isActive && this.withWidget(widget),
241
241
  when: ENABLE_AI_CONTEXT_KEY
242
242
  });
@@ -82,12 +82,18 @@ export class ChatInputHistoryContribution implements CommandContribution, Keybin
82
82
  return;
83
83
  }
84
84
 
85
+ const position = chatInputWidget.editor.getControl().getPosition();
86
+ const isCursorAtBeginning = position && (position.lineNumber > 1 || position.column > 1);
87
+ if (isCursorAtBeginning) {
88
+ this.positionCursorAtBeginning(chatInputWidget);
89
+ return;
90
+ }
91
+
85
92
  const currentInput = chatInputWidget.editor.getControl().getValue();
86
93
  const previousPrompt = chatInputWidget.getPreviousPrompt(currentInput);
87
-
88
94
  if (previousPrompt !== undefined) {
89
95
  chatInputWidget.editor.getControl().setValue(previousPrompt);
90
- this.positionCursorAtEnd(chatInputWidget);
96
+ this.positionCursorAtBeginning(chatInputWidget);
91
97
  }
92
98
  }
93
99
 
@@ -97,14 +103,31 @@ export class ChatInputHistoryContribution implements CommandContribution, Keybin
97
103
  return;
98
104
  }
99
105
 
100
- const nextPrompt = chatInputWidget.getNextPrompt();
106
+ const position = chatInputWidget.editor.getControl().getPosition();
107
+ const model = chatInputWidget.editor.getControl().getModel();
108
+ const isCursorAtEnd = position && model && (
109
+ position.lineNumber < model.getLineCount() || position.column < model.getLineMaxColumn(position.lineNumber)
110
+ );
111
+ if (isCursorAtEnd) {
112
+ this.positionCursorAtEnd(chatInputWidget);
113
+ return;
114
+ }
101
115
 
116
+ const nextPrompt = chatInputWidget.getNextPrompt();
102
117
  if (nextPrompt !== undefined) {
103
118
  chatInputWidget.editor.getControl().setValue(nextPrompt);
104
119
  this.positionCursorAtEnd(chatInputWidget);
105
120
  }
106
121
  }
107
122
 
123
+ protected positionCursorAtBeginning(widget: AIChatInputWidget): void {
124
+ const editor = widget.editor?.getControl();
125
+ if (editor) {
126
+ editor.setPosition({ lineNumber: 1, column: 1 });
127
+ editor.focus();
128
+ }
129
+ }
130
+
108
131
  protected positionCursorAtEnd(widget: AIChatInputWidget): void {
109
132
  const editor = widget.editor?.getControl();
110
133
  const model = editor?.getModel();
@@ -114,13 +137,6 @@ export class ChatInputHistoryContribution implements CommandContribution, Keybin
114
137
  const lastColumn = model.getLineContent(lastLine).length + 1;
115
138
  editor.setPosition({ lineNumber: lastLine, column: lastColumn });
116
139
  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
140
  }
125
141
  }
126
142
 
@@ -15,13 +15,14 @@
15
15
  // *****************************************************************************
16
16
  import {
17
17
  ChangeSet, ChangeSetElement, ChatAgent, ChatChangeEvent, ChatHierarchyBranch,
18
- ChatModel, ChatRequestModel, ChatService, ChatSuggestion, EditableChatRequestModel
18
+ ChatModel, ChatRequestModel, ChatService, ChatSuggestion, EditableChatRequestModel,
19
+ ChatRequestParser
19
20
  } from '@theia/ai-chat';
20
21
  import { ChangeSetDecoratorService } from '@theia/ai-chat/lib/browser/change-set-decorator-service';
21
22
  import { ImageContextVariable } from '@theia/ai-chat/lib/common/image-context-variable';
22
23
  import { AIVariableResolutionRequest } from '@theia/ai-core';
23
24
  import { AgentCompletionNotificationService, FrontendVariableService, AIActivationService } from '@theia/ai-core/lib/browser';
24
- import { DisposableCollection, Emitter, InMemoryResources, URI, nls } from '@theia/core';
25
+ import { DisposableCollection, Emitter, InMemoryResources, URI, nls, Disposable } from '@theia/core';
25
26
  import { ContextMenuRenderer, LabelProvider, Message, OpenerService, ReactWidget } from '@theia/core/lib/browser';
26
27
  import { ContextKey, ContextKeyService } from '@theia/core/lib/browser/context-key-service';
27
28
  import { Deferred } from '@theia/core/lib/common/promise-util';
@@ -36,6 +37,7 @@ import { CHAT_VIEW_LANGUAGE_EXTENSION } from './chat-view-language-contribution'
36
37
  import { ContextVariablePicker } from './context-variable-picker';
37
38
  import { TASK_CONTEXT_VARIABLE } from '@theia/ai-chat/lib/browser/task-context-variable';
38
39
  import { IModelDeltaDecoration } from '@theia/monaco-editor-core/esm/vs/editor/common/model';
40
+ import { EditorOption } from '@theia/monaco-editor-core/esm/vs/editor/common/config/editorOptions';
39
41
  import { ChatInputHistoryService, ChatInputNavigationState } from './chat-input-history';
40
42
 
41
43
  type Query = (query: string) => Promise<void>;
@@ -101,6 +103,9 @@ export class AIChatInputWidget extends ReactWidget {
101
103
  @inject(ChatInputHistoryService)
102
104
  protected readonly historyService: ChatInputHistoryService;
103
105
 
106
+ @inject(ChatRequestParser)
107
+ protected readonly chatRequestParser: ChatRequestParser;
108
+
104
109
  protected navigationState: ChatInputNavigationState;
105
110
 
106
111
  @inject(ContextKeyService)
@@ -134,10 +139,13 @@ export class AIChatInputWidget extends ReactWidget {
134
139
  protected chatInputFocusKey: ContextKey<boolean>;
135
140
  protected chatInputFirstLineKey: ContextKey<boolean>;
136
141
  protected chatInputLastLineKey: ContextKey<boolean>;
142
+ protected chatInputReceivingAgentKey: ContextKey<string>;
137
143
 
138
144
  protected isEnabled = false;
139
145
  protected heightInLines = 12;
140
146
 
147
+ protected updateReceivingAgentTimeout: number | undefined;
148
+
141
149
  protected _branch?: ChatHierarchyBranch;
142
150
  set branch(branch: ChatHierarchyBranch | undefined) {
143
151
  if (this._branch !== branch) {
@@ -189,11 +197,13 @@ export class AIChatInputWidget extends ReactWidget {
189
197
  }
190
198
  }));
191
199
  this._chatModel = chatModel;
200
+ this.scheduleUpdateReceivingAgent();
192
201
  this.update();
193
202
  }
194
203
  protected _pinnedAgent: ChatAgent | undefined;
195
204
  set pinnedAgent(pinnedAgent: ChatAgent | undefined) {
196
205
  this._pinnedAgent = pinnedAgent;
206
+ this.scheduleUpdateReceivingAgent();
197
207
  this.update();
198
208
  }
199
209
 
@@ -209,6 +219,12 @@ export class AIChatInputWidget extends ReactWidget {
209
219
  this.setEnabled(this.aiActivationService.isActive);
210
220
  }));
211
221
  this.toDispose.push(this.onDidResizeEmitter);
222
+ this.toDispose.push(Disposable.create(() => {
223
+ if (this.updateReceivingAgentTimeout !== undefined) {
224
+ clearTimeout(this.updateReceivingAgentTimeout);
225
+ this.updateReceivingAgentTimeout = undefined;
226
+ }
227
+ }));
212
228
  this.setEnabled(this.aiActivationService.isActive);
213
229
  this.historyService.init().then(() => {
214
230
  this.navigationState = new ChatInputNavigationState(this.historyService);
@@ -221,6 +237,7 @@ export class AIChatInputWidget extends ReactWidget {
221
237
  this.chatInputFocusKey = this.contextKeyService.createKey<boolean>('chatInputFocus', false);
222
238
  this.chatInputFirstLineKey = this.contextKeyService.createKey<boolean>('chatInputFirstLine', false);
223
239
  this.chatInputLastLineKey = this.contextKeyService.createKey<boolean>('chatInputLastLine', false);
240
+ this.chatInputReceivingAgentKey = this.contextKeyService.createKey<string>('chatInputReceivingAgent', '');
224
241
  }
225
242
 
226
243
  updateCursorPositionKeys(): void {
@@ -240,11 +257,57 @@ export class AIChatInputWidget extends ReactWidget {
240
257
  return;
241
258
  }
242
259
 
243
- const isFirstLine = position.lineNumber === 1;
244
- const isLastLine = position.lineNumber === model.getLineCount();
260
+ const line = position.lineNumber;
261
+ const col = position.column;
262
+
263
+ const topAtPos = editor.getTopForPosition(line, col);
264
+ const topAtLineStart = editor.getTopForLineNumber(line);
265
+ const topAtLineEnd = editor.getTopForPosition(line, model.getLineMaxColumn(line));
266
+ const lineHeight = editor.getOption(EditorOption.lineHeight);
267
+ const toleranceValue = 0.5;
268
+
269
+ const isFirstVisualOfThisLine = Math.abs(topAtPos - topAtLineStart) < toleranceValue;
270
+ const isLastVisualOfThisLine = Math.abs(topAtPos - topAtLineEnd) < toleranceValue || (topAtPos > topAtLineEnd - lineHeight + toleranceValue);
271
+ const isFirstVisualOverall = line === 1 && isFirstVisualOfThisLine;
245
272
 
246
- this.chatInputFirstLineKey.set(isFirstLine);
247
- this.chatInputLastLineKey.set(isLastLine);
273
+ const isLastVisualOverall = line === model.getLineCount() && isLastVisualOfThisLine;
274
+
275
+ this.chatInputFirstLineKey.set(isFirstVisualOverall);
276
+ this.chatInputLastLineKey.set(isLastVisualOverall);
277
+ }
278
+
279
+ protected scheduleUpdateReceivingAgent(): void {
280
+ if (this.updateReceivingAgentTimeout !== undefined) {
281
+ clearTimeout(this.updateReceivingAgentTimeout);
282
+ }
283
+ this.updateReceivingAgentTimeout = window.setTimeout(() => {
284
+ this.updateReceivingAgent();
285
+ this.updateReceivingAgentTimeout = undefined;
286
+ }, 200);
287
+ }
288
+
289
+ protected async updateReceivingAgent(): Promise<void> {
290
+ if (!this.editorRef || !this._chatModel) {
291
+ this.chatInputReceivingAgentKey.set('');
292
+ return;
293
+ }
294
+
295
+ try {
296
+ const inputText = this.editorRef.getControl().getValue();
297
+ const request = { text: inputText };
298
+ const resolvedContext = { variables: [] };
299
+ const parsedRequest = await this.chatRequestParser.parseChatRequest(request, this._chatModel.location, resolvedContext);
300
+ const session = this.chatService.getSessions().find(s => s.model.id === this._chatModel.id);
301
+ if (session) {
302
+ const agent = this.chatService.getAgent(parsedRequest, session);
303
+ this.chatInputReceivingAgentKey.set(agent?.id ?? '');
304
+ } else {
305
+ this.chatInputReceivingAgentKey.set('');
306
+ }
307
+ } catch (error) {
308
+ console.warn('Failed to determine receiving agent:', error);
309
+ this.chatInputReceivingAgentKey.set('');
310
+ }
248
311
  }
249
312
 
250
313
  protected setupEditorEventListeners(): void {
@@ -275,6 +338,7 @@ export class AIChatInputWidget extends ReactWidget {
275
338
  if (editor.hasWidgetFocus()) {
276
339
  this.updateCursorPositionKeys();
277
340
  }
341
+ this.scheduleUpdateReceivingAgent();
278
342
  }));
279
343
 
280
344
  if (editor.hasWidgetFocus()) {
@@ -319,7 +383,6 @@ export class AIChatInputWidget extends ReactWidget {
319
383
  const isEditing = !!(currentRequest && (EditableChatRequestModel.isEditing(currentRequest)));
320
384
  const isPending = () => !!(currentRequest && !isEditing && ChatRequestModel.isInProgress(currentRequest));
321
385
  const pending = isPending();
322
- const hasPromptHistory = this.configuration?.enablePromptHistory && this.historyService.getPrompts().length > 0;
323
386
 
324
387
  return (
325
388
  <ChatInput
@@ -353,7 +416,7 @@ export class AIChatInputWidget extends ReactWidget {
353
416
  showPinnedAgent={this.configuration?.showPinnedAgent}
354
417
  showChangeSet={this.configuration?.showChangeSet}
355
418
  showSuggestions={this.configuration?.showSuggestions}
356
- hasPromptHistory={hasPromptHistory}
419
+ hasPromptHistory={this.configuration?.enablePromptHistory}
357
420
  labelProvider={this.labelProvider}
358
421
  actionService={this.changeSetActionService}
359
422
  decoratorService={this.changeSetDecoratorService}
@@ -529,6 +592,8 @@ const ChatInput: React.FunctionComponent<ChatInputProperties> = (props: ChatInpu
529
592
  const onDeleteChangeSetElement = (uri: URI) => props.onDeleteChangeSetElement(props.chatModel.id, uri);
530
593
 
531
594
  const [isInputEmpty, setIsInputEmpty] = React.useState(true);
595
+ const [isInputFocused, setIsInputFocused] = React.useState(false);
596
+ const [placeholderText, setPlaceholderText] = React.useState('');
532
597
  const [changeSetUI, setChangeSetUI] = React.useState(
533
598
  () => buildChangeSetUI(
534
599
  props.chatModel.changeSet,
@@ -552,11 +617,16 @@ const ChatInput: React.FunctionComponent<ChatInputProperties> = (props: ChatInpu
552
617
  const isFirstRequest = props.chatModel.getRequests().length === 0;
553
618
  const shouldUseTaskPlaceholder = isFirstRequest && props.pinnedAgent && hasTaskContext(props.chatModel);
554
619
  const taskPlaceholder = nls.localize('theia/ai/chat-ui/performThisTask', 'Perform this task.');
555
- const placeholderText = !props.isEnabled
556
- ? nls.localize('theia/ai/chat-ui/aiDisabled', 'AI features are disabled')
557
- : shouldUseTaskPlaceholder
558
- ? taskPlaceholder
559
- : nls.localizeByDefault('Ask a question') + (props.hasPromptHistory ? nls.localizeByDefault(' ({0} for history)', '⇅') : '');
620
+
621
+ // Update placeholder text when focus state or other dependencies change
622
+ React.useEffect(() => {
623
+ const newPlaceholderText = !props.isEnabled
624
+ ? nls.localize('theia/ai/chat-ui/aiDisabled', 'AI features are disabled')
625
+ : shouldUseTaskPlaceholder
626
+ ? taskPlaceholder
627
+ : nls.localizeByDefault('Ask a question') + (props.hasPromptHistory && isInputFocused ? nls.localizeByDefault(' ({0} for history)', '⇅') : '');
628
+ setPlaceholderText(newPlaceholderText);
629
+ }, [props.isEnabled, shouldUseTaskPlaceholder, taskPlaceholder, props.hasPromptHistory, isInputFocused]);
560
630
 
561
631
  // Handle paste events on the container
562
632
  const handlePaste = React.useCallback((event: ClipboardEvent) => {
@@ -797,6 +867,7 @@ const ChatInput: React.FunctionComponent<ChatInputProperties> = (props: ChatInpu
797
867
  }, [props.isEnabled, submit]);
798
868
 
799
869
  const handleInputFocus = () => {
870
+ setIsInputFocused(true);
800
871
  hidePlaceholderIfEditorFilled();
801
872
  };
802
873
 
@@ -806,6 +877,7 @@ const ChatInput: React.FunctionComponent<ChatInputProperties> = (props: ChatInpu
806
877
  };
807
878
 
808
879
  const handleInputBlur = () => {
880
+ setIsInputFocused(false);
809
881
  showPlaceholderIfEditorEmpty();
810
882
  };
811
883
 
@@ -18,26 +18,29 @@ import { Command, nls } from '@theia/core';
18
18
  import { codicon } from '@theia/core/lib/browser';
19
19
 
20
20
  export namespace ChatCommands {
21
- const CHAT_CATEGORY = 'Chat';
22
- const CHAT_CATEGORY_KEY = nls.getDefaultKey(CHAT_CATEGORY);
21
+ export const CHAT_CATEGORY = 'Chat';
22
+ export const CHAT_CATEGORY_KEY = nls.getDefaultKey(CHAT_CATEGORY);
23
23
 
24
24
  export const SCROLL_LOCK_WIDGET = Command.toLocalizedCommand({
25
25
  id: 'chat:widget:lock',
26
26
  category: CHAT_CATEGORY,
27
- iconClass: codicon('unlock')
28
- }, '', CHAT_CATEGORY_KEY);
27
+ iconClass: codicon('unlock'),
28
+ label: 'Lock Scroll'
29
+ }, 'theia/ai-chat-ui/scroll-lock', CHAT_CATEGORY_KEY);
29
30
 
30
31
  export const SCROLL_UNLOCK_WIDGET = Command.toLocalizedCommand({
31
32
  id: 'chat:widget:unlock',
32
33
  category: CHAT_CATEGORY,
33
- iconClass: codicon('lock')
34
- }, '', CHAT_CATEGORY_KEY);
34
+ iconClass: codicon('lock'),
35
+ label: 'Unlock Scroll'
36
+ }, 'theia/ai-chat-ui/scroll-unlock', CHAT_CATEGORY_KEY);
35
37
 
36
38
  export const EDIT_SESSION_SETTINGS = Command.toLocalizedCommand({
37
39
  id: 'chat:widget:session-settings',
38
40
  category: CHAT_CATEGORY,
39
- iconClass: codicon('bracket')
40
- }, 'Set Session Settings', CHAT_CATEGORY_KEY);
41
+ iconClass: codicon('bracket'),
42
+ label: 'Set Session Settings'
43
+ }, 'theia/ai-chat-ui/session-settings', CHAT_CATEGORY_KEY);
41
44
 
42
45
  export const AI_CHAT_NEW_WITH_TASK_CONTEXT: Command = {
43
46
  id: 'ai-chat.new-with-task-context',
@@ -47,29 +50,33 @@ export namespace ChatCommands {
47
50
  id: 'ai-chat.initiate-session-with-task-context',
48
51
  label: 'Task Context: Initiate Session',
49
52
  category: CHAT_CATEGORY
50
- }, undefined, CHAT_CATEGORY_KEY);
53
+ }, 'theia/ai-chat-ui/initiate-session-task-context', CHAT_CATEGORY_KEY);
51
54
 
52
55
  export const AI_CHAT_SUMMARIZE_CURRENT_SESSION = Command.toLocalizedCommand({
53
56
  id: 'ai-chat-summary-current-session',
54
57
  iconClass: codicon('go-to-editing-session'),
55
58
  label: 'Summarize Current Session',
56
59
  category: CHAT_CATEGORY
57
- }, undefined, CHAT_CATEGORY_KEY);
60
+ }, 'theia/ai-chat-ui/summarize-current-session', CHAT_CATEGORY_KEY);
58
61
 
59
62
  export const AI_CHAT_OPEN_SUMMARY_FOR_CURRENT_SESSION = Command.toLocalizedCommand({
60
63
  id: 'ai-chat-open-current-session-summary',
61
64
  iconClass: codicon('note'),
62
65
  label: 'Open Current Session Summary',
63
66
  category: CHAT_CATEGORY
64
- }, undefined, CHAT_CATEGORY_KEY);
67
+ }, 'theia/ai-chat-ui/open-current-session-summary', CHAT_CATEGORY_KEY);
65
68
  }
66
69
 
67
- export const AI_CHAT_NEW_CHAT_WINDOW_COMMAND: Command = {
70
+ export const AI_CHAT_NEW_CHAT_WINDOW_COMMAND = Command.toDefaultLocalizedCommand({
68
71
  id: 'ai-chat-ui.new-chat',
69
- iconClass: codicon('add')
70
- };
72
+ iconClass: codicon('add'),
73
+ category: ChatCommands.CHAT_CATEGORY,
74
+ label: 'New Chat'
75
+ });
71
76
 
72
- export const AI_CHAT_SHOW_CHATS_COMMAND: Command = {
77
+ export const AI_CHAT_SHOW_CHATS_COMMAND = Command.toDefaultLocalizedCommand({
73
78
  id: 'ai-chat-ui.show-chats',
74
- iconClass: codicon('history')
75
- };
79
+ iconClass: codicon('history'),
80
+ category: ChatCommands.CHAT_CATEGORY,
81
+ label: 'Show Chats...'
82
+ });