@opensumi/ide-ai-native 3.7.2-next-1740107209.0 → 3.7.2-next-1740365741.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 (180) hide show
  1. package/lib/browser/ai-core.contribution.d.ts +3 -1
  2. package/lib/browser/ai-core.contribution.d.ts.map +1 -1
  3. package/lib/browser/ai-core.contribution.js +13 -1
  4. package/lib/browser/ai-core.contribution.js.map +1 -1
  5. package/lib/browser/chat/chat-manager.service.d.ts +30 -2
  6. package/lib/browser/chat/chat-manager.service.d.ts.map +1 -1
  7. package/lib/browser/chat/chat-manager.service.js +45 -1
  8. package/lib/browser/chat/chat-manager.service.js.map +1 -1
  9. package/lib/browser/chat/chat-model.d.ts +33 -6
  10. package/lib/browser/chat/chat-model.d.ts.map +1 -1
  11. package/lib/browser/chat/chat-model.js +50 -29
  12. package/lib/browser/chat/chat-model.js.map +1 -1
  13. package/lib/browser/chat/chat-proxy.service.d.ts +1 -1
  14. package/lib/browser/chat/chat-proxy.service.d.ts.map +1 -1
  15. package/lib/browser/chat/chat-proxy.service.js +1 -1
  16. package/lib/browser/chat/chat-proxy.service.js.map +1 -1
  17. package/lib/browser/chat/chat.internal.service.d.ts +4 -2
  18. package/lib/browser/chat/chat.internal.service.d.ts.map +1 -1
  19. package/lib/browser/chat/chat.internal.service.js +31 -12
  20. package/lib/browser/chat/chat.internal.service.js.map +1 -1
  21. package/lib/browser/chat/chat.module.less +8 -42
  22. package/lib/browser/chat/chat.view.d.ts.map +1 -1
  23. package/lib/browser/chat/chat.view.js +85 -31
  24. package/lib/browser/chat/chat.view.js.map +1 -1
  25. package/lib/browser/components/ChatContext/index.d.ts.map +1 -1
  26. package/lib/browser/components/ChatContext/index.js +18 -2
  27. package/lib/browser/components/ChatContext/index.js.map +1 -1
  28. package/lib/browser/components/ChatContext/style.module.less +12 -0
  29. package/lib/browser/components/ChatHistory.d.ts +21 -0
  30. package/lib/browser/components/ChatHistory.d.ts.map +1 -0
  31. package/lib/browser/components/ChatHistory.js +148 -0
  32. package/lib/browser/components/ChatHistory.js.map +1 -0
  33. package/lib/browser/components/ChatReply.d.ts.map +1 -1
  34. package/lib/browser/components/ChatReply.js +3 -1
  35. package/lib/browser/components/ChatReply.js.map +1 -1
  36. package/lib/browser/components/ChatThinking.js +1 -1
  37. package/lib/browser/components/ChatThinking.js.map +1 -1
  38. package/lib/browser/components/ChatToolRender.d.ts +1 -1
  39. package/lib/browser/components/ChatToolRender.d.ts.map +1 -1
  40. package/lib/browser/components/ChatToolRender.js +15 -18
  41. package/lib/browser/components/ChatToolRender.js.map +1 -1
  42. package/lib/browser/components/chat-history.css +139 -0
  43. package/lib/browser/components/components.module.less +2 -2
  44. package/lib/browser/components/utils.d.ts +2 -2
  45. package/lib/browser/context/llm-context.service.d.ts +1 -0
  46. package/lib/browser/context/llm-context.service.d.ts.map +1 -1
  47. package/lib/browser/context/llm-context.service.js +24 -18
  48. package/lib/browser/context/llm-context.service.js.map +1 -1
  49. package/lib/browser/index.d.ts.map +1 -1
  50. package/lib/browser/index.js +5 -13
  51. package/lib/browser/index.js.map +1 -1
  52. package/lib/browser/layout/layout.module.less +1 -1
  53. package/lib/browser/mcp/mcp-server.feature.registry.d.ts.map +1 -1
  54. package/lib/browser/mcp/mcp-server.feature.registry.js +2 -1
  55. package/lib/browser/mcp/mcp-server.feature.registry.js.map +1 -1
  56. package/lib/browser/mcp/tools/components/SearchResult.d.ts +11 -0
  57. package/lib/browser/mcp/tools/components/SearchResult.d.ts.map +1 -0
  58. package/lib/browser/mcp/tools/components/SearchResult.js +60 -0
  59. package/lib/browser/mcp/tools/components/SearchResult.js.map +1 -0
  60. package/lib/browser/mcp/tools/components/Terminal.d.ts +4 -0
  61. package/lib/browser/mcp/tools/components/Terminal.d.ts.map +1 -0
  62. package/lib/browser/mcp/tools/components/Terminal.js +64 -0
  63. package/lib/browser/mcp/tools/components/Terminal.js.map +1 -0
  64. package/lib/browser/mcp/tools/components/index.module.less +101 -0
  65. package/lib/browser/mcp/tools/{findFilesByNameSubstring.d.ts → fileSearch.d.ts} +3 -2
  66. package/lib/browser/mcp/tools/fileSearch.d.ts.map +1 -0
  67. package/lib/browser/mcp/tools/fileSearch.js +94 -0
  68. package/lib/browser/mcp/tools/fileSearch.js.map +1 -0
  69. package/lib/browser/mcp/tools/{getFileTextByPath.d.ts → grepSearch.d.ts} +4 -3
  70. package/lib/browser/mcp/tools/grepSearch.d.ts.map +1 -0
  71. package/lib/browser/mcp/tools/grepSearch.js +118 -0
  72. package/lib/browser/mcp/tools/grepSearch.js.map +1 -0
  73. package/lib/browser/mcp/tools/handlers/RunCommand.d.ts +43 -0
  74. package/lib/browser/mcp/tools/handlers/RunCommand.d.ts.map +1 -0
  75. package/lib/browser/mcp/tools/handlers/RunCommand.js +104 -0
  76. package/lib/browser/mcp/tools/handlers/RunCommand.js.map +1 -0
  77. package/lib/browser/mcp/tools/listDir.d.ts.map +1 -1
  78. package/lib/browser/mcp/tools/listDir.js +1 -0
  79. package/lib/browser/mcp/tools/listDir.js.map +1 -1
  80. package/lib/browser/mcp/tools/readFile.d.ts.map +1 -1
  81. package/lib/browser/mcp/tools/readFile.js +1 -0
  82. package/lib/browser/mcp/tools/readFile.js.map +1 -1
  83. package/lib/browser/mcp/tools/runTerminalCmd.d.ts +1 -6
  84. package/lib/browser/mcp/tools/runTerminalCmd.d.ts.map +1 -1
  85. package/lib/browser/mcp/tools/runTerminalCmd.js +9 -55
  86. package/lib/browser/mcp/tools/runTerminalCmd.js.map +1 -1
  87. package/lib/browser/model/msg-history-manager.d.ts +15 -0
  88. package/lib/browser/model/msg-history-manager.d.ts.map +1 -1
  89. package/lib/browser/model/msg-history-manager.js +28 -9
  90. package/lib/browser/model/msg-history-manager.js.map +1 -1
  91. package/lib/common/mcp-server-manager.d.ts +1 -1
  92. package/lib/common/mcp-server-manager.d.ts.map +1 -1
  93. package/lib/common/mcp-server-manager.js.map +1 -1
  94. package/lib/common/tool-invocation-registry.d.ts +2 -1
  95. package/lib/common/tool-invocation-registry.d.ts.map +1 -1
  96. package/lib/common/tool-invocation-registry.js.map +1 -1
  97. package/lib/node/base-language-model.d.ts.map +1 -1
  98. package/lib/node/base-language-model.js +1 -1
  99. package/lib/node/base-language-model.js.map +1 -1
  100. package/lib/node/mcp/sumi-mcp-server.d.ts +1 -1
  101. package/lib/node/mcp/sumi-mcp-server.d.ts.map +1 -1
  102. package/lib/node/mcp/sumi-mcp-server.js +5 -2
  103. package/lib/node/mcp/sumi-mcp-server.js.map +1 -1
  104. package/lib/node/mcp-server-manager-impl.d.ts +1 -1
  105. package/lib/node/mcp-server-manager-impl.d.ts.map +1 -1
  106. package/lib/node/mcp-server-manager-impl.js +4 -4
  107. package/lib/node/mcp-server-manager-impl.js.map +1 -1
  108. package/lib/node/mcp-server.d.ts +2 -2
  109. package/lib/node/mcp-server.d.ts.map +1 -1
  110. package/lib/node/mcp-server.js +2 -1
  111. package/lib/node/mcp-server.js.map +1 -1
  112. package/package.json +23 -22
  113. package/src/browser/ai-core.contribution.ts +13 -1
  114. package/src/browser/chat/chat-manager.service.ts +83 -7
  115. package/src/browser/chat/chat-model.ts +62 -12
  116. package/src/browser/chat/chat-proxy.service.ts +1 -1
  117. package/src/browser/chat/chat.internal.service.ts +23 -5
  118. package/src/browser/chat/chat.module.less +8 -42
  119. package/src/browser/chat/chat.view.tsx +143 -60
  120. package/src/browser/components/ChatContext/index.tsx +19 -3
  121. package/src/browser/components/ChatContext/style.module.less +12 -0
  122. package/src/browser/components/ChatHistory.tsx +292 -0
  123. package/src/browser/components/ChatReply.tsx +5 -1
  124. package/src/browser/components/ChatThinking.tsx +1 -1
  125. package/src/browser/components/ChatToolRender.tsx +13 -15
  126. package/src/browser/components/chat-history.css +139 -0
  127. package/src/browser/components/components.module.less +2 -2
  128. package/src/browser/context/llm-context.service.ts +30 -18
  129. package/src/browser/index.ts +5 -13
  130. package/src/browser/layout/layout.module.less +1 -1
  131. package/src/browser/mcp/mcp-server.feature.registry.ts +2 -1
  132. package/src/browser/mcp/tools/components/SearchResult.tsx +92 -0
  133. package/src/browser/mcp/tools/components/Terminal.tsx +97 -0
  134. package/src/browser/mcp/tools/components/index.module.less +101 -0
  135. package/src/browser/mcp/tools/fileSearch.ts +99 -0
  136. package/src/browser/mcp/tools/grepSearch.ts +121 -0
  137. package/src/browser/mcp/tools/handlers/RunCommand.ts +115 -0
  138. package/src/browser/mcp/tools/listDir.ts +1 -0
  139. package/src/browser/mcp/tools/readFile.ts +1 -0
  140. package/src/browser/mcp/tools/runTerminalCmd.ts +7 -68
  141. package/src/browser/model/msg-history-manager.ts +34 -1
  142. package/src/common/mcp-server-manager.ts +18 -13
  143. package/src/common/tool-invocation-registry.ts +122 -124
  144. package/src/node/base-language-model.ts +3 -2
  145. package/src/node/mcp/sumi-mcp-server.ts +5 -2
  146. package/src/node/mcp-server-manager-impl.ts +11 -4
  147. package/src/node/mcp-server.ts +3 -2
  148. package/lib/browser/mcp/tools/findFilesByNameSubstring.d.ts.map +0 -1
  149. package/lib/browser/mcp/tools/findFilesByNameSubstring.js +0 -91
  150. package/lib/browser/mcp/tools/findFilesByNameSubstring.js.map +0 -1
  151. package/lib/browser/mcp/tools/getCurrentFilePath.d.ts +0 -8
  152. package/lib/browser/mcp/tools/getCurrentFilePath.d.ts.map +0 -1
  153. package/lib/browser/mcp/tools/getCurrentFilePath.js +0 -48
  154. package/lib/browser/mcp/tools/getCurrentFilePath.js.map +0 -1
  155. package/lib/browser/mcp/tools/getFileTextByPath.d.ts.map +0 -1
  156. package/lib/browser/mcp/tools/getFileTextByPath.js +0 -96
  157. package/lib/browser/mcp/tools/getFileTextByPath.js.map +0 -1
  158. package/lib/browser/mcp/tools/getOpenEditorFileText.d.ts +0 -8
  159. package/lib/browser/mcp/tools/getOpenEditorFileText.d.ts.map +0 -1
  160. package/lib/browser/mcp/tools/getOpenEditorFileText.js +0 -49
  161. package/lib/browser/mcp/tools/getOpenEditorFileText.js.map +0 -1
  162. package/lib/browser/mcp/tools/getSelectedText.d.ts +0 -8
  163. package/lib/browser/mcp/tools/getSelectedText.d.ts.map +0 -1
  164. package/lib/browser/mcp/tools/getSelectedText.js +0 -56
  165. package/lib/browser/mcp/tools/getSelectedText.js.map +0 -1
  166. package/lib/browser/mcp/tools/replaceOpenEditorFile.d.ts +0 -8
  167. package/lib/browser/mcp/tools/replaceOpenEditorFile.d.ts.map +0 -1
  168. package/lib/browser/mcp/tools/replaceOpenEditorFile.js +0 -80
  169. package/lib/browser/mcp/tools/replaceOpenEditorFile.js.map +0 -1
  170. package/lib/browser/mcp/tools/replaceOpenEditorFileByDiffPreviewer.d.ts +0 -8
  171. package/lib/browser/mcp/tools/replaceOpenEditorFileByDiffPreviewer.d.ts.map +0 -1
  172. package/lib/browser/mcp/tools/replaceOpenEditorFileByDiffPreviewer.js +0 -83
  173. package/lib/browser/mcp/tools/replaceOpenEditorFileByDiffPreviewer.js.map +0 -1
  174. package/src/browser/mcp/tools/findFilesByNameSubstring.ts +0 -92
  175. package/src/browser/mcp/tools/getCurrentFilePath.ts +0 -48
  176. package/src/browser/mcp/tools/getFileTextByPath.ts +0 -96
  177. package/src/browser/mcp/tools/getOpenEditorFileText.ts +0 -49
  178. package/src/browser/mcp/tools/getSelectedText.ts +0 -56
  179. package/src/browser/mcp/tools/replaceOpenEditorFile.ts +0 -81
  180. package/src/browser/mcp/tools/replaceOpenEditorFileByDiffPreviewer.ts +0 -90
@@ -0,0 +1,292 @@
1
+ import cls from 'classnames';
2
+ import React, { FC, memo, useCallback, useEffect, useRef, useState } from 'react';
3
+
4
+ import { Icon, Input, Loading, Popover, PopoverPosition, PopoverTriggerType, getIcon } from '@opensumi/ide-components';
5
+ import './chat-history.css';
6
+ import { localize } from '@opensumi/ide-core-browser';
7
+ import { EnhanceIcon } from '@opensumi/ide-core-browser/lib/components/ai-native';
8
+
9
+ export interface IChatHistoryItem {
10
+ id: string;
11
+ title: string;
12
+ updatedAt: number;
13
+ loading: boolean;
14
+ }
15
+
16
+ export interface IChatHistoryProps {
17
+ title: string;
18
+ historyList: IChatHistoryItem[];
19
+ currentId?: string;
20
+ className?: string;
21
+ onNewChat: () => void;
22
+ onHistoryItemSelect: (item: IChatHistoryItem) => void;
23
+ onHistoryItemDelete: (item: IChatHistoryItem) => void;
24
+ onHistoryItemChange: (item: IChatHistoryItem, title: string) => void;
25
+ }
26
+
27
+ // 最大历史记录数
28
+ const MAX_HISTORY_LIST = 100;
29
+
30
+ const ChatHistory: FC<IChatHistoryProps> = memo(
31
+ ({
32
+ title,
33
+ historyList,
34
+ currentId,
35
+ onNewChat,
36
+ onHistoryItemSelect,
37
+ onHistoryItemChange,
38
+ onHistoryItemDelete,
39
+ className,
40
+ }) => {
41
+ const [historyTitleEditable, setHistoryTitleEditable] = useState<{
42
+ [key: string]: boolean;
43
+ } | null>(null);
44
+ const [searchValue, setSearchValue] = useState('');
45
+ const inputRef = useRef<any>(null);
46
+
47
+ // 处理搜索输入变化
48
+ const handleSearchChange = useCallback(
49
+ (event: React.ChangeEvent<HTMLInputElement>) => {
50
+ setSearchValue(event.target.value);
51
+ },
52
+ [searchValue],
53
+ );
54
+
55
+ // 处理历史记录项选择
56
+ const handleHistoryItemSelect = useCallback(
57
+ (item: IChatHistoryItem) => {
58
+ onHistoryItemSelect(item);
59
+ setSearchValue('');
60
+ },
61
+ [onHistoryItemSelect, searchValue],
62
+ );
63
+
64
+ // 处理标题编辑
65
+ const handleTitleEdit = useCallback(
66
+ (item: IChatHistoryItem) => {
67
+ setHistoryTitleEditable({
68
+ [item.id]: true,
69
+ });
70
+ },
71
+ [historyTitleEditable],
72
+ );
73
+
74
+ // 处理标题编辑完成
75
+ const handleTitleEditComplete = useCallback(
76
+ (item: IChatHistoryItem, newTitle: string) => {
77
+ setHistoryTitleEditable({
78
+ [item.id]: false,
79
+ });
80
+ onHistoryItemChange(item, newTitle);
81
+ },
82
+ [onHistoryItemChange, historyTitleEditable],
83
+ );
84
+
85
+ // 处理标题编辑取消
86
+ const handleTitleEditCancel = useCallback(
87
+ (item: IChatHistoryItem) => {
88
+ setHistoryTitleEditable({
89
+ [item.id]: false,
90
+ });
91
+ },
92
+ [historyTitleEditable],
93
+ );
94
+
95
+ // 处理新建聊天
96
+ const handleNewChat = useCallback(() => {
97
+ onNewChat();
98
+ }, [onNewChat]);
99
+
100
+ useEffect(() => {
101
+ if (historyTitleEditable) {
102
+ inputRef.current?.focus({ cursor: 'end' });
103
+ }
104
+ }, [historyTitleEditable]);
105
+
106
+ // 处理删除历史记录
107
+ const handleHistoryItemDelete = useCallback(
108
+ (item: IChatHistoryItem) => {
109
+ onHistoryItemDelete(item);
110
+ },
111
+ [onHistoryItemDelete],
112
+ );
113
+
114
+ // 获取时间标签
115
+ const getTimeKey = useCallback((diff: number): string => {
116
+ if (diff < 60 * 60 * 1000) {
117
+ const minutes = Math.floor(diff / (60 * 1000));
118
+ return minutes === 0 ? 'Just now' : `${minutes}m ago`;
119
+ } else if (diff < 24 * 60 * 60 * 1000) {
120
+ const hours = Math.floor(diff / (60 * 60 * 1000));
121
+ return `${hours}h ago`;
122
+ } else if (diff < 7 * 24 * 60 * 60 * 1000) {
123
+ const days = Math.floor(diff / (24 * 60 * 60 * 1000));
124
+ return `${days}d ago`;
125
+ } else if (diff < 30 * 24 * 60 * 60 * 1000) {
126
+ const weeks = Math.floor(diff / (7 * 24 * 60 * 60 * 1000));
127
+ return `${weeks}w ago`;
128
+ } else if (diff < 365 * 24 * 60 * 60 * 1000) {
129
+ const months = Math.floor(diff / (30 * 24 * 60 * 60 * 1000));
130
+ return `${months}mo ago`;
131
+ }
132
+ const years = Math.floor(diff / (365 * 24 * 60 * 60 * 1000));
133
+ return `${years}y ago`;
134
+ }, []);
135
+
136
+ // 格式化历史记录
137
+ const formatHistory = useCallback(
138
+ (list: IChatHistoryItem[]) => {
139
+ const now = new Date();
140
+ const result = [] as { key: string; items: typeof list }[];
141
+
142
+ list.forEach((item: IChatHistoryItem) => {
143
+ const updatedAt = new Date(item.updatedAt);
144
+ const diff = now.getTime() - updatedAt.getTime();
145
+ const key = getTimeKey(diff);
146
+
147
+ const existingGroup = result.find((group) => group.key === key);
148
+ if (existingGroup) {
149
+ existingGroup.items.push(item);
150
+ } else {
151
+ result.push({ key, items: [item] });
152
+ }
153
+ });
154
+
155
+ return result;
156
+ },
157
+ [getTimeKey],
158
+ );
159
+
160
+ // 渲染历史记录项
161
+ const renderHistoryItem = useCallback(
162
+ (item: IChatHistoryItem) => (
163
+ <div
164
+ key={item.id}
165
+ className={cls('dm-chat-history-item', item.id === currentId ? 'dm-chat-history-item-selected' : '')}
166
+ onClick={() => handleHistoryItemSelect(item)}
167
+ >
168
+ <div className='dm-chat-history-item-content'>
169
+ {item.loading ? (
170
+ <Loading />
171
+ ) : (
172
+ <Icon icon='message' style={{ width: '16px', height: '16px', marginRight: 4 }} />
173
+ )}
174
+ {!historyTitleEditable?.[item.id] ? (
175
+ <span id={`dm-chat-history-item-title-${item.id}`} className='dm-chat-history-item-title'>
176
+ {item.title}
177
+ </span>
178
+ ) : (
179
+ <Input
180
+ className='dm-chat-history-item-title'
181
+ defaultValue={item.title}
182
+ ref={inputRef}
183
+ onPressEnter={(e: any) => {
184
+ handleTitleEditComplete(item, e.target.value);
185
+ }}
186
+ onBlur={() => handleTitleEditCancel(item)}
187
+ />
188
+ )}
189
+ </div>
190
+ <div className='dm-chat-history-item-actions'>
191
+ {/* <EditOutlined
192
+ title={localize('aiNative.operate.chatHistory.edit')}
193
+ style={{ marginRight: 8 }}
194
+ onClick={(e) => {
195
+ e.preventDefault();
196
+ e.stopPropagation();
197
+ handleTitleEdit(item);
198
+ }}
199
+ /> */}
200
+ <EnhanceIcon
201
+ className={cls('dm-chat-history-item-actions-delete', getIcon('delete'))}
202
+ onClick={(e) => {
203
+ e.preventDefault();
204
+ e.stopPropagation();
205
+ handleHistoryItemDelete(item);
206
+ }}
207
+ ariaLabel={localize('aiNative.operate.chatHistory.delete')}
208
+ />
209
+ </div>
210
+ </div>
211
+ ),
212
+ [
213
+ historyTitleEditable,
214
+ handleHistoryItemSelect,
215
+ handleTitleEditComplete,
216
+ handleTitleEditCancel,
217
+ handleTitleEdit,
218
+ handleHistoryItemDelete,
219
+ currentId,
220
+ inputRef,
221
+ ],
222
+ );
223
+
224
+ // 渲染历史记录列表
225
+ const renderHistory = useCallback(() => {
226
+ const filteredList = historyList
227
+ .slice(0, MAX_HISTORY_LIST)
228
+ .filter((item) => item.title && item.title.includes(searchValue));
229
+
230
+ const groupedHistoryList = formatHistory(filteredList);
231
+
232
+ return (
233
+ <div>
234
+ <Input
235
+ placeholder={localize('aiNative.operate.chatHistory.searchPlaceholder')}
236
+ style={{ width: '100%', maxWidth: '100%' }}
237
+ value={searchValue}
238
+ onChange={handleSearchChange}
239
+ />
240
+ <div className='dm-chat-history-list'>
241
+ {groupedHistoryList.map((group) => (
242
+ <div key={group.key} style={{ padding: '4px' }}>
243
+ <div className='dm-chat-history-time'>{group.key}</div>
244
+ {group.items.map(renderHistoryItem)}
245
+ </div>
246
+ ))}
247
+ </div>
248
+ </div>
249
+ );
250
+ }, [historyList, searchValue, formatHistory, handleSearchChange, renderHistoryItem]);
251
+
252
+ // getPopupContainer 处理函数
253
+ const getPopupContainer = useCallback((triggerNode: HTMLElement) => triggerNode.parentElement!, []);
254
+
255
+ return (
256
+ <div className={cls('dm-chat-history-header', className)}>
257
+ <div className='dm-chat-history-header-title'>
258
+ <span>{title}</span>
259
+ </div>
260
+ <div className='dm-chat-history-header-actions'>
261
+ <Popover
262
+ id='dm-chat-history-header-actions-history'
263
+ content={renderHistory()}
264
+ trigger={PopoverTriggerType.click}
265
+ position={PopoverPosition.bottomRight}
266
+ title={localize('aiNative.operate.chatHistory.title')}
267
+ getPopupContainer={getPopupContainer}
268
+ >
269
+ <div
270
+ className='dm-chat-history-header-actions-history'
271
+ title={localize('aiNative.operate.chatHistory.title')}
272
+ >
273
+ <EnhanceIcon className={cls('dm-chat-history-header-actions-history', 'codicon codicon-history')} />
274
+ </div>
275
+ </Popover>
276
+ <Popover
277
+ id={'ai-chat-header-close'}
278
+ position={PopoverPosition.top}
279
+ title={localize('aiNative.operate.newChat.title')}
280
+ >
281
+ <EnhanceIcon
282
+ className={cls('dm-chat-history-header-actions-new', getIcon('plus'))}
283
+ onClick={handleNewChat}
284
+ />
285
+ </Popover>
286
+ </div>
287
+ </div>
288
+ );
289
+ },
290
+ );
291
+
292
+ export default ChatHistory;
@@ -360,7 +360,11 @@ export const ChatReply = (props: IChatReplyProps) => {
360
360
 
361
361
  return (
362
362
  <ChatThinkingResult
363
- hasMessage={request.response.responseParts.length > 0 || !!request.response.errorDetails?.message}
363
+ hasMessage={
364
+ request.response.responseParts.length > 0 ||
365
+ request.response.responseContents.length > 0 ||
366
+ !!request.response.errorDetails?.message
367
+ }
364
368
  onRegenerate={handleRegenerate}
365
369
  requestId={request.requestId}
366
370
  >
@@ -118,7 +118,7 @@ export const ChatThinkingResult = ({
118
118
 
119
119
  const isRenderRegenerate = useMemo(() => {
120
120
  if (isUndefined(showRegenerate)) {
121
- return latestRequestId === requestId;
121
+ return latestRequestId === requestId && !!requestId;
122
122
  }
123
123
 
124
124
  return !!showRegenerate;
@@ -54,8 +54,17 @@ export const ChatToolRender = (props: { value: IChatToolContent['content']; mess
54
54
 
55
55
  const stateInfo = getStateInfo(value.state);
56
56
 
57
- return [
58
- <div className={styles['chat-tool-render']} key='chat-tool-render'>
57
+ return ToolComponent && (value.state === 'complete' || value.state === 'result') ? (
58
+ <ToolComponent
59
+ state={value.state}
60
+ args={getParsedArgs()}
61
+ result={value.result}
62
+ index={value.index}
63
+ messageId={messageId}
64
+ toolCallId={value.id}
65
+ />
66
+ ) : (
67
+ <div className={styles['chat-tool-render']}>
59
68
  <div className={styles['tool-header']} onClick={toggleExpand}>
60
69
  <div className={styles['tool-name']}>
61
70
  <span className={cls(styles['expand-icon'], { [styles.expanded]: isExpanded })}>▶</span>
@@ -82,17 +91,6 @@ export const ChatToolRender = (props: { value: IChatToolContent['content']; mess
82
91
  </div>
83
92
  )}
84
93
  </div>
85
- </div>,
86
- ToolComponent && (
87
- <ToolComponent
88
- key='tool-component'
89
- state={value.state}
90
- args={getParsedArgs()}
91
- result={value.result}
92
- index={value.index}
93
- messageId={messageId}
94
- toolCallId={value.id}
95
- />
96
- ),
97
- ];
94
+ </div>
95
+ );
98
96
  };
@@ -0,0 +1,139 @@
1
+ .dm-chat-history-header {
2
+ display: flex;
3
+ align-items: center;
4
+ justify-content: space-between;
5
+ font-size: 13px;
6
+ padding: 0 4px 0 12px;
7
+ color: var(--editor-foreground);
8
+ text-overflow: ellipsis;
9
+ white-space: nowrap;
10
+
11
+ .dm-chat-history-header-title {
12
+ opacity: 0.6;
13
+ display: flex;
14
+ align-items: center;
15
+ overflow: hidden;
16
+ span {
17
+ overflow: hidden;
18
+ text-overflow: ellipsis;
19
+ max-width: calc(100vw - 80px);
20
+ display: inline-block;
21
+ white-space: nowrap;
22
+ }
23
+ }
24
+
25
+ .dm-chat-history-header-actions {
26
+ display: flex;
27
+ align-items: center;
28
+ font-size: 12px;
29
+
30
+ .dm-chat-history-header-actions-history {
31
+ cursor: pointer;
32
+ }
33
+
34
+ .dm-chat-history-header-actions-new {
35
+ margin-left: 2px;
36
+ cursor: pointer;
37
+ }
38
+
39
+ .kt-popover-title {
40
+ margin-bottom: 8px;
41
+ }
42
+ }
43
+
44
+ .kt-popover {
45
+ .kt-popover-content {
46
+ width: 300px;
47
+ }
48
+ .kt-popover-content {
49
+ color: var(--editor-foreground);
50
+ background-color: var(--editor-background);
51
+ padding: 12px 12px;
52
+ border-radius: 3px;
53
+ box-shadow: 0 0 8px 2px var(--widget-shadow);
54
+ }
55
+ .kt-popover-title {
56
+ color: var(--editor-foreground);
57
+ font-size: 13px;
58
+ }
59
+ .kt-input {
60
+ color: var(--input-foreground);
61
+ background: var(--input-background);
62
+ border: 1px solid var(--input-border);
63
+ text-align: left;
64
+ height: 24px;
65
+ font-size: 13px;
66
+ border-radius: 4px;
67
+ &:focus {
68
+ border-color: var(--inputValidation-infoBorder);
69
+ }
70
+
71
+ &::placeholder {
72
+ color: var(--input-placeholderForeground);
73
+ opacity: 0.6;
74
+ }
75
+ }
76
+ }
77
+
78
+ .dm-chat-history-list {
79
+ overflow: auto;
80
+ max-height: 400px;
81
+ margin-top: 4px;
82
+ font-size: 13px;
83
+ }
84
+
85
+ .dm-chat-history-time {
86
+ opacity: 0.6;
87
+ padding-left: 4px;
88
+ }
89
+
90
+ .dm-chat-history-item {
91
+ display: flex;
92
+ align-items: center;
93
+ justify-content: space-between;
94
+ cursor: pointer;
95
+ padding: 4px;
96
+ margin-top: 2px;
97
+ border-radius: 3px;
98
+
99
+ .dm-chat-history-item-content {
100
+ display: flex;
101
+ align-items: center;
102
+ width: 100%;
103
+ max-width: 100%;
104
+ height: 24px;
105
+ }
106
+
107
+ .dm-chat-history-item-title {
108
+ overflow: hidden;
109
+ text-overflow: ellipsis;
110
+ display: inline-block;
111
+ white-space: nowrap;
112
+ }
113
+
114
+ .dm-chat-history-item-actions {
115
+ display: none;
116
+ }
117
+
118
+ .dm-chat-history-item-selected {
119
+ background: var(--textPreformat-background);
120
+ }
121
+
122
+ &:hover {
123
+ background: var(--textPreformat-background);
124
+
125
+ .dm-chat-history-item-actions {
126
+ display: block;
127
+ }
128
+ .dm-chat-history-item-content {
129
+ max-width: calc(100% - 50px);
130
+ }
131
+ }
132
+ }
133
+
134
+ svg {
135
+ path {
136
+ fill: var(--foreground);
137
+ }
138
+ }
139
+ }
@@ -35,7 +35,7 @@
35
35
  }
36
36
 
37
37
  .thinking_text {
38
- font-size: 14px;
38
+ font-size: 12px;
39
39
  }
40
40
 
41
41
  .bottom_container {
@@ -480,7 +480,7 @@
480
480
  * welcome
481
481
  */
482
482
  .chat_welcome_head {
483
- font-size: 14px;
483
+ font-size: 12px;
484
484
  line-height: 22px;
485
485
  a {
486
486
  color: #3c8dff;
@@ -27,32 +27,40 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
27
27
 
28
28
  private isAutoCollecting = false;
29
29
 
30
- private contextFiles: Map<string, FileContext> = new Map();
30
+ private contextFiles: FileContext[] = [];
31
+
32
+ private maxFiles: number = 10; // 上下文的最大长度限制
31
33
 
32
34
  private onDidContextFilesChangeEmitter = new Emitter<FileContext[]>();
33
35
  onDidContextFilesChangeEvent = this.onDidContextFilesChangeEmitter.event;
34
36
 
35
37
  addFileToContext(uri: URI, selection?: [number, number], isManual = true): void {
36
- this.contextFiles.set(uri.toString(), {
37
- uri,
38
- selection,
39
- isManual,
40
- });
38
+ this.removeFileFromContext(uri);
39
+
40
+ this.contextFiles.push({ uri, selection, isManual });
41
+
42
+ if (this.contextFiles.length > this.maxFiles) {
43
+ this.contextFiles.shift();
44
+ }
45
+
41
46
  this.onDidContextFilesChangeEmitter.fire(this.getAllContextFiles());
42
47
  }
43
48
 
44
49
  cleanFileContext() {
45
- this.contextFiles.clear();
50
+ this.contextFiles = [];
46
51
  this.onDidContextFilesChangeEmitter.fire(this.getAllContextFiles());
47
52
  }
48
53
 
49
54
  private getAllContextFiles() {
50
- return Array.from(this.contextFiles.values());
55
+ return [...this.contextFiles];
51
56
  }
52
57
 
53
58
  removeFileFromContext(uri: URI): void {
54
- this.contextFiles.delete(uri.toString());
55
- this.onDidContextFilesChangeEmitter.fire(this.getAllContextFiles());
59
+ const index = this.contextFiles.findIndex((file) => file.uri.toString() === uri.toString());
60
+ if (index > -1) {
61
+ this.contextFiles.splice(index, 1);
62
+ this.onDidContextFilesChangeEmitter.fire(this.getAllContextFiles());
63
+ }
56
64
  }
57
65
 
58
66
  startAutoCollection(): void {
@@ -65,18 +73,16 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
65
73
  }
66
74
 
67
75
  private startAutoCollectionInternal(): void {
68
- // 文件打开
69
76
  this.disposables.push(
70
77
  this.eventBus.on(EditorDocumentModelCreationEvent, (event) => {
71
78
  if (event.payload.uri.scheme !== 'file') {
72
79
  return;
73
80
  }
74
- // TODO: 是否自动添加文件到上下文?
81
+ // FIXME: 暂时不自动添加
75
82
  // this.addFileToContext(event.payload.uri);
76
83
  }),
77
84
  );
78
85
 
79
- // 删除
80
86
  this.disposables.push(
81
87
  this.eventBus.on(EditorDocumentModelRemovalEvent, (event) => {
82
88
  if (event.payload.scheme !== 'file') {
@@ -85,16 +91,15 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
85
91
  }),
86
92
  );
87
93
 
88
- // 保存
89
94
  this.disposables.push(
90
95
  this.eventBus.on(EditorDocumentModelSavedEvent, (event) => {
91
96
  if (event.payload.scheme !== 'file') {
92
97
  return;
93
98
  }
99
+ // TODO: 保存文件的逻辑
94
100
  }),
95
101
  );
96
102
 
97
- // 光标选中
98
103
  this.disposables.push(
99
104
  this.eventBus.on(EditorSelectionChangeEvent, (event) => {
100
105
  if (event.payload.selections.length > 0) {
@@ -102,9 +107,9 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
102
107
  event.payload.selections[0].selectionStartLineNumber,
103
108
  event.payload.selections[0].positionLineNumber,
104
109
  ].sort() as [number, number];
110
+
105
111
  if (selection[0] === selection[1]) {
106
- // TODO: 是否自动添加文件到上下文?
107
- // this.addFileToContext(event.payload.editorUri, undefined);
112
+ this.addFileToContext(event.payload.editorUri, undefined);
108
113
  } else {
109
114
  this.addFileToContext(
110
115
  event.payload.editorUri,
@@ -124,8 +129,15 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
124
129
  const files = this.getAllContextFiles();
125
130
  const recentlyViewFiles = files
126
131
  .filter((v) => !v.selection)
127
- .map((file) => URI.file(this.appConfig.workspaceDir).relative(file.uri)!.toString())
132
+ .map((file) => {
133
+ const relativePath = URI.file(this.appConfig.workspaceDir).relative(file.uri);
134
+ if (relativePath) {
135
+ return relativePath.toString();
136
+ }
137
+ return file.uri.parent.toString();
138
+ })
128
139
  .filter(Boolean);
140
+
129
141
  const attachedFiles = files
130
142
  .filter((v) => v.selection)
131
143
  .map((file) => {
@@ -59,16 +59,12 @@ import { MCPServerProxyService } from './mcp/mcp-server-proxy.service';
59
59
  import { MCPServerRegistry } from './mcp/mcp-server.feature.registry';
60
60
  import { CreateNewFileWithTextTool } from './mcp/tools/createNewFileWithText';
61
61
  import { EditFileTool } from './mcp/tools/editFile';
62
- import { FindFilesByNameSubstringTool } from './mcp/tools/findFilesByNameSubstring';
63
- import { GetCurrentFilePathTool } from './mcp/tools/getCurrentFilePath';
62
+ import { FileSearchTool } from './mcp/tools/fileSearch';
64
63
  import { GetDiagnosticsByPathTool } from './mcp/tools/getDiagnosticsByPath';
65
- import { GetFileTextByPathTool } from './mcp/tools/getFileTextByPath';
66
64
  import { GetOpenEditorFileDiagnosticsTool } from './mcp/tools/getOpenEditorFileDiagnostics';
67
- import { GetOpenEditorFileTextTool } from './mcp/tools/getOpenEditorFileText';
68
- import { GetSelectedTextTool } from './mcp/tools/getSelectedText';
65
+ import { GrepSearchTool } from './mcp/tools/grepSearch';
69
66
  import { ListDirTool } from './mcp/tools/listDir';
70
67
  import { ReadFileTool } from './mcp/tools/readFile';
71
- import { ReplaceOpenEditorFileByDiffPreviewerTool } from './mcp/tools/replaceOpenEditorFileByDiffPreviewer';
72
68
  import { RunTerminalCommandTool } from './mcp/tools/runTerminalCmd';
73
69
  import { AINativePreferencesContribution } from './preferences';
74
70
  import { AINativeCoreContribution, MCPServerContribution, TokenMCPServerRegistry } from './types';
@@ -101,15 +97,11 @@ export class AINativeModule extends BrowserModule {
101
97
  ReadFileTool,
102
98
  EditFileTool,
103
99
  CreateNewFileWithTextTool,
104
- GetSelectedTextTool,
105
100
  GetOpenEditorFileDiagnosticsTool,
106
- GetOpenEditorFileTextTool,
107
- GetFileTextByPathTool,
108
- GetCurrentFilePathTool,
109
- FindFilesByNameSubstringTool,
101
+ FileSearchTool,
102
+ GrepSearchTool,
110
103
  GetDiagnosticsByPathTool,
111
104
  RunTerminalCommandTool,
112
- ReplaceOpenEditorFileByDiffPreviewerTool,
113
105
  // MCP Server Contributions END
114
106
 
115
107
  // Context Service
@@ -201,7 +193,7 @@ export class AINativeModule extends BrowserModule {
201
193
  },
202
194
  {
203
195
  token: ChatAgentPromptProvider,
204
- useValue: DefaultChatAgentPromptProvider,
196
+ useClass: DefaultChatAgentPromptProvider,
205
197
  },
206
198
  ];
207
199
 
@@ -23,7 +23,7 @@
23
23
  .rce-mbox-text {
24
24
  line-height: 18px;
25
25
  width: inherit;
26
- font-size: 14px;
26
+ font-size: 12px;
27
27
  }
28
28
 
29
29
  .rce-smsg {
@@ -62,8 +62,9 @@ export class MCPServerRegistry implements IMCPServerRegistry {
62
62
  throw new Error(`MCP tool ${name} not found`);
63
63
  }
64
64
  // 统一校验并转换
65
+ const toolCallId = args.toolCallId;
65
66
  args = tool.inputSchema.parse(args);
66
- return await tool.handler(args, this.logger);
67
+ return await tool.handler({ ...args, toolCallId }, this.logger);
67
68
  } catch (error) {
68
69
  // eslint-disable-next-line no-console
69
70
  console.error('callMCPTool error:', error);