@opensumi/ide-ai-native 3.8.1-next-1740475512.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.
- package/lib/browser/ai-core.contribution.d.ts +4 -1
- package/lib/browser/ai-core.contribution.d.ts.map +1 -1
- package/lib/browser/ai-core.contribution.js +23 -11
- package/lib/browser/ai-core.contribution.js.map +1 -1
- package/lib/browser/chat/chat-manager.service.d.ts +1 -5
- package/lib/browser/chat/chat-manager.service.d.ts.map +1 -1
- package/lib/browser/chat/chat-manager.service.js +13 -17
- package/lib/browser/chat/chat-manager.service.js.map +1 -1
- package/lib/browser/chat/chat-model.d.ts +0 -2
- package/lib/browser/chat/chat-model.d.ts.map +1 -1
- package/lib/browser/chat/chat-model.js +2 -8
- package/lib/browser/chat/chat-model.js.map +1 -1
- package/lib/browser/chat/chat.internal.service.d.ts +1 -0
- package/lib/browser/chat/chat.internal.service.d.ts.map +1 -1
- package/lib/browser/chat/chat.internal.service.js +3 -0
- package/lib/browser/chat/chat.internal.service.js.map +1 -1
- package/lib/browser/chat/chat.module.less +2 -1
- package/lib/browser/chat/chat.view.d.ts.map +1 -1
- package/lib/browser/chat/chat.view.js +9 -6
- package/lib/browser/chat/chat.view.js.map +1 -1
- package/lib/browser/components/ChatContext/index.js +2 -2
- package/lib/browser/components/ChatContext/index.js.map +1 -1
- package/lib/browser/components/ChatHistory.d.ts +0 -1
- 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/components/ChatInput.d.ts.map +1 -1
- package/lib/browser/components/ChatInput.js +1 -25
- package/lib/browser/components/ChatInput.js.map +1 -1
- package/lib/browser/components/ChatToolRender.d.ts.map +1 -1
- package/lib/browser/components/ChatToolRender.js +3 -2
- package/lib/browser/components/ChatToolRender.js.map +1 -1
- package/lib/browser/components/{chat-history.css → chat-history.module.less} +1 -1
- package/lib/browser/components/components.module.less +0 -20
- package/lib/browser/context/llm-context.service.d.ts +5 -16
- package/lib/browser/context/llm-context.service.d.ts.map +1 -1
- package/lib/browser/context/llm-context.service.js +47 -78
- package/lib/browser/context/llm-context.service.js.map +1 -1
- package/lib/browser/index.d.ts.map +1 -1
- package/lib/browser/index.js +0 -4
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/layout/layout.module.less +4 -4
- package/lib/browser/mcp/base-apply.service.d.ts +31 -40
- package/lib/browser/mcp/base-apply.service.d.ts.map +1 -1
- package/lib/browser/mcp/base-apply.service.js +233 -167
- package/lib/browser/mcp/base-apply.service.js.map +1 -1
- package/lib/browser/mcp/mcp-server-proxy.service.d.ts +0 -6
- package/lib/browser/mcp/mcp-server-proxy.service.d.ts.map +1 -1
- package/lib/browser/mcp/mcp-server-proxy.service.js +1 -10
- 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 +2 -3
- 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 +55 -41
- package/lib/browser/mcp/tools/components/EditFile.js.map +1 -1
- package/lib/browser/mcp/tools/components/index.module.less +22 -4
- package/lib/browser/mcp/tools/createNewFileWithText.d.ts.map +1 -1
- package/lib/browser/mcp/tools/createNewFileWithText.js +0 -1
- package/lib/browser/mcp/tools/createNewFileWithText.js.map +1 -1
- package/lib/browser/mcp/tools/editFile.js +1 -1
- package/lib/browser/mcp/tools/editFile.js.map +1 -1
- package/lib/browser/mcp/tools/getDiagnosticsByPath.d.ts.map +1 -1
- package/lib/browser/mcp/tools/getDiagnosticsByPath.js +0 -1
- package/lib/browser/mcp/tools/getDiagnosticsByPath.js.map +1 -1
- package/lib/browser/mcp/tools/handlers/EditFile.d.ts +5 -1
- 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/mcp/tools/handlers/RunCommand.d.ts.map +1 -1
- package/lib/browser/mcp/tools/handlers/RunCommand.js +0 -2
- package/lib/browser/mcp/tools/handlers/RunCommand.js.map +1 -1
- package/lib/browser/mcp/tools/runTerminalCmd.d.ts.map +1 -1
- package/lib/browser/mcp/tools/runTerminalCmd.js +0 -1
- package/lib/browser/mcp/tools/runTerminalCmd.js.map +1 -1
- package/lib/browser/model/msg-history-manager.d.ts +1 -0
- package/lib/browser/model/msg-history-manager.d.ts.map +1 -1
- package/lib/browser/model/msg-history-manager.js +12 -2
- 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 +0 -16
- 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-manager.d.ts +6 -0
- package/lib/browser/widget/inline-diff/inline-diff-manager.d.ts.map +1 -0
- package/lib/browser/widget/inline-diff/inline-diff-manager.js +27 -0
- package/lib/browser/widget/inline-diff/inline-diff-manager.js.map +1 -0
- package/lib/browser/widget/inline-diff/inline-diff-widget.module.less +12 -0
- package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts +2 -0
- 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 +11 -4
- package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js.map +1 -1
- package/lib/common/index.d.ts +1 -8
- package/lib/common/index.d.ts.map +1 -1
- package/lib/common/index.js +1 -3
- package/lib/common/index.js.map +1 -1
- package/lib/common/llm-context.d.ts +9 -12
- package/lib/common/llm-context.d.ts.map +1 -1
- package/lib/common/llm-context.js.map +1 -1
- package/lib/common/mcp-server-manager.d.ts +1 -17
- package/lib/common/mcp-server-manager.d.ts.map +1 -1
- package/lib/common/mcp-server-manager.js.map +1 -1
- package/lib/common/prompts/context-prompt-provider.d.ts +3 -2
- package/lib/common/prompts/context-prompt-provider.d.ts.map +1 -1
- package/lib/common/prompts/context-prompt-provider.js +22 -21
- package/lib/common/prompts/context-prompt-provider.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 +17 -6
- 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 +1 -2
- 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 +54 -3
- package/lib/node/base-language-model.js.map +1 -1
- package/lib/node/mcp/sumi-mcp-server.d.ts +3 -17
- package/lib/node/mcp/sumi-mcp-server.d.ts.map +1 -1
- package/lib/node/mcp/sumi-mcp-server.js +6 -59
- package/lib/node/mcp/sumi-mcp-server.js.map +1 -1
- package/lib/node/mcp-server-manager-impl.d.ts +3 -4
- package/lib/node/mcp-server-manager-impl.d.ts.map +1 -1
- package/lib/node/mcp-server-manager-impl.js +6 -26
- package/lib/node/mcp-server-manager-impl.js.map +1 -1
- package/lib/node/mcp-server.d.ts +16 -5
- package/lib/node/mcp-server.d.ts.map +1 -1
- package/lib/node/mcp-server.js +6 -12
- package/lib/node/mcp-server.js.map +1 -1
- package/lib/node/openai/openai-language-model.d.ts +3 -4
- package/lib/node/openai/openai-language-model.d.ts.map +1 -1
- package/lib/node/openai/openai-language-model.js +2 -3
- package/lib/node/openai/openai-language-model.js.map +1 -1
- package/package.json +27 -27
- package/src/browser/ai-core.contribution.ts +29 -14
- package/src/browser/chat/chat-manager.service.ts +13 -17
- package/src/browser/chat/chat-model.ts +3 -18
- package/src/browser/chat/chat.internal.service.ts +4 -0
- package/src/browser/chat/chat.module.less +2 -1
- package/src/browser/chat/chat.view.tsx +26 -10
- package/src/browser/components/ChatContext/index.tsx +2 -2
- package/src/browser/components/ChatHistory.tsx +21 -15
- package/src/browser/components/ChatInput.tsx +4 -67
- package/src/browser/components/ChatToolRender.tsx +2 -1
- package/src/browser/components/{chat-history.css → chat-history.module.less} +1 -1
- package/src/browser/components/components.module.less +0 -20
- package/src/browser/context/llm-context.service.ts +54 -90
- package/src/browser/index.ts +0 -4
- package/src/browser/layout/layout.module.less +4 -4
- package/src/browser/mcp/base-apply.service.ts +266 -213
- package/src/browser/mcp/mcp-server-proxy.service.ts +2 -14
- package/src/browser/mcp/mcp-server.feature.registry.ts +2 -3
- package/src/browser/mcp/tools/components/EditFile.tsx +82 -60
- package/src/browser/mcp/tools/components/index.module.less +22 -4
- package/src/browser/mcp/tools/createNewFileWithText.ts +0 -1
- package/src/browser/mcp/tools/editFile.ts +2 -2
- package/src/browser/mcp/tools/getDiagnosticsByPath.ts +0 -1
- package/src/browser/mcp/tools/handlers/EditFile.ts +4 -4
- package/src/browser/mcp/tools/handlers/RunCommand.ts +0 -2
- package/src/browser/mcp/tools/runTerminalCmd.ts +0 -1
- package/src/browser/model/msg-history-manager.ts +12 -2
- package/src/browser/preferences/schema.ts +0 -16
- package/src/browser/types.ts +1 -1
- package/src/browser/widget/inline-diff/inline-diff-manager.tsx +38 -0
- package/src/browser/widget/inline-diff/inline-diff-widget.module.less +12 -0
- package/src/browser/widget/inline-stream-diff/inline-stream-diff.handler.tsx +13 -4
- package/src/common/index.ts +1 -7
- package/src/common/llm-context.ts +4 -10
- package/src/common/mcp-server-manager.ts +1 -17
- package/src/common/prompts/context-prompt-provider.ts +28 -26
- package/src/common/tool-invocation-registry.ts +2 -2
- package/src/common/types.ts +20 -6
- package/src/common/utils.ts +1 -3
- package/src/node/base-language-model.ts +63 -1
- package/src/node/mcp/sumi-mcp-server.ts +9 -67
- package/src/node/mcp-server-manager-impl.ts +9 -30
- package/src/node/mcp-server.ts +14 -11
- package/src/node/openai/openai-language-model.ts +4 -7
- package/lib/browser/mcp/config/components/mcp-config.module.less +0 -178
- package/lib/browser/mcp/config/components/mcp-config.view.d.ts +0 -3
- package/lib/browser/mcp/config/components/mcp-config.view.d.ts.map +0 -1
- package/lib/browser/mcp/config/components/mcp-config.view.js +0 -150
- package/lib/browser/mcp/config/components/mcp-config.view.js.map +0 -1
- package/lib/browser/mcp/config/components/mcp-server-form.d.ts +0 -16
- package/lib/browser/mcp/config/components/mcp-server-form.d.ts.map +0 -1
- package/lib/browser/mcp/config/components/mcp-server-form.js +0 -84
- package/lib/browser/mcp/config/components/mcp-server-form.js.map +0 -1
- package/lib/browser/mcp/config/components/mcp-server-form.module.less +0 -78
- package/lib/browser/mcp/config/mcp-config.commands.d.ts +0 -10
- package/lib/browser/mcp/config/mcp-config.commands.d.ts.map +0 -1
- package/lib/browser/mcp/config/mcp-config.commands.js +0 -35
- package/lib/browser/mcp/config/mcp-config.commands.js.map +0 -1
- package/lib/browser/mcp/config/mcp-config.contribution.d.ts +0 -16
- package/lib/browser/mcp/config/mcp-config.contribution.d.ts.map +0 -1
- package/lib/browser/mcp/config/mcp-config.contribution.js +0 -62
- package/lib/browser/mcp/config/mcp-config.contribution.js.map +0 -1
- package/src/browser/mcp/config/components/mcp-config.module.less +0 -178
- package/src/browser/mcp/config/components/mcp-config.view.tsx +0 -215
- package/src/browser/mcp/config/components/mcp-server-form.module.less +0 -78
- package/src/browser/mcp/config/components/mcp-server-form.tsx +0 -144
- package/src/browser/mcp/config/mcp-config.commands.ts +0 -29
- 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
|
-
|
|
21
|
-
|
|
22
|
-
${context.recentlyViewFiles.map((file, idx) =>
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
</
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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) {
|
package/src/common/types.ts
CHANGED
|
@@ -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';
|
package/src/common/utils.ts
CHANGED
|
@@ -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 =
|
|
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
|
-
|
|
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 {
|
|
14
|
-
import {
|
|
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 {
|
|
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(
|
|
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
|
|
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 =
|
|
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
|
|
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 {
|
|
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 {
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
146
|
-
async initBuiltinServer(builtinMCPServer: BuiltinMCPServer, enabled: boolean = true): Promise<void> {
|
|
134
|
+
async initBuiltinServer(builtinMCPServer: BuiltinMCPServer): Promise<void> {
|
|
147
135
|
this.addOrUpdateServerDirectly(builtinMCPServer);
|
|
148
|
-
|
|
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
|
}
|
package/src/node/mcp-server.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|
17
|
+
export class MCPServerImpl implements IMCPServer {
|
|
10
18
|
private name: string;
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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):
|
|
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
|
|
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:
|
|
22
|
+
protected getModelIdentifier(provider: OpenAIProvider, modelId?: string) {
|
|
26
23
|
return provider(modelId || 'qwen-max');
|
|
27
24
|
}
|
|
28
25
|
}
|