@opensumi/ide-ai-native 3.8.3-next-1745309832.0 → 3.8.3-next-1745566910.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/lib/browser/chat/chat.view.d.ts.map +1 -1
  2. package/lib/browser/chat/chat.view.js +18 -7
  3. package/lib/browser/chat/chat.view.js.map +1 -1
  4. package/lib/browser/components/ChatMentionInput.d.ts +2 -0
  5. package/lib/browser/components/ChatMentionInput.d.ts.map +1 -1
  6. package/lib/browser/components/ChatMentionInput.js +69 -23
  7. package/lib/browser/components/ChatMentionInput.js.map +1 -1
  8. package/lib/browser/components/mention-input/mention-input.d.ts.map +1 -1
  9. package/lib/browser/components/mention-input/mention-input.js +41 -10
  10. package/lib/browser/components/mention-input/mention-input.js.map +1 -1
  11. package/lib/browser/components/mention-input/mention-input.module.less +78 -6
  12. package/lib/browser/components/mention-input/types.d.ts +5 -0
  13. package/lib/browser/components/mention-input/types.d.ts.map +1 -1
  14. package/lib/browser/components/mention-input/types.js.map +1 -1
  15. package/lib/browser/context/llm-context.service.d.ts +1 -0
  16. package/lib/browser/context/llm-context.service.d.ts.map +1 -1
  17. package/lib/browser/context/llm-context.service.js.map +1 -1
  18. package/lib/browser/types.d.ts +2 -0
  19. package/lib/browser/types.d.ts.map +1 -1
  20. package/lib/browser/types.js.map +1 -1
  21. package/lib/common/llm-context.d.ts +1 -0
  22. package/lib/common/llm-context.d.ts.map +1 -1
  23. package/lib/common/llm-context.js.map +1 -1
  24. package/package.json +24 -23
  25. package/src/browser/chat/chat.view.tsx +20 -5
  26. package/src/browser/components/ChatMentionInput.tsx +85 -24
  27. package/src/browser/components/mention-input/mention-input.module.less +78 -6
  28. package/src/browser/components/mention-input/mention-input.tsx +77 -12
  29. package/src/browser/components/mention-input/types.ts +7 -0
  30. package/src/browser/context/llm-context.service.ts +1 -0
  31. package/src/browser/types.ts +2 -0
  32. package/src/common/llm-context.ts +6 -3
@@ -1,18 +1,21 @@
1
1
  import { DataContent } from 'ai';
2
- import React, { useCallback, useEffect, useMemo, useState } from 'react';
2
+ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
3
 
4
4
  import { Image } from '@opensumi/ide-components/lib/image';
5
- import { LabelService, RecentFilesManager, useInjectable } from '@opensumi/ide-core-browser';
5
+ import { LabelService, RecentFilesManager, getSymbolIcon, useInjectable } from '@opensumi/ide-core-browser';
6
6
  import { Icon, getIcon } from '@opensumi/ide-core-browser/lib/components';
7
7
  import { ChatFeatureRegistryToken, URI, localize } from '@opensumi/ide-core-common';
8
8
  import { CommandService } from '@opensumi/ide-core-common/lib/command';
9
9
  import { defaultFilesWatcherExcludes } from '@opensumi/ide-core-common/lib/preferences/file-watch';
10
10
  import { WorkbenchEditorService } from '@opensumi/ide-editor';
11
11
  import { FileSearchServicePath, IFileSearchService } from '@opensumi/ide-file-search';
12
+ import { OutlineCompositeTreeNode, OutlineTreeNode } from '@opensumi/ide-outline/lib/browser/outline-node.define';
13
+ import { OutlineTreeService } from '@opensumi/ide-outline/lib/browser/services/outline-tree.service';
12
14
  import { IMessageService } from '@opensumi/ide-overlay';
13
15
  import { IWorkspaceService } from '@opensumi/ide-workspace';
14
16
 
15
17
  import { IChatInternalService } from '../../common';
18
+ import { LLMContextService } from '../../common/llm-context';
16
19
  import { ChatFeatureRegistry } from '../chat/chat.feature.registry';
17
20
  import { ChatInternalService } from '../chat/chat.internal.service';
18
21
  import { OPEN_MCP_CONFIG_COMMAND } from '../mcp/config/mcp-config.commands';
@@ -48,11 +51,11 @@ export interface IChatMentionInputProps {
48
51
  setCommand: (command: string) => void;
49
52
  disableModelSelector?: boolean;
50
53
  sessionModelId?: string;
54
+ contextService?: LLMContextService;
51
55
  }
52
56
 
53
- // 指令命令激活组件
54
57
  export const ChatMentionInput = (props: IChatMentionInputProps) => {
55
- const { onSend, disabled = false } = props;
58
+ const { onSend, disabled = false, contextService } = props;
56
59
 
57
60
  const [value, setValue] = useState(props.value || '');
58
61
  const [images, setImages] = useState(props.images || []);
@@ -65,6 +68,8 @@ export const ChatMentionInput = (props: IChatMentionInputProps) => {
65
68
  const labelService = useInjectable<LabelService>(LabelService);
66
69
  const messageService = useInjectable<IMessageService>(IMessageService);
67
70
  const chatFeatureRegistry = useInjectable<ChatFeatureRegistry>(ChatFeatureRegistryToken);
71
+ const outlineTreeService = useInjectable<OutlineTreeService>(OutlineTreeService);
72
+ const prevOutlineItems = useRef<MentionItem[]>([]);
68
73
  const handleShowMCPConfig = React.useCallback(() => {
69
74
  commandService.executeCommand(OPEN_MCP_CONFIG_COMMAND.id);
70
75
  }, [commandService]);
@@ -75,27 +80,76 @@ export const ChatMentionInput = (props: IChatMentionInputProps) => {
75
80
  }
76
81
  }, [props.value]);
77
82
 
83
+ const resolveSymbols = useCallback(
84
+ async (parent?: OutlineCompositeTreeNode, symbols: (OutlineTreeNode | OutlineCompositeTreeNode)[] = []) => {
85
+ if (!parent) {
86
+ parent = (await outlineTreeService.resolveChildren())[0] as OutlineCompositeTreeNode;
87
+ }
88
+ const children = (await outlineTreeService.resolveChildren(parent)) as (
89
+ | OutlineTreeNode
90
+ | OutlineCompositeTreeNode
91
+ )[];
92
+ for (const child of children) {
93
+ symbols.push(child);
94
+ if (OutlineCompositeTreeNode.is(child)) {
95
+ await resolveSymbols(child, symbols);
96
+ }
97
+ }
98
+ return symbols;
99
+ },
100
+ [outlineTreeService],
101
+ );
102
+
78
103
  // 默认菜单项
79
104
  const defaultMenuItems: MentionItem[] = [
80
- // {
81
- // id: 'code',
82
- // type: 'code',
83
- // text: 'Code',
84
- // icon: getIcon('codebraces'),
85
- // getHighestLevelItems: () => [],
86
- // getItems: async (searchText: string) => {
87
- // const currentEditor = editorService.currentEditor;
88
- // if (!currentEditor) {
89
- // return [];
90
- // }
91
- // const currentDocumentModel = currentEditor.currentDocumentModel;
92
- // if (!currentDocumentModel) {
93
- // return [];
94
- // }
95
- // const symbols = await commandService.executeCommand('_executeFormatDocumentProvider', currentDocumentModel.uri.codeUri);
96
- // return [];
97
- // },
98
- // },
105
+ {
106
+ id: 'code',
107
+ type: 'code',
108
+ text: 'Code',
109
+ icon: getIcon('codebraces'),
110
+ getHighestLevelItems: () => [],
111
+ getItems: async (searchText: string) => {
112
+ if (!searchText || prevOutlineItems.current.length === 0) {
113
+ const uri = outlineTreeService.currentUri;
114
+ if (!uri) {
115
+ return [];
116
+ }
117
+ const treeNodes = await resolveSymbols();
118
+ prevOutlineItems.current = await Promise.all(
119
+ treeNodes.map(async (treeNode) => {
120
+ const relativePath = await workspaceService.asRelativePath(uri);
121
+ return {
122
+ id: treeNode.raw.id,
123
+ type: MentionType.CODE,
124
+ text: treeNode.raw.name,
125
+ symbol: treeNode.raw,
126
+ value: treeNode.raw.id,
127
+ description: `${relativePath?.root ? relativePath.path : ''}:L${treeNode.raw.range.startLineNumber}-${
128
+ treeNode.raw.range.endLineNumber
129
+ }`,
130
+ kind: treeNode.raw.kind,
131
+ contextId: `${outlineTreeService.currentUri?.codeUri.fsPath}:L${treeNode.raw.range.startLineNumber}-${treeNode.raw.range.endLineNumber}`,
132
+ icon: getSymbolIcon(treeNode.raw.kind) + ' outline-icon',
133
+ };
134
+ }),
135
+ );
136
+ return prevOutlineItems.current;
137
+ } else {
138
+ searchText = searchText.toLocaleLowerCase();
139
+ return prevOutlineItems.current.sort((a, b) => {
140
+ if (a.text.toLocaleLowerCase().includes(searchText) && b.text.toLocaleLowerCase().includes(searchText)) {
141
+ return 0;
142
+ }
143
+ if (a.text.toLocaleLowerCase().includes(searchText)) {
144
+ return -1;
145
+ } else if (b.text.toLocaleLowerCase().includes(searchText)) {
146
+ return 1;
147
+ }
148
+ return 0;
149
+ });
150
+ }
151
+ },
152
+ },
99
153
  {
100
154
  id: MentionType.FILE,
101
155
  type: MentionType.FILE,
@@ -194,7 +248,13 @@ export const ChatMentionInput = (props: IChatMentionInputProps) => {
194
248
  let folders: MentionItem[] = [];
195
249
  if (!searchText) {
196
250
  const recentFile = await recentFilesManager.getMostRecentlyOpenedFiles();
197
- const recentFolder = Array.from(new Set(recentFile.map((file) => new URI(file).parent.codeUri.fsPath)));
251
+ const recentFolder = Array.from(
252
+ new Set(
253
+ recentFile
254
+ .map((file) => new URI(file).parent.codeUri.fsPath)
255
+ .filter((folder) => folder !== workspaceService.workspace?.uri.toString() && folder !== '/'),
256
+ ),
257
+ );
198
258
  folders = await Promise.all(
199
259
  recentFolder.map(async (folder) => {
200
260
  const uri = new URI(folder);
@@ -354,6 +414,7 @@ export const ChatMentionInput = (props: IChatMentionInputProps) => {
354
414
  placeholder={localize('aiNative.chat.input.placeholder.default')}
355
415
  footerConfig={defaultMentionInputFooterOptions}
356
416
  onImageUpload={handleImageUpload}
417
+ contextService={contextService}
357
418
  />
358
419
  </div>
359
420
  );
@@ -12,8 +12,6 @@
12
12
  .editor_area {
13
13
  position: relative;
14
14
  padding: 0 15px;
15
- min-height: 42px;
16
- max-height: 105px;
17
15
  }
18
16
 
19
17
  .editor {
@@ -21,11 +19,11 @@
21
19
  background-color: transparent;
22
20
  border: none;
23
21
  font-size: 14px;
24
- line-height: 1.5;
22
+ line-height: 24px;
23
+ min-height: 72px;
24
+ max-height: 120px;
25
25
  outline: none;
26
26
  resize: none;
27
- min-height: 24px;
28
- max-height: 120px;
29
27
  overflow-y: auto;
30
28
  border-radius: 4px;
31
29
  word-break: break-word;
@@ -142,6 +140,43 @@
142
140
  display: flex;
143
141
  justify-content: center;
144
142
  }
143
+ .context_container {
144
+ display: flex;
145
+ align-items: center;
146
+ justify-content: center;
147
+ cursor: pointer;
148
+ .context_icon {
149
+ flex-grow: 0;
150
+ flex-shrink: 0;
151
+ :global(.kt-icon) {
152
+ font-size: 12px;
153
+ }
154
+ :global(.kticon-close) {
155
+ display: none;
156
+ }
157
+ }
158
+ &:hover {
159
+ .context_icon {
160
+ :global(.kticon-close) {
161
+ display: block;
162
+ }
163
+ :global(.kticon-out-link) {
164
+ display: none;
165
+ }
166
+ }
167
+ }
168
+ .context_description {
169
+ flex: 1;
170
+ margin-left: 3px;
171
+ margin-right: 10px;
172
+ text-align: left;
173
+ font-size: 11px;
174
+ overflow: hidden;
175
+ text-overflow: ellipsis;
176
+ white-space: nowrap;
177
+ color: var(--descriptionForeground);
178
+ }
179
+ }
145
180
 
146
181
  .mention_panel {
147
182
  background-color: var(--editor-background);
@@ -191,6 +226,7 @@
191
226
 
192
227
  .mention_item_left {
193
228
  display: flex;
229
+ max-width: 100%;
194
230
  align-items: center;
195
231
  flex: 1;
196
232
  }
@@ -198,7 +234,8 @@
198
234
  .mention_item_icon {
199
235
  margin-right: 8px;
200
236
  width: 18px;
201
- height: 18px;
237
+ height: 22px;
238
+ line-height: 22px !important;
202
239
  display: flex;
203
240
  align-items: center;
204
241
  justify-content: center;
@@ -216,6 +253,7 @@
216
253
  font-size: 13px;
217
254
  display: inline;
218
255
  flex: 1;
256
+ direction: rtl;
219
257
  text-overflow: ellipsis;
220
258
  overflow: hidden;
221
259
  white-space: nowrap;
@@ -236,6 +274,40 @@
236
274
  align-items: center;
237
275
  }
238
276
 
277
+ .context_item {
278
+ display: flex;
279
+ align-items: center;
280
+ background-color: var(--badge-background);
281
+ color: var(--badge-foreground);
282
+ border-radius: 4px;
283
+ padding: 2px 6px;
284
+ font-size: 12px;
285
+ }
286
+
287
+ .context_item_icon {
288
+ margin-right: 4px;
289
+ }
290
+
291
+ .context_item_text {
292
+ margin-right: 4px;
293
+ max-width: 150px;
294
+ overflow: hidden;
295
+ text-overflow: ellipsis;
296
+ white-space: nowrap;
297
+ }
298
+
299
+ .context_item_remove {
300
+ cursor: pointer;
301
+ font-size: 12px;
302
+ display: flex;
303
+ align-items: center;
304
+ opacity: 0.7;
305
+
306
+ &:hover {
307
+ opacity: 1;
308
+ }
309
+ }
310
+
239
311
  .back_button {
240
312
  background: none;
241
313
  border: none;
@@ -1,13 +1,23 @@
1
1
  import cls from 'classnames';
2
2
  import * as React from 'react';
3
3
 
4
- import { Popover, PopoverPosition, Select, getIcon } from '@opensumi/ide-core-browser/lib/components';
4
+ import { formatLocalize, getSymbolIcon, localize } from '@opensumi/ide-core-browser';
5
+ import { Icon, Popover, PopoverPosition, Select, getIcon } from '@opensumi/ide-core-browser/lib/components';
5
6
  import { EnhanceIcon } from '@opensumi/ide-core-browser/lib/components/ai-native';
6
7
  import { URI } from '@opensumi/ide-utils';
7
8
 
9
+ import { FileContext } from '../../../common/llm-context';
10
+
8
11
  import styles from './mention-input.module.less';
9
12
  import { MentionPanel } from './mention-panel';
10
- import { FooterButtonPosition, MENTION_KEYWORD, MentionInputProps, MentionItem, MentionState } from './types';
13
+ import {
14
+ FooterButtonPosition,
15
+ MENTION_KEYWORD,
16
+ MentionInputProps,
17
+ MentionItem,
18
+ MentionState,
19
+ MentionType,
20
+ } from './types';
11
21
 
12
22
  export const WHITE_SPACE_TEXT = '&nbsp;';
13
23
 
@@ -26,6 +36,7 @@ export const MentionInput: React.FC<MentionInputProps> = ({
26
36
  buttons: [],
27
37
  showModelSelector: false,
28
38
  },
39
+ contextService,
29
40
  }) => {
30
41
  const editorRef = React.useRef<HTMLDivElement>(null);
31
42
  const [mentionState, setMentionState] = React.useState<MentionState>({
@@ -53,8 +64,14 @@ export const MentionInput: React.FC<MentionInputProps> = ({
53
64
  const [historyIndex, setHistoryIndex] = React.useState<number>(-1);
54
65
  const [currentInput, setCurrentInput] = React.useState<string>('');
55
66
  const [isNavigatingHistory, setIsNavigatingHistory] = React.useState<boolean>(false);
67
+ const [attachedFiles, setAttachedFiles] = React.useState<{
68
+ files: FileContext[];
69
+ folders: FileContext[];
70
+ }>({
71
+ files: [],
72
+ folders: [],
73
+ });
56
74
 
57
- // 获取当前菜单项
58
75
  const getCurrentItems = (): MentionItem[] => {
59
76
  if (mentionState.level === 0) {
60
77
  return mentionItems;
@@ -70,7 +87,6 @@ export const MentionInput: React.FC<MentionInputProps> = ({
70
87
  return [];
71
88
  };
72
89
 
73
- // 添加防抖函数
74
90
  const useDebounce = <T,>(value: T, delay: number): T => {
75
91
  const [debouncedValue, setDebouncedValue] = React.useState<T>(value);
76
92
 
@@ -87,14 +103,12 @@ export const MentionInput: React.FC<MentionInputProps> = ({
87
103
  return debouncedValue;
88
104
  };
89
105
 
90
- // 使用防抖处理搜索文本
91
106
  const debouncedSecondLevelFilter = useDebounce(mentionState.secondLevelFilter, 300);
92
107
 
93
108
  React.useEffect(() => {
94
109
  setSelectedModel(footerConfig.defaultModel || '');
95
110
  }, [footerConfig.defaultModel]);
96
111
 
97
- // 监听搜索文本变化,实时更新二级菜单
98
112
  React.useEffect(() => {
99
113
  if (mentionState.level === 1 && mentionState.parentType && debouncedSecondLevelFilter !== undefined) {
100
114
  // 查找父级菜单项
@@ -162,6 +176,16 @@ export const MentionInput: React.FC<MentionInputProps> = ({
162
176
  }
163
177
  }, [debouncedSecondLevelFilter, mentionState.level, mentionState.parentType]);
164
178
 
179
+ React.useEffect(() => {
180
+ const disposable = contextService?.onDidContextFilesChangeEvent(({ attached, attachedFolders }) => {
181
+ setAttachedFiles({ files: attached, folders: attachedFolders });
182
+ });
183
+
184
+ return () => {
185
+ disposable?.dispose();
186
+ };
187
+ }, [contextService]);
188
+
165
189
  // 获取光标位置
166
190
  const getCursorPosition = (element: HTMLElement): number => {
167
191
  const selection = window.getSelection();
@@ -176,7 +200,6 @@ export const MentionInput: React.FC<MentionInputProps> = ({
176
200
  return preCaretRange.toString().length;
177
201
  };
178
202
 
179
- // 处理输入事件
180
203
  const handleInput = () => {
181
204
  // 如果用户开始输入,退出历史导航模式
182
205
  if (isNavigatingHistory) {
@@ -262,7 +285,7 @@ export const MentionInput: React.FC<MentionInputProps> = ({
262
285
  // 检查输入框高度,如果超过最大高度则添加滚动条
263
286
  if (editorRef.current) {
264
287
  const editorHeight = editorRef.current.scrollHeight;
265
- if (editorHeight > 120) {
288
+ if (editorHeight >= 120) {
266
289
  editorRef.current.style.overflowY = 'auto';
267
290
  } else {
268
291
  editorRef.current.style.overflowY = 'hidden';
@@ -665,15 +688,30 @@ export const MentionInput: React.FC<MentionInputProps> = ({
665
688
  mentionTag.dataset.contextId = item.contextId || '';
666
689
  mentionTag.contentEditable = 'false';
667
690
 
668
- // file folder 类型添加图标
669
- if (item.type === 'file' || item.type === 'folder') {
691
+ if (item.type === MentionType.FILE || item.type === MentionType.FOLDER) {
670
692
  // 创建图标容器
671
693
  const iconSpan = document.createElement('span');
672
694
  iconSpan.className = cls(
673
695
  styles.mention_icon,
674
- item.type === 'file' ? labelService?.getIcon(new URI(item.text)) : getIcon('folder'),
696
+ item.type === MentionType.FILE ? labelService?.getIcon(new URI(item.text)) : getIcon('folder'),
675
697
  );
676
698
  mentionTag.appendChild(iconSpan);
699
+ if (item.type === MentionType.FOLDER) {
700
+ contextService?.addFolderToContext(new URI(item.contextId), true);
701
+ } else {
702
+ contextService?.addFileToContext(new URI(item.contextId), undefined, true);
703
+ }
704
+ } else if (item.type === MentionType.CODE) {
705
+ const iconSpan = document.createElement('span');
706
+ iconSpan.className = cls(styles.mention_icon, item.kind && getSymbolIcon(item.kind) + ' outline-icon');
707
+ mentionTag.appendChild(iconSpan);
708
+ if (item.symbol) {
709
+ contextService?.addFileToContext(
710
+ new URI(item.contextId),
711
+ [item.symbol.range.startLineNumber, item.symbol.range.endLineNumber],
712
+ true,
713
+ );
714
+ }
677
715
  }
678
716
  const workspace = workspaceService?.workspace;
679
717
  let relativePath = item.text;
@@ -913,7 +951,6 @@ export const MentionInput: React.FC<MentionInputProps> = ({
913
951
  setHistoryIndex(-1);
914
952
  setIsNavigatingHistory(false);
915
953
  }
916
-
917
954
  if (onSend) {
918
955
  // 传递当前选择的模型和其他配置信息
919
956
  onSend(processedContent, {
@@ -931,6 +968,10 @@ export const MentionInput: React.FC<MentionInputProps> = ({
931
968
  }
932
969
  };
933
970
 
971
+ const handleClearContext = React.useCallback(() => {
972
+ contextService?.cleanFileContext();
973
+ }, [contextService]);
974
+
934
975
  const handleStop = React.useCallback(() => {
935
976
  if (onStop) {
936
977
  onStop();
@@ -962,6 +1003,11 @@ export const MentionInput: React.FC<MentionInputProps> = ({
962
1003
  [footerConfig.buttons],
963
1004
  );
964
1005
 
1006
+ const hasContext = React.useMemo(
1007
+ () => attachedFiles.files.length > 0 || attachedFiles.folders.length > 0,
1008
+ [attachedFiles],
1009
+ );
1010
+
965
1011
  return (
966
1012
  <div className={styles.input_container}>
967
1013
  {mentionState.active && (
@@ -1005,6 +1051,25 @@ export const MentionInput: React.FC<MentionInputProps> = ({
1005
1051
  </div>
1006
1052
  <div className={styles.right_control}>
1007
1053
  {renderButtons(FooterButtonPosition.RIGHT)}
1054
+ <Popover
1055
+ overlayClassName={styles.popover_icon}
1056
+ id={'ai-chat-clear-context'}
1057
+ position={PopoverPosition.top}
1058
+ content={localize('aiNative.chat.context.clear')}
1059
+ >
1060
+ <div className={styles.context_container} onClick={handleClearContext}>
1061
+ <div className={styles.context_icon}>
1062
+ <Icon icon='out-link' />
1063
+ <Icon icon='close' />
1064
+ </div>
1065
+ <div className={styles.context_description}>
1066
+ {formatLocalize(
1067
+ 'aiNative.chat.context.description',
1068
+ attachedFiles.files.length + attachedFiles.folders.length,
1069
+ )}
1070
+ </div>
1071
+ </div>
1072
+ </Popover>
1008
1073
  <Popover
1009
1074
  overlayClassName={styles.popover_icon}
1010
1075
  id={'ai-chat-send'}
@@ -1,3 +1,7 @@
1
+ import { DocumentSymbol, SymbolKind } from '@opensumi/ide-monaco';
2
+
3
+ import { LLMContextService } from '../../../common/llm-context';
4
+
1
5
  import type { LabelService } from '@opensumi/ide-core-browser';
2
6
  import type { IWorkspaceService } from '@opensumi/ide-workspace';
3
7
 
@@ -8,7 +12,9 @@ export interface MentionItem {
8
12
  value?: string;
9
13
  description?: string;
10
14
  contextId?: string;
15
+ symbol?: DocumentSymbol;
11
16
  icon?: string;
17
+ kind?: SymbolKind;
12
18
  getHighestLevelItems?: () => MentionItem[];
13
19
  getItems?: (searchText: string) => Promise<MentionItem[]>;
14
20
  }
@@ -82,6 +88,7 @@ export interface MentionInputProps {
82
88
  mentionKeyword?: string;
83
89
  labelService?: LabelService;
84
90
  workspaceService?: IWorkspaceService;
91
+ contextService?: LLMContextService;
85
92
  }
86
93
 
87
94
  export const MENTION_KEYWORD = '@';
@@ -45,6 +45,7 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
45
45
  private readonly onDidContextFilesChangeEmitter = new Emitter<{
46
46
  viewed: FileContext[];
47
47
  attached: FileContext[];
48
+ attachedFolders: FileContext[];
48
49
  version: number;
49
50
  }>();
50
51
  onDidContextFilesChangeEvent = this.onDidContextFilesChangeEmitter.event;
@@ -28,6 +28,7 @@ import { SumiReadableStream } from '@opensumi/ide-utils/lib/stream';
28
28
  import { IMarker } from '@opensumi/monaco-editor-core/esm/vs/platform/markers/common/markers';
29
29
 
30
30
  import { IChatWelcomeMessageContent, ISampleQuestions, ITerminalCommandSuggestionDesc } from '../common';
31
+ import { LLMContextService } from '../common/llm-context';
31
32
 
32
33
  import {
33
34
  ICodeEditsContextBean,
@@ -166,6 +167,7 @@ export type ChatInputRender = (props: {
166
167
  defaultAgentId?: string;
167
168
  command: string;
168
169
  setCommand: (theme: string) => void;
170
+ contextService?: LLMContextService;
169
171
  }) => React.ReactElement | React.JSX.Element;
170
172
  export type ChatViewHeaderRender = (props: {
171
173
  handleClear: () => any;
@@ -1,5 +1,3 @@
1
- import { DataContent } from 'ai';
2
-
3
1
  import { Event, URI } from '@opensumi/ide-core-common/lib/utils';
4
2
 
5
3
  export interface LLMContextService {
@@ -31,7 +29,12 @@ export interface LLMContextService {
31
29
  /**
32
30
  * 上下文文件变化事件
33
31
  */
34
- onDidContextFilesChangeEvent: Event<{ viewed: FileContext[]; attached: FileContext[]; version: number }>;
32
+ onDidContextFilesChangeEvent: Event<{
33
+ viewed: FileContext[];
34
+ attached: FileContext[];
35
+ attachedFolders: FileContext[];
36
+ version: number;
37
+ }>;
35
38
 
36
39
  /**
37
40
  * 从 context 中移除文件