@opensumi/ide-ai-native 3.7.2-next-1739859371.0 → 3.7.2-next-1740013940.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 +68 -2
- 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 +16 -5
- package/lib/browser/chat/chat-model.js.map +1 -1
- package/lib/browser/chat/chat-proxy.service.d.ts +4 -0
- package/lib/browser/chat/chat-proxy.service.d.ts.map +1 -1
- package/lib/browser/chat/chat-proxy.service.js +43 -0
- package/lib/browser/chat/chat-proxy.service.js.map +1 -1
- package/lib/browser/chat/chat.view.d.ts.map +1 -1
- package/lib/browser/chat/chat.view.js +29 -2
- package/lib/browser/chat/chat.view.js.map +1 -1
- package/lib/browser/components/ChatContext/ContextSelector.d.ts +12 -0
- package/lib/browser/components/ChatContext/ContextSelector.d.ts.map +1 -0
- package/lib/browser/components/ChatContext/ContextSelector.js +113 -0
- package/lib/browser/components/ChatContext/ContextSelector.js.map +1 -0
- package/lib/browser/components/ChatContext/index.d.ts +4 -0
- package/lib/browser/components/ChatContext/index.d.ts.map +1 -0
- package/lib/browser/components/ChatContext/index.js +84 -0
- package/lib/browser/components/ChatContext/index.js.map +1 -0
- package/lib/browser/components/ChatContext/style.module.less +189 -0
- package/lib/browser/components/ChatInput.d.ts.map +1 -1
- package/lib/browser/components/ChatInput.js.map +1 -1
- package/lib/browser/components/ChatReply.d.ts.map +1 -1
- package/lib/browser/components/ChatReply.js +25 -0
- 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 +53 -0
- package/lib/browser/components/ChatToolRender.js.map +1 -0
- package/lib/browser/components/ChatToolRender.module.less +86 -0
- package/lib/browser/components/components.module.less +32 -31
- package/lib/browser/components/utils.d.ts +2 -2
- package/lib/browser/context/llm-context.contribution.d.ts +7 -0
- package/lib/browser/context/llm-context.contribution.d.ts.map +1 -0
- package/lib/browser/context/llm-context.contribution.js +21 -0
- package/lib/browser/context/llm-context.contribution.js.map +1 -0
- package/lib/browser/context/llm-context.service.d.ts +24 -0
- package/lib/browser/context/llm-context.service.d.ts.map +1 -0
- package/lib/browser/context/llm-context.service.js +136 -0
- package/lib/browser/context/llm-context.service.js.map +1 -0
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.d.ts +2 -2
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.d.ts.map +1 -1
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.js.map +1 -1
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.feature.registry.d.ts +4 -0
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.feature.registry.d.ts.map +1 -1
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.feature.registry.js +7 -0
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.feature.registry.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 +56 -3
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/mcp/mcp-server-proxy.service.d.ts +25 -0
- package/lib/browser/mcp/mcp-server-proxy.service.d.ts.map +1 -0
- package/lib/browser/mcp/mcp-server-proxy.service.js +56 -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 +53 -0
- package/lib/browser/mcp/mcp-server.feature.registry.js.map +1 -0
- package/lib/browser/mcp/mcp-tools-dialog.module.less +44 -0
- package/lib/browser/mcp/mcp-tools-dialog.view.d.ts +8 -0
- package/lib/browser/mcp/mcp-tools-dialog.view.d.ts.map +1 -0
- package/lib/browser/mcp/mcp-tools-dialog.view.js +16 -0
- package/lib/browser/mcp/mcp-tools-dialog.view.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 +83 -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/mcp/tools/handlers/ListDir.d.ts +21 -0
- package/lib/browser/mcp/tools/handlers/ListDir.d.ts.map +1 -0
- package/lib/browser/mcp/tools/handlers/ListDir.js +112 -0
- package/lib/browser/mcp/tools/handlers/ListDir.js.map +1 -0
- package/lib/browser/mcp/tools/handlers/ReadFile.d.ts +47 -0
- package/lib/browser/mcp/tools/handlers/ReadFile.d.ts.map +1 -0
- package/lib/browser/mcp/tools/handlers/ReadFile.js +147 -0
- package/lib/browser/mcp/tools/handlers/ReadFile.js.map +1 -0
- package/lib/browser/mcp/tools/listDir.d.ts +8 -0
- package/lib/browser/mcp/tools/listDir.d.ts.map +1 -0
- package/lib/browser/mcp/tools/listDir.js +65 -0
- package/lib/browser/mcp/tools/listDir.js.map +1 -0
- package/lib/browser/mcp/tools/readFile.d.ts +8 -0
- package/lib/browser/mcp/tools/readFile.d.ts.map +1 -0
- package/lib/browser/mcp/tools/readFile.js +82 -0
- package/lib/browser/mcp/tools/readFile.js.map +1 -0
- package/lib/browser/mcp/tools/replaceOpenEditorFile.d.ts +8 -0
- package/lib/browser/mcp/tools/replaceOpenEditorFile.d.ts.map +1 -0
- package/lib/browser/mcp/tools/replaceOpenEditorFile.js +79 -0
- package/lib/browser/mcp/tools/replaceOpenEditorFile.js.map +1 -0
- package/lib/browser/mcp/tools/replaceOpenEditorFileByDiffPreviewer.d.ts +8 -0
- package/lib/browser/mcp/tools/replaceOpenEditorFileByDiffPreviewer.d.ts.map +1 -0
- package/lib/browser/mcp/tools/replaceOpenEditorFileByDiffPreviewer.js +84 -0
- package/lib/browser/mcp/tools/replaceOpenEditorFileByDiffPreviewer.js.map +1 -0
- package/lib/browser/mcp/tools/runTerminalCmd.d.ts +18 -0
- package/lib/browser/mcp/tools/runTerminalCmd.d.ts.map +1 -0
- package/lib/browser/mcp/tools/runTerminalCmd.js +96 -0
- package/lib/browser/mcp/tools/runTerminalCmd.js.map +1 -0
- package/lib/browser/preferences/schema.d.ts.map +1 -1
- package/lib/browser/preferences/schema.js +60 -0
- package/lib/browser/preferences/schema.js.map +1 -1
- package/lib/browser/types.d.ts +64 -3
- package/lib/browser/types.d.ts.map +1 -1
- package/lib/browser/types.js +5 -1
- package/lib/browser/types.js.map +1 -1
- package/lib/browser/widget/inline-chat/inline-chat-editor.controller.js +1 -1
- package/lib/browser/widget/inline-chat/inline-chat-editor.controller.js.map +1 -1
- package/lib/browser/widget/inline-diff/inline-diff.controller.d.ts.map +1 -1
- package/lib/browser/widget/inline-input/inline-input.controller.d.ts.map +1 -1
- package/lib/common/index.d.ts +9 -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/llm-context.d.ts +37 -0
- package/lib/common/llm-context.d.ts.map +1 -0
- package/lib/common/llm-context.js +5 -0
- package/lib/common/llm-context.js.map +1 -0
- package/lib/common/mcp-server-manager.d.ts +40 -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 +91 -0
- package/lib/common/tool-invocation-registry.d.ts.map +1 -0
- package/lib/common/tool-invocation-registry.js +90 -0
- package/lib/common/tool-invocation-registry.js.map +1 -0
- package/lib/common/types.d.ts +17 -0
- package/lib/common/types.d.ts.map +1 -1
- package/lib/node/anthropic/anthropic-language-model.d.ts +9 -0
- package/lib/node/anthropic/anthropic-language-model.d.ts.map +1 -0
- package/lib/node/anthropic/anthropic-language-model.js +26 -0
- package/lib/node/anthropic/anthropic-language-model.js.map +1 -0
- package/lib/node/base-language-model.d.ts +14 -0
- package/lib/node/base-language-model.d.ts.map +1 -0
- package/lib/node/base-language-model.js +136 -0
- package/lib/node/base-language-model.js.map +1 -0
- package/lib/node/deepseek/deepseek-language-model.d.ts +9 -0
- package/lib/node/deepseek/deepseek-language-model.d.ts.map +1 -0
- package/lib/node/deepseek/deepseek-language-model.js +26 -0
- package/lib/node/deepseek/deepseek-language-model.js.map +1 -0
- package/lib/node/index.d.ts.map +1 -1
- package/lib/node/index.js +19 -0
- package/lib/node/index.js.map +1 -1
- package/lib/node/mcp/sumi-mcp-server.d.ts +91 -0
- package/lib/node/mcp/sumi-mcp-server.d.ts.map +1 -0
- package/lib/node/mcp/sumi-mcp-server.js +172 -0
- package/lib/node/mcp/sumi-mcp-server.js.map +1 -0
- package/lib/node/mcp-server-manager-impl.d.ts +27 -0
- package/lib/node/mcp-server-manager-impl.d.ts.map +1 -0
- package/lib/node/mcp-server-manager-impl.js +127 -0
- package/lib/node/mcp-server-manager-impl.js.map +1 -0
- package/lib/node/mcp-server.d.ts +207 -0
- package/lib/node/mcp-server.d.ts.map +1 -0
- package/lib/node/mcp-server.js +91 -0
- package/lib/node/mcp-server.js.map +1 -0
- package/lib/node/openai/openai-language-model.d.ts +9 -0
- package/lib/node/openai/openai-language-model.d.ts.map +1 -0
- package/lib/node/openai/openai-language-model.js +29 -0
- package/lib/node/openai/openai-language-model.js.map +1 -0
- package/package.json +34 -22
- package/src/browser/ai-core.contribution.ts +77 -1
- package/src/browser/chat/chat-model.ts +24 -6
- package/src/browser/chat/chat-proxy.service.ts +42 -0
- package/src/browser/chat/chat.view.tsx +59 -6
- package/src/browser/components/ChatContext/ContextSelector.tsx +177 -0
- package/src/browser/components/ChatContext/index.tsx +135 -0
- package/src/browser/components/ChatContext/style.module.less +189 -0
- package/src/browser/components/ChatInput.tsx +1 -0
- package/src/browser/components/ChatReply.tsx +32 -0
- package/src/browser/components/ChatToolRender.module.less +86 -0
- package/src/browser/components/ChatToolRender.tsx +77 -0
- package/src/browser/components/components.module.less +32 -31
- package/src/browser/context/llm-context.contribution.ts +14 -0
- package/src/browser/context/llm-context.service.ts +156 -0
- package/src/browser/contrib/intelligent-completions/intelligent-completions.controller.ts +2 -3
- package/src/browser/contrib/intelligent-completions/intelligent-completions.feature.registry.ts +11 -0
- package/src/browser/index.ts +68 -4
- package/src/browser/mcp/mcp-server-proxy.service.ts +53 -0
- package/src/browser/mcp/mcp-server.feature.registry.ts +54 -0
- package/src/browser/mcp/mcp-tools-dialog.module.less +44 -0
- package/src/browser/mcp/mcp-tools-dialog.view.tsx +24 -0
- package/src/browser/mcp/tools/createNewFileWithText.ts +83 -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/mcp/tools/handlers/ListDir.ts +117 -0
- package/src/browser/mcp/tools/handlers/ReadFile.ts +174 -0
- package/src/browser/mcp/tools/listDir.ts +66 -0
- package/src/browser/mcp/tools/readFile.ts +82 -0
- package/src/browser/mcp/tools/replaceOpenEditorFile.ts +80 -0
- package/src/browser/mcp/tools/replaceOpenEditorFileByDiffPreviewer.ts +91 -0
- package/src/browser/mcp/tools/runTerminalCmd.ts +107 -0
- package/src/browser/preferences/schema.ts +60 -0
- package/src/browser/types.ts +92 -3
- package/src/browser/widget/inline-chat/inline-chat-editor.controller.ts +1 -1
- package/src/browser/widget/inline-diff/inline-diff.controller.ts +1 -1
- package/src/browser/widget/inline-input/inline-input.controller.ts +1 -1
- package/src/common/index.ts +14 -0
- package/src/common/llm-context.ts +41 -0
- package/src/common/mcp-server-manager.ts +46 -0
- package/src/common/tool-invocation-registry.ts +170 -0
- package/src/common/types.ts +22 -0
- package/src/node/anthropic/anthropic-language-model.ts +25 -0
- package/src/node/base-language-model.ts +163 -0
- package/src/node/deepseek/deepseek-language-model.ts +25 -0
- package/src/node/index.ts +21 -0
- package/src/node/mcp/sumi-mcp-server.ts +197 -0
- package/src/node/mcp-server-manager-impl.ts +148 -0
- package/src/node/mcp-server.ts +126 -0
- package/src/node/openai/openai-language-model.ts +25 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { Autowired, Injectable } from '@opensumi/di';
|
|
2
|
+
import { AppConfig } from '@opensumi/ide-core-browser/lib/react-providers/config-provider';
|
|
3
|
+
import { WithEventBus } from '@opensumi/ide-core-common/lib/event-bus/event-decorator';
|
|
4
|
+
import { MarkerSeverity } from '@opensumi/ide-core-common/lib/types/markers/markers';
|
|
5
|
+
import { Emitter, URI } from '@opensumi/ide-core-common/lib/utils';
|
|
6
|
+
import {
|
|
7
|
+
EditorDocumentModelCreationEvent,
|
|
8
|
+
EditorDocumentModelRemovalEvent,
|
|
9
|
+
EditorDocumentModelSavedEvent,
|
|
10
|
+
IEditorDocumentModelService,
|
|
11
|
+
} from '@opensumi/ide-editor/lib/browser/doc-model/types';
|
|
12
|
+
import { EditorSelectionChangeEvent } from '@opensumi/ide-editor/lib/browser/types';
|
|
13
|
+
import { IMarkerService } from '@opensumi/ide-markers/lib/common/types';
|
|
14
|
+
|
|
15
|
+
import { FileContext, LLMContextService, SerializedContext } from '../../common/llm-context';
|
|
16
|
+
|
|
17
|
+
@Injectable()
|
|
18
|
+
export class LLMContextServiceImpl extends WithEventBus implements LLMContextService {
|
|
19
|
+
@Autowired(AppConfig)
|
|
20
|
+
protected readonly appConfig: AppConfig;
|
|
21
|
+
|
|
22
|
+
@Autowired(IEditorDocumentModelService)
|
|
23
|
+
protected readonly docModelManager: IEditorDocumentModelService;
|
|
24
|
+
|
|
25
|
+
@Autowired(IMarkerService)
|
|
26
|
+
protected readonly markerService: IMarkerService;
|
|
27
|
+
|
|
28
|
+
private isAutoCollecting = false;
|
|
29
|
+
|
|
30
|
+
private contextFiles: Map<string, FileContext> = new Map();
|
|
31
|
+
|
|
32
|
+
private onDidContextFilesChangeEmitter = new Emitter<FileContext[]>();
|
|
33
|
+
onDidContextFilesChangeEvent = this.onDidContextFilesChangeEmitter.event;
|
|
34
|
+
|
|
35
|
+
addFileToContext(uri: URI, selection?: [number, number], isManual = true): void {
|
|
36
|
+
this.contextFiles.set(uri.toString(), {
|
|
37
|
+
uri,
|
|
38
|
+
selection,
|
|
39
|
+
isManual,
|
|
40
|
+
});
|
|
41
|
+
this.onDidContextFilesChangeEmitter.fire(this.getAllContextFiles());
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
cleanFileContext() {
|
|
45
|
+
this.contextFiles.clear();
|
|
46
|
+
this.onDidContextFilesChangeEmitter.fire(this.getAllContextFiles());
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
private getAllContextFiles() {
|
|
50
|
+
return Array.from(this.contextFiles.values());
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
removeFileFromContext(uri: URI): void {
|
|
54
|
+
this.contextFiles.delete(uri.toString());
|
|
55
|
+
this.onDidContextFilesChangeEmitter.fire(this.getAllContextFiles());
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
startAutoCollection(): void {
|
|
59
|
+
if (this.isAutoCollecting) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
this.isAutoCollecting = true;
|
|
63
|
+
|
|
64
|
+
this.startAutoCollectionInternal();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private startAutoCollectionInternal(): void {
|
|
68
|
+
// 文件打开
|
|
69
|
+
this.disposables.push(
|
|
70
|
+
this.eventBus.on(EditorDocumentModelCreationEvent, (event) => {
|
|
71
|
+
if (event.payload.uri.scheme !== 'file') {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
// TODO: 是否自动添加文件到上下文?
|
|
75
|
+
// this.addFileToContext(event.payload.uri);
|
|
76
|
+
}),
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
// 删除
|
|
80
|
+
this.disposables.push(
|
|
81
|
+
this.eventBus.on(EditorDocumentModelRemovalEvent, (event) => {
|
|
82
|
+
if (event.payload.scheme !== 'file') {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
}),
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
// 保存
|
|
89
|
+
this.disposables.push(
|
|
90
|
+
this.eventBus.on(EditorDocumentModelSavedEvent, (event) => {
|
|
91
|
+
if (event.payload.scheme !== 'file') {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
}),
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
// 光标选中
|
|
98
|
+
this.disposables.push(
|
|
99
|
+
this.eventBus.on(EditorSelectionChangeEvent, (event) => {
|
|
100
|
+
if (event.payload.selections.length > 0) {
|
|
101
|
+
const selection = [
|
|
102
|
+
event.payload.selections[0].selectionStartLineNumber,
|
|
103
|
+
event.payload.selections[0].positionLineNumber,
|
|
104
|
+
].sort() as [number, number];
|
|
105
|
+
if (selection[0] === selection[1]) {
|
|
106
|
+
// TODO: 是否自动添加文件到上下文?
|
|
107
|
+
// this.addFileToContext(event.payload.editorUri, undefined);
|
|
108
|
+
} else {
|
|
109
|
+
this.addFileToContext(
|
|
110
|
+
event.payload.editorUri,
|
|
111
|
+
selection.sort((a, b) => a - b),
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}),
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
stopAutoCollection(): void {
|
|
120
|
+
this.dispose();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
serialize(): SerializedContext {
|
|
124
|
+
const files = this.getAllContextFiles();
|
|
125
|
+
const recentlyViewFiles = files
|
|
126
|
+
.filter((v) => !v.selection)
|
|
127
|
+
.map((file) => URI.file(this.appConfig.workspaceDir).relative(file.uri)!.toString())
|
|
128
|
+
.filter(Boolean);
|
|
129
|
+
const attachedFiles = files
|
|
130
|
+
.filter((v) => v.selection)
|
|
131
|
+
.map((file) => {
|
|
132
|
+
const ref = this.docModelManager.getModelReference(file.uri);
|
|
133
|
+
const content = ref!.instance.getText();
|
|
134
|
+
const lineErrors = this.markerService
|
|
135
|
+
.getManager()
|
|
136
|
+
.getMarkers({
|
|
137
|
+
resource: file.uri.toString(),
|
|
138
|
+
severities: MarkerSeverity.Error,
|
|
139
|
+
})
|
|
140
|
+
.map((marker) => marker.message);
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
content,
|
|
144
|
+
lineErrors,
|
|
145
|
+
path: URI.file(this.appConfig.workspaceDir).relative(file.uri)!.toString(),
|
|
146
|
+
language: ref?.instance.languageId!,
|
|
147
|
+
};
|
|
148
|
+
})
|
|
149
|
+
.filter(Boolean);
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
recentlyViewFiles,
|
|
153
|
+
attachedFiles,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
}
|
|
@@ -40,7 +40,7 @@ import { InlineCompletionsController } from '@opensumi/monaco-editor-core/esm/vs
|
|
|
40
40
|
import {
|
|
41
41
|
SuggestItemInfo,
|
|
42
42
|
SuggestWidgetAdaptor,
|
|
43
|
-
} from '@opensumi/monaco-editor-core/esm/vs/editor/contrib/inlineCompletions/browser/model/
|
|
43
|
+
} from '@opensumi/monaco-editor-core/esm/vs/editor/contrib/inlineCompletions/browser/model/suggestWidgetAdapter';
|
|
44
44
|
import { ContextKeyExpr } from '@opensumi/monaco-editor-core/esm/vs/platform/contextkey/common/contextkey';
|
|
45
45
|
|
|
46
46
|
import { AINativeContextKey } from '../../ai-core.contextkeys';
|
|
@@ -166,8 +166,7 @@ export class IntelligentCompletionsController extends BaseAIMonacoEditorControll
|
|
|
166
166
|
model?.inlineCompletionState.read(reader);
|
|
167
167
|
|
|
168
168
|
const suggestWidgetSelectedItem = inlineCompletionsController['_suggestWidgetSelectedItem'] as IObservable<
|
|
169
|
-
SuggestItemInfo | undefined
|
|
170
|
-
unknown
|
|
169
|
+
SuggestItemInfo | undefined
|
|
171
170
|
>;
|
|
172
171
|
const selectedItem = suggestWidgetSelectedItem.get();
|
|
173
172
|
if (selectedItem) {
|
package/src/browser/contrib/intelligent-completions/intelligent-completions.feature.registry.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Injectable } from '@opensumi/di';
|
|
2
2
|
import { Disposable } from '@opensumi/ide-core-common';
|
|
3
|
+
import { InlineEditProvider } from '@opensumi/ide-monaco';
|
|
3
4
|
|
|
4
5
|
import { ICodeEditsProvider, IIntelligentCompletionProvider, IIntelligentCompletionsRegistry } from '../../types';
|
|
5
6
|
|
|
@@ -7,6 +8,7 @@ import { ICodeEditsProvider, IIntelligentCompletionProvider, IIntelligentComplet
|
|
|
7
8
|
export class IntelligentCompletionsRegistry extends Disposable implements IIntelligentCompletionsRegistry {
|
|
8
9
|
private inlineCompletionsProvider: IIntelligentCompletionProvider | undefined;
|
|
9
10
|
private codeEditsProvider: ICodeEditsProvider | undefined;
|
|
11
|
+
private inlineEditProvider: InlineEditProvider | undefined;
|
|
10
12
|
|
|
11
13
|
registerIntelligentCompletionProvider(provider: IIntelligentCompletionProvider): void {
|
|
12
14
|
this.inlineCompletionsProvider = provider;
|
|
@@ -16,6 +18,10 @@ export class IntelligentCompletionsRegistry extends Disposable implements IIntel
|
|
|
16
18
|
this.inlineCompletionsProvider = provider;
|
|
17
19
|
}
|
|
18
20
|
|
|
21
|
+
registerInlineEditProvider(provider: InlineEditProvider): void {
|
|
22
|
+
this.inlineEditProvider = provider;
|
|
23
|
+
}
|
|
24
|
+
|
|
19
25
|
registerCodeEditsProvider(provider: ICodeEditsProvider): void {
|
|
20
26
|
this.codeEditsProvider = provider;
|
|
21
27
|
}
|
|
@@ -27,4 +33,9 @@ export class IntelligentCompletionsRegistry extends Disposable implements IIntel
|
|
|
27
33
|
getCodeEditsProvider(): ICodeEditsProvider | undefined {
|
|
28
34
|
return this.codeEditsProvider;
|
|
29
35
|
}
|
|
36
|
+
|
|
37
|
+
getInlineEditProvider(): InlineEditProvider | undefined {
|
|
38
|
+
// TODO: 支持模块内调用
|
|
39
|
+
return this.inlineEditProvider;
|
|
40
|
+
}
|
|
30
41
|
}
|
package/src/browser/index.ts
CHANGED
|
@@ -19,8 +19,17 @@ import {
|
|
|
19
19
|
TerminalRegistryToken,
|
|
20
20
|
} from '@opensumi/ide-core-common';
|
|
21
21
|
|
|
22
|
-
import {
|
|
23
|
-
|
|
22
|
+
import {
|
|
23
|
+
ChatProxyServiceToken,
|
|
24
|
+
IAIInlineCompletionsProvider,
|
|
25
|
+
IChatAgentService,
|
|
26
|
+
IChatInternalService,
|
|
27
|
+
IChatManagerService,
|
|
28
|
+
SumiMCPServerProxyServicePath,
|
|
29
|
+
TokenMCPServerProxyService,
|
|
30
|
+
} from '../common';
|
|
31
|
+
import { LLMContextServiceToken } from '../common/llm-context';
|
|
32
|
+
import { MCPServerManager, MCPServerManagerPath } from '../common/mcp-server-manager';
|
|
24
33
|
|
|
25
34
|
import { AINativeBrowserContribution } from './ai-core.contribution';
|
|
26
35
|
import { ChatAgentService } from './chat/chat-agent.service';
|
|
@@ -31,6 +40,8 @@ import { ChatService } from './chat/chat.api.service';
|
|
|
31
40
|
import { ChatFeatureRegistry } from './chat/chat.feature.registry';
|
|
32
41
|
import { ChatInternalService } from './chat/chat.internal.service';
|
|
33
42
|
import { ChatRenderRegistry } from './chat/chat.render.registry';
|
|
43
|
+
import { LlmContextContribution } from './context/llm-context.contribution';
|
|
44
|
+
import { LLMContextServiceImpl } from './context/llm-context.service';
|
|
34
45
|
import { AICodeActionContribution } from './contrib/code-action/code-action.contribution';
|
|
35
46
|
import { AIInlineCompletionsProvider } from './contrib/inline-completions/completeProvider';
|
|
36
47
|
import { IntelligentCompletionsContribution } from './contrib/intelligent-completions/intelligent-completions.contribution';
|
|
@@ -43,8 +54,22 @@ import { RenameCandidatesProviderRegistry } from './contrib/rename/rename.featur
|
|
|
43
54
|
import { TerminalAIContribution } from './contrib/terminal/terminal-ai.contributon';
|
|
44
55
|
import { TerminalFeatureRegistry } from './contrib/terminal/terminal.feature.registry';
|
|
45
56
|
import { LanguageParserService } from './languages/service';
|
|
57
|
+
import { MCPServerProxyService } from './mcp/mcp-server-proxy.service';
|
|
58
|
+
import { MCPServerRegistry } from './mcp/mcp-server.feature.registry';
|
|
59
|
+
import { CreateNewFileWithTextTool } from './mcp/tools/createNewFileWithText';
|
|
60
|
+
import { FindFilesByNameSubstringTool } from './mcp/tools/findFilesByNameSubstring';
|
|
61
|
+
import { GetCurrentFilePathTool } from './mcp/tools/getCurrentFilePath';
|
|
62
|
+
import { GetDiagnosticsByPathTool } from './mcp/tools/getDiagnosticsByPath';
|
|
63
|
+
import { GetFileTextByPathTool } from './mcp/tools/getFileTextByPath';
|
|
64
|
+
import { GetOpenEditorFileDiagnosticsTool } from './mcp/tools/getOpenEditorFileDiagnostics';
|
|
65
|
+
import { GetOpenEditorFileTextTool } from './mcp/tools/getOpenEditorFileText';
|
|
66
|
+
import { GetSelectedTextTool } from './mcp/tools/getSelectedText';
|
|
67
|
+
import { ListDirTool } from './mcp/tools/listDir';
|
|
68
|
+
import { ReadFileTool } from './mcp/tools/readFile';
|
|
69
|
+
import { ReplaceOpenEditorFileByDiffPreviewerTool } from './mcp/tools/replaceOpenEditorFileByDiffPreviewer';
|
|
70
|
+
import { RunTerminalCommandTool } from './mcp/tools/runTerminalCmd';
|
|
46
71
|
import { AINativePreferencesContribution } from './preferences';
|
|
47
|
-
import { AINativeCoreContribution } from './types';
|
|
72
|
+
import { AINativeCoreContribution, MCPServerContribution, TokenMCPServerRegistry } from './types';
|
|
48
73
|
import { InlineChatFeatureRegistry } from './widget/inline-chat/inline-chat.feature.registry';
|
|
49
74
|
import { InlineChatService } from './widget/inline-chat/inline-chat.service';
|
|
50
75
|
import { InlineDiffService } from './widget/inline-diff';
|
|
@@ -59,7 +84,7 @@ export class AINativeModule extends BrowserModule {
|
|
|
59
84
|
this.aiNativeConfig.setAINativeModuleLoaded(true);
|
|
60
85
|
}
|
|
61
86
|
|
|
62
|
-
contributionProvider = AINativeCoreContribution;
|
|
87
|
+
contributionProvider = [AINativeCoreContribution, MCPServerContribution];
|
|
63
88
|
providers: Provider[] = [
|
|
64
89
|
AINativeBrowserContribution,
|
|
65
90
|
InterfaceNavigationContribution,
|
|
@@ -68,6 +93,37 @@ export class AINativeModule extends BrowserModule {
|
|
|
68
93
|
AICodeActionContribution,
|
|
69
94
|
AINativePreferencesContribution,
|
|
70
95
|
IntelligentCompletionsContribution,
|
|
96
|
+
|
|
97
|
+
// MCP Server Contributions START
|
|
98
|
+
ListDirTool,
|
|
99
|
+
ReadFileTool,
|
|
100
|
+
CreateNewFileWithTextTool,
|
|
101
|
+
GetSelectedTextTool,
|
|
102
|
+
GetOpenEditorFileDiagnosticsTool,
|
|
103
|
+
GetOpenEditorFileTextTool,
|
|
104
|
+
GetFileTextByPathTool,
|
|
105
|
+
GetCurrentFilePathTool,
|
|
106
|
+
FindFilesByNameSubstringTool,
|
|
107
|
+
GetDiagnosticsByPathTool,
|
|
108
|
+
RunTerminalCommandTool,
|
|
109
|
+
ReplaceOpenEditorFileByDiffPreviewerTool,
|
|
110
|
+
// MCP Server Contributions END
|
|
111
|
+
|
|
112
|
+
// Context Service
|
|
113
|
+
LlmContextContribution,
|
|
114
|
+
{
|
|
115
|
+
token: LLMContextServiceToken,
|
|
116
|
+
useClass: LLMContextServiceImpl,
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
{
|
|
120
|
+
token: TokenMCPServerRegistry,
|
|
121
|
+
useClass: MCPServerRegistry,
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
token: TokenMCPServerProxyService,
|
|
125
|
+
useClass: MCPServerProxyService,
|
|
126
|
+
},
|
|
71
127
|
{
|
|
72
128
|
token: InlineChatFeatureRegistryToken,
|
|
73
129
|
useClass: InlineChatFeatureRegistry,
|
|
@@ -148,5 +204,13 @@ export class AINativeModule extends BrowserModule {
|
|
|
148
204
|
token: AIBackSerivceToken,
|
|
149
205
|
clientToken: ChatProxyServiceToken,
|
|
150
206
|
},
|
|
207
|
+
{
|
|
208
|
+
servicePath: MCPServerManagerPath,
|
|
209
|
+
token: MCPServerManager,
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
clientToken: TokenMCPServerProxyService,
|
|
213
|
+
servicePath: SumiMCPServerProxyServicePath,
|
|
214
|
+
},
|
|
151
215
|
];
|
|
152
216
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Autowired, Injectable } from '@opensumi/di';
|
|
2
|
+
import { ILogger } from '@opensumi/ide-core-browser';
|
|
3
|
+
import { Emitter, Event } from '@opensumi/ide-core-common';
|
|
4
|
+
|
|
5
|
+
import { ISumiMCPServerBackend, SumiMCPServerProxyServicePath } from '../../common';
|
|
6
|
+
import { IMCPServerProxyService } from '../../common/types';
|
|
7
|
+
import { IMCPServerRegistry, TokenMCPServerRegistry } from '../types';
|
|
8
|
+
|
|
9
|
+
@Injectable()
|
|
10
|
+
export class MCPServerProxyService implements IMCPServerProxyService {
|
|
11
|
+
@Autowired(TokenMCPServerRegistry)
|
|
12
|
+
private readonly mcpServerRegistry: IMCPServerRegistry;
|
|
13
|
+
|
|
14
|
+
@Autowired(ILogger)
|
|
15
|
+
private readonly logger: ILogger;
|
|
16
|
+
|
|
17
|
+
@Autowired(SumiMCPServerProxyServicePath)
|
|
18
|
+
private readonly sumiMCPServerProxyService: ISumiMCPServerBackend;
|
|
19
|
+
|
|
20
|
+
private readonly _onChangeMCPServers = new Emitter<any>();
|
|
21
|
+
public readonly onChangeMCPServers: Event<any> = this._onChangeMCPServers.event;
|
|
22
|
+
|
|
23
|
+
// 调用 OpenSumi 内部注册的 MCP 工具
|
|
24
|
+
$callMCPTool(name: string, args: any) {
|
|
25
|
+
return this.mcpServerRegistry.callMCPTool(name, args);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// 获取 OpenSumi 内部注册的 MCP tools
|
|
29
|
+
async $getMCPTools() {
|
|
30
|
+
const tools = await this.mcpServerRegistry.getMCPTools().map((tool) =>
|
|
31
|
+
// 不要传递 handler
|
|
32
|
+
({
|
|
33
|
+
name: tool.name,
|
|
34
|
+
description: tool.description,
|
|
35
|
+
inputSchema: tool.inputSchema,
|
|
36
|
+
providerName: 'sumi-builtin',
|
|
37
|
+
}),
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
this.logger.log('SUMI MCP tools', tools);
|
|
41
|
+
|
|
42
|
+
return tools;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 通知前端 MCP 服务注册表发生了变化
|
|
46
|
+
async $updateMCPServers() {
|
|
47
|
+
this._onChangeMCPServers.fire('update');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async getAllMCPTools() {
|
|
51
|
+
return this.sumiMCPServerProxyService.getAllMCPTools();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// OpenSumi as MCP Server 前端的代理服务
|
|
2
|
+
import { Autowired, Injectable } from '@opensumi/di';
|
|
3
|
+
import { IAIBackService, ILogger } from '@opensumi/ide-core-common';
|
|
4
|
+
|
|
5
|
+
import { IMCPServerRegistry, MCPLogger, MCPToolDefinition } from '../types';
|
|
6
|
+
|
|
7
|
+
class LoggerAdapter implements MCPLogger {
|
|
8
|
+
constructor(private readonly logger: ILogger) { }
|
|
9
|
+
|
|
10
|
+
appendLine(message: string): void {
|
|
11
|
+
this.logger.log(message);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@Injectable()
|
|
16
|
+
export class MCPServerRegistry implements IMCPServerRegistry {
|
|
17
|
+
private tools: MCPToolDefinition[] = [];
|
|
18
|
+
|
|
19
|
+
@Autowired(ILogger)
|
|
20
|
+
private readonly baseLogger: ILogger;
|
|
21
|
+
|
|
22
|
+
private get logger(): MCPLogger {
|
|
23
|
+
return new LoggerAdapter(this.baseLogger);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
registerMCPTool(tool: MCPToolDefinition): void {
|
|
27
|
+
this.tools.push(tool);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
getMCPTools(): MCPToolDefinition[] {
|
|
31
|
+
return this.tools;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async callMCPTool(
|
|
35
|
+
name: string,
|
|
36
|
+
args: any,
|
|
37
|
+
): Promise<{
|
|
38
|
+
content: { type: string; text: string }[];
|
|
39
|
+
isError?: boolean;
|
|
40
|
+
}> {
|
|
41
|
+
try {
|
|
42
|
+
const tool = this.tools.find((tool) => tool.name === name);
|
|
43
|
+
if (!tool) {
|
|
44
|
+
throw new Error(`MCP tool ${name} not found`);
|
|
45
|
+
}
|
|
46
|
+
return await tool.handler(args, this.logger);
|
|
47
|
+
} catch (error) {
|
|
48
|
+
return {
|
|
49
|
+
content: [{ type: 'text', text: `The tool ${name} failed to execute. Error: ${error}` }],
|
|
50
|
+
isError: true,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
.mcp_tools_dialog {
|
|
2
|
+
.dialog_title {
|
|
3
|
+
font-size: 16px;
|
|
4
|
+
font-weight: 600;
|
|
5
|
+
color: var(--foreground);
|
|
6
|
+
padding-bottom: 16px;
|
|
7
|
+
padding-top: 8px;
|
|
8
|
+
border-bottom: 1px solid var(--menu-separatorBackground);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.tools_list {
|
|
12
|
+
max-height: calc(60vh - 53px); // 减去标题高度
|
|
13
|
+
overflow: auto;
|
|
14
|
+
|
|
15
|
+
.tool_item {
|
|
16
|
+
padding-top: 12px;
|
|
17
|
+
padding-bottom: 12px;
|
|
18
|
+
border-radius: 6px;
|
|
19
|
+
|
|
20
|
+
&:hover {
|
|
21
|
+
background-color: var(--list-hoverBackground);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.tool_name {
|
|
25
|
+
font-weight: 600;
|
|
26
|
+
color: var(--foreground);
|
|
27
|
+
margin-bottom: 8px;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.tool_description {
|
|
31
|
+
font-size: 12px;
|
|
32
|
+
line-height: 1.5;
|
|
33
|
+
color: var(--descriptionForeground);
|
|
34
|
+
margin-bottom: 4px;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.tool_provider {
|
|
38
|
+
font-size: 12px;
|
|
39
|
+
color: var(--descriptionForeground);
|
|
40
|
+
font-style: italic;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import { MCPTool } from '../../common/types';
|
|
4
|
+
|
|
5
|
+
import styles from './mcp-tools-dialog.module.less';
|
|
6
|
+
|
|
7
|
+
interface MCPToolsDialogProps {
|
|
8
|
+
tools: MCPTool[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const MCPToolsDialog: React.FC<MCPToolsDialogProps> = ({ tools }) => (
|
|
12
|
+
<div className={styles.mcp_tools_dialog}>
|
|
13
|
+
<div className={styles.dialog_title}>MCP Tools</div>
|
|
14
|
+
<div className={styles.tools_list}>
|
|
15
|
+
{tools.map((tool) => (
|
|
16
|
+
<div key={tool.name} className={styles.tool_item}>
|
|
17
|
+
<div className={styles.tool_name}>{tool.name}</div>
|
|
18
|
+
<div className={styles.tool_description}>{tool.description}</div>
|
|
19
|
+
{tool.providerName && <div className={styles.tool_provider}>Provider: {tool.providerName}</div>}
|
|
20
|
+
</div>
|
|
21
|
+
))}
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
3
|
+
|
|
4
|
+
import { Autowired } from '@opensumi/di';
|
|
5
|
+
import { Domain, URI, path } from '@opensumi/ide-core-common';
|
|
6
|
+
import { IFileServiceClient } from '@opensumi/ide-file-service';
|
|
7
|
+
import { IWorkspaceService } from '@opensumi/ide-workspace';
|
|
8
|
+
|
|
9
|
+
import { IMCPServerRegistry, MCPLogger, MCPServerContribution, MCPToolDefinition } from '../../types';
|
|
10
|
+
|
|
11
|
+
const inputSchema = z.object({
|
|
12
|
+
pathInProject: z.string().describe('The relative path where the file should be created'),
|
|
13
|
+
text: z.string().describe('The content to write into the new file'),
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
@Domain(MCPServerContribution)
|
|
17
|
+
export class CreateNewFileWithTextTool implements MCPServerContribution {
|
|
18
|
+
@Autowired(IWorkspaceService)
|
|
19
|
+
private readonly workspaceService: IWorkspaceService;
|
|
20
|
+
|
|
21
|
+
@Autowired(IFileServiceClient)
|
|
22
|
+
private readonly fileService: IFileServiceClient;
|
|
23
|
+
|
|
24
|
+
registerMCPServer(registry: IMCPServerRegistry): void {
|
|
25
|
+
registry.registerMCPTool(this.getToolDefinition());
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
getToolDefinition(): MCPToolDefinition {
|
|
29
|
+
return {
|
|
30
|
+
name: 'create_new_file_with_text',
|
|
31
|
+
description:
|
|
32
|
+
'Creates a new file at the specified path within the project directory and populates it with the provided text. ' +
|
|
33
|
+
'Use this tool to generate new files in your project structure. ' +
|
|
34
|
+
'Requires two parameters: ' +
|
|
35
|
+
'- pathInProject: The relative path where the file should be created ' +
|
|
36
|
+
'- text: The content to write into the new file ' +
|
|
37
|
+
'Returns one of two possible responses: ' +
|
|
38
|
+
'"ok" if the file was successfully created and populated, ' +
|
|
39
|
+
'"can\'t find project dir" if the project directory cannot be determined. ' +
|
|
40
|
+
'Note: Creates any necessary parent directories automatically.',
|
|
41
|
+
inputSchema: zodToJsonSchema(inputSchema),
|
|
42
|
+
handler: this.handler.bind(this),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private async handler(args: z.infer<typeof inputSchema>, logger: MCPLogger) {
|
|
47
|
+
try {
|
|
48
|
+
// 获取工作区根目录
|
|
49
|
+
const workspaceRoots = this.workspaceService.tryGetRoots();
|
|
50
|
+
if (!workspaceRoots || workspaceRoots.length === 0) {
|
|
51
|
+
logger.appendLine('Error: Cannot determine project directory');
|
|
52
|
+
return {
|
|
53
|
+
content: [{ type: 'text', text: "can't find project dir" }],
|
|
54
|
+
isError: true,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// 构建完整的文件路径
|
|
59
|
+
const rootUri = URI.parse(workspaceRoots[0].uri);
|
|
60
|
+
const fullPath = path.join(rootUri.codeUri.fsPath, args.pathInProject);
|
|
61
|
+
const fileUri = URI.file(fullPath);
|
|
62
|
+
|
|
63
|
+
// 创建父目录
|
|
64
|
+
const parentDir = path.dirname(fullPath);
|
|
65
|
+
const parentUri = URI.file(parentDir);
|
|
66
|
+
await this.fileService.createFolder(parentUri.toString());
|
|
67
|
+
|
|
68
|
+
// 写入文件内容
|
|
69
|
+
await this.fileService.createFile(fileUri.toString(), { content: args.text });
|
|
70
|
+
|
|
71
|
+
logger.appendLine(`Successfully created file at: ${args.pathInProject}`);
|
|
72
|
+
return {
|
|
73
|
+
content: [{ type: 'text', text: 'ok' }],
|
|
74
|
+
};
|
|
75
|
+
} catch (error) {
|
|
76
|
+
logger.appendLine(`Error during file creation: ${error}`);
|
|
77
|
+
return {
|
|
78
|
+
content: [{ type: 'text', text: 'unknown error' }],
|
|
79
|
+
isError: true,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
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 { IFileSearchService } from '@opensumi/ide-file-search/lib/common';
|
|
9
|
+
import { IWorkspaceService } from '@opensumi/ide-workspace';
|
|
10
|
+
|
|
11
|
+
import { IMCPServerRegistry, MCPLogger, MCPServerContribution, MCPToolDefinition } from '../../types';
|
|
12
|
+
|
|
13
|
+
const inputSchema = z.object({
|
|
14
|
+
nameSubstring: z.string().describe('The substring to search for in file names'),
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
@Domain(MCPServerContribution)
|
|
18
|
+
export class FindFilesByNameSubstringTool implements MCPServerContribution {
|
|
19
|
+
@Autowired(IWorkspaceService)
|
|
20
|
+
private readonly workspaceService: IWorkspaceService;
|
|
21
|
+
|
|
22
|
+
@Autowired(IFileSearchService)
|
|
23
|
+
private readonly fileSearchService: IFileSearchService;
|
|
24
|
+
|
|
25
|
+
registerMCPServer(registry: IMCPServerRegistry): void {
|
|
26
|
+
registry.registerMCPTool(this.getToolDefinition());
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
getToolDefinition(): MCPToolDefinition {
|
|
30
|
+
return {
|
|
31
|
+
name: 'find_files_by_name_substring',
|
|
32
|
+
description:
|
|
33
|
+
'Searches for all files in the project whose names contain the specified substring (case-insensitive). ' +
|
|
34
|
+
'Use this tool to locate files when you know part of the filename. ' +
|
|
35
|
+
'Requires a nameSubstring parameter for the search term. ' +
|
|
36
|
+
'Returns a JSON array of objects containing file information: ' +
|
|
37
|
+
'- path: Path relative to project root ' +
|
|
38
|
+
'- name: File name ' +
|
|
39
|
+
'Returns an empty array ([]) if no matching files are found. ' +
|
|
40
|
+
'Note: Only searches through files within the project directory, excluding libraries and external dependencies.',
|
|
41
|
+
inputSchema: zodToJsonSchema(inputSchema),
|
|
42
|
+
handler: this.handler.bind(this),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private async handler(args: z.infer<typeof inputSchema>, logger: MCPLogger) {
|
|
47
|
+
try {
|
|
48
|
+
// 获取工作区根目录
|
|
49
|
+
const workspaceRoots = this.workspaceService.tryGetRoots();
|
|
50
|
+
if (!workspaceRoots || workspaceRoots.length === 0) {
|
|
51
|
+
logger.appendLine('Error: Cannot determine project directory');
|
|
52
|
+
return {
|
|
53
|
+
content: [{ type: 'text', text: '[]' }],
|
|
54
|
+
isError: true,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// 使用 OpenSumi 的文件搜索 API
|
|
59
|
+
const searchPattern = `**/*${args.nameSubstring}*`;
|
|
60
|
+
const searchResults = await this.fileSearchService.find(searchPattern, {
|
|
61
|
+
rootUris: [workspaceRoots[0].uri],
|
|
62
|
+
excludePatterns: ['**/node_modules/**'],
|
|
63
|
+
limit: 1000,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// 转换结果为所需的格式
|
|
67
|
+
const results = searchResults.map((file) => {
|
|
68
|
+
const uri = URI.parse(file);
|
|
69
|
+
const rootUri = URI.parse(workspaceRoots[0].uri);
|
|
70
|
+
const relativePath = path.relative(rootUri.codeUri.fsPath, uri.codeUri.fsPath);
|
|
71
|
+
const fileName = path.basename(uri.codeUri.fsPath);
|
|
72
|
+
return {
|
|
73
|
+
path: relativePath,
|
|
74
|
+
name: fileName,
|
|
75
|
+
};
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// 将结果转换为 JSON 字符串
|
|
79
|
+
const resultJson = JSON.stringify(results, null, 2);
|
|
80
|
+
logger.appendLine(`Found ${results.length} files matching "${args.nameSubstring}"`);
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
content: [{ type: 'text', text: resultJson }],
|
|
84
|
+
};
|
|
85
|
+
} catch (error) {
|
|
86
|
+
logger.appendLine(`Error during file search: ${error}`);
|
|
87
|
+
return {
|
|
88
|
+
content: [{ type: 'text', text: '[]' }],
|
|
89
|
+
isError: true,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|