@opensumi/ide-ai-native 3.7.1-next-1737628160.0 → 3.7.1-next-1737703128.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 +3 -0
- package/lib/browser/ai-core.contribution.d.ts.map +1 -1
- package/lib/browser/ai-core.contribution.js +31 -4
- package/lib/browser/ai-core.contribution.js.map +1 -1
- package/lib/browser/chat/chat-model.d.ts +2 -2
- package/lib/browser/chat/chat-model.d.ts.map +1 -1
- package/lib/browser/chat/chat-model.js +21 -9
- package/lib/browser/chat/chat-model.js.map +1 -1
- package/lib/browser/chat/chat-proxy.service.d.ts +1 -0
- package/lib/browser/chat/chat-proxy.service.d.ts.map +1 -1
- package/lib/browser/chat/chat-proxy.service.js +11 -0
- package/lib/browser/chat/chat-proxy.service.js.map +1 -1
- package/lib/browser/components/ChatEditor.d.ts +8 -0
- package/lib/browser/components/ChatEditor.d.ts.map +1 -1
- package/lib/browser/components/ChatEditor.js +8 -7
- package/lib/browser/components/ChatEditor.js.map +1 -1
- package/lib/browser/components/ChatReply.d.ts.map +1 -1
- package/lib/browser/components/ChatReply.js +33 -4
- package/lib/browser/components/ChatReply.js.map +1 -1
- package/lib/browser/components/ChatToolRender.d.ts +6 -0
- package/lib/browser/components/ChatToolRender.d.ts.map +1 -0
- package/lib/browser/components/ChatToolRender.js +24 -0
- package/lib/browser/components/ChatToolRender.js.map +1 -0
- package/lib/browser/components/components.module.less +32 -31
- package/lib/browser/contrib/intelligent-completions/index.d.ts +1 -5
- package/lib/browser/contrib/intelligent-completions/index.d.ts.map +1 -1
- package/lib/browser/contrib/intelligent-completions/index.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 +1 -2
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.js.map +1 -1
- package/lib/browser/contrib/intelligent-completions/source/base.d.ts +2 -1
- package/lib/browser/contrib/intelligent-completions/source/base.d.ts.map +1 -1
- package/lib/browser/contrib/intelligent-completions/source/base.js.map +1 -1
- package/lib/browser/contrib/intelligent-completions/source/line-change.source.d.ts +3 -2
- package/lib/browser/contrib/intelligent-completions/source/line-change.source.d.ts.map +1 -1
- package/lib/browser/contrib/intelligent-completions/source/line-change.source.js +21 -51
- package/lib/browser/contrib/intelligent-completions/source/line-change.source.js.map +1 -1
- package/lib/browser/index.d.ts +11 -3
- package/lib/browser/index.d.ts.map +1 -1
- package/lib/browser/index.js +39 -3
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/mcp/mcp-server-proxy.service.d.ts +17 -0
- package/lib/browser/mcp/mcp-server-proxy.service.d.ts.map +1 -0
- package/lib/browser/mcp/mcp-server-proxy.service.js +36 -0
- package/lib/browser/mcp/mcp-server-proxy.service.js.map +1 -0
- package/lib/browser/mcp/mcp-server.feature.registry.d.ts +16 -0
- package/lib/browser/mcp/mcp-server.feature.registry.d.ts.map +1 -0
- package/lib/browser/mcp/mcp-server.feature.registry.js +45 -0
- package/lib/browser/mcp/mcp-server.feature.registry.js.map +1 -0
- package/lib/browser/mcp/tools/createNewFileWithText.d.ts +9 -0
- package/lib/browser/mcp/tools/createNewFileWithText.d.ts.map +1 -0
- package/lib/browser/mcp/tools/createNewFileWithText.js +84 -0
- package/lib/browser/mcp/tools/createNewFileWithText.js.map +1 -0
- package/lib/browser/mcp/tools/findFilesByNameSubstring.d.ts +9 -0
- package/lib/browser/mcp/tools/findFilesByNameSubstring.d.ts.map +1 -0
- package/lib/browser/mcp/tools/findFilesByNameSubstring.js +92 -0
- package/lib/browser/mcp/tools/findFilesByNameSubstring.js.map +1 -0
- package/lib/browser/mcp/tools/getCurrentFilePath.d.ts +8 -0
- package/lib/browser/mcp/tools/getCurrentFilePath.d.ts.map +1 -0
- package/lib/browser/mcp/tools/getCurrentFilePath.js +49 -0
- package/lib/browser/mcp/tools/getCurrentFilePath.js.map +1 -0
- package/lib/browser/mcp/tools/getDiagnosticsByPath.d.ts +10 -0
- package/lib/browser/mcp/tools/getDiagnosticsByPath.d.ts.map +1 -0
- package/lib/browser/mcp/tools/getDiagnosticsByPath.js +119 -0
- package/lib/browser/mcp/tools/getDiagnosticsByPath.js.map +1 -0
- package/lib/browser/mcp/tools/getFileTextByPath.d.ts +9 -0
- package/lib/browser/mcp/tools/getFileTextByPath.d.ts.map +1 -0
- package/lib/browser/mcp/tools/getFileTextByPath.js +97 -0
- package/lib/browser/mcp/tools/getFileTextByPath.js.map +1 -0
- package/lib/browser/mcp/tools/getOpenEditorFileDiagnostics.d.ts +11 -0
- package/lib/browser/mcp/tools/getOpenEditorFileDiagnostics.d.ts.map +1 -0
- package/lib/browser/mcp/tools/getOpenEditorFileDiagnostics.js +119 -0
- package/lib/browser/mcp/tools/getOpenEditorFileDiagnostics.js.map +1 -0
- package/lib/browser/mcp/tools/getOpenEditorFileText.d.ts +8 -0
- package/lib/browser/mcp/tools/getOpenEditorFileText.d.ts.map +1 -0
- package/lib/browser/mcp/tools/getOpenEditorFileText.js +50 -0
- package/lib/browser/mcp/tools/getOpenEditorFileText.js.map +1 -0
- package/lib/browser/mcp/tools/getSelectedText.d.ts +8 -0
- package/lib/browser/mcp/tools/getSelectedText.d.ts.map +1 -0
- package/lib/browser/mcp/tools/getSelectedText.js +57 -0
- package/lib/browser/mcp/tools/getSelectedText.js.map +1 -0
- package/lib/browser/preferences/schema.d.ts.map +1 -1
- package/lib/browser/preferences/schema.js +0 -4
- package/lib/browser/preferences/schema.js.map +1 -1
- package/lib/browser/types.d.ts +31 -0
- package/lib/browser/types.d.ts.map +1 -1
- package/lib/browser/types.js +4 -1
- package/lib/browser/types.js.map +1 -1
- package/lib/common/index.d.ts +5 -0
- package/lib/common/index.d.ts.map +1 -1
- package/lib/common/index.js +4 -1
- package/lib/common/index.js.map +1 -1
- package/lib/common/mcp-server-manager.d.ts +39 -0
- package/lib/common/mcp-server-manager.d.ts.map +1 -0
- package/lib/common/mcp-server-manager.js +6 -0
- package/lib/common/mcp-server-manager.js.map +1 -0
- package/lib/common/tool-invocation-registry.d.ts +67 -0
- package/lib/common/tool-invocation-registry.d.ts.map +1 -0
- package/lib/common/tool-invocation-registry.js +68 -0
- package/lib/common/tool-invocation-registry.js.map +1 -0
- package/lib/common/types.d.ts +14 -0
- package/lib/common/types.d.ts.map +1 -1
- package/lib/node/anthropic/anthropic-language-model.d.ts +13 -0
- package/lib/node/anthropic/anthropic-language-model.d.ts.map +1 -0
- package/lib/node/anthropic/anthropic-language-model.js +79 -0
- package/lib/node/anthropic/anthropic-language-model.js.map +1 -0
- package/lib/node/index.d.ts.map +1 -1
- package/lib/node/index.js +21 -0
- package/lib/node/index.js.map +1 -1
- package/lib/node/mcp/sumi-mcp-server.d.ts +84 -0
- package/lib/node/mcp/sumi-mcp-server.d.ts.map +1 -0
- package/lib/node/mcp/sumi-mcp-server.js +134 -0
- package/lib/node/mcp/sumi-mcp-server.js.map +1 -0
- package/lib/node/mcp-server-manager-impl.d.ts +20 -0
- package/lib/node/mcp-server-manager-impl.d.ts.map +1 -0
- package/lib/node/mcp-server-manager-impl.js +123 -0
- package/lib/node/mcp-server-manager-impl.js.map +1 -0
- package/lib/node/mcp-server.d.ts +205 -0
- package/lib/node/mcp-server.d.ts.map +1 -0
- package/lib/node/mcp-server.js +86 -0
- package/lib/node/mcp-server.js.map +1 -0
- package/lib/node/openai/openai-language-model.d.ts +12 -0
- package/lib/node/openai/openai-language-model.d.ts.map +1 -0
- package/lib/node/openai/openai-language-model.js +136 -0
- package/lib/node/openai/openai-language-model.js.map +1 -0
- package/package.json +26 -21
- package/src/browser/ai-core.contribution.ts +47 -4
- package/src/browser/chat/chat-model.ts +21 -9
- package/src/browser/chat/chat-proxy.service.ts +12 -0
- package/src/browser/components/ChatEditor.tsx +6 -4
- package/src/browser/components/ChatReply.tsx +40 -4
- package/src/browser/components/ChatToolRender.tsx +27 -0
- package/src/browser/components/components.module.less +32 -31
- package/src/browser/contrib/intelligent-completions/index.ts +2 -3
- package/src/browser/contrib/intelligent-completions/intelligent-completions.controller.ts +1 -2
- package/src/browser/contrib/intelligent-completions/source/base.ts +2 -0
- package/src/browser/contrib/intelligent-completions/source/line-change.source.ts +24 -79
- package/src/browser/index.ts +50 -4
- package/src/browser/mcp/mcp-server-proxy.service.ts +32 -0
- package/src/browser/mcp/mcp-server.feature.registry.ts +47 -0
- package/src/browser/mcp/tools/createNewFileWithText.ts +85 -0
- package/src/browser/mcp/tools/findFilesByNameSubstring.ts +93 -0
- package/src/browser/mcp/tools/getCurrentFilePath.ts +49 -0
- package/src/browser/mcp/tools/getDiagnosticsByPath.ts +123 -0
- package/src/browser/mcp/tools/getFileTextByPath.ts +97 -0
- package/src/browser/mcp/tools/getOpenEditorFileDiagnostics.ts +121 -0
- package/src/browser/mcp/tools/getOpenEditorFileText.ts +50 -0
- package/src/browser/mcp/tools/getSelectedText.ts +57 -0
- package/src/browser/preferences/schema.ts +0 -4
- package/src/browser/types.ts +39 -0
- package/src/common/index.ts +9 -0
- package/src/common/mcp-server-manager.ts +45 -0
- package/src/common/tool-invocation-registry.ts +124 -0
- package/src/common/types.ts +18 -0
- package/src/node/anthropic/anthropic-language-model.ts +96 -0
- package/src/node/index.ts +24 -0
- package/src/node/mcp/sumi-mcp-server.ts +161 -0
- package/src/node/mcp-server-manager-impl.ts +130 -0
- package/src/node/mcp-server.ts +118 -0
- package/src/node/openai/openai-language-model.ts +152 -0
- package/lib/browser/contrib/intelligent-completions/source/typing.source.d.ts +0 -9
- package/lib/browser/contrib/intelligent-completions/source/typing.source.d.ts.map +0 -1
- package/lib/browser/contrib/intelligent-completions/source/typing.source.js +0 -38
- package/lib/browser/contrib/intelligent-completions/source/typing.source.js.map +0 -1
- package/src/browser/contrib/intelligent-completions/source/typing.source.ts +0 -36
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
5
|
+
|
|
6
|
+
import { Autowired, Injectable } from '@opensumi/di';
|
|
7
|
+
import { Domain, URI } from '@opensumi/ide-core-common';
|
|
8
|
+
import { WorkbenchEditorService } from '@opensumi/ide-editor';
|
|
9
|
+
import { IWorkspaceService } from '@opensumi/ide-workspace';
|
|
10
|
+
import { URI as MonacoURI } from '@opensumi/monaco-editor-core/esm/vs/base/common/uri';
|
|
11
|
+
import { IMarkerService, MarkerSeverity } from '@opensumi/monaco-editor-core/esm/vs/platform/markers/common/markers';
|
|
12
|
+
|
|
13
|
+
import { IMCPServerRegistry, MCPLogger, MCPServerContribution, MCPToolDefinition } from '../../types';
|
|
14
|
+
|
|
15
|
+
const inputSchema = z.object({});
|
|
16
|
+
|
|
17
|
+
@Domain(MCPServerContribution)
|
|
18
|
+
export class GetOpenEditorFileDiagnosticsTool implements MCPServerContribution {
|
|
19
|
+
@Autowired(WorkbenchEditorService)
|
|
20
|
+
private readonly editorService: WorkbenchEditorService;
|
|
21
|
+
|
|
22
|
+
@Autowired(IWorkspaceService)
|
|
23
|
+
private readonly workspaceService: IWorkspaceService;
|
|
24
|
+
|
|
25
|
+
@Autowired(IMarkerService)
|
|
26
|
+
private readonly markerService: IMarkerService;
|
|
27
|
+
|
|
28
|
+
registerMCPServer(registry: IMCPServerRegistry): void {
|
|
29
|
+
registry.registerMCPTool(this.getToolDefinition());
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
getToolDefinition(): MCPToolDefinition {
|
|
33
|
+
return {
|
|
34
|
+
name: 'get_open_in_editor_file_diagnostics',
|
|
35
|
+
description:
|
|
36
|
+
'Retrieves diagnostic information (errors, warnings, etc.) from the currently active file in VS Code editor. ' +
|
|
37
|
+
'Use this tool to get information about problems in your current file. ' +
|
|
38
|
+
'IMPORTANT: This tool should be called after any code generation or modification operations to verify and fix potential issues. ' +
|
|
39
|
+
'Returns a JSON-formatted list of diagnostics, where each entry contains: ' +
|
|
40
|
+
'- path: The file path where the diagnostic was found ' +
|
|
41
|
+
'- line: The line number (1-based) of the diagnostic ' +
|
|
42
|
+
'- severity: The severity level ("error", "warning", "information", or "hint") ' +
|
|
43
|
+
'- message: The diagnostic message ' +
|
|
44
|
+
'Returns an empty list ([]) if no diagnostics are found or no file is open. ' +
|
|
45
|
+
'Best Practice: Always check diagnostics after code generation to ensure code quality and fix any issues immediately. ' +
|
|
46
|
+
'Diagnostic Severity Handling Guidelines: ' +
|
|
47
|
+
'- "error": Must be fixed immediately as they indicate critical issues that will prevent code from working correctly. ' +
|
|
48
|
+
'- "warning": For user code, preserve unless the warning indicates a clear improvement opportunity. For generated code, optimize to remove warnings. ' +
|
|
49
|
+
'- "information"/"hint": For user code, preserve as they might reflect intentional patterns. For generated code, optimize if it improves code quality without changing functionality.',
|
|
50
|
+
inputSchema: zodToJsonSchema(inputSchema),
|
|
51
|
+
handler: this.handler.bind(this),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private async handler(args: z.infer<typeof inputSchema>, logger: MCPLogger) {
|
|
56
|
+
try {
|
|
57
|
+
// 获取当前活动的编辑器
|
|
58
|
+
const editor = this.editorService.currentEditor;
|
|
59
|
+
if (!editor || !editor.currentUri) {
|
|
60
|
+
logger.appendLine('Error: No active text editor found');
|
|
61
|
+
return {
|
|
62
|
+
content: [{ type: 'text', text: '[]' }],
|
|
63
|
+
isError: true,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 获取工作区根目录
|
|
68
|
+
const workspaceRoots = this.workspaceService.tryGetRoots();
|
|
69
|
+
if (!workspaceRoots || workspaceRoots.length === 0) {
|
|
70
|
+
logger.appendLine('Error: Cannot determine project directory');
|
|
71
|
+
return {
|
|
72
|
+
content: [{ type: 'text', text: '[]' }],
|
|
73
|
+
isError: true,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// 获取当前文件的诊断信息
|
|
78
|
+
const monacoUri = MonacoURI.parse(editor.currentUri.toString());
|
|
79
|
+
const markers = this.markerService.read({ resource: monacoUri });
|
|
80
|
+
const rootUri = URI.parse(workspaceRoots[0].uri);
|
|
81
|
+
const relativePath = path.relative(rootUri.codeUri.fsPath, editor.currentUri.codeUri.fsPath);
|
|
82
|
+
|
|
83
|
+
// 转换诊断信息
|
|
84
|
+
const diagnosticInfos = markers.map((marker) => ({
|
|
85
|
+
path: relativePath,
|
|
86
|
+
line: marker.startLineNumber,
|
|
87
|
+
severity: this.getSeverityString(marker.severity),
|
|
88
|
+
message: marker.message,
|
|
89
|
+
}));
|
|
90
|
+
|
|
91
|
+
// 将结果转换为 JSON 字符串
|
|
92
|
+
const resultJson = JSON.stringify(diagnosticInfos, null, 2);
|
|
93
|
+
logger.appendLine(`Found ${diagnosticInfos.length} diagnostics in current file`);
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
content: [{ type: 'text', text: resultJson }],
|
|
97
|
+
};
|
|
98
|
+
} catch (error) {
|
|
99
|
+
logger.appendLine(`Error getting diagnostics: ${error}`);
|
|
100
|
+
return {
|
|
101
|
+
content: [{ type: 'text', text: '[]' }],
|
|
102
|
+
isError: true,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private getSeverityString(severity: MarkerSeverity): string {
|
|
108
|
+
switch (severity) {
|
|
109
|
+
case MarkerSeverity.Error:
|
|
110
|
+
return 'error';
|
|
111
|
+
case MarkerSeverity.Warning:
|
|
112
|
+
return 'warning';
|
|
113
|
+
case MarkerSeverity.Info:
|
|
114
|
+
return 'information';
|
|
115
|
+
case MarkerSeverity.Hint:
|
|
116
|
+
return 'hint';
|
|
117
|
+
default:
|
|
118
|
+
return 'unknown';
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
3
|
+
|
|
4
|
+
import { Autowired, Injectable } from '@opensumi/di';
|
|
5
|
+
import { Domain } from '@opensumi/ide-core-common';
|
|
6
|
+
import { WorkbenchEditorService } from '@opensumi/ide-editor';
|
|
7
|
+
|
|
8
|
+
import { IMCPServerRegistry, MCPLogger, MCPServerContribution, MCPToolDefinition } from '../../types';
|
|
9
|
+
|
|
10
|
+
const inputSchema = z.object({});
|
|
11
|
+
|
|
12
|
+
@Domain(MCPServerContribution)
|
|
13
|
+
export class GetOpenEditorFileTextTool implements MCPServerContribution {
|
|
14
|
+
@Autowired(WorkbenchEditorService)
|
|
15
|
+
private readonly editorService: WorkbenchEditorService;
|
|
16
|
+
|
|
17
|
+
registerMCPServer(registry: IMCPServerRegistry): void {
|
|
18
|
+
registry.registerMCPTool(this.getToolDefinition());
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
getToolDefinition(): MCPToolDefinition {
|
|
22
|
+
return {
|
|
23
|
+
name: 'get_open_in_editor_file_text',
|
|
24
|
+
description:
|
|
25
|
+
'Retrieves the complete text content of the currently active file in the IDE editor. ' +
|
|
26
|
+
"Use this tool to access and analyze the file's contents for tasks such as code review, content inspection, or text processing. " +
|
|
27
|
+
'Returns empty string if no file is currently open.',
|
|
28
|
+
inputSchema: zodToJsonSchema(inputSchema),
|
|
29
|
+
handler: this.handler.bind(this),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
private async handler(args: z.infer<typeof inputSchema>, logger: MCPLogger) {
|
|
34
|
+
const editor = this.editorService.currentEditor;
|
|
35
|
+
if (!editor || !editor.currentDocumentModel) {
|
|
36
|
+
logger.appendLine('Error: No active text editor found');
|
|
37
|
+
return {
|
|
38
|
+
content: [{ type: 'text', text: '' }],
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const document = editor.currentDocumentModel;
|
|
43
|
+
logger.appendLine(`Reading content from: ${document.uri.toString()}`);
|
|
44
|
+
const content = document.getText();
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
content: [{ type: 'text', text: content }],
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
3
|
+
|
|
4
|
+
import { Autowired, Injectable } from '@opensumi/di';
|
|
5
|
+
import { Domain } from '@opensumi/ide-core-common';
|
|
6
|
+
import { WorkbenchEditorService } from '@opensumi/ide-editor';
|
|
7
|
+
|
|
8
|
+
import { IMCPServerRegistry, MCPLogger, MCPServerContribution, MCPToolDefinition } from '../../types';
|
|
9
|
+
|
|
10
|
+
const inputSchema = z.object({});
|
|
11
|
+
|
|
12
|
+
@Domain(MCPServerContribution)
|
|
13
|
+
export class GetSelectedTextTool implements MCPServerContribution {
|
|
14
|
+
@Autowired(WorkbenchEditorService)
|
|
15
|
+
private readonly editorService: WorkbenchEditorService;
|
|
16
|
+
|
|
17
|
+
registerMCPServer(registry: IMCPServerRegistry): void {
|
|
18
|
+
registry.registerMCPTool(this.getToolDefinition());
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
getToolDefinition(): MCPToolDefinition {
|
|
22
|
+
return {
|
|
23
|
+
name: 'get_selected_in_editor_text',
|
|
24
|
+
description:
|
|
25
|
+
'Retrieves the currently selected text from the active editor in VS Code. ' +
|
|
26
|
+
'Use this tool when you need to access and analyze text that has been highlighted/selected by the user. ' +
|
|
27
|
+
'Returns an empty string if no text is selected or no editor is open.',
|
|
28
|
+
inputSchema: zodToJsonSchema(inputSchema),
|
|
29
|
+
handler: this.handler.bind(this),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
private async handler(args: z.infer<typeof inputSchema>, logger: MCPLogger) {
|
|
34
|
+
const editor = this.editorService.currentEditor;
|
|
35
|
+
if (!editor || !editor.monacoEditor) {
|
|
36
|
+
logger.appendLine('Error: No active text editor found');
|
|
37
|
+
return {
|
|
38
|
+
content: [{ type: 'text', text: '' }],
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const selection = editor.monacoEditor.getSelection();
|
|
43
|
+
if (!selection) {
|
|
44
|
+
logger.appendLine('No text is currently selected');
|
|
45
|
+
return {
|
|
46
|
+
content: [{ type: 'text', text: '' }],
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const selectedText = editor.monacoEditor.getModel()?.getValueInRange(selection) || '';
|
|
51
|
+
logger.appendLine(`Retrieved selected text of length: ${selectedText.length}`);
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
content: [{ type: 'text', text: selectedText }],
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
package/src/browser/types.ts
CHANGED
|
@@ -292,6 +292,45 @@ export interface AINativeCoreContribution {
|
|
|
292
292
|
registerIntelligentCompletionFeature?(registry: IIntelligentCompletionsRegistry): void;
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
+
// MCP Server 的 贡献点
|
|
296
|
+
export const MCPServerContribution = Symbol('MCPServerContribution');
|
|
297
|
+
|
|
298
|
+
export const TokenMCPServerRegistry = Symbol('TokenMCPServerRegistry');
|
|
299
|
+
|
|
300
|
+
export interface MCPServerContribution {
|
|
301
|
+
registerMCPServer(registry: IMCPServerRegistry): void;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export interface MCPLogger {
|
|
305
|
+
appendLine(message: string): void;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
export interface MCPToolDefinition {
|
|
309
|
+
name: string;
|
|
310
|
+
description: string;
|
|
311
|
+
inputSchema: any; // JSON Schema
|
|
312
|
+
handler: (
|
|
313
|
+
args: any,
|
|
314
|
+
logger: MCPLogger,
|
|
315
|
+
) => Promise<{
|
|
316
|
+
content: { type: string; text: string }[];
|
|
317
|
+
isError?: boolean;
|
|
318
|
+
}>;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
export interface IMCPServerRegistry {
|
|
322
|
+
registerMCPTool(tool: MCPToolDefinition): void;
|
|
323
|
+
getMCPTools(): MCPToolDefinition[];
|
|
324
|
+
callMCPTool(
|
|
325
|
+
name: string,
|
|
326
|
+
args: any,
|
|
327
|
+
): Promise<{
|
|
328
|
+
content: { type: string; text: string }[];
|
|
329
|
+
isError?: boolean;
|
|
330
|
+
}>;
|
|
331
|
+
// 后续支持其他 MCP 功能
|
|
332
|
+
}
|
|
333
|
+
|
|
295
334
|
export interface IChatComponentConfig {
|
|
296
335
|
id: string;
|
|
297
336
|
component: React.ComponentType<Record<string, unknown>>;
|
package/src/common/index.ts
CHANGED
|
@@ -116,6 +116,15 @@ export const IChatAgentService = Symbol('IChatAgentService');
|
|
|
116
116
|
|
|
117
117
|
export const ChatProxyServiceToken = Symbol('ChatProxyServiceToken');
|
|
118
118
|
|
|
119
|
+
// 暴露给 Node.js 层,使其可以感知 Opensumi 注册的 MCP 能力
|
|
120
|
+
export const TokenMCPServerProxyService = Symbol('TokenMCPServerProxyService');
|
|
121
|
+
|
|
122
|
+
export interface ISumiMCPServerBackend {
|
|
123
|
+
initBuiltinMCPServer(): void;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export const SumiMCPServerProxyServicePath = 'SumiMCPServerProxyServicePath';
|
|
127
|
+
|
|
119
128
|
export interface IChatAgentService {
|
|
120
129
|
readonly onDidChangeAgents: Event<void>;
|
|
121
130
|
readonly onDidSendMessage: Event<IChatProgress>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
+
|
|
3
|
+
export interface MCPServerManager {
|
|
4
|
+
callTool(serverName: string, toolName: string, arg_string: string): ReturnType<Client['callTool']>;
|
|
5
|
+
removeServer(name: string): void;
|
|
6
|
+
addOrUpdateServer(description: MCPServerDescription): void;
|
|
7
|
+
// invoke in node.js only
|
|
8
|
+
addOrUpdateServerDirectly(server: any): void;
|
|
9
|
+
initBuiltinServer(builtinMCPServer: any): void;
|
|
10
|
+
getTools(serverName: string): ReturnType<Client['listTools']>;
|
|
11
|
+
getServerNames(): Promise<string[]>;
|
|
12
|
+
startServer(serverName: string): Promise<void>;
|
|
13
|
+
stopServer(serverName: string): Promise<void>;
|
|
14
|
+
getStartedServers(): Promise<string[]>;
|
|
15
|
+
collectTools(serverName: string): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type MCPTool = Awaited<ReturnType<MCPServerManager['getTools']>>['tools'][number];
|
|
19
|
+
|
|
20
|
+
export type MCPToolParameter = Awaited<ReturnType<MCPServerManager['getTools']>>['tools'][number]['inputSchema'];
|
|
21
|
+
|
|
22
|
+
export interface MCPServerDescription {
|
|
23
|
+
/**
|
|
24
|
+
* The unique name of the MCP server.
|
|
25
|
+
*/
|
|
26
|
+
name: string;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The command to execute the MCP server.
|
|
30
|
+
*/
|
|
31
|
+
command: string;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* An array of arguments to pass to the command.
|
|
35
|
+
*/
|
|
36
|
+
args?: string[];
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Optional environment variables to set when starting the server.
|
|
40
|
+
*/
|
|
41
|
+
env?: { [key: string]: string };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const MCPServerManager = Symbol('MCPServerManager');
|
|
45
|
+
export const MCPServerManagerPath = 'ServicesMCPServerManager';
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { Injectable } from '@opensumi/di';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { MCPToolParameter } from './mcp-server-manager';
|
|
4
|
+
|
|
5
|
+
export const ToolParameterSchema = z.object({
|
|
6
|
+
type: z.enum(['string', 'number', 'boolean', 'object', 'array']),
|
|
7
|
+
description: z.string().optional(),
|
|
8
|
+
enum: z.array(z.any()).optional(),
|
|
9
|
+
items: z.lazy(() => ToolParameterSchema).optional(),
|
|
10
|
+
properties: z.record(z.lazy(() => ToolParameterSchema)).optional(),
|
|
11
|
+
required: z.array(z.string()).optional(),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export type ToolParameter = z.infer<typeof ToolParameterSchema>;
|
|
15
|
+
|
|
16
|
+
export interface ToolRequest {
|
|
17
|
+
id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
parameters?: any;
|
|
20
|
+
description?: string;
|
|
21
|
+
handler: (arg_string: string) => Promise<any>;
|
|
22
|
+
providerName?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export namespace ToolRequest {
|
|
26
|
+
export function isToolParameter(obj: unknown): obj is ToolParameter {
|
|
27
|
+
return ToolParameterSchema.safeParse(obj).success;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const ToolInvocationRegistry = Symbol('ToolInvocationRegistry');
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Registry for all the function calls available to Agents.
|
|
35
|
+
*/
|
|
36
|
+
export interface ToolInvocationRegistry {
|
|
37
|
+
/**
|
|
38
|
+
* Registers a tool into the registry.
|
|
39
|
+
*
|
|
40
|
+
* @param tool - The `ToolRequest` object representing the tool to be registered.
|
|
41
|
+
*/
|
|
42
|
+
registerTool(tool: ToolRequest): void;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Retrieves a specific `ToolRequest` from the registry.
|
|
46
|
+
*
|
|
47
|
+
* @param toolId - The unique identifier of the tool to retrieve.
|
|
48
|
+
* @returns The `ToolRequest` object corresponding to the provided tool ID,
|
|
49
|
+
* or `undefined` if the tool is not found in the registry.
|
|
50
|
+
*/
|
|
51
|
+
getFunction(toolId: string): ToolRequest | undefined;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Retrieves multiple `ToolRequest`s from the registry.
|
|
55
|
+
*
|
|
56
|
+
* @param toolIds - A list of tool IDs to retrieve.
|
|
57
|
+
* @returns An array of `ToolRequest` objects for the specified tool IDs.
|
|
58
|
+
* If a tool ID is not found, it is skipped in the returned array.
|
|
59
|
+
*/
|
|
60
|
+
getFunctions(...toolIds: string[]): ToolRequest[];
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Retrieves all `ToolRequest`s currently registered in the registry.
|
|
64
|
+
*
|
|
65
|
+
* @returns An array of all `ToolRequest` objects in the registry.
|
|
66
|
+
*/
|
|
67
|
+
getAllFunctions(): ToolRequest[];
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Unregisters all tools provided by a specific tool provider.
|
|
71
|
+
*
|
|
72
|
+
* @param providerName - The name of the tool provider whose tools should be removed (as specificed in the `ToolRequest`).
|
|
73
|
+
*/
|
|
74
|
+
unregisterAllTools(providerName: string): void;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export const ToolProvider = Symbol('ToolProvider');
|
|
78
|
+
export interface ToolProvider {
|
|
79
|
+
getTool(): ToolRequest;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@Injectable()
|
|
83
|
+
export class ToolInvocationRegistryImpl implements ToolInvocationRegistry {
|
|
84
|
+
|
|
85
|
+
private tools: Map<string, ToolRequest> = new Map<string, ToolRequest>();
|
|
86
|
+
|
|
87
|
+
unregisterAllTools(providerName: string): void {
|
|
88
|
+
const toolsToRemove: string[] = [];
|
|
89
|
+
for (const [id, tool] of this.tools.entries()) {
|
|
90
|
+
if (tool.providerName === providerName) {
|
|
91
|
+
toolsToRemove.push(id);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
toolsToRemove.forEach(id => this.tools.delete(id));
|
|
95
|
+
}
|
|
96
|
+
getAllFunctions(): ToolRequest[] {
|
|
97
|
+
return Array.from(this.tools.values());
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
registerTool(tool: ToolRequest): void {
|
|
101
|
+
if (this.tools.has(tool.id)) {
|
|
102
|
+
console.warn(`Function with id ${tool.id} is already registered.`);
|
|
103
|
+
} else {
|
|
104
|
+
this.tools.set(tool.id, tool);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
getFunction(toolId: string): ToolRequest | undefined {
|
|
109
|
+
return this.tools.get(toolId);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
getFunctions(...toolIds: string[]): ToolRequest[] {
|
|
113
|
+
const tools: ToolRequest[] = toolIds.map(toolId => {
|
|
114
|
+
const tool = this.tools.get(toolId);
|
|
115
|
+
if (tool) {
|
|
116
|
+
return tool;
|
|
117
|
+
} else {
|
|
118
|
+
throw new Error(`Function with id ${toolId} does not exist.`);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
return tools;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
package/src/common/types.ts
CHANGED
|
@@ -18,3 +18,21 @@ export interface INearestCodeBlock {
|
|
|
18
18
|
offset: number;
|
|
19
19
|
type?: NearestCodeBlockType;
|
|
20
20
|
}
|
|
21
|
+
|
|
22
|
+
// SUMI MCP Server 网页部分暴露给 Node.js 部分的能力
|
|
23
|
+
export interface IMCPServerProxyService {
|
|
24
|
+
$callMCPTool(
|
|
25
|
+
name: string,
|
|
26
|
+
args: any,
|
|
27
|
+
): Promise<{
|
|
28
|
+
content: { type: string; text: string }[];
|
|
29
|
+
isError?: boolean;
|
|
30
|
+
}>;
|
|
31
|
+
$getMCPTools(): Promise<
|
|
32
|
+
{
|
|
33
|
+
name: string;
|
|
34
|
+
description: string;
|
|
35
|
+
inputSchema: any;
|
|
36
|
+
}[]
|
|
37
|
+
>;
|
|
38
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { AnthropicProvider, createAnthropic } from '@ai-sdk/anthropic';
|
|
2
|
+
import { jsonSchema, streamText, tool } from 'ai';
|
|
3
|
+
|
|
4
|
+
import { Autowired, Injectable } from '@opensumi/di';
|
|
5
|
+
import { ChatReadableStream } from '@opensumi/ide-core-node';
|
|
6
|
+
import { CancellationToken } from '@opensumi/ide-utils';
|
|
7
|
+
|
|
8
|
+
import { ToolInvocationRegistry, ToolInvocationRegistryImpl, ToolRequest } from '../../common/tool-invocation-registry';
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
export const AnthropicModelIdentifier = Symbol('AnthropicModelIdentifier');
|
|
12
|
+
|
|
13
|
+
const apiKey = '';
|
|
14
|
+
|
|
15
|
+
@Injectable()
|
|
16
|
+
export class AnthropicModel {
|
|
17
|
+
@Autowired(ToolInvocationRegistry)
|
|
18
|
+
private readonly toolInvocationRegistry: ToolInvocationRegistryImpl;
|
|
19
|
+
|
|
20
|
+
protected initializeAnthropicProvider() {
|
|
21
|
+
if (!apiKey) {
|
|
22
|
+
throw new Error('Please provide ANTHROPIC_API_KEY in preferences or via environment variable');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const anthropic = createAnthropic({ apiKey });
|
|
26
|
+
|
|
27
|
+
return anthropic;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async request(request: string, chatReadableStream: ChatReadableStream, cancellationToken?: CancellationToken): Promise<any> {
|
|
31
|
+
const anthropic = this.initializeAnthropicProvider();
|
|
32
|
+
const allFunctions = this.toolInvocationRegistry.getAllFunctions();
|
|
33
|
+
return this.handleStreamingRequest(anthropic, request, allFunctions, chatReadableStream, cancellationToken);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
private convertToolRequestToAITool(toolRequest: ToolRequest) {
|
|
37
|
+
return tool({
|
|
38
|
+
description: toolRequest.description || '',
|
|
39
|
+
// TODO 这里应该是 z.object 而不是 JSON Schema
|
|
40
|
+
parameters: jsonSchema(toolRequest.parameters),
|
|
41
|
+
execute: async (args: any) => await toolRequest.handler(JSON.stringify(args)),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
protected async handleStreamingRequest(
|
|
46
|
+
anthropic: AnthropicProvider,
|
|
47
|
+
request: string,
|
|
48
|
+
tools: ToolRequest[],
|
|
49
|
+
chatReadableStream: ChatReadableStream,
|
|
50
|
+
cancellationToken?: CancellationToken,
|
|
51
|
+
): Promise<any> {
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
const aiTools = Object.fromEntries(
|
|
55
|
+
tools.map((tool) => [tool.name, this.convertToolRequestToAITool(tool)]),
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
const abortController = new AbortController();
|
|
59
|
+
if (cancellationToken) {
|
|
60
|
+
cancellationToken.onCancellationRequested(() => {
|
|
61
|
+
abortController.abort();
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const stream = await streamText({
|
|
66
|
+
model: anthropic('claude-3-5-sonnet-20241022'),
|
|
67
|
+
maxTokens: 4096,
|
|
68
|
+
tools: aiTools,
|
|
69
|
+
messages: [{ role: 'user', content: request }],
|
|
70
|
+
abortSignal: abortController.signal,
|
|
71
|
+
maxSteps: 5,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
for await (const chunk of stream.fullStream) {
|
|
75
|
+
console.log(chunk);
|
|
76
|
+
if (chunk.type === 'text-delta') {
|
|
77
|
+
chatReadableStream.emitData({ kind: 'content', content: chunk.textDelta });
|
|
78
|
+
} else if (chunk.type === 'tool-call') {
|
|
79
|
+
chatReadableStream.emitData({ kind: 'toolCall', content: {
|
|
80
|
+
id: chunk.toolCallId || Date.now().toString(),
|
|
81
|
+
type: 'function',
|
|
82
|
+
function: { name: chunk.toolName, arguments: JSON.stringify(chunk.args) },
|
|
83
|
+
}});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
chatReadableStream.end();
|
|
88
|
+
} catch (error) {
|
|
89
|
+
console.error('Error during streaming:', error);
|
|
90
|
+
chatReadableStream.emitError(error);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return chatReadableStream;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
}
|
package/src/node/index.ts
CHANGED
|
@@ -3,6 +3,14 @@ import { AIBackSerivcePath, AIBackSerivceToken } from '@opensumi/ide-core-common
|
|
|
3
3
|
import { NodeModule } from '@opensumi/ide-core-node';
|
|
4
4
|
import { BaseAIBackService } from '@opensumi/ide-core-node/lib/ai-native/base-back.service';
|
|
5
5
|
|
|
6
|
+
import { SumiMCPServerProxyServicePath , TokenMCPServerProxyService } from '../common';
|
|
7
|
+
import { MCPServerManager } from '../common/mcp-server-manager';
|
|
8
|
+
import { ToolInvocationRegistry, ToolInvocationRegistryImpl } from '../common/tool-invocation-registry';
|
|
9
|
+
|
|
10
|
+
import { SumiMCPServerBackend } from './mcp/sumi-mcp-server';
|
|
11
|
+
import { MCPServerManagerImpl } from './mcp-server-manager-impl';
|
|
12
|
+
|
|
13
|
+
|
|
6
14
|
@Injectable()
|
|
7
15
|
export class AINativeModule extends NodeModule {
|
|
8
16
|
providers: Provider[] = [
|
|
@@ -10,6 +18,18 @@ export class AINativeModule extends NodeModule {
|
|
|
10
18
|
token: AIBackSerivceToken,
|
|
11
19
|
useClass: BaseAIBackService,
|
|
12
20
|
},
|
|
21
|
+
{
|
|
22
|
+
token: MCPServerManager,
|
|
23
|
+
useClass: MCPServerManagerImpl,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
token: ToolInvocationRegistry,
|
|
27
|
+
useClass: ToolInvocationRegistryImpl,
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
token: TokenMCPServerProxyService,
|
|
31
|
+
useClass: SumiMCPServerBackend,
|
|
32
|
+
},
|
|
13
33
|
];
|
|
14
34
|
|
|
15
35
|
backServices = [
|
|
@@ -17,5 +37,9 @@ export class AINativeModule extends NodeModule {
|
|
|
17
37
|
servicePath: AIBackSerivcePath,
|
|
18
38
|
token: AIBackSerivceToken,
|
|
19
39
|
},
|
|
40
|
+
{
|
|
41
|
+
servicePath: SumiMCPServerProxyServicePath,
|
|
42
|
+
token: TokenMCPServerProxyService,
|
|
43
|
+
},
|
|
20
44
|
];
|
|
21
45
|
}
|