@opensumi/ide-ai-native 3.7.2-next-1739848467.0 → 3.7.2-next-1739945875.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 (227) hide show
  1. package/lib/browser/ai-core.contribution.d.ts +3 -0
  2. package/lib/browser/ai-core.contribution.d.ts.map +1 -1
  3. package/lib/browser/ai-core.contribution.js +68 -2
  4. package/lib/browser/ai-core.contribution.js.map +1 -1
  5. package/lib/browser/chat/chat-model.d.ts +2 -2
  6. package/lib/browser/chat/chat-model.d.ts.map +1 -1
  7. package/lib/browser/chat/chat-model.js +16 -5
  8. package/lib/browser/chat/chat-model.js.map +1 -1
  9. package/lib/browser/chat/chat-proxy.service.d.ts +4 -0
  10. package/lib/browser/chat/chat-proxy.service.d.ts.map +1 -1
  11. package/lib/browser/chat/chat-proxy.service.js +43 -0
  12. package/lib/browser/chat/chat-proxy.service.js.map +1 -1
  13. package/lib/browser/chat/chat.view.d.ts.map +1 -1
  14. package/lib/browser/chat/chat.view.js +29 -2
  15. package/lib/browser/chat/chat.view.js.map +1 -1
  16. package/lib/browser/components/ChatContext/ContextSelector.d.ts +12 -0
  17. package/lib/browser/components/ChatContext/ContextSelector.d.ts.map +1 -0
  18. package/lib/browser/components/ChatContext/ContextSelector.js +113 -0
  19. package/lib/browser/components/ChatContext/ContextSelector.js.map +1 -0
  20. package/lib/browser/components/ChatContext/index.d.ts +4 -0
  21. package/lib/browser/components/ChatContext/index.d.ts.map +1 -0
  22. package/lib/browser/components/ChatContext/index.js +84 -0
  23. package/lib/browser/components/ChatContext/index.js.map +1 -0
  24. package/lib/browser/components/ChatContext/style.module.less +189 -0
  25. package/lib/browser/components/ChatInput.d.ts.map +1 -1
  26. package/lib/browser/components/ChatInput.js.map +1 -1
  27. package/lib/browser/components/ChatReply.d.ts.map +1 -1
  28. package/lib/browser/components/ChatReply.js +25 -0
  29. package/lib/browser/components/ChatReply.js.map +1 -1
  30. package/lib/browser/components/ChatToolRender.d.ts +6 -0
  31. package/lib/browser/components/ChatToolRender.d.ts.map +1 -0
  32. package/lib/browser/components/ChatToolRender.js +53 -0
  33. package/lib/browser/components/ChatToolRender.js.map +1 -0
  34. package/lib/browser/components/ChatToolRender.module.less +86 -0
  35. package/lib/browser/components/components.module.less +32 -31
  36. package/lib/browser/components/utils.d.ts +2 -2
  37. package/lib/browser/context/llm-context.contribution.d.ts +7 -0
  38. package/lib/browser/context/llm-context.contribution.d.ts.map +1 -0
  39. package/lib/browser/context/llm-context.contribution.js +21 -0
  40. package/lib/browser/context/llm-context.contribution.js.map +1 -0
  41. package/lib/browser/context/llm-context.service.d.ts +24 -0
  42. package/lib/browser/context/llm-context.service.d.ts.map +1 -0
  43. package/lib/browser/context/llm-context.service.js +136 -0
  44. package/lib/browser/context/llm-context.service.js.map +1 -0
  45. package/lib/browser/index.d.ts +11 -3
  46. package/lib/browser/index.d.ts.map +1 -1
  47. package/lib/browser/index.js +56 -3
  48. package/lib/browser/index.js.map +1 -1
  49. package/lib/browser/mcp/mcp-server-proxy.service.d.ts +25 -0
  50. package/lib/browser/mcp/mcp-server-proxy.service.d.ts.map +1 -0
  51. package/lib/browser/mcp/mcp-server-proxy.service.js +56 -0
  52. package/lib/browser/mcp/mcp-server-proxy.service.js.map +1 -0
  53. package/lib/browser/mcp/mcp-server.feature.registry.d.ts +16 -0
  54. package/lib/browser/mcp/mcp-server.feature.registry.d.ts.map +1 -0
  55. package/lib/browser/mcp/mcp-server.feature.registry.js +53 -0
  56. package/lib/browser/mcp/mcp-server.feature.registry.js.map +1 -0
  57. package/lib/browser/mcp/mcp-tools-dialog.module.less +44 -0
  58. package/lib/browser/mcp/mcp-tools-dialog.view.d.ts +8 -0
  59. package/lib/browser/mcp/mcp-tools-dialog.view.d.ts.map +1 -0
  60. package/lib/browser/mcp/mcp-tools-dialog.view.js +16 -0
  61. package/lib/browser/mcp/mcp-tools-dialog.view.js.map +1 -0
  62. package/lib/browser/mcp/tools/createNewFileWithText.d.ts +9 -0
  63. package/lib/browser/mcp/tools/createNewFileWithText.d.ts.map +1 -0
  64. package/lib/browser/mcp/tools/createNewFileWithText.js +83 -0
  65. package/lib/browser/mcp/tools/createNewFileWithText.js.map +1 -0
  66. package/lib/browser/mcp/tools/findFilesByNameSubstring.d.ts +9 -0
  67. package/lib/browser/mcp/tools/findFilesByNameSubstring.d.ts.map +1 -0
  68. package/lib/browser/mcp/tools/findFilesByNameSubstring.js +92 -0
  69. package/lib/browser/mcp/tools/findFilesByNameSubstring.js.map +1 -0
  70. package/lib/browser/mcp/tools/getCurrentFilePath.d.ts +8 -0
  71. package/lib/browser/mcp/tools/getCurrentFilePath.d.ts.map +1 -0
  72. package/lib/browser/mcp/tools/getCurrentFilePath.js +49 -0
  73. package/lib/browser/mcp/tools/getCurrentFilePath.js.map +1 -0
  74. package/lib/browser/mcp/tools/getDiagnosticsByPath.d.ts +10 -0
  75. package/lib/browser/mcp/tools/getDiagnosticsByPath.d.ts.map +1 -0
  76. package/lib/browser/mcp/tools/getDiagnosticsByPath.js +119 -0
  77. package/lib/browser/mcp/tools/getDiagnosticsByPath.js.map +1 -0
  78. package/lib/browser/mcp/tools/getFileTextByPath.d.ts +9 -0
  79. package/lib/browser/mcp/tools/getFileTextByPath.d.ts.map +1 -0
  80. package/lib/browser/mcp/tools/getFileTextByPath.js +97 -0
  81. package/lib/browser/mcp/tools/getFileTextByPath.js.map +1 -0
  82. package/lib/browser/mcp/tools/getOpenEditorFileDiagnostics.d.ts +11 -0
  83. package/lib/browser/mcp/tools/getOpenEditorFileDiagnostics.d.ts.map +1 -0
  84. package/lib/browser/mcp/tools/getOpenEditorFileDiagnostics.js +119 -0
  85. package/lib/browser/mcp/tools/getOpenEditorFileDiagnostics.js.map +1 -0
  86. package/lib/browser/mcp/tools/getOpenEditorFileText.d.ts +8 -0
  87. package/lib/browser/mcp/tools/getOpenEditorFileText.d.ts.map +1 -0
  88. package/lib/browser/mcp/tools/getOpenEditorFileText.js +50 -0
  89. package/lib/browser/mcp/tools/getOpenEditorFileText.js.map +1 -0
  90. package/lib/browser/mcp/tools/getSelectedText.d.ts +8 -0
  91. package/lib/browser/mcp/tools/getSelectedText.d.ts.map +1 -0
  92. package/lib/browser/mcp/tools/getSelectedText.js +57 -0
  93. package/lib/browser/mcp/tools/getSelectedText.js.map +1 -0
  94. package/lib/browser/mcp/tools/handlers/ListDir.d.ts +21 -0
  95. package/lib/browser/mcp/tools/handlers/ListDir.d.ts.map +1 -0
  96. package/lib/browser/mcp/tools/handlers/ListDir.js +112 -0
  97. package/lib/browser/mcp/tools/handlers/ListDir.js.map +1 -0
  98. package/lib/browser/mcp/tools/handlers/ReadFile.d.ts +47 -0
  99. package/lib/browser/mcp/tools/handlers/ReadFile.d.ts.map +1 -0
  100. package/lib/browser/mcp/tools/handlers/ReadFile.js +147 -0
  101. package/lib/browser/mcp/tools/handlers/ReadFile.js.map +1 -0
  102. package/lib/browser/mcp/tools/listDir.d.ts +8 -0
  103. package/lib/browser/mcp/tools/listDir.d.ts.map +1 -0
  104. package/lib/browser/mcp/tools/listDir.js +65 -0
  105. package/lib/browser/mcp/tools/listDir.js.map +1 -0
  106. package/lib/browser/mcp/tools/readFile.d.ts +8 -0
  107. package/lib/browser/mcp/tools/readFile.d.ts.map +1 -0
  108. package/lib/browser/mcp/tools/readFile.js +82 -0
  109. package/lib/browser/mcp/tools/readFile.js.map +1 -0
  110. package/lib/browser/mcp/tools/replaceOpenEditorFile.d.ts +8 -0
  111. package/lib/browser/mcp/tools/replaceOpenEditorFile.d.ts.map +1 -0
  112. package/lib/browser/mcp/tools/replaceOpenEditorFile.js +79 -0
  113. package/lib/browser/mcp/tools/replaceOpenEditorFile.js.map +1 -0
  114. package/lib/browser/mcp/tools/replaceOpenEditorFileByDiffPreviewer.d.ts +8 -0
  115. package/lib/browser/mcp/tools/replaceOpenEditorFileByDiffPreviewer.d.ts.map +1 -0
  116. package/lib/browser/mcp/tools/replaceOpenEditorFileByDiffPreviewer.js +84 -0
  117. package/lib/browser/mcp/tools/replaceOpenEditorFileByDiffPreviewer.js.map +1 -0
  118. package/lib/browser/mcp/tools/runTerminalCmd.d.ts +18 -0
  119. package/lib/browser/mcp/tools/runTerminalCmd.d.ts.map +1 -0
  120. package/lib/browser/mcp/tools/runTerminalCmd.js +96 -0
  121. package/lib/browser/mcp/tools/runTerminalCmd.js.map +1 -0
  122. package/lib/browser/preferences/schema.d.ts.map +1 -1
  123. package/lib/browser/preferences/schema.js +60 -0
  124. package/lib/browser/preferences/schema.js.map +1 -1
  125. package/lib/browser/types.d.ts +45 -0
  126. package/lib/browser/types.d.ts.map +1 -1
  127. package/lib/browser/types.js +5 -1
  128. package/lib/browser/types.js.map +1 -1
  129. package/lib/common/index.d.ts +9 -0
  130. package/lib/common/index.d.ts.map +1 -1
  131. package/lib/common/index.js +4 -1
  132. package/lib/common/index.js.map +1 -1
  133. package/lib/common/llm-context.d.ts +37 -0
  134. package/lib/common/llm-context.d.ts.map +1 -0
  135. package/lib/common/llm-context.js +5 -0
  136. package/lib/common/llm-context.js.map +1 -0
  137. package/lib/common/mcp-server-manager.d.ts +40 -0
  138. package/lib/common/mcp-server-manager.d.ts.map +1 -0
  139. package/lib/common/mcp-server-manager.js +6 -0
  140. package/lib/common/mcp-server-manager.js.map +1 -0
  141. package/lib/common/tool-invocation-registry.d.ts +91 -0
  142. package/lib/common/tool-invocation-registry.d.ts.map +1 -0
  143. package/lib/common/tool-invocation-registry.js +90 -0
  144. package/lib/common/tool-invocation-registry.js.map +1 -0
  145. package/lib/common/types.d.ts +17 -0
  146. package/lib/common/types.d.ts.map +1 -1
  147. package/lib/node/anthropic/anthropic-language-model.d.ts +9 -0
  148. package/lib/node/anthropic/anthropic-language-model.d.ts.map +1 -0
  149. package/lib/node/anthropic/anthropic-language-model.js +26 -0
  150. package/lib/node/anthropic/anthropic-language-model.js.map +1 -0
  151. package/lib/node/base-language-model.d.ts +14 -0
  152. package/lib/node/base-language-model.d.ts.map +1 -0
  153. package/lib/node/base-language-model.js +136 -0
  154. package/lib/node/base-language-model.js.map +1 -0
  155. package/lib/node/deepseek/deepseek-language-model.d.ts +9 -0
  156. package/lib/node/deepseek/deepseek-language-model.d.ts.map +1 -0
  157. package/lib/node/deepseek/deepseek-language-model.js +26 -0
  158. package/lib/node/deepseek/deepseek-language-model.js.map +1 -0
  159. package/lib/node/index.d.ts.map +1 -1
  160. package/lib/node/index.js +19 -0
  161. package/lib/node/index.js.map +1 -1
  162. package/lib/node/mcp/sumi-mcp-server.d.ts +91 -0
  163. package/lib/node/mcp/sumi-mcp-server.d.ts.map +1 -0
  164. package/lib/node/mcp/sumi-mcp-server.js +172 -0
  165. package/lib/node/mcp/sumi-mcp-server.js.map +1 -0
  166. package/lib/node/mcp-server-manager-impl.d.ts +27 -0
  167. package/lib/node/mcp-server-manager-impl.d.ts.map +1 -0
  168. package/lib/node/mcp-server-manager-impl.js +127 -0
  169. package/lib/node/mcp-server-manager-impl.js.map +1 -0
  170. package/lib/node/mcp-server.d.ts +207 -0
  171. package/lib/node/mcp-server.d.ts.map +1 -0
  172. package/lib/node/mcp-server.js +91 -0
  173. package/lib/node/mcp-server.js.map +1 -0
  174. package/lib/node/openai/openai-language-model.d.ts +9 -0
  175. package/lib/node/openai/openai-language-model.d.ts.map +1 -0
  176. package/lib/node/openai/openai-language-model.js +29 -0
  177. package/lib/node/openai/openai-language-model.js.map +1 -0
  178. package/package.json +34 -22
  179. package/src/browser/ai-core.contribution.ts +77 -1
  180. package/src/browser/chat/chat-model.ts +24 -6
  181. package/src/browser/chat/chat-proxy.service.ts +42 -0
  182. package/src/browser/chat/chat.view.tsx +59 -6
  183. package/src/browser/components/ChatContext/ContextSelector.tsx +177 -0
  184. package/src/browser/components/ChatContext/index.tsx +135 -0
  185. package/src/browser/components/ChatContext/style.module.less +189 -0
  186. package/src/browser/components/ChatInput.tsx +1 -0
  187. package/src/browser/components/ChatReply.tsx +32 -0
  188. package/src/browser/components/ChatToolRender.module.less +86 -0
  189. package/src/browser/components/ChatToolRender.tsx +77 -0
  190. package/src/browser/components/components.module.less +32 -31
  191. package/src/browser/context/llm-context.contribution.ts +14 -0
  192. package/src/browser/context/llm-context.service.ts +156 -0
  193. package/src/browser/index.ts +68 -4
  194. package/src/browser/mcp/mcp-server-proxy.service.ts +53 -0
  195. package/src/browser/mcp/mcp-server.feature.registry.ts +54 -0
  196. package/src/browser/mcp/mcp-tools-dialog.module.less +44 -0
  197. package/src/browser/mcp/mcp-tools-dialog.view.tsx +24 -0
  198. package/src/browser/mcp/tools/createNewFileWithText.ts +83 -0
  199. package/src/browser/mcp/tools/findFilesByNameSubstring.ts +93 -0
  200. package/src/browser/mcp/tools/getCurrentFilePath.ts +49 -0
  201. package/src/browser/mcp/tools/getDiagnosticsByPath.ts +123 -0
  202. package/src/browser/mcp/tools/getFileTextByPath.ts +97 -0
  203. package/src/browser/mcp/tools/getOpenEditorFileDiagnostics.ts +121 -0
  204. package/src/browser/mcp/tools/getOpenEditorFileText.ts +50 -0
  205. package/src/browser/mcp/tools/getSelectedText.ts +57 -0
  206. package/src/browser/mcp/tools/handlers/ListDir.ts +117 -0
  207. package/src/browser/mcp/tools/handlers/ReadFile.ts +174 -0
  208. package/src/browser/mcp/tools/listDir.ts +66 -0
  209. package/src/browser/mcp/tools/readFile.ts +82 -0
  210. package/src/browser/mcp/tools/replaceOpenEditorFile.ts +80 -0
  211. package/src/browser/mcp/tools/replaceOpenEditorFileByDiffPreviewer.ts +91 -0
  212. package/src/browser/mcp/tools/runTerminalCmd.ts +107 -0
  213. package/src/browser/preferences/schema.ts +60 -0
  214. package/src/browser/types.ts +56 -0
  215. package/src/common/index.ts +14 -0
  216. package/src/common/llm-context.ts +41 -0
  217. package/src/common/mcp-server-manager.ts +46 -0
  218. package/src/common/tool-invocation-registry.ts +170 -0
  219. package/src/common/types.ts +22 -0
  220. package/src/node/anthropic/anthropic-language-model.ts +25 -0
  221. package/src/node/base-language-model.ts +163 -0
  222. package/src/node/deepseek/deepseek-language-model.ts +25 -0
  223. package/src/node/index.ts +21 -0
  224. package/src/node/mcp/sumi-mcp-server.ts +197 -0
  225. package/src/node/mcp-server-manager-impl.ts +148 -0
  226. package/src/node/mcp-server.ts +126 -0
  227. package/src/node/openai/openai-language-model.ts +25 -0
@@ -38,6 +38,7 @@ import {
38
38
  IChatComponent,
39
39
  IChatContent,
40
40
  IChatResponseProgressFileTreeData,
41
+ IChatToolContent,
41
42
  URI,
42
43
  } from '@opensumi/ide-core-common';
43
44
  import { IIconService } from '@opensumi/ide-theme';
@@ -148,6 +149,33 @@ const TreeRenderer = (props: { treeData: IChatResponseProgressFileTreeData }) =>
148
149
  );
149
150
  };
150
151
 
152
+ const ToolCallRender = (props: { toolCall: IChatToolContent['content'] }) => {
153
+ const { toolCall } = props;
154
+ const chatAgentViewService = useInjectable<IChatAgentViewService>(ChatAgentViewServiceToken);
155
+ const [node, setNode] = useState<React.JSX.Element | null>(null);
156
+
157
+ useEffect(() => {
158
+ const config = chatAgentViewService.getChatComponent('toolCall');
159
+ if (config) {
160
+ const { component: Component, initialProps } = config;
161
+ setNode(<Component {...initialProps} value={toolCall} />);
162
+ return;
163
+ }
164
+ setNode(
165
+ <div>
166
+ <Loading />
167
+ <span style={{ marginLeft: 4 }}>正在加载组件</span>
168
+ </div>,
169
+ );
170
+ const deferred = chatAgentViewService.getChatComponentDeferred('toolCall')!;
171
+ deferred.promise.then(({ component: Component, initialProps }) => {
172
+ setNode(<Component {...initialProps} value={toolCall} />);
173
+ });
174
+ }, [toolCall.state]);
175
+
176
+ return node;
177
+ };
178
+
151
179
  const ComponentRender = (props: { component: string; value?: unknown }) => {
152
180
  const chatAgentViewService = useInjectable<IChatAgentViewService>(ChatAgentViewServiceToken);
153
181
  const [node, setNode] = useState<React.JSX.Element | null>(null);
@@ -274,6 +302,8 @@ export const ChatReply = (props: IChatReplyProps) => {
274
302
  <ComponentRender component={componentId} value={value} />
275
303
  );
276
304
 
305
+ const renderToolCall = (toolCall: IChatToolContent['content']) => <ToolCallRender toolCall={toolCall} />;
306
+
277
307
  const contentNode = React.useMemo(
278
308
  () =>
279
309
  request.response.responseContents.map((item, index) => {
@@ -284,6 +314,8 @@ export const ChatReply = (props: IChatReplyProps) => {
284
314
  node = renderTreeData(item.treeData);
285
315
  } else if (item.kind === 'component') {
286
316
  node = renderComponent(item.component, item.value);
317
+ } else if (item.kind === 'toolCall') {
318
+ node = renderToolCall(item.content);
287
319
  } else {
288
320
  node = renderMarkdown(item.content);
289
321
  }
@@ -0,0 +1,86 @@
1
+ .chat-tool-render {
2
+ margin: 8px 0;
3
+ border: 1px solid var(--design-borderColor);
4
+ border-radius: 6px;
5
+ overflow: hidden;
6
+
7
+ .tool-header {
8
+ display: flex;
9
+ align-items: center;
10
+ justify-content: space-between;
11
+ padding: 8px 12px;
12
+ background-color: var(--design-block-background);
13
+ cursor: pointer;
14
+ user-select: none;
15
+
16
+ &:hover {
17
+ background-color: var(--design-block-hoverBackground);
18
+ }
19
+ }
20
+
21
+ .tool-name {
22
+ display: flex;
23
+ align-items: center;
24
+ font-weight: 500;
25
+ color: var(--design-text-foreground);
26
+ }
27
+
28
+ .expand-icon {
29
+ display: inline-block;
30
+ margin-right: 8px;
31
+ transition: transform 0.2s;
32
+ color: var(--design-text-placeholderForeground);
33
+
34
+ &.expanded {
35
+ transform: rotate(90deg);
36
+ }
37
+ }
38
+
39
+ .tool-state {
40
+ display: flex;
41
+ align-items: center;
42
+ font-size: 12px;
43
+ color: var(--design-text-placeholderForeground);
44
+ }
45
+
46
+ .state-icon {
47
+ display: flex;
48
+ align-items: center;
49
+ margin-right: 6px;
50
+ }
51
+
52
+ .loading-icon {
53
+ width: 12px;
54
+ height: 12px;
55
+ }
56
+
57
+ .state-label {
58
+ margin-left: 4px;
59
+ }
60
+
61
+ .tool-content {
62
+ max-height: 0;
63
+ overflow: hidden;
64
+ transition: max-height 0.3s ease-out;
65
+ background-color: var(--design-container-background);
66
+
67
+ &.expanded {
68
+ max-height: 1000px;
69
+ }
70
+ }
71
+
72
+ .tool-arguments,
73
+ .tool-result {
74
+ padding: 12px;
75
+ }
76
+
77
+ .section-label {
78
+ font-size: 12px;
79
+ color: var(--design-text-placeholderForeground);
80
+ margin-bottom: 8px;
81
+ }
82
+
83
+ .tool-result {
84
+ border-top: 1px solid var(--design-borderColor);
85
+ }
86
+ }
@@ -0,0 +1,77 @@
1
+ import cls from 'classnames';
2
+ import React, { useState } from 'react';
3
+
4
+ import { Icon } from '@opensumi/ide-core-browser/lib/components';
5
+ import { Loading } from '@opensumi/ide-core-browser/lib/components/ai-native';
6
+ import { IChatToolContent, uuid } from '@opensumi/ide-core-common';
7
+
8
+ import { CodeEditorWithHighlight } from './ChatEditor';
9
+ import styles from './ChatToolRender.module.less';
10
+
11
+ export const ChatToolRender = (props: { value: IChatToolContent['content'] }) => {
12
+ const { value } = props;
13
+ const [isExpanded, setIsExpanded] = useState(false);
14
+
15
+ if (!value || !value.function || !value.id) {
16
+ return null;
17
+ }
18
+
19
+ const getStateInfo = (state?: string): { label: string; icon: React.ReactNode } => {
20
+ switch (state) {
21
+ case 'streaming-start':
22
+ case 'streaming':
23
+ return { label: 'Generating', icon: <Loading /> };
24
+ case 'complete':
25
+ return { label: 'Complete', icon: <Icon iconClass="codicon codicon-check" /> };
26
+ case 'result':
27
+ return { label: 'Result Ready', icon: <Icon iconClass="codicon codicon-check-all" /> };
28
+ default:
29
+ return { label: state || 'Unknown', icon: <Icon iconClass="codicon codicon-question" /> };
30
+ }
31
+ };
32
+
33
+ const toggleExpand = () => {
34
+ setIsExpanded(!isExpanded);
35
+ };
36
+
37
+ const stateInfo = getStateInfo(value.state);
38
+
39
+ return (
40
+ <div className={styles['chat-tool-render']}>
41
+ <div className={styles['tool-header']} onClick={toggleExpand}>
42
+ <div className={styles['tool-name']}>
43
+ <span className={cls(styles['expand-icon'], { [styles.expanded]: isExpanded })}>▶</span>
44
+ {value?.function?.name}
45
+ </div>
46
+ {value.state && (
47
+ <div className={styles['tool-state']}>
48
+ <span className={styles['state-icon']}>{stateInfo.icon}</span>
49
+ <span className={styles['state-label']}>{stateInfo.label}</span>
50
+ </div>
51
+ )}
52
+ </div>
53
+ <div className={cls(styles['tool-content'], { [styles.expanded]: isExpanded })}>
54
+ {value?.function?.arguments && (
55
+ <div className={styles['tool-arguments']}>
56
+ <div className={styles['section-label']}>Arguments</div>
57
+ <CodeEditorWithHighlight
58
+ input={value?.function?.arguments}
59
+ language={'json'}
60
+ relationId={uuid(4)}
61
+ />
62
+ </div>
63
+ )}
64
+ {value?.result && (
65
+ <div className={styles['tool-result']}>
66
+ <div className={styles['section-label']}>Result</div>
67
+ <CodeEditorWithHighlight
68
+ input={value.result}
69
+ language={'json'}
70
+ relationId={uuid(4)}
71
+ />
72
+ </div>
73
+ )}
74
+ </div>
75
+ </div>
76
+ );
77
+ };
@@ -244,44 +244,45 @@
244
244
  }
245
245
  }
246
246
 
247
- .code_block {
247
+ .monaco_wrapper {
248
248
  position: relative;
249
- min-width: 100px;
250
- margin-top: 4px;
251
- .monaco_wrapper {
252
- position: relative;
253
- min-width: 130px;
254
- > pre {
255
- margin-bottom: 10px;
256
- }
257
- .editor {
258
- border-radius: 8px;
259
- font-size: 12px;
260
- padding: 32px 8px 8px 8px;
261
- line-height: 18px;
262
- &::-webkit-scrollbar {
263
- width: auto;
264
- height: 4px;
265
- }
249
+ min-width: 130px;
250
+ > pre {
251
+ margin-bottom: 10px;
252
+ }
253
+ .editor {
254
+ border-radius: 8px;
255
+ font-size: 12px;
256
+ padding: 32px 8px 8px 8px;
257
+ line-height: 18px;
258
+ &::-webkit-scrollbar {
259
+ width: auto;
260
+ height: 4px;
266
261
  }
262
+ }
267
263
 
268
- .action_toolbar {
269
- display: flex;
270
- position: absolute;
271
- right: 8px;
272
- top: 6px;
273
- z-index: 100;
274
- height: 20px;
275
- align-items: center;
276
- overflow: hidden;
264
+ .action_toolbar {
265
+ display: flex;
266
+ position: absolute;
267
+ right: 8px;
268
+ top: 6px;
269
+ z-index: 100;
270
+ height: 20px;
271
+ align-items: center;
272
+ overflow: hidden;
277
273
 
278
- :global {
279
- .kt-popover {
280
- height: inherit;
281
- }
274
+ :global {
275
+ .kt-popover {
276
+ height: inherit;
282
277
  }
283
278
  }
284
279
  }
280
+ }
281
+
282
+ .code_block {
283
+ position: relative;
284
+ min-width: 100px;
285
+ margin-top: 4px;
285
286
 
286
287
  :global {
287
288
  .hljs {
@@ -0,0 +1,14 @@
1
+ import { Autowired } from '@opensumi/di';
2
+ import { ClientAppContribution, Domain } from '@opensumi/ide-core-browser';
3
+
4
+ import { LLMContextService, LLMContextServiceToken } from '../../common/llm-context';
5
+
6
+ @Domain(ClientAppContribution)
7
+ export class LlmContextContribution implements ClientAppContribution {
8
+ @Autowired(LLMContextServiceToken)
9
+ protected readonly llmContextService: LLMContextService;
10
+
11
+ initialize() {
12
+ this.llmContextService.startAutoCollection();
13
+ }
14
+ }
@@ -0,0 +1,156 @@
1
+ import { Autowired, Injectable } from '@opensumi/di';
2
+ import { AppConfig } from '@opensumi/ide-core-browser/lib/react-providers/config-provider';
3
+ import { WithEventBus } from '@opensumi/ide-core-common/lib/event-bus/event-decorator';
4
+ import { MarkerSeverity } from '@opensumi/ide-core-common/lib/types/markers/markers';
5
+ import { Emitter, URI } from '@opensumi/ide-core-common/lib/utils';
6
+ import {
7
+ EditorDocumentModelCreationEvent,
8
+ EditorDocumentModelRemovalEvent,
9
+ EditorDocumentModelSavedEvent,
10
+ IEditorDocumentModelService,
11
+ } from '@opensumi/ide-editor/lib/browser/doc-model/types';
12
+ import { EditorSelectionChangeEvent } from '@opensumi/ide-editor/lib/browser/types';
13
+ import { IMarkerService } from '@opensumi/ide-markers/lib/common/types';
14
+
15
+ import { FileContext, LLMContextService, SerializedContext } from '../../common/llm-context';
16
+
17
+ @Injectable()
18
+ export class LLMContextServiceImpl extends WithEventBus implements LLMContextService {
19
+ @Autowired(AppConfig)
20
+ protected readonly appConfig: AppConfig;
21
+
22
+ @Autowired(IEditorDocumentModelService)
23
+ protected readonly docModelManager: IEditorDocumentModelService;
24
+
25
+ @Autowired(IMarkerService)
26
+ protected readonly markerService: IMarkerService;
27
+
28
+ private isAutoCollecting = false;
29
+
30
+ private contextFiles: Map<string, FileContext> = new Map();
31
+
32
+ private onDidContextFilesChangeEmitter = new Emitter<FileContext[]>();
33
+ onDidContextFilesChangeEvent = this.onDidContextFilesChangeEmitter.event;
34
+
35
+ addFileToContext(uri: URI, selection?: [number, number], isManual = true): void {
36
+ this.contextFiles.set(uri.toString(), {
37
+ uri,
38
+ selection,
39
+ isManual,
40
+ });
41
+ this.onDidContextFilesChangeEmitter.fire(this.getAllContextFiles());
42
+ }
43
+
44
+ cleanFileContext() {
45
+ this.contextFiles.clear();
46
+ this.onDidContextFilesChangeEmitter.fire(this.getAllContextFiles());
47
+ }
48
+
49
+ private getAllContextFiles() {
50
+ return Array.from(this.contextFiles.values());
51
+ }
52
+
53
+ removeFileFromContext(uri: URI): void {
54
+ this.contextFiles.delete(uri.toString());
55
+ this.onDidContextFilesChangeEmitter.fire(this.getAllContextFiles());
56
+ }
57
+
58
+ startAutoCollection(): void {
59
+ if (this.isAutoCollecting) {
60
+ return;
61
+ }
62
+ this.isAutoCollecting = true;
63
+
64
+ this.startAutoCollectionInternal();
65
+ }
66
+
67
+ private startAutoCollectionInternal(): void {
68
+ // 文件打开
69
+ this.disposables.push(
70
+ this.eventBus.on(EditorDocumentModelCreationEvent, (event) => {
71
+ if (event.payload.uri.scheme !== 'file') {
72
+ return;
73
+ }
74
+ // TODO: 是否自动添加文件到上下文?
75
+ // this.addFileToContext(event.payload.uri);
76
+ }),
77
+ );
78
+
79
+ // 删除
80
+ this.disposables.push(
81
+ this.eventBus.on(EditorDocumentModelRemovalEvent, (event) => {
82
+ if (event.payload.scheme !== 'file') {
83
+ return;
84
+ }
85
+ }),
86
+ );
87
+
88
+ // 保存
89
+ this.disposables.push(
90
+ this.eventBus.on(EditorDocumentModelSavedEvent, (event) => {
91
+ if (event.payload.scheme !== 'file') {
92
+ return;
93
+ }
94
+ }),
95
+ );
96
+
97
+ // 光标选中
98
+ this.disposables.push(
99
+ this.eventBus.on(EditorSelectionChangeEvent, (event) => {
100
+ if (event.payload.selections.length > 0) {
101
+ const selection = [
102
+ event.payload.selections[0].selectionStartLineNumber,
103
+ event.payload.selections[0].positionLineNumber,
104
+ ].sort() as [number, number];
105
+ if (selection[0] === selection[1]) {
106
+ // TODO: 是否自动添加文件到上下文?
107
+ // this.addFileToContext(event.payload.editorUri, undefined);
108
+ } else {
109
+ this.addFileToContext(
110
+ event.payload.editorUri,
111
+ selection.sort((a, b) => a - b),
112
+ );
113
+ }
114
+ }
115
+ }),
116
+ );
117
+ }
118
+
119
+ stopAutoCollection(): void {
120
+ this.dispose();
121
+ }
122
+
123
+ serialize(): SerializedContext {
124
+ const files = this.getAllContextFiles();
125
+ const recentlyViewFiles = files
126
+ .filter((v) => !v.selection)
127
+ .map((file) => URI.file(this.appConfig.workspaceDir).relative(file.uri)!.toString())
128
+ .filter(Boolean);
129
+ const attachedFiles = files
130
+ .filter((v) => v.selection)
131
+ .map((file) => {
132
+ const ref = this.docModelManager.getModelReference(file.uri);
133
+ const content = ref!.instance.getText();
134
+ const lineErrors = this.markerService
135
+ .getManager()
136
+ .getMarkers({
137
+ resource: file.uri.toString(),
138
+ severities: MarkerSeverity.Error,
139
+ })
140
+ .map((marker) => marker.message);
141
+
142
+ return {
143
+ content,
144
+ lineErrors,
145
+ path: URI.file(this.appConfig.workspaceDir).relative(file.uri)!.toString(),
146
+ language: ref?.instance.languageId!,
147
+ };
148
+ })
149
+ .filter(Boolean);
150
+
151
+ return {
152
+ recentlyViewFiles,
153
+ attachedFiles,
154
+ };
155
+ }
156
+ }
@@ -19,8 +19,17 @@ import {
19
19
  TerminalRegistryToken,
20
20
  } from '@opensumi/ide-core-common';
21
21
 
22
- import { ChatProxyServiceToken, IChatAgentService, IChatInternalService, IChatManagerService } from '../common';
23
- import { IAIInlineCompletionsProvider } from '../common';
22
+ import {
23
+ ChatProxyServiceToken,
24
+ IAIInlineCompletionsProvider,
25
+ IChatAgentService,
26
+ IChatInternalService,
27
+ IChatManagerService,
28
+ SumiMCPServerProxyServicePath,
29
+ TokenMCPServerProxyService,
30
+ } from '../common';
31
+ import { LLMContextServiceToken } from '../common/llm-context';
32
+ import { MCPServerManager, MCPServerManagerPath } from '../common/mcp-server-manager';
24
33
 
25
34
  import { AINativeBrowserContribution } from './ai-core.contribution';
26
35
  import { ChatAgentService } from './chat/chat-agent.service';
@@ -31,6 +40,8 @@ import { ChatService } from './chat/chat.api.service';
31
40
  import { ChatFeatureRegistry } from './chat/chat.feature.registry';
32
41
  import { ChatInternalService } from './chat/chat.internal.service';
33
42
  import { ChatRenderRegistry } from './chat/chat.render.registry';
43
+ import { LlmContextContribution } from './context/llm-context.contribution';
44
+ import { LLMContextServiceImpl } from './context/llm-context.service';
34
45
  import { AICodeActionContribution } from './contrib/code-action/code-action.contribution';
35
46
  import { AIInlineCompletionsProvider } from './contrib/inline-completions/completeProvider';
36
47
  import { IntelligentCompletionsContribution } from './contrib/intelligent-completions/intelligent-completions.contribution';
@@ -43,8 +54,22 @@ import { RenameCandidatesProviderRegistry } from './contrib/rename/rename.featur
43
54
  import { TerminalAIContribution } from './contrib/terminal/terminal-ai.contributon';
44
55
  import { TerminalFeatureRegistry } from './contrib/terminal/terminal.feature.registry';
45
56
  import { LanguageParserService } from './languages/service';
57
+ import { MCPServerProxyService } from './mcp/mcp-server-proxy.service';
58
+ import { MCPServerRegistry } from './mcp/mcp-server.feature.registry';
59
+ import { CreateNewFileWithTextTool } from './mcp/tools/createNewFileWithText';
60
+ import { FindFilesByNameSubstringTool } from './mcp/tools/findFilesByNameSubstring';
61
+ import { GetCurrentFilePathTool } from './mcp/tools/getCurrentFilePath';
62
+ import { GetDiagnosticsByPathTool } from './mcp/tools/getDiagnosticsByPath';
63
+ import { GetFileTextByPathTool } from './mcp/tools/getFileTextByPath';
64
+ import { GetOpenEditorFileDiagnosticsTool } from './mcp/tools/getOpenEditorFileDiagnostics';
65
+ import { GetOpenEditorFileTextTool } from './mcp/tools/getOpenEditorFileText';
66
+ import { GetSelectedTextTool } from './mcp/tools/getSelectedText';
67
+ import { ListDirTool } from './mcp/tools/listDir';
68
+ import { ReadFileTool } from './mcp/tools/readFile';
69
+ import { ReplaceOpenEditorFileByDiffPreviewerTool } from './mcp/tools/replaceOpenEditorFileByDiffPreviewer';
70
+ import { RunTerminalCommandTool } from './mcp/tools/runTerminalCmd';
46
71
  import { AINativePreferencesContribution } from './preferences';
47
- import { AINativeCoreContribution } from './types';
72
+ import { AINativeCoreContribution, MCPServerContribution, TokenMCPServerRegistry } from './types';
48
73
  import { InlineChatFeatureRegistry } from './widget/inline-chat/inline-chat.feature.registry';
49
74
  import { InlineChatService } from './widget/inline-chat/inline-chat.service';
50
75
  import { InlineDiffService } from './widget/inline-diff';
@@ -59,7 +84,7 @@ export class AINativeModule extends BrowserModule {
59
84
  this.aiNativeConfig.setAINativeModuleLoaded(true);
60
85
  }
61
86
 
62
- contributionProvider = AINativeCoreContribution;
87
+ contributionProvider = [AINativeCoreContribution, MCPServerContribution];
63
88
  providers: Provider[] = [
64
89
  AINativeBrowserContribution,
65
90
  InterfaceNavigationContribution,
@@ -68,6 +93,37 @@ export class AINativeModule extends BrowserModule {
68
93
  AICodeActionContribution,
69
94
  AINativePreferencesContribution,
70
95
  IntelligentCompletionsContribution,
96
+
97
+ // MCP Server Contributions START
98
+ ListDirTool,
99
+ ReadFileTool,
100
+ CreateNewFileWithTextTool,
101
+ GetSelectedTextTool,
102
+ GetOpenEditorFileDiagnosticsTool,
103
+ GetOpenEditorFileTextTool,
104
+ GetFileTextByPathTool,
105
+ GetCurrentFilePathTool,
106
+ FindFilesByNameSubstringTool,
107
+ GetDiagnosticsByPathTool,
108
+ RunTerminalCommandTool,
109
+ ReplaceOpenEditorFileByDiffPreviewerTool,
110
+ // MCP Server Contributions END
111
+
112
+ // Context Service
113
+ LlmContextContribution,
114
+ {
115
+ token: LLMContextServiceToken,
116
+ useClass: LLMContextServiceImpl,
117
+ },
118
+
119
+ {
120
+ token: TokenMCPServerRegistry,
121
+ useClass: MCPServerRegistry,
122
+ },
123
+ {
124
+ token: TokenMCPServerProxyService,
125
+ useClass: MCPServerProxyService,
126
+ },
71
127
  {
72
128
  token: InlineChatFeatureRegistryToken,
73
129
  useClass: InlineChatFeatureRegistry,
@@ -148,5 +204,13 @@ export class AINativeModule extends BrowserModule {
148
204
  token: AIBackSerivceToken,
149
205
  clientToken: ChatProxyServiceToken,
150
206
  },
207
+ {
208
+ servicePath: MCPServerManagerPath,
209
+ token: MCPServerManager,
210
+ },
211
+ {
212
+ clientToken: TokenMCPServerProxyService,
213
+ servicePath: SumiMCPServerProxyServicePath,
214
+ },
151
215
  ];
152
216
  }
@@ -0,0 +1,53 @@
1
+ import { Autowired, Injectable } from '@opensumi/di';
2
+ import { ILogger } from '@opensumi/ide-core-browser';
3
+ import { Emitter, Event } from '@opensumi/ide-core-common';
4
+
5
+ import { ISumiMCPServerBackend, SumiMCPServerProxyServicePath } from '../../common';
6
+ import { IMCPServerProxyService } from '../../common/types';
7
+ import { IMCPServerRegistry, TokenMCPServerRegistry } from '../types';
8
+
9
+ @Injectable()
10
+ export class MCPServerProxyService implements IMCPServerProxyService {
11
+ @Autowired(TokenMCPServerRegistry)
12
+ private readonly mcpServerRegistry: IMCPServerRegistry;
13
+
14
+ @Autowired(ILogger)
15
+ private readonly logger: ILogger;
16
+
17
+ @Autowired(SumiMCPServerProxyServicePath)
18
+ private readonly sumiMCPServerProxyService: ISumiMCPServerBackend;
19
+
20
+ private readonly _onChangeMCPServers = new Emitter<any>();
21
+ public readonly onChangeMCPServers: Event<any> = this._onChangeMCPServers.event;
22
+
23
+ // 调用 OpenSumi 内部注册的 MCP 工具
24
+ $callMCPTool(name: string, args: any) {
25
+ return this.mcpServerRegistry.callMCPTool(name, args);
26
+ }
27
+
28
+ // 获取 OpenSumi 内部注册的 MCP tools
29
+ async $getMCPTools() {
30
+ const tools = await this.mcpServerRegistry.getMCPTools().map((tool) =>
31
+ // 不要传递 handler
32
+ ({
33
+ name: tool.name,
34
+ description: tool.description,
35
+ inputSchema: tool.inputSchema,
36
+ providerName: 'sumi-builtin',
37
+ }),
38
+ );
39
+
40
+ this.logger.log('SUMI MCP tools', tools);
41
+
42
+ return tools;
43
+ }
44
+
45
+ // 通知前端 MCP 服务注册表发生了变化
46
+ async $updateMCPServers() {
47
+ this._onChangeMCPServers.fire('update');
48
+ }
49
+
50
+ async getAllMCPTools() {
51
+ return this.sumiMCPServerProxyService.getAllMCPTools();
52
+ }
53
+ }
@@ -0,0 +1,54 @@
1
+ // OpenSumi as MCP Server 前端的代理服务
2
+ import { Autowired, Injectable } from '@opensumi/di';
3
+ import { IAIBackService, ILogger } from '@opensumi/ide-core-common';
4
+
5
+ import { IMCPServerRegistry, MCPLogger, MCPToolDefinition } from '../types';
6
+
7
+ class LoggerAdapter implements MCPLogger {
8
+ constructor(private readonly logger: ILogger) { }
9
+
10
+ appendLine(message: string): void {
11
+ this.logger.log(message);
12
+ }
13
+ }
14
+
15
+ @Injectable()
16
+ export class MCPServerRegistry implements IMCPServerRegistry {
17
+ private tools: MCPToolDefinition[] = [];
18
+
19
+ @Autowired(ILogger)
20
+ private readonly baseLogger: ILogger;
21
+
22
+ private get logger(): MCPLogger {
23
+ return new LoggerAdapter(this.baseLogger);
24
+ }
25
+
26
+ registerMCPTool(tool: MCPToolDefinition): void {
27
+ this.tools.push(tool);
28
+ }
29
+
30
+ getMCPTools(): MCPToolDefinition[] {
31
+ return this.tools;
32
+ }
33
+
34
+ async callMCPTool(
35
+ name: string,
36
+ args: any,
37
+ ): Promise<{
38
+ content: { type: string; text: string }[];
39
+ isError?: boolean;
40
+ }> {
41
+ try {
42
+ const tool = this.tools.find((tool) => tool.name === name);
43
+ if (!tool) {
44
+ throw new Error(`MCP tool ${name} not found`);
45
+ }
46
+ return await tool.handler(args, this.logger);
47
+ } catch (error) {
48
+ return {
49
+ content: [{ type: 'text', text: `The tool ${name} failed to execute. Error: ${error}` }],
50
+ isError: true,
51
+ };
52
+ }
53
+ }
54
+ }