@opensumi/ide-ai-native 3.8.1-next-1740478950.0 → 3.8.1-next-1740556231.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 (206) hide show
  1. package/lib/browser/ai-core.contribution.d.ts +4 -1
  2. package/lib/browser/ai-core.contribution.d.ts.map +1 -1
  3. package/lib/browser/ai-core.contribution.js +23 -11
  4. package/lib/browser/ai-core.contribution.js.map +1 -1
  5. package/lib/browser/chat/chat-manager.service.d.ts +1 -5
  6. package/lib/browser/chat/chat-manager.service.d.ts.map +1 -1
  7. package/lib/browser/chat/chat-manager.service.js +13 -17
  8. package/lib/browser/chat/chat-manager.service.js.map +1 -1
  9. package/lib/browser/chat/chat-model.d.ts +0 -2
  10. package/lib/browser/chat/chat-model.d.ts.map +1 -1
  11. package/lib/browser/chat/chat-model.js +2 -8
  12. package/lib/browser/chat/chat-model.js.map +1 -1
  13. package/lib/browser/chat/chat.internal.service.d.ts +1 -0
  14. package/lib/browser/chat/chat.internal.service.d.ts.map +1 -1
  15. package/lib/browser/chat/chat.internal.service.js +3 -0
  16. package/lib/browser/chat/chat.internal.service.js.map +1 -1
  17. package/lib/browser/chat/chat.module.less +2 -1
  18. package/lib/browser/chat/chat.view.d.ts.map +1 -1
  19. package/lib/browser/chat/chat.view.js +9 -6
  20. package/lib/browser/chat/chat.view.js.map +1 -1
  21. package/lib/browser/components/ChatContext/index.js +2 -2
  22. package/lib/browser/components/ChatContext/index.js.map +1 -1
  23. package/lib/browser/components/ChatHistory.d.ts +0 -1
  24. package/lib/browser/components/ChatHistory.d.ts.map +1 -1
  25. package/lib/browser/components/ChatHistory.js +14 -14
  26. package/lib/browser/components/ChatHistory.js.map +1 -1
  27. package/lib/browser/components/ChatInput.d.ts.map +1 -1
  28. package/lib/browser/components/ChatInput.js +1 -25
  29. package/lib/browser/components/ChatInput.js.map +1 -1
  30. package/lib/browser/components/ChatToolRender.d.ts.map +1 -1
  31. package/lib/browser/components/ChatToolRender.js +3 -2
  32. package/lib/browser/components/ChatToolRender.js.map +1 -1
  33. package/lib/browser/components/{chat-history.css → chat-history.module.less} +1 -1
  34. package/lib/browser/components/components.module.less +0 -20
  35. package/lib/browser/context/llm-context.service.d.ts +5 -16
  36. package/lib/browser/context/llm-context.service.d.ts.map +1 -1
  37. package/lib/browser/context/llm-context.service.js +47 -78
  38. package/lib/browser/context/llm-context.service.js.map +1 -1
  39. package/lib/browser/index.d.ts.map +1 -1
  40. package/lib/browser/index.js +0 -4
  41. package/lib/browser/index.js.map +1 -1
  42. package/lib/browser/layout/layout.module.less +4 -4
  43. package/lib/browser/mcp/base-apply.service.d.ts +31 -40
  44. package/lib/browser/mcp/base-apply.service.d.ts.map +1 -1
  45. package/lib/browser/mcp/base-apply.service.js +233 -167
  46. package/lib/browser/mcp/base-apply.service.js.map +1 -1
  47. package/lib/browser/mcp/mcp-server-proxy.service.d.ts +0 -6
  48. package/lib/browser/mcp/mcp-server-proxy.service.d.ts.map +1 -1
  49. package/lib/browser/mcp/mcp-server-proxy.service.js +1 -10
  50. package/lib/browser/mcp/mcp-server-proxy.service.js.map +1 -1
  51. package/lib/browser/mcp/mcp-server.feature.registry.d.ts.map +1 -1
  52. package/lib/browser/mcp/mcp-server.feature.registry.js +2 -3
  53. package/lib/browser/mcp/mcp-server.feature.registry.js.map +1 -1
  54. package/lib/browser/mcp/tools/components/EditFile.d.ts.map +1 -1
  55. package/lib/browser/mcp/tools/components/EditFile.js +55 -41
  56. package/lib/browser/mcp/tools/components/EditFile.js.map +1 -1
  57. package/lib/browser/mcp/tools/components/index.module.less +22 -4
  58. package/lib/browser/mcp/tools/createNewFileWithText.d.ts.map +1 -1
  59. package/lib/browser/mcp/tools/createNewFileWithText.js +0 -1
  60. package/lib/browser/mcp/tools/createNewFileWithText.js.map +1 -1
  61. package/lib/browser/mcp/tools/editFile.js +1 -1
  62. package/lib/browser/mcp/tools/editFile.js.map +1 -1
  63. package/lib/browser/mcp/tools/getDiagnosticsByPath.d.ts.map +1 -1
  64. package/lib/browser/mcp/tools/getDiagnosticsByPath.js +0 -1
  65. package/lib/browser/mcp/tools/getDiagnosticsByPath.js.map +1 -1
  66. package/lib/browser/mcp/tools/handlers/EditFile.d.ts +5 -1
  67. package/lib/browser/mcp/tools/handlers/EditFile.d.ts.map +1 -1
  68. package/lib/browser/mcp/tools/handlers/EditFile.js +4 -4
  69. package/lib/browser/mcp/tools/handlers/EditFile.js.map +1 -1
  70. package/lib/browser/mcp/tools/handlers/RunCommand.d.ts.map +1 -1
  71. package/lib/browser/mcp/tools/handlers/RunCommand.js +0 -2
  72. package/lib/browser/mcp/tools/handlers/RunCommand.js.map +1 -1
  73. package/lib/browser/mcp/tools/runTerminalCmd.d.ts.map +1 -1
  74. package/lib/browser/mcp/tools/runTerminalCmd.js +0 -1
  75. package/lib/browser/mcp/tools/runTerminalCmd.js.map +1 -1
  76. package/lib/browser/model/msg-history-manager.d.ts +1 -0
  77. package/lib/browser/model/msg-history-manager.d.ts.map +1 -1
  78. package/lib/browser/model/msg-history-manager.js +12 -2
  79. package/lib/browser/model/msg-history-manager.js.map +1 -1
  80. package/lib/browser/preferences/schema.d.ts.map +1 -1
  81. package/lib/browser/preferences/schema.js +0 -16
  82. package/lib/browser/preferences/schema.js.map +1 -1
  83. package/lib/browser/types.d.ts +1 -1
  84. package/lib/browser/types.d.ts.map +1 -1
  85. package/lib/browser/widget/inline-diff/inline-diff-manager.d.ts +6 -0
  86. package/lib/browser/widget/inline-diff/inline-diff-manager.d.ts.map +1 -0
  87. package/lib/browser/widget/inline-diff/inline-diff-manager.js +27 -0
  88. package/lib/browser/widget/inline-diff/inline-diff-manager.js.map +1 -0
  89. package/lib/browser/widget/inline-diff/inline-diff-widget.module.less +12 -0
  90. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts +2 -0
  91. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts.map +1 -1
  92. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js +11 -4
  93. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js.map +1 -1
  94. package/lib/common/index.d.ts +1 -8
  95. package/lib/common/index.d.ts.map +1 -1
  96. package/lib/common/index.js +1 -3
  97. package/lib/common/index.js.map +1 -1
  98. package/lib/common/llm-context.d.ts +9 -12
  99. package/lib/common/llm-context.d.ts.map +1 -1
  100. package/lib/common/llm-context.js.map +1 -1
  101. package/lib/common/mcp-server-manager.d.ts +1 -17
  102. package/lib/common/mcp-server-manager.d.ts.map +1 -1
  103. package/lib/common/mcp-server-manager.js.map +1 -1
  104. package/lib/common/prompts/context-prompt-provider.d.ts +3 -2
  105. package/lib/common/prompts/context-prompt-provider.d.ts.map +1 -1
  106. package/lib/common/prompts/context-prompt-provider.js +22 -21
  107. package/lib/common/prompts/context-prompt-provider.js.map +1 -1
  108. package/lib/common/tool-invocation-registry.d.ts +2 -2
  109. package/lib/common/tool-invocation-registry.d.ts.map +1 -1
  110. package/lib/common/tool-invocation-registry.js +1 -1
  111. package/lib/common/tool-invocation-registry.js.map +1 -1
  112. package/lib/common/types.d.ts +17 -6
  113. package/lib/common/types.d.ts.map +1 -1
  114. package/lib/common/types.js.map +1 -1
  115. package/lib/common/utils.d.ts.map +1 -1
  116. package/lib/common/utils.js +1 -2
  117. package/lib/common/utils.js.map +1 -1
  118. package/lib/node/base-language-model.d.ts +1 -1
  119. package/lib/node/base-language-model.d.ts.map +1 -1
  120. package/lib/node/base-language-model.js +54 -3
  121. package/lib/node/base-language-model.js.map +1 -1
  122. package/lib/node/mcp/sumi-mcp-server.d.ts +3 -17
  123. package/lib/node/mcp/sumi-mcp-server.d.ts.map +1 -1
  124. package/lib/node/mcp/sumi-mcp-server.js +6 -59
  125. package/lib/node/mcp/sumi-mcp-server.js.map +1 -1
  126. package/lib/node/mcp-server-manager-impl.d.ts +3 -4
  127. package/lib/node/mcp-server-manager-impl.d.ts.map +1 -1
  128. package/lib/node/mcp-server-manager-impl.js +6 -26
  129. package/lib/node/mcp-server-manager-impl.js.map +1 -1
  130. package/lib/node/mcp-server.d.ts +16 -5
  131. package/lib/node/mcp-server.d.ts.map +1 -1
  132. package/lib/node/mcp-server.js +6 -12
  133. package/lib/node/mcp-server.js.map +1 -1
  134. package/lib/node/openai/openai-language-model.d.ts +3 -4
  135. package/lib/node/openai/openai-language-model.d.ts.map +1 -1
  136. package/lib/node/openai/openai-language-model.js +2 -3
  137. package/lib/node/openai/openai-language-model.js.map +1 -1
  138. package/package.json +27 -27
  139. package/src/browser/ai-core.contribution.ts +29 -14
  140. package/src/browser/chat/chat-manager.service.ts +13 -17
  141. package/src/browser/chat/chat-model.ts +3 -18
  142. package/src/browser/chat/chat.internal.service.ts +4 -0
  143. package/src/browser/chat/chat.module.less +2 -1
  144. package/src/browser/chat/chat.view.tsx +26 -10
  145. package/src/browser/components/ChatContext/index.tsx +2 -2
  146. package/src/browser/components/ChatHistory.tsx +21 -15
  147. package/src/browser/components/ChatInput.tsx +4 -67
  148. package/src/browser/components/ChatToolRender.tsx +2 -1
  149. package/src/browser/components/{chat-history.css → chat-history.module.less} +1 -1
  150. package/src/browser/components/components.module.less +0 -20
  151. package/src/browser/context/llm-context.service.ts +54 -90
  152. package/src/browser/index.ts +0 -4
  153. package/src/browser/layout/layout.module.less +4 -4
  154. package/src/browser/mcp/base-apply.service.ts +266 -213
  155. package/src/browser/mcp/mcp-server-proxy.service.ts +2 -14
  156. package/src/browser/mcp/mcp-server.feature.registry.ts +2 -3
  157. package/src/browser/mcp/tools/components/EditFile.tsx +82 -60
  158. package/src/browser/mcp/tools/components/index.module.less +22 -4
  159. package/src/browser/mcp/tools/createNewFileWithText.ts +0 -1
  160. package/src/browser/mcp/tools/editFile.ts +2 -2
  161. package/src/browser/mcp/tools/getDiagnosticsByPath.ts +0 -1
  162. package/src/browser/mcp/tools/handlers/EditFile.ts +4 -4
  163. package/src/browser/mcp/tools/handlers/RunCommand.ts +0 -2
  164. package/src/browser/mcp/tools/runTerminalCmd.ts +0 -1
  165. package/src/browser/model/msg-history-manager.ts +12 -2
  166. package/src/browser/preferences/schema.ts +0 -16
  167. package/src/browser/types.ts +1 -1
  168. package/src/browser/widget/inline-diff/inline-diff-manager.tsx +38 -0
  169. package/src/browser/widget/inline-diff/inline-diff-widget.module.less +12 -0
  170. package/src/browser/widget/inline-stream-diff/inline-stream-diff.handler.tsx +13 -4
  171. package/src/common/index.ts +1 -7
  172. package/src/common/llm-context.ts +4 -10
  173. package/src/common/mcp-server-manager.ts +1 -17
  174. package/src/common/prompts/context-prompt-provider.ts +28 -26
  175. package/src/common/tool-invocation-registry.ts +2 -2
  176. package/src/common/types.ts +20 -6
  177. package/src/common/utils.ts +1 -3
  178. package/src/node/base-language-model.ts +63 -1
  179. package/src/node/mcp/sumi-mcp-server.ts +9 -67
  180. package/src/node/mcp-server-manager-impl.ts +9 -30
  181. package/src/node/mcp-server.ts +14 -11
  182. package/src/node/openai/openai-language-model.ts +4 -7
  183. package/lib/browser/mcp/config/components/mcp-config.module.less +0 -178
  184. package/lib/browser/mcp/config/components/mcp-config.view.d.ts +0 -3
  185. package/lib/browser/mcp/config/components/mcp-config.view.d.ts.map +0 -1
  186. package/lib/browser/mcp/config/components/mcp-config.view.js +0 -150
  187. package/lib/browser/mcp/config/components/mcp-config.view.js.map +0 -1
  188. package/lib/browser/mcp/config/components/mcp-server-form.d.ts +0 -16
  189. package/lib/browser/mcp/config/components/mcp-server-form.d.ts.map +0 -1
  190. package/lib/browser/mcp/config/components/mcp-server-form.js +0 -84
  191. package/lib/browser/mcp/config/components/mcp-server-form.js.map +0 -1
  192. package/lib/browser/mcp/config/components/mcp-server-form.module.less +0 -78
  193. package/lib/browser/mcp/config/mcp-config.commands.d.ts +0 -10
  194. package/lib/browser/mcp/config/mcp-config.commands.d.ts.map +0 -1
  195. package/lib/browser/mcp/config/mcp-config.commands.js +0 -35
  196. package/lib/browser/mcp/config/mcp-config.commands.js.map +0 -1
  197. package/lib/browser/mcp/config/mcp-config.contribution.d.ts +0 -16
  198. package/lib/browser/mcp/config/mcp-config.contribution.d.ts.map +0 -1
  199. package/lib/browser/mcp/config/mcp-config.contribution.js +0 -62
  200. package/lib/browser/mcp/config/mcp-config.contribution.js.map +0 -1
  201. package/src/browser/mcp/config/components/mcp-config.module.less +0 -178
  202. package/src/browser/mcp/config/components/mcp-config.view.tsx +0 -215
  203. package/src/browser/mcp/config/components/mcp-server-form.module.less +0 -78
  204. package/src/browser/mcp/config/components/mcp-server-form.tsx +0 -144
  205. package/src/browser/mcp/config/mcp-config.commands.ts +0 -29
  206. package/src/browser/mcp/config/mcp-config.contribution.ts +0 -65
@@ -1,4 +1,5 @@
1
1
  import { Injectable } from '@opensumi/di';
2
+ import { MaybePromise } from '@opensumi/ide-core-common/lib/utils';
2
3
 
3
4
  import { SerializedContext } from '../llm-context';
4
5
 
@@ -9,36 +10,37 @@ export interface ChatAgentPromptProvider {
9
10
  * 提供上下文提示
10
11
  * @param context 上下文
11
12
  */
12
- provideContextPrompt(context: SerializedContext, userMessage: string): string;
13
+ provideContextPrompt(context: SerializedContext, userMessage: string): MaybePromise<string>;
13
14
  }
14
15
 
15
16
  @Injectable()
16
17
  export class DefaultChatAgentPromptProvider implements ChatAgentPromptProvider {
17
- provideContextPrompt(context: SerializedContext, userMessage: string): string {
18
+ provideContextPrompt(context: SerializedContext, userMessage: string): MaybePromise<string> {
18
19
  return `
19
- <additional_data>
20
- Below are some potentially helpful/relevant pieces of information for figuring out to respond
21
- <recently_viewed_files>
22
- ${context.recentlyViewFiles.map((file, idx) => ` ${idx + 1}: ${file}`).join('\n')}
23
- </recently_viewed_files>
24
- <attached_files>
25
- ${context.attachedFiles.map(
26
- (file) =>
27
- `
28
- <file_contents>
29
- \`\`\`${file.language} ${file.path}
30
- ${file.content}
31
- \`\`\`
32
- </file_contents>
33
- <linter_errors>
34
- ${file.lineErrors.join('\n')}
35
- </linter_errors>
36
- `,
37
- )}
38
- </attached_files>
39
- </additional_data>
40
- <user_query>
41
- ${userMessage}
42
- </user_query>`;
20
+ <additional_data>
21
+ Below are some potentially helpful/relevant pieces of information for figuring out to respond
22
+ <recently_viewed_files>
23
+ ${context.recentlyViewFiles.map((file, idx) => `${idx + 1} : ${file}`)}
24
+ </recently_viewed_files>
25
+ <attached_files>
26
+ ${context.attachedFiles.map(
27
+ (file) =>
28
+ `
29
+ <file_contents>
30
+ \`\`\`${file.language} ${file.path}
31
+ ${file.content}
32
+ \`\`\`
33
+ </file_contents>
34
+ <linter_errors>
35
+ ${file.lineErrors.join('\n')}
36
+ </linter_errors>
37
+ `,
38
+ )}
39
+
40
+ </attached_files>
41
+ </additional_data>
42
+ <user_query>
43
+ ${userMessage}
44
+ </user_query>`;
43
45
  }
44
46
  }
@@ -72,7 +72,7 @@ export interface ToolInvocationRegistry {
72
72
  *
73
73
  * @param providerName - 要移除其工具的工具提供者名称(在 `ToolRequest` 中指定)
74
74
  */
75
- unregisterProviderTools(providerName: string): void;
75
+ unregisterAllTools(providerName: string): void;
76
76
  }
77
77
 
78
78
  export const ToolProvider = Symbol('ToolProvider');
@@ -83,7 +83,7 @@ export interface ToolProvider {
83
83
  export class ToolInvocationRegistryImpl implements ToolInvocationRegistry {
84
84
  private tools: Map<string, ToolRequest> = new Map<string, ToolRequest>();
85
85
 
86
- unregisterProviderTools(providerName: string): void {
86
+ unregisterAllTools(providerName: string): void {
87
87
  const toolsToRemove: string[] = [];
88
88
  for (const [id, tool] of this.tools.entries()) {
89
89
  if (tool.providerName === providerName) {
@@ -1,3 +1,5 @@
1
+ import { IMarker } from '@opensumi/ide-core-browser';
2
+
1
3
  export enum NearestCodeBlockType {
2
4
  Block = 'block',
3
5
  Line = 'line',
@@ -32,12 +34,6 @@ export interface IMCPServerProxyService {
32
34
  $getMCPTools(): Promise<MCPTool[]>;
33
35
  // 通知前端 MCP 服务注册表发生了变化
34
36
  $updateMCPServers(): Promise<void>;
35
- // 获取所有 MCP 服务器列表
36
- $getServers(): Promise<Array<{ name: string; isStarted: boolean }>>;
37
- // 启动指定的 MCP 服务器
38
- $startServer(serverName: string): Promise<void>;
39
- // 停止指定的 MCP 服务器
40
- $stopServer(serverName: string): Promise<void>;
41
37
  }
42
38
 
43
39
  export interface MCPTool {
@@ -46,3 +42,21 @@ export interface MCPTool {
46
42
  inputSchema: any;
47
43
  providerName: string;
48
44
  }
45
+
46
+ export interface CodeBlockData {
47
+ toolCallId: string;
48
+ codeEdit: string;
49
+ updatedCode?: string;
50
+ relativePath: string;
51
+ status: CodeBlockStatus;
52
+ iterationCount: number;
53
+ createdAt: number;
54
+ version: number;
55
+ instructions?: string;
56
+ applyResult?: {
57
+ diff: string;
58
+ diagnosticInfos: IMarker[];
59
+ };
60
+ }
61
+
62
+ export type CodeBlockStatus = 'generating' | 'pending' | 'success' | 'rejected' | 'failed' | 'cancelled';
@@ -1,7 +1,5 @@
1
1
  import { IEditorDocumentModel } from '@opensumi/ide-editor';
2
2
 
3
- import { BUILTIN_MCP_SERVER_NAME } from './index';
4
-
5
3
  const BACK_QUOTE_3_SYMBOL = '```';
6
4
  const MIN_PROMPT_CHARS = 10;
7
5
 
@@ -51,4 +49,4 @@ export const extractCodeBlocks = (content: string): string => {
51
49
  return newContents.join('\n');
52
50
  };
53
51
 
54
- export const getToolName = (toolName: string, serverName = BUILTIN_MCP_SERVER_NAME) => `mcp_${serverName}_${toolName}`;
52
+ export const getToolName = (toolName: string, serverName = 'sumi-builtin') => `mcp_${serverName}_${toolName}`;
@@ -57,6 +57,7 @@ export abstract class BaseLanguageModel {
57
57
  options.topP,
58
58
  options.topK,
59
59
  options.providerOptions,
60
+ options.trimTexts,
60
61
  cancellationToken,
61
62
  );
62
63
  }
@@ -84,6 +85,7 @@ export abstract class BaseLanguageModel {
84
85
  topP?: number,
85
86
  topK?: number,
86
87
  providerOptions?: Record<string, any>,
88
+ trimTexts?: [string, string],
87
89
  cancellationToken?: CancellationToken,
88
90
  ): Promise<any> {
89
91
  try {
@@ -117,9 +119,42 @@ export abstract class BaseLanguageModel {
117
119
  providerOptions,
118
120
  });
119
121
 
122
+ // 状态跟踪变量
123
+ let isFirstChunk = true;
124
+ let bufferedText = '';
125
+ const pendingLines: string[] = [];
120
126
  for await (const chunk of stream.fullStream) {
121
127
  if (chunk.type === 'text-delta') {
122
- chatReadableStream.emitData({ kind: 'content', content: chunk.textDelta });
128
+ if (trimTexts?.length) {
129
+ // 将收到的文本追加到缓冲区
130
+ bufferedText += chunk.textDelta;
131
+
132
+ // 处理第一个文本块的前缀(只处理一次)
133
+ if (isFirstChunk && bufferedText.includes(trimTexts[0])) {
134
+ bufferedText = bufferedText.substring(bufferedText.indexOf(trimTexts[0]) + trimTexts[0].length);
135
+ isFirstChunk = false;
136
+ }
137
+
138
+ // 检查是否有完整的行,并将它们添加到待发送行队列
139
+ const lines = bufferedText.split('\n');
140
+
141
+ // 最后一个元素可能是不完整的行,保留在缓冲区
142
+ bufferedText = lines.pop() || '';
143
+
144
+ // 将完整的行添加到待发送队列
145
+ if (lines.length > 0) {
146
+ pendingLines.push(...lines);
147
+ }
148
+
149
+ // 发送除最后几行外的所有行(保留足够的行以处理后缀)
150
+ while (pendingLines.length > 3) {
151
+ // 保留最后3行以确保能完整识别后缀
152
+ const lineToSend = pendingLines.shift() + '\n';
153
+ chatReadableStream.emitData({ kind: 'content', content: lineToSend });
154
+ }
155
+ } else {
156
+ chatReadableStream.emitData({ kind: 'content', content: chunk.textDelta });
157
+ }
123
158
  } else if (chunk.type === 'tool-call') {
124
159
  chatReadableStream.emitData({
125
160
  kind: 'toolCall',
@@ -166,6 +201,33 @@ export abstract class BaseLanguageModel {
166
201
  }
167
202
  }
168
203
 
204
+ if (trimTexts?.[1]) {
205
+ // 完成处理所有块后,检查并发送剩余文本
206
+
207
+ // 将剩余缓冲区加入待发送行
208
+ if (bufferedText) {
209
+ pendingLines.push(bufferedText);
210
+ }
211
+
212
+ // 处理最后一行可能存在的后缀
213
+ if (pendingLines.length > 0) {
214
+ let lastLine = pendingLines[pendingLines.length - 1];
215
+
216
+ if (lastLine.endsWith(trimTexts[1])) {
217
+ // 移除后缀
218
+ lastLine = lastLine.substring(0, lastLine.length - trimTexts[1].length);
219
+ pendingLines[pendingLines.length - 1] = lastLine;
220
+ }
221
+ }
222
+
223
+ // 发送所有剩余的行
224
+ for (let i = 0; i < pendingLines.length; i++) {
225
+ const isLastLine = i === pendingLines.length - 1;
226
+ const lineToSend = pendingLines[i] + (isLastLine ? '' : '\n');
227
+ chatReadableStream.emitData({ kind: 'content', content: lineToSend });
228
+ }
229
+ }
230
+
169
231
  chatReadableStream.end();
170
232
  } catch (error) {
171
233
  // Use a logger service in production instead of console
@@ -10,11 +10,11 @@ import { RPCService } from '@opensumi/ide-connection';
10
10
  import { ILogger } from '@opensumi/ide-core-common';
11
11
  import { INodeLogger } from '@opensumi/ide-core-node';
12
12
 
13
- import { BUILTIN_MCP_SERVER_NAME, ISumiMCPServerBackend } from '../../common';
14
- import { IMCPServer, MCPServerDescription } from '../../common/mcp-server-manager';
13
+ import { ISumiMCPServerBackend } from '../../common';
14
+ import { MCPServerDescription, MCPServerManager } from '../../common/mcp-server-manager';
15
15
  import { IToolInvocationRegistryManager, ToolInvocationRegistryManager } from '../../common/tool-invocation-registry';
16
16
  import { IMCPServerProxyService, MCPTool } from '../../common/types';
17
- import { StdioMCPServerImpl } from '../mcp-server';
17
+ import { IMCPServer } from '../mcp-server';
18
18
  import { MCPServerManagerImpl } from '../mcp-server-manager-impl';
19
19
 
20
20
  // 每个 BrowserTab 都对应了一个 SumiMCPServerBackend 实例
@@ -55,6 +55,7 @@ export class SumiMCPServerBackend extends RPCService<IMCPServerProxyService> imp
55
55
  }
56
56
  // 获取 MCP 工具
57
57
  const tools = await this.client.$getMCPTools();
58
+ this.logger.log('[Node backend] SUMI MCP tools', tools);
58
59
  return tools;
59
60
  }
60
61
 
@@ -80,10 +81,10 @@ export class SumiMCPServerBackend extends RPCService<IMCPServerProxyService> imp
80
81
  }));
81
82
  }
82
83
 
83
- public async initBuiltinMCPServer(enabled: boolean) {
84
+ public async initBuiltinMCPServer() {
84
85
  const builtinMCPServer = new BuiltinMCPServer(this, this.logger);
85
86
  this.mcpServerManager.setClientId(this.clientId);
86
- await this.mcpServerManager.initBuiltinServer(builtinMCPServer, enabled);
87
+ await this.mcpServerManager.initBuiltinServer(builtinMCPServer);
87
88
  this.client?.$updateMCPServers();
88
89
  }
89
90
 
@@ -129,72 +130,12 @@ export class SumiMCPServerBackend extends RPCService<IMCPServerProxyService> imp
129
130
 
130
131
  return this.server;
131
132
  }
132
-
133
- async getServers() {
134
- const servers = Array.from(this.mcpServerManager.getServers().entries());
135
- const serverInfos = await Promise.all(
136
- servers.map(async ([serverName, server]) => {
137
- let toolNames: string[] = [];
138
- if (server.isStarted()) {
139
- // 只获取正在运行的 MCP Server 的工具列表
140
- const toolsResponse = await server.getTools();
141
- toolNames = toolsResponse.tools.map((tool) => tool.name);
142
- }
143
-
144
- // OpenSumi 内置的 MCP Server
145
- if (serverName === BUILTIN_MCP_SERVER_NAME) {
146
- return {
147
- name: server.getServerName(),
148
- isStarted: server.isStarted(),
149
- type: 'builtin rpc',
150
- tools: toolNames,
151
- };
152
- }
153
-
154
- // 第三方 Stdio 类型的 MCP Server
155
- if (server instanceof StdioMCPServerImpl) {
156
- return {
157
- name: server.getServerName(),
158
- isStarted: server.isStarted(),
159
- type: 'stdio',
160
- command: server.command + ' ' + (server.args?.join(' ') || ''),
161
- tools: toolNames,
162
- };
163
- }
164
-
165
- // TODO SSE 类型的 MCP Server
166
-
167
- return {
168
- name: server.getServerName(),
169
- isStarted: server.isStarted(),
170
- type: '[MOCK] stdio',
171
- command: '[MOCK] npx sumi-ide-mcp-server',
172
- tools: toolNames,
173
- };
174
- }),
175
- );
176
-
177
- // 将 builtin server 放在第一位
178
- const builtinServer = serverInfos.find((server) => server.name === BUILTIN_MCP_SERVER_NAME);
179
- const otherServers = serverInfos.filter((server) => server.name !== BUILTIN_MCP_SERVER_NAME);
180
- return builtinServer ? [builtinServer, ...otherServers] : otherServers;
181
- }
182
-
183
- async startServer(serverName: string) {
184
- await this.mcpServerManager.startServer(serverName);
185
- this.client?.$updateMCPServers();
186
- }
187
-
188
- async stopServer(serverName: string) {
189
- await this.mcpServerManager.stopServer(serverName);
190
- this.client?.$updateMCPServers();
191
- }
192
133
  }
193
134
 
194
135
  export const TokenBuiltinMCPServer = Symbol('TokenBuiltinMCPServer');
195
136
 
196
137
  export class BuiltinMCPServer implements IMCPServer {
197
- private started: boolean = false;
138
+ private started: boolean = true;
198
139
 
199
140
  constructor(private readonly sumiMCPServer: SumiMCPServerBackend, private readonly logger: ILogger) {}
200
141
 
@@ -203,7 +144,7 @@ export class BuiltinMCPServer implements IMCPServer {
203
144
  }
204
145
 
205
146
  getServerName(): string {
206
- return BUILTIN_MCP_SERVER_NAME;
147
+ return 'sumi-builtin';
207
148
  }
208
149
 
209
150
  async start(): Promise<void> {
@@ -241,6 +182,7 @@ export class BuiltinMCPServer implements IMCPServer {
241
182
  throw new Error('MCP Server not started');
242
183
  }
243
184
  const tools = await this.sumiMCPServer.getMCPTools();
185
+ this.logger.debug('[BuiltinMCPServer] getTools', tools);
244
186
  return { tools } as any;
245
187
  }
246
188
 
@@ -2,12 +2,13 @@ import { ToolExecutionOptions } from 'ai';
2
2
 
3
3
  import { ILogger } from '@opensumi/ide-core-common';
4
4
 
5
- import { IMCPServer, MCPServerDescription, MCPServerManager, MCPTool } from '../common/mcp-server-manager';
5
+ import { MCPServerDescription, MCPServerManager, MCPTool } from '../common/mcp-server-manager';
6
6
  import { IToolInvocationRegistryManager, ToolRequest } from '../common/tool-invocation-registry';
7
7
  import { getToolName } from '../common/utils';
8
8
 
9
9
  import { BuiltinMCPServer } from './mcp/sumi-mcp-server';
10
- import { StdioMCPServerImpl } from './mcp-server';
10
+ import { IMCPServer, MCPServerImpl } from './mcp-server';
11
+
11
12
  // 这应该是 Browser Tab 维度的,每个 Tab 对应一个 MCPServerManagerImpl
12
13
  export class MCPServerManagerImpl implements MCPServerManager {
13
14
  protected servers: Map<string, IMCPServer> = new Map();
@@ -15,10 +16,6 @@ export class MCPServerManagerImpl implements MCPServerManager {
15
16
  // 当前实例对应的 clientId
16
17
  private clientId: string;
17
18
 
18
- getServers(): Map<string, IMCPServer> {
19
- return this.servers;
20
- }
21
-
22
19
  constructor(
23
20
  private readonly toolInvocationRegistryManager: IToolInvocationRegistryManager,
24
21
  private readonly logger: ILogger,
@@ -28,20 +25,13 @@ export class MCPServerManagerImpl implements MCPServerManager {
28
25
  this.clientId = clientId;
29
26
  }
30
27
 
31
- private unregisterServerTools(serverName: string) {
32
- const registry = this.toolInvocationRegistryManager.getRegistry(this.clientId);
33
- registry.unregisterProviderTools(serverName);
34
- }
35
-
36
28
  async stopServer(serverName: string): Promise<void> {
37
29
  const server = this.servers.get(serverName);
38
30
  if (!server) {
39
31
  throw new Error(`MCP server "${serverName}" not found.`);
40
32
  }
41
- await server.stop();
42
- // 停止服务器后,需要从注册表中移除该服务器的所有工具
43
- this.unregisterServerTools(serverName);
44
- this.logger.log(`MCP server "${serverName}" stopped and tools unregistered.`);
33
+ server.stop();
34
+ this.logger.log(`MCP server "${serverName}" stopped.`);
45
35
  }
46
36
 
47
37
  async getStartedServers(): Promise<string[]> {
@@ -73,7 +63,6 @@ export class MCPServerManagerImpl implements MCPServerManager {
73
63
  throw new Error(`MCP server "${serverName}" not found.`);
74
64
  }
75
65
  await server.start();
76
- await this.registerTools(serverName);
77
66
  }
78
67
 
79
68
  async getServerNames(): Promise<string[]> {
@@ -133,7 +122,7 @@ export class MCPServerManagerImpl implements MCPServerManager {
133
122
  if (existingServer) {
134
123
  existingServer.update(command, args, env);
135
124
  } else {
136
- const newServer = new StdioMCPServerImpl(name, command, args, env, this.logger);
125
+ const newServer = new MCPServerImpl(name, command, args, env, this.logger);
137
126
  this.servers.set(name, newServer);
138
127
  }
139
128
  }
@@ -142,23 +131,16 @@ export class MCPServerManagerImpl implements MCPServerManager {
142
131
  this.servers.set(server.getServerName(), server);
143
132
  }
144
133
 
145
- // enabled true 时,会自动启动内置服务器, 并注册工具
146
- async initBuiltinServer(builtinMCPServer: BuiltinMCPServer, enabled: boolean = true): Promise<void> {
134
+ async initBuiltinServer(builtinMCPServer: BuiltinMCPServer): Promise<void> {
147
135
  this.addOrUpdateServerDirectly(builtinMCPServer);
148
- if (enabled) {
149
- await builtinMCPServer.start();
150
- await this.registerTools(builtinMCPServer.getServerName());
151
- }
136
+ await this.registerTools(builtinMCPServer.getServerName());
152
137
  }
153
138
 
154
139
  async addExternalMCPServers(servers: MCPServerDescription[]): Promise<void> {
155
140
  for (const server of servers) {
156
141
  this.addOrUpdateServer(server);
157
- if (!server.enabled) {
158
- // 如果是 enabled 为 false 的 server,则不进行启动
159
- continue;
160
- }
161
142
  await this.startServer(server.name);
143
+ await this.registerTools(server.name);
162
144
  }
163
145
  }
164
146
 
@@ -166,10 +148,7 @@ export class MCPServerManagerImpl implements MCPServerManager {
166
148
  const server = this.servers.get(name);
167
149
  if (server) {
168
150
  server.stop();
169
- // 移除服务器时,也需要从注册表中移除该服务器的所有工具
170
- this.unregisterServerTools(name);
171
151
  this.servers.delete(name);
172
- this.logger.log(`MCP server "${name}" removed and tools unregistered.`);
173
152
  } else {
174
153
  this.logger.warn(`MCP server "${name}" not found.`);
175
154
  }
@@ -4,12 +4,20 @@ import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'
4
4
 
5
5
  import { ILogger } from '@opensumi/ide-core-common';
6
6
 
7
- import { IMCPServer } from '../common/mcp-server-manager';
7
+ export interface IMCPServer {
8
+ isStarted(): boolean;
9
+ start(): Promise<void>;
10
+ getServerName(): string;
11
+ callTool(toolName: string, toolCallId: string, arg_string: string): ReturnType<Client['callTool']>;
12
+ getTools(): ReturnType<Client['listTools']>;
13
+ update(command: string, args?: string[], env?: { [key: string]: string }): void;
14
+ stop(): void;
15
+ }
8
16
 
9
- export class StdioMCPServerImpl implements IMCPServer {
17
+ export class MCPServerImpl implements IMCPServer {
10
18
  private name: string;
11
- public command: string;
12
- public args?: string[];
19
+ private command: string;
20
+ private args?: string[];
13
21
  private client: Client;
14
22
  private env?: { [key: string]: string };
15
23
  private started: boolean = false;
@@ -108,17 +116,12 @@ export class StdioMCPServerImpl implements IMCPServer {
108
116
  this.env = env;
109
117
  }
110
118
 
111
- async stop(): Promise<void> {
119
+ stop(): void {
112
120
  if (!this.started || !this.client) {
113
121
  return;
114
122
  }
115
123
  this.logger?.log(`Stopping MCP server "${this.name}"`);
116
- try {
117
- await this.client.close();
118
- } catch (error) {
119
- this.logger?.error(`Failed to stop MCP server "${this.name}":`, error);
120
- }
121
- this.logger?.log(`MCP server "${this.name}" stopped`);
124
+ this.client.close();
122
125
  this.started = false;
123
126
  }
124
127
  }
@@ -1,28 +1,25 @@
1
- import { OpenAICompatibleProvider, createOpenAICompatible } from '@ai-sdk/openai-compatible';
2
- import { LanguageModelV1 } from 'ai';
1
+ import { OpenAIProvider, createOpenAI } from '@ai-sdk/openai';
3
2
 
4
3
  import { Injectable } from '@opensumi/di';
5
4
  import { AINativeSettingSectionsId, IAIBackServiceOption } from '@opensumi/ide-core-common';
6
5
 
7
6
  import { BaseLanguageModel } from '../base-language-model';
8
-
9
7
  export const DeepSeekModelIdentifier = Symbol('DeepSeekModelIdentifier');
10
8
 
11
9
  @Injectable()
12
10
  export class OpenAIModel extends BaseLanguageModel {
13
- protected initializeProvider(options: IAIBackServiceOption): OpenAICompatibleProvider {
11
+ protected initializeProvider(options: IAIBackServiceOption): OpenAIProvider {
14
12
  const apiKey = options.apiKey;
15
13
  if (!apiKey) {
16
14
  throw new Error(`Please provide OpenAI API Key in preferences (${AINativeSettingSectionsId.OpenaiApiKey})`);
17
15
  }
18
- return createOpenAICompatible({
16
+ return createOpenAI({
19
17
  apiKey,
20
18
  baseURL: options.baseURL || 'https://dashscope.aliyuncs.com/compatible-mode/v1',
21
- name: 'openai',
22
19
  });
23
20
  }
24
21
 
25
- protected getModelIdentifier(provider: OpenAICompatibleProvider, modelId?: string): LanguageModelV1 {
22
+ protected getModelIdentifier(provider: OpenAIProvider, modelId?: string) {
26
23
  return provider(modelId || 'qwen-max');
27
24
  }
28
25
  }