@opensumi/ide-ai-native 3.8.1-next-1740556231.0 → 3.8.1-next-1740571693.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 (182) hide show
  1. package/lib/browser/ai-core.contextkeys.d.ts +1 -1
  2. package/lib/browser/ai-core.contextkeys.d.ts.map +1 -1
  3. package/lib/browser/ai-core.contextkeys.js +1 -1
  4. package/lib/browser/ai-core.contextkeys.js.map +1 -1
  5. package/lib/browser/ai-core.contribution.d.ts +1 -4
  6. package/lib/browser/ai-core.contribution.d.ts.map +1 -1
  7. package/lib/browser/ai-core.contribution.js +11 -23
  8. package/lib/browser/ai-core.contribution.js.map +1 -1
  9. package/lib/browser/chat/chat-manager.service.d.ts +0 -1
  10. package/lib/browser/chat/chat-manager.service.d.ts.map +1 -1
  11. package/lib/browser/chat/chat-manager.service.js +0 -13
  12. package/lib/browser/chat/chat-manager.service.js.map +1 -1
  13. package/lib/browser/chat/chat.internal.service.d.ts +0 -1
  14. package/lib/browser/chat/chat.internal.service.d.ts.map +1 -1
  15. package/lib/browser/chat/chat.internal.service.js +0 -3
  16. package/lib/browser/chat/chat.internal.service.js.map +1 -1
  17. package/lib/browser/chat/chat.view.d.ts.map +1 -1
  18. package/lib/browser/chat/chat.view.js +30 -1
  19. package/lib/browser/chat/chat.view.js.map +1 -1
  20. package/lib/browser/components/ChatHistory.d.ts +1 -0
  21. package/lib/browser/components/ChatHistory.d.ts.map +1 -1
  22. package/lib/browser/components/ChatHistory.js +14 -14
  23. package/lib/browser/components/ChatHistory.js.map +1 -1
  24. package/lib/browser/contrib/inline-completions/inline-completions.controller.js +1 -1
  25. package/lib/browser/contrib/inline-completions/inline-completions.controller.js.map +1 -1
  26. package/lib/browser/contrib/intelligent-completions/index.d.ts +2 -1
  27. package/lib/browser/contrib/intelligent-completions/index.d.ts.map +1 -1
  28. package/lib/browser/contrib/intelligent-completions/index.js +4 -1
  29. package/lib/browser/contrib/intelligent-completions/index.js.map +1 -1
  30. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.js +2 -2
  31. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.js.map +1 -1
  32. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.d.ts.map +1 -1
  33. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.js +5 -4
  34. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.js.map +1 -1
  35. package/lib/browser/contrib/intelligent-completions/view/code-edits-previewer.d.ts.map +1 -1
  36. package/lib/browser/contrib/intelligent-completions/view/code-edits-previewer.js +4 -2
  37. package/lib/browser/contrib/intelligent-completions/view/code-edits-previewer.js.map +1 -1
  38. package/lib/browser/contrib/intelligent-completions/view/default.d.ts.map +1 -1
  39. package/lib/browser/contrib/intelligent-completions/view/default.js +17 -11
  40. package/lib/browser/contrib/intelligent-completions/view/default.js.map +1 -1
  41. package/lib/browser/index.d.ts.map +1 -1
  42. package/lib/browser/index.js +4 -0
  43. package/lib/browser/index.js.map +1 -1
  44. package/lib/browser/mcp/base-apply.service.d.ts +40 -31
  45. package/lib/browser/mcp/base-apply.service.d.ts.map +1 -1
  46. package/lib/browser/mcp/base-apply.service.js +167 -233
  47. package/lib/browser/mcp/base-apply.service.js.map +1 -1
  48. package/lib/browser/mcp/config/components/mcp-config.module.less +178 -0
  49. package/lib/browser/mcp/config/components/mcp-config.view.d.ts +3 -0
  50. package/lib/browser/mcp/config/components/mcp-config.view.d.ts.map +1 -0
  51. package/lib/browser/mcp/config/components/mcp-config.view.js +150 -0
  52. package/lib/browser/mcp/config/components/mcp-config.view.js.map +1 -0
  53. package/lib/browser/mcp/config/components/mcp-server-form.d.ts +16 -0
  54. package/lib/browser/mcp/config/components/mcp-server-form.d.ts.map +1 -0
  55. package/lib/browser/mcp/config/components/mcp-server-form.js +84 -0
  56. package/lib/browser/mcp/config/components/mcp-server-form.js.map +1 -0
  57. package/lib/browser/mcp/config/components/mcp-server-form.module.less +78 -0
  58. package/lib/browser/mcp/config/mcp-config.commands.d.ts +10 -0
  59. package/lib/browser/mcp/config/mcp-config.commands.d.ts.map +1 -0
  60. package/lib/browser/mcp/config/mcp-config.commands.js +35 -0
  61. package/lib/browser/mcp/config/mcp-config.commands.js.map +1 -0
  62. package/lib/browser/mcp/config/mcp-config.contribution.d.ts +16 -0
  63. package/lib/browser/mcp/config/mcp-config.contribution.d.ts.map +1 -0
  64. package/lib/browser/mcp/config/mcp-config.contribution.js +62 -0
  65. package/lib/browser/mcp/config/mcp-config.contribution.js.map +1 -0
  66. package/lib/browser/mcp/mcp-server-proxy.service.d.ts +6 -0
  67. package/lib/browser/mcp/mcp-server-proxy.service.d.ts.map +1 -1
  68. package/lib/browser/mcp/mcp-server-proxy.service.js +10 -1
  69. package/lib/browser/mcp/mcp-server-proxy.service.js.map +1 -1
  70. package/lib/browser/mcp/mcp-server.feature.registry.d.ts.map +1 -1
  71. package/lib/browser/mcp/mcp-server.feature.registry.js +3 -2
  72. package/lib/browser/mcp/mcp-server.feature.registry.js.map +1 -1
  73. package/lib/browser/mcp/tools/components/EditFile.d.ts.map +1 -1
  74. package/lib/browser/mcp/tools/components/EditFile.js +41 -55
  75. package/lib/browser/mcp/tools/components/EditFile.js.map +1 -1
  76. package/lib/browser/mcp/tools/components/index.module.less +3 -22
  77. package/lib/browser/mcp/tools/editFile.js +1 -1
  78. package/lib/browser/mcp/tools/editFile.js.map +1 -1
  79. package/lib/browser/mcp/tools/handlers/EditFile.d.ts +1 -5
  80. package/lib/browser/mcp/tools/handlers/EditFile.d.ts.map +1 -1
  81. package/lib/browser/mcp/tools/handlers/EditFile.js +4 -4
  82. package/lib/browser/mcp/tools/handlers/EditFile.js.map +1 -1
  83. package/lib/browser/model/msg-history-manager.d.ts +0 -1
  84. package/lib/browser/model/msg-history-manager.d.ts.map +1 -1
  85. package/lib/browser/model/msg-history-manager.js +2 -12
  86. package/lib/browser/model/msg-history-manager.js.map +1 -1
  87. package/lib/browser/preferences/schema.d.ts.map +1 -1
  88. package/lib/browser/preferences/schema.js +16 -0
  89. package/lib/browser/preferences/schema.js.map +1 -1
  90. package/lib/browser/types.d.ts +1 -1
  91. package/lib/browser/types.d.ts.map +1 -1
  92. package/lib/browser/widget/inline-diff/inline-diff-widget.module.less +0 -12
  93. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts +0 -2
  94. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts.map +1 -1
  95. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js +4 -11
  96. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js.map +1 -1
  97. package/lib/common/index.d.ts +8 -1
  98. package/lib/common/index.d.ts.map +1 -1
  99. package/lib/common/index.js +3 -1
  100. package/lib/common/index.js.map +1 -1
  101. package/lib/common/mcp-server-manager.d.ts +17 -1
  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/tool-invocation-registry.d.ts +2 -2
  105. package/lib/common/tool-invocation-registry.d.ts.map +1 -1
  106. package/lib/common/tool-invocation-registry.js +1 -1
  107. package/lib/common/tool-invocation-registry.js.map +1 -1
  108. package/lib/common/types.d.ts +6 -17
  109. package/lib/common/types.d.ts.map +1 -1
  110. package/lib/common/types.js.map +1 -1
  111. package/lib/common/utils.d.ts.map +1 -1
  112. package/lib/common/utils.js +2 -1
  113. package/lib/common/utils.js.map +1 -1
  114. package/lib/node/base-language-model.d.ts +1 -1
  115. package/lib/node/base-language-model.d.ts.map +1 -1
  116. package/lib/node/base-language-model.js +8 -58
  117. package/lib/node/base-language-model.js.map +1 -1
  118. package/lib/node/mcp/sumi-mcp-server.d.ts +17 -3
  119. package/lib/node/mcp/sumi-mcp-server.d.ts.map +1 -1
  120. package/lib/node/mcp/sumi-mcp-server.js +59 -6
  121. package/lib/node/mcp/sumi-mcp-server.js.map +1 -1
  122. package/lib/node/mcp-server-manager-impl.d.ts +4 -3
  123. package/lib/node/mcp-server-manager-impl.d.ts.map +1 -1
  124. package/lib/node/mcp-server-manager-impl.js +26 -6
  125. package/lib/node/mcp-server-manager-impl.js.map +1 -1
  126. package/lib/node/mcp-server.d.ts +5 -16
  127. package/lib/node/mcp-server.d.ts.map +1 -1
  128. package/lib/node/mcp-server.js +12 -6
  129. package/lib/node/mcp-server.js.map +1 -1
  130. package/lib/node/openai/openai-language-model.d.ts +4 -3
  131. package/lib/node/openai/openai-language-model.d.ts.map +1 -1
  132. package/lib/node/openai/openai-language-model.js +3 -2
  133. package/lib/node/openai/openai-language-model.js.map +1 -1
  134. package/package.json +27 -27
  135. package/src/browser/ai-core.contextkeys.ts +3 -3
  136. package/src/browser/ai-core.contribution.ts +14 -29
  137. package/src/browser/chat/chat-manager.service.ts +0 -12
  138. package/src/browser/chat/chat.internal.service.ts +0 -4
  139. package/src/browser/chat/chat.view.tsx +47 -0
  140. package/src/browser/components/ChatHistory.tsx +15 -21
  141. package/src/browser/contrib/inline-completions/inline-completions.controller.ts +1 -1
  142. package/src/browser/contrib/intelligent-completions/index.ts +5 -1
  143. package/src/browser/contrib/intelligent-completions/intelligent-completions.contribution.ts +3 -3
  144. package/src/browser/contrib/intelligent-completions/intelligent-completions.controller.ts +6 -5
  145. package/src/browser/contrib/intelligent-completions/view/code-edits-previewer.ts +4 -2
  146. package/src/browser/contrib/intelligent-completions/view/default.ts +27 -19
  147. package/src/browser/index.ts +4 -0
  148. package/src/browser/mcp/base-apply.service.ts +213 -266
  149. package/src/browser/mcp/config/components/mcp-config.module.less +178 -0
  150. package/src/browser/mcp/config/components/mcp-config.view.tsx +215 -0
  151. package/src/browser/mcp/config/components/mcp-server-form.module.less +78 -0
  152. package/src/browser/mcp/config/components/mcp-server-form.tsx +144 -0
  153. package/src/browser/mcp/config/mcp-config.commands.ts +29 -0
  154. package/src/browser/mcp/config/mcp-config.contribution.ts +65 -0
  155. package/src/browser/mcp/mcp-server-proxy.service.ts +14 -2
  156. package/src/browser/mcp/mcp-server.feature.registry.ts +3 -2
  157. package/src/browser/mcp/tools/components/EditFile.tsx +60 -82
  158. package/src/browser/mcp/tools/components/index.module.less +3 -22
  159. package/src/browser/mcp/tools/editFile.ts +2 -2
  160. package/src/browser/mcp/tools/handlers/EditFile.ts +4 -4
  161. package/src/browser/model/msg-history-manager.ts +2 -12
  162. package/src/browser/preferences/schema.ts +16 -0
  163. package/src/browser/types.ts +1 -1
  164. package/src/browser/widget/inline-diff/inline-diff-widget.module.less +0 -12
  165. package/src/browser/widget/inline-stream-diff/inline-stream-diff.handler.tsx +4 -13
  166. package/src/common/index.ts +7 -1
  167. package/src/common/mcp-server-manager.ts +17 -1
  168. package/src/common/tool-invocation-registry.ts +2 -2
  169. package/src/common/types.ts +6 -20
  170. package/src/common/utils.ts +3 -1
  171. package/src/node/base-language-model.ts +8 -67
  172. package/src/node/mcp/sumi-mcp-server.ts +67 -9
  173. package/src/node/mcp-server-manager-impl.ts +30 -9
  174. package/src/node/mcp-server.ts +11 -14
  175. package/src/node/openai/openai-language-model.ts +7 -4
  176. package/lib/browser/widget/inline-diff/inline-diff-manager.d.ts +0 -6
  177. package/lib/browser/widget/inline-diff/inline-diff-manager.d.ts.map +0 -1
  178. package/lib/browser/widget/inline-diff/inline-diff-manager.js +0 -27
  179. package/lib/browser/widget/inline-diff/inline-diff-manager.js.map +0 -1
  180. package/src/browser/widget/inline-diff/inline-diff-manager.tsx +0 -38
  181. /package/lib/browser/components/{chat-history.module.less → chat-history.css} +0 -0
  182. /package/src/browser/components/{chat-history.module.less → chat-history.css} +0 -0
@@ -41,11 +41,14 @@ export abstract class BaseLanguageModel {
41
41
  ): Promise<any> {
42
42
  const provider = this.initializeProvider(options);
43
43
  const clientId = options.clientId;
44
- if (!clientId) {
45
- throw new Error('clientId is required');
44
+
45
+ let allFunctions: ToolRequest[] = [];
46
+ // 如果没有传入 clientId,则不使用工具
47
+ if (clientId) {
48
+ const registry = this.toolInvocationRegistryManager.getRegistry(clientId);
49
+ allFunctions = options.noTool ? [] : registry.getAllFunctions();
46
50
  }
47
- const registry = this.toolInvocationRegistryManager.getRegistry(clientId);
48
- const allFunctions = options.noTool ? [] : registry.getAllFunctions();
51
+
49
52
  return this.handleStreamingRequest(
50
53
  provider,
51
54
  request,
@@ -57,7 +60,6 @@ export abstract class BaseLanguageModel {
57
60
  options.topP,
58
61
  options.topK,
59
62
  options.providerOptions,
60
- options.trimTexts,
61
63
  cancellationToken,
62
64
  );
63
65
  }
@@ -85,7 +87,6 @@ export abstract class BaseLanguageModel {
85
87
  topP?: number,
86
88
  topK?: number,
87
89
  providerOptions?: Record<string, any>,
88
- trimTexts?: [string, string],
89
90
  cancellationToken?: CancellationToken,
90
91
  ): Promise<any> {
91
92
  try {
@@ -119,42 +120,9 @@ export abstract class BaseLanguageModel {
119
120
  providerOptions,
120
121
  });
121
122
 
122
- // 状态跟踪变量
123
- let isFirstChunk = true;
124
- let bufferedText = '';
125
- const pendingLines: string[] = [];
126
123
  for await (const chunk of stream.fullStream) {
127
124
  if (chunk.type === 'text-delta') {
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
- }
125
+ chatReadableStream.emitData({ kind: 'content', content: chunk.textDelta });
158
126
  } else if (chunk.type === 'tool-call') {
159
127
  chatReadableStream.emitData({
160
128
  kind: 'toolCall',
@@ -201,33 +169,6 @@ export abstract class BaseLanguageModel {
201
169
  }
202
170
  }
203
171
 
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
-
231
172
  chatReadableStream.end();
232
173
  } catch (error) {
233
174
  // 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 { ISumiMCPServerBackend } from '../../common';
14
- import { MCPServerDescription, MCPServerManager } from '../../common/mcp-server-manager';
13
+ import { BUILTIN_MCP_SERVER_NAME, ISumiMCPServerBackend } from '../../common';
14
+ import { IMCPServer, MCPServerDescription } 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 { IMCPServer } from '../mcp-server';
17
+ import { StdioMCPServerImpl } from '../mcp-server';
18
18
  import { MCPServerManagerImpl } from '../mcp-server-manager-impl';
19
19
 
20
20
  // 每个 BrowserTab 都对应了一个 SumiMCPServerBackend 实例
@@ -55,7 +55,6 @@ 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);
59
58
  return tools;
60
59
  }
61
60
 
@@ -81,10 +80,10 @@ export class SumiMCPServerBackend extends RPCService<IMCPServerProxyService> imp
81
80
  }));
82
81
  }
83
82
 
84
- public async initBuiltinMCPServer() {
83
+ public async initBuiltinMCPServer(enabled: boolean) {
85
84
  const builtinMCPServer = new BuiltinMCPServer(this, this.logger);
86
85
  this.mcpServerManager.setClientId(this.clientId);
87
- await this.mcpServerManager.initBuiltinServer(builtinMCPServer);
86
+ await this.mcpServerManager.initBuiltinServer(builtinMCPServer, enabled);
88
87
  this.client?.$updateMCPServers();
89
88
  }
90
89
 
@@ -130,12 +129,72 @@ export class SumiMCPServerBackend extends RPCService<IMCPServerProxyService> imp
130
129
 
131
130
  return this.server;
132
131
  }
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
+ }
133
192
  }
134
193
 
135
194
  export const TokenBuiltinMCPServer = Symbol('TokenBuiltinMCPServer');
136
195
 
137
196
  export class BuiltinMCPServer implements IMCPServer {
138
- private started: boolean = true;
197
+ private started: boolean = false;
139
198
 
140
199
  constructor(private readonly sumiMCPServer: SumiMCPServerBackend, private readonly logger: ILogger) {}
141
200
 
@@ -144,7 +203,7 @@ export class BuiltinMCPServer implements IMCPServer {
144
203
  }
145
204
 
146
205
  getServerName(): string {
147
- return 'sumi-builtin';
206
+ return BUILTIN_MCP_SERVER_NAME;
148
207
  }
149
208
 
150
209
  async start(): Promise<void> {
@@ -182,7 +241,6 @@ export class BuiltinMCPServer implements IMCPServer {
182
241
  throw new Error('MCP Server not started');
183
242
  }
184
243
  const tools = await this.sumiMCPServer.getMCPTools();
185
- this.logger.debug('[BuiltinMCPServer] getTools', tools);
186
244
  return { tools } as any;
187
245
  }
188
246
 
@@ -2,13 +2,12 @@ import { ToolExecutionOptions } from 'ai';
2
2
 
3
3
  import { ILogger } from '@opensumi/ide-core-common';
4
4
 
5
- import { MCPServerDescription, MCPServerManager, MCPTool } from '../common/mcp-server-manager';
5
+ import { IMCPServer, 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 { IMCPServer, MCPServerImpl } from './mcp-server';
11
-
10
+ import { StdioMCPServerImpl } from './mcp-server';
12
11
  // 这应该是 Browser Tab 维度的,每个 Tab 对应一个 MCPServerManagerImpl
13
12
  export class MCPServerManagerImpl implements MCPServerManager {
14
13
  protected servers: Map<string, IMCPServer> = new Map();
@@ -16,6 +15,10 @@ export class MCPServerManagerImpl implements MCPServerManager {
16
15
  // 当前实例对应的 clientId
17
16
  private clientId: string;
18
17
 
18
+ getServers(): Map<string, IMCPServer> {
19
+ return this.servers;
20
+ }
21
+
19
22
  constructor(
20
23
  private readonly toolInvocationRegistryManager: IToolInvocationRegistryManager,
21
24
  private readonly logger: ILogger,
@@ -25,13 +28,20 @@ export class MCPServerManagerImpl implements MCPServerManager {
25
28
  this.clientId = clientId;
26
29
  }
27
30
 
31
+ private unregisterServerTools(serverName: string) {
32
+ const registry = this.toolInvocationRegistryManager.getRegistry(this.clientId);
33
+ registry.unregisterProviderTools(serverName);
34
+ }
35
+
28
36
  async stopServer(serverName: string): Promise<void> {
29
37
  const server = this.servers.get(serverName);
30
38
  if (!server) {
31
39
  throw new Error(`MCP server "${serverName}" not found.`);
32
40
  }
33
- server.stop();
34
- this.logger.log(`MCP server "${serverName}" stopped.`);
41
+ await server.stop();
42
+ // 停止服务器后,需要从注册表中移除该服务器的所有工具
43
+ this.unregisterServerTools(serverName);
44
+ this.logger.log(`MCP server "${serverName}" stopped and tools unregistered.`);
35
45
  }
36
46
 
37
47
  async getStartedServers(): Promise<string[]> {
@@ -63,6 +73,7 @@ export class MCPServerManagerImpl implements MCPServerManager {
63
73
  throw new Error(`MCP server "${serverName}" not found.`);
64
74
  }
65
75
  await server.start();
76
+ await this.registerTools(serverName);
66
77
  }
67
78
 
68
79
  async getServerNames(): Promise<string[]> {
@@ -122,7 +133,7 @@ export class MCPServerManagerImpl implements MCPServerManager {
122
133
  if (existingServer) {
123
134
  existingServer.update(command, args, env);
124
135
  } else {
125
- const newServer = new MCPServerImpl(name, command, args, env, this.logger);
136
+ const newServer = new StdioMCPServerImpl(name, command, args, env, this.logger);
126
137
  this.servers.set(name, newServer);
127
138
  }
128
139
  }
@@ -131,16 +142,23 @@ export class MCPServerManagerImpl implements MCPServerManager {
131
142
  this.servers.set(server.getServerName(), server);
132
143
  }
133
144
 
134
- async initBuiltinServer(builtinMCPServer: BuiltinMCPServer): Promise<void> {
145
+ // enabled true 时,会自动启动内置服务器, 并注册工具
146
+ async initBuiltinServer(builtinMCPServer: BuiltinMCPServer, enabled: boolean = true): Promise<void> {
135
147
  this.addOrUpdateServerDirectly(builtinMCPServer);
136
- await this.registerTools(builtinMCPServer.getServerName());
148
+ if (enabled) {
149
+ await builtinMCPServer.start();
150
+ await this.registerTools(builtinMCPServer.getServerName());
151
+ }
137
152
  }
138
153
 
139
154
  async addExternalMCPServers(servers: MCPServerDescription[]): Promise<void> {
140
155
  for (const server of servers) {
141
156
  this.addOrUpdateServer(server);
157
+ if (!server.enabled) {
158
+ // 如果是 enabled 为 false 的 server,则不进行启动
159
+ continue;
160
+ }
142
161
  await this.startServer(server.name);
143
- await this.registerTools(server.name);
144
162
  }
145
163
  }
146
164
 
@@ -148,7 +166,10 @@ export class MCPServerManagerImpl implements MCPServerManager {
148
166
  const server = this.servers.get(name);
149
167
  if (server) {
150
168
  server.stop();
169
+ // 移除服务器时,也需要从注册表中移除该服务器的所有工具
170
+ this.unregisterServerTools(name);
151
171
  this.servers.delete(name);
172
+ this.logger.log(`MCP server "${name}" removed and tools unregistered.`);
152
173
  } else {
153
174
  this.logger.warn(`MCP server "${name}" not found.`);
154
175
  }
@@ -4,20 +4,12 @@ import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'
4
4
 
5
5
  import { ILogger } from '@opensumi/ide-core-common';
6
6
 
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
- }
7
+ import { IMCPServer } from '../common/mcp-server-manager';
16
8
 
17
- export class MCPServerImpl implements IMCPServer {
9
+ export class StdioMCPServerImpl implements IMCPServer {
18
10
  private name: string;
19
- private command: string;
20
- private args?: string[];
11
+ public command: string;
12
+ public args?: string[];
21
13
  private client: Client;
22
14
  private env?: { [key: string]: string };
23
15
  private started: boolean = false;
@@ -116,12 +108,17 @@ export class MCPServerImpl implements IMCPServer {
116
108
  this.env = env;
117
109
  }
118
110
 
119
- stop(): void {
111
+ async stop(): Promise<void> {
120
112
  if (!this.started || !this.client) {
121
113
  return;
122
114
  }
123
115
  this.logger?.log(`Stopping MCP server "${this.name}"`);
124
- this.client.close();
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`);
125
122
  this.started = false;
126
123
  }
127
124
  }
@@ -1,25 +1,28 @@
1
- import { OpenAIProvider, createOpenAI } from '@ai-sdk/openai';
1
+ import { OpenAICompatibleProvider, createOpenAICompatible } from '@ai-sdk/openai-compatible';
2
+ import { LanguageModelV1 } from 'ai';
2
3
 
3
4
  import { Injectable } from '@opensumi/di';
4
5
  import { AINativeSettingSectionsId, IAIBackServiceOption } from '@opensumi/ide-core-common';
5
6
 
6
7
  import { BaseLanguageModel } from '../base-language-model';
8
+
7
9
  export const DeepSeekModelIdentifier = Symbol('DeepSeekModelIdentifier');
8
10
 
9
11
  @Injectable()
10
12
  export class OpenAIModel extends BaseLanguageModel {
11
- protected initializeProvider(options: IAIBackServiceOption): OpenAIProvider {
13
+ protected initializeProvider(options: IAIBackServiceOption): OpenAICompatibleProvider {
12
14
  const apiKey = options.apiKey;
13
15
  if (!apiKey) {
14
16
  throw new Error(`Please provide OpenAI API Key in preferences (${AINativeSettingSectionsId.OpenaiApiKey})`);
15
17
  }
16
- return createOpenAI({
18
+ return createOpenAICompatible({
17
19
  apiKey,
18
20
  baseURL: options.baseURL || 'https://dashscope.aliyuncs.com/compatible-mode/v1',
21
+ name: 'openai',
19
22
  });
20
23
  }
21
24
 
22
- protected getModelIdentifier(provider: OpenAIProvider, modelId?: string) {
25
+ protected getModelIdentifier(provider: OpenAICompatibleProvider, modelId?: string): LanguageModelV1 {
23
26
  return provider(modelId || 'qwen-max');
24
27
  }
25
28
  }
@@ -1,6 +0,0 @@
1
- import React from 'react';
2
- import { IResource } from '@opensumi/ide-editor';
3
- export declare const InlineDiffManager: React.FC<{
4
- resource: IResource;
5
- }>;
6
- //# sourceMappingURL=inline-diff-manager.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"inline-diff-manager.d.ts","sourceRoot":"","sources":["../../../../src/browser/widget/inline-diff/inline-diff-manager.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAInD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAMjD,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,CA2B/D,CAAC"}
@@ -1,27 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.InlineDiffManager = void 0;
4
- const tslib_1 = require("tslib");
5
- const react_1 = tslib_1.__importStar(require("react"));
6
- const ide_components_1 = require("@opensumi/ide-components");
7
- const ide_core_browser_1 = require("@opensumi/ide-core-browser");
8
- const base_apply_service_1 = require("../../mcp/base-apply.service");
9
- const inline_diff_widget_module_less_1 = tslib_1.__importDefault(require("./inline-diff-widget.module.less"));
10
- const InlineDiffManager = (props) => {
11
- const applyService = (0, ide_core_browser_1.useInjectable)(base_apply_service_1.BaseApplyService);
12
- const [show, setShow] = (0, react_1.useState)(true);
13
- (0, react_1.useEffect)(() => {
14
- applyService.onCodeBlockUpdate((codeBlock) => {
15
- setShow(codeBlock.status === 'pending');
16
- });
17
- }, []);
18
- return (react_1.default.createElement("div", { className: inline_diff_widget_module_less_1.default.inlineDiffManager, style: { display: show ? 'flex' : 'none' } },
19
- react_1.default.createElement(ide_components_1.Button, { onClick: () => {
20
- applyService.processAll(props.resource.uri, 'accept');
21
- } }, (0, ide_core_browser_1.localize)('aiNative.inlineDiff.acceptAll')),
22
- react_1.default.createElement(ide_components_1.Button, { type: 'ghost', onClick: () => {
23
- applyService.processAll(props.resource.uri, 'reject');
24
- } }, (0, ide_core_browser_1.localize)('aiNative.inlineDiff.rejectAll'))));
25
- };
26
- exports.InlineDiffManager = InlineDiffManager;
27
- //# sourceMappingURL=inline-diff-manager.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"inline-diff-manager.js","sourceRoot":"","sources":["../../../../src/browser/widget/inline-diff/inline-diff-manager.tsx"],"names":[],"mappings":";;;;AAAA,uDAAmD;AAEnD,6DAAkD;AAClD,iEAAqE;AAGrE,qEAAgE;AAEhE,8GAAsD;AAE/C,MAAM,iBAAiB,GAAsC,CAAC,KAAK,EAAE,EAAE;IAC5E,MAAM,YAAY,GAAG,IAAA,gCAAa,EAAmB,qCAAgB,CAAC,CAAC;IACvE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,IAAA,gBAAQ,EAAC,IAAI,CAAC,CAAC;IACvC,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,YAAY,CAAC,iBAAiB,CAAC,CAAC,SAAS,EAAE,EAAE;YAC3C,OAAO,CAAC,SAAS,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,EAAE,CAAC,CAAC;IACP,OAAO,CACL,uCAAK,SAAS,EAAE,wCAAM,CAAC,iBAAiB,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE;QAClF,8BAAC,uBAAM,IACL,OAAO,EAAE,GAAG,EAAE;gBACZ,YAAY,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;YACxD,CAAC,IAEA,IAAA,2BAAQ,EAAC,+BAA+B,CAAC,CACnC;QACT,8BAAC,uBAAM,IACL,IAAI,EAAC,OAAO,EACZ,OAAO,EAAE,GAAG,EAAE;gBACZ,YAAY,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;YACxD,CAAC,IAEA,IAAA,2BAAQ,EAAC,+BAA+B,CAAC,CACnC,CACL,CACP,CAAC;AACJ,CAAC,CAAC;AA3BW,QAAA,iBAAiB,qBA2B5B"}
@@ -1,38 +0,0 @@
1
- import React, { useEffect, useState } from 'react';
2
-
3
- import { Button } from '@opensumi/ide-components';
4
- import { localize, useInjectable } from '@opensumi/ide-core-browser';
5
- import { IResource } from '@opensumi/ide-editor';
6
-
7
- import { BaseApplyService } from '../../mcp/base-apply.service';
8
-
9
- import styles from './inline-diff-widget.module.less';
10
-
11
- export const InlineDiffManager: React.FC<{ resource: IResource }> = (props) => {
12
- const applyService = useInjectable<BaseApplyService>(BaseApplyService);
13
- const [show, setShow] = useState(true);
14
- useEffect(() => {
15
- applyService.onCodeBlockUpdate((codeBlock) => {
16
- setShow(codeBlock.status === 'pending');
17
- });
18
- }, []);
19
- return (
20
- <div className={styles.inlineDiffManager} style={{ display: show ? 'flex' : 'none' }}>
21
- <Button
22
- onClick={() => {
23
- applyService.processAll(props.resource.uri, 'accept');
24
- }}
25
- >
26
- {localize('aiNative.inlineDiff.acceptAll')}
27
- </Button>
28
- <Button
29
- type='ghost'
30
- onClick={() => {
31
- applyService.processAll(props.resource.uri, 'reject');
32
- }}
33
- >
34
- {localize('aiNative.inlineDiff.rejectAll')}
35
- </Button>
36
- </div>
37
- );
38
- };