@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.
- package/lib/browser/ai-core.contextkeys.d.ts +1 -1
- package/lib/browser/ai-core.contextkeys.d.ts.map +1 -1
- package/lib/browser/ai-core.contextkeys.js +1 -1
- package/lib/browser/ai-core.contextkeys.js.map +1 -1
- package/lib/browser/ai-core.contribution.d.ts +1 -4
- package/lib/browser/ai-core.contribution.d.ts.map +1 -1
- package/lib/browser/ai-core.contribution.js +11 -23
- package/lib/browser/ai-core.contribution.js.map +1 -1
- package/lib/browser/chat/chat-manager.service.d.ts +0 -1
- package/lib/browser/chat/chat-manager.service.d.ts.map +1 -1
- package/lib/browser/chat/chat-manager.service.js +0 -13
- package/lib/browser/chat/chat-manager.service.js.map +1 -1
- package/lib/browser/chat/chat.internal.service.d.ts +0 -1
- package/lib/browser/chat/chat.internal.service.d.ts.map +1 -1
- package/lib/browser/chat/chat.internal.service.js +0 -3
- package/lib/browser/chat/chat.internal.service.js.map +1 -1
- package/lib/browser/chat/chat.view.d.ts.map +1 -1
- package/lib/browser/chat/chat.view.js +30 -1
- package/lib/browser/chat/chat.view.js.map +1 -1
- package/lib/browser/components/ChatHistory.d.ts +1 -0
- package/lib/browser/components/ChatHistory.d.ts.map +1 -1
- package/lib/browser/components/ChatHistory.js +14 -14
- package/lib/browser/components/ChatHistory.js.map +1 -1
- package/lib/browser/contrib/inline-completions/inline-completions.controller.js +1 -1
- package/lib/browser/contrib/inline-completions/inline-completions.controller.js.map +1 -1
- package/lib/browser/contrib/intelligent-completions/index.d.ts +2 -1
- package/lib/browser/contrib/intelligent-completions/index.d.ts.map +1 -1
- package/lib/browser/contrib/intelligent-completions/index.js +4 -1
- package/lib/browser/contrib/intelligent-completions/index.js.map +1 -1
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.js +2 -2
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.js.map +1 -1
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.d.ts.map +1 -1
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.js +5 -4
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.js.map +1 -1
- package/lib/browser/contrib/intelligent-completions/view/code-edits-previewer.d.ts.map +1 -1
- package/lib/browser/contrib/intelligent-completions/view/code-edits-previewer.js +4 -2
- package/lib/browser/contrib/intelligent-completions/view/code-edits-previewer.js.map +1 -1
- package/lib/browser/contrib/intelligent-completions/view/default.d.ts.map +1 -1
- package/lib/browser/contrib/intelligent-completions/view/default.js +17 -11
- package/lib/browser/contrib/intelligent-completions/view/default.js.map +1 -1
- package/lib/browser/index.d.ts.map +1 -1
- package/lib/browser/index.js +4 -0
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/mcp/base-apply.service.d.ts +40 -31
- package/lib/browser/mcp/base-apply.service.d.ts.map +1 -1
- package/lib/browser/mcp/base-apply.service.js +167 -233
- package/lib/browser/mcp/base-apply.service.js.map +1 -1
- package/lib/browser/mcp/config/components/mcp-config.module.less +178 -0
- package/lib/browser/mcp/config/components/mcp-config.view.d.ts +3 -0
- package/lib/browser/mcp/config/components/mcp-config.view.d.ts.map +1 -0
- package/lib/browser/mcp/config/components/mcp-config.view.js +150 -0
- package/lib/browser/mcp/config/components/mcp-config.view.js.map +1 -0
- package/lib/browser/mcp/config/components/mcp-server-form.d.ts +16 -0
- package/lib/browser/mcp/config/components/mcp-server-form.d.ts.map +1 -0
- package/lib/browser/mcp/config/components/mcp-server-form.js +84 -0
- package/lib/browser/mcp/config/components/mcp-server-form.js.map +1 -0
- package/lib/browser/mcp/config/components/mcp-server-form.module.less +78 -0
- package/lib/browser/mcp/config/mcp-config.commands.d.ts +10 -0
- package/lib/browser/mcp/config/mcp-config.commands.d.ts.map +1 -0
- package/lib/browser/mcp/config/mcp-config.commands.js +35 -0
- package/lib/browser/mcp/config/mcp-config.commands.js.map +1 -0
- package/lib/browser/mcp/config/mcp-config.contribution.d.ts +16 -0
- package/lib/browser/mcp/config/mcp-config.contribution.d.ts.map +1 -0
- package/lib/browser/mcp/config/mcp-config.contribution.js +62 -0
- package/lib/browser/mcp/config/mcp-config.contribution.js.map +1 -0
- package/lib/browser/mcp/mcp-server-proxy.service.d.ts +6 -0
- package/lib/browser/mcp/mcp-server-proxy.service.d.ts.map +1 -1
- package/lib/browser/mcp/mcp-server-proxy.service.js +10 -1
- package/lib/browser/mcp/mcp-server-proxy.service.js.map +1 -1
- package/lib/browser/mcp/mcp-server.feature.registry.d.ts.map +1 -1
- package/lib/browser/mcp/mcp-server.feature.registry.js +3 -2
- package/lib/browser/mcp/mcp-server.feature.registry.js.map +1 -1
- package/lib/browser/mcp/tools/components/EditFile.d.ts.map +1 -1
- package/lib/browser/mcp/tools/components/EditFile.js +41 -55
- package/lib/browser/mcp/tools/components/EditFile.js.map +1 -1
- package/lib/browser/mcp/tools/components/index.module.less +3 -22
- package/lib/browser/mcp/tools/editFile.js +1 -1
- package/lib/browser/mcp/tools/editFile.js.map +1 -1
- package/lib/browser/mcp/tools/handlers/EditFile.d.ts +1 -5
- package/lib/browser/mcp/tools/handlers/EditFile.d.ts.map +1 -1
- package/lib/browser/mcp/tools/handlers/EditFile.js +4 -4
- package/lib/browser/mcp/tools/handlers/EditFile.js.map +1 -1
- package/lib/browser/model/msg-history-manager.d.ts +0 -1
- package/lib/browser/model/msg-history-manager.d.ts.map +1 -1
- package/lib/browser/model/msg-history-manager.js +2 -12
- package/lib/browser/model/msg-history-manager.js.map +1 -1
- package/lib/browser/preferences/schema.d.ts.map +1 -1
- package/lib/browser/preferences/schema.js +16 -0
- package/lib/browser/preferences/schema.js.map +1 -1
- package/lib/browser/types.d.ts +1 -1
- package/lib/browser/types.d.ts.map +1 -1
- package/lib/browser/widget/inline-diff/inline-diff-widget.module.less +0 -12
- package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts +0 -2
- package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts.map +1 -1
- package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js +4 -11
- package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js.map +1 -1
- package/lib/common/index.d.ts +8 -1
- package/lib/common/index.d.ts.map +1 -1
- package/lib/common/index.js +3 -1
- package/lib/common/index.js.map +1 -1
- package/lib/common/mcp-server-manager.d.ts +17 -1
- package/lib/common/mcp-server-manager.d.ts.map +1 -1
- package/lib/common/mcp-server-manager.js.map +1 -1
- package/lib/common/tool-invocation-registry.d.ts +2 -2
- package/lib/common/tool-invocation-registry.d.ts.map +1 -1
- package/lib/common/tool-invocation-registry.js +1 -1
- package/lib/common/tool-invocation-registry.js.map +1 -1
- package/lib/common/types.d.ts +6 -17
- package/lib/common/types.d.ts.map +1 -1
- package/lib/common/types.js.map +1 -1
- package/lib/common/utils.d.ts.map +1 -1
- package/lib/common/utils.js +2 -1
- package/lib/common/utils.js.map +1 -1
- package/lib/node/base-language-model.d.ts +1 -1
- package/lib/node/base-language-model.d.ts.map +1 -1
- package/lib/node/base-language-model.js +8 -58
- package/lib/node/base-language-model.js.map +1 -1
- package/lib/node/mcp/sumi-mcp-server.d.ts +17 -3
- package/lib/node/mcp/sumi-mcp-server.d.ts.map +1 -1
- package/lib/node/mcp/sumi-mcp-server.js +59 -6
- package/lib/node/mcp/sumi-mcp-server.js.map +1 -1
- package/lib/node/mcp-server-manager-impl.d.ts +4 -3
- package/lib/node/mcp-server-manager-impl.d.ts.map +1 -1
- package/lib/node/mcp-server-manager-impl.js +26 -6
- package/lib/node/mcp-server-manager-impl.js.map +1 -1
- package/lib/node/mcp-server.d.ts +5 -16
- package/lib/node/mcp-server.d.ts.map +1 -1
- package/lib/node/mcp-server.js +12 -6
- package/lib/node/mcp-server.js.map +1 -1
- package/lib/node/openai/openai-language-model.d.ts +4 -3
- package/lib/node/openai/openai-language-model.d.ts.map +1 -1
- package/lib/node/openai/openai-language-model.js +3 -2
- package/lib/node/openai/openai-language-model.js.map +1 -1
- package/package.json +27 -27
- package/src/browser/ai-core.contextkeys.ts +3 -3
- package/src/browser/ai-core.contribution.ts +14 -29
- package/src/browser/chat/chat-manager.service.ts +0 -12
- package/src/browser/chat/chat.internal.service.ts +0 -4
- package/src/browser/chat/chat.view.tsx +47 -0
- package/src/browser/components/ChatHistory.tsx +15 -21
- package/src/browser/contrib/inline-completions/inline-completions.controller.ts +1 -1
- package/src/browser/contrib/intelligent-completions/index.ts +5 -1
- package/src/browser/contrib/intelligent-completions/intelligent-completions.contribution.ts +3 -3
- package/src/browser/contrib/intelligent-completions/intelligent-completions.controller.ts +6 -5
- package/src/browser/contrib/intelligent-completions/view/code-edits-previewer.ts +4 -2
- package/src/browser/contrib/intelligent-completions/view/default.ts +27 -19
- package/src/browser/index.ts +4 -0
- package/src/browser/mcp/base-apply.service.ts +213 -266
- package/src/browser/mcp/config/components/mcp-config.module.less +178 -0
- package/src/browser/mcp/config/components/mcp-config.view.tsx +215 -0
- package/src/browser/mcp/config/components/mcp-server-form.module.less +78 -0
- package/src/browser/mcp/config/components/mcp-server-form.tsx +144 -0
- package/src/browser/mcp/config/mcp-config.commands.ts +29 -0
- package/src/browser/mcp/config/mcp-config.contribution.ts +65 -0
- package/src/browser/mcp/mcp-server-proxy.service.ts +14 -2
- package/src/browser/mcp/mcp-server.feature.registry.ts +3 -2
- package/src/browser/mcp/tools/components/EditFile.tsx +60 -82
- package/src/browser/mcp/tools/components/index.module.less +3 -22
- package/src/browser/mcp/tools/editFile.ts +2 -2
- package/src/browser/mcp/tools/handlers/EditFile.ts +4 -4
- package/src/browser/model/msg-history-manager.ts +2 -12
- package/src/browser/preferences/schema.ts +16 -0
- package/src/browser/types.ts +1 -1
- package/src/browser/widget/inline-diff/inline-diff-widget.module.less +0 -12
- package/src/browser/widget/inline-stream-diff/inline-stream-diff.handler.tsx +4 -13
- package/src/common/index.ts +7 -1
- package/src/common/mcp-server-manager.ts +17 -1
- package/src/common/tool-invocation-registry.ts +2 -2
- package/src/common/types.ts +6 -20
- package/src/common/utils.ts +3 -1
- package/src/node/base-language-model.ts +8 -67
- package/src/node/mcp/sumi-mcp-server.ts +67 -9
- package/src/node/mcp-server-manager-impl.ts +30 -9
- package/src/node/mcp-server.ts +11 -14
- package/src/node/openai/openai-language-model.ts +7 -4
- package/lib/browser/widget/inline-diff/inline-diff-manager.d.ts +0 -6
- package/lib/browser/widget/inline-diff/inline-diff-manager.d.ts.map +0 -1
- package/lib/browser/widget/inline-diff/inline-diff-manager.js +0 -27
- package/lib/browser/widget/inline-diff/inline-diff-manager.js.map +0 -1
- package/src/browser/widget/inline-diff/inline-diff-manager.tsx +0 -38
- /package/lib/browser/components/{chat-history.module.less → chat-history.css} +0 -0
- /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
|
-
|
|
45
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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 {
|
|
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 =
|
|
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
|
|
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 {
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
145
|
+
// enabled 为 true 时,会自动启动内置服务器, 并注册工具
|
|
146
|
+
async initBuiltinServer(builtinMCPServer: BuiltinMCPServer, enabled: boolean = true): Promise<void> {
|
|
135
147
|
this.addOrUpdateServerDirectly(builtinMCPServer);
|
|
136
|
-
|
|
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
|
}
|
package/src/node/mcp-server.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|
9
|
+
export class StdioMCPServerImpl implements IMCPServer {
|
|
18
10
|
private name: string;
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
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 {
|
|
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):
|
|
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
|
|
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:
|
|
25
|
+
protected getModelIdentifier(provider: OpenAICompatibleProvider, modelId?: string): LanguageModelV1 {
|
|
23
26
|
return provider(modelId || 'qwen-max');
|
|
24
27
|
}
|
|
25
28
|
}
|
|
@@ -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
|
-
};
|
|
File without changes
|
|
File without changes
|