@opensumi/ide-ai-native 3.8.1-next-1741080291.0 → 3.8.1-next-1741092802.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.map +1 -1
- package/lib/browser/ai-core.contribution.js +22 -22
- package/lib/browser/ai-core.contribution.js.map +1 -1
- package/lib/browser/chat/chat-agent.service.d.ts +8 -0
- package/lib/browser/chat/chat-agent.service.d.ts.map +1 -1
- package/lib/browser/chat/chat-agent.service.js +32 -5
- package/lib/browser/chat/chat-agent.service.js.map +1 -1
- package/lib/browser/chat/chat-model.d.ts.map +1 -1
- package/lib/browser/chat/chat-model.js +3 -2
- package/lib/browser/chat/chat-model.js.map +1 -1
- package/lib/browser/chat/chat-proxy.service.d.ts.map +1 -1
- package/lib/browser/chat/chat-proxy.service.js +3 -1
- package/lib/browser/chat/chat-proxy.service.js.map +1 -1
- package/lib/browser/chat/chat.module.less +1 -2
- package/lib/browser/chat/chat.view.d.ts.map +1 -1
- package/lib/browser/chat/chat.view.js +6 -38
- 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/ChatInput.d.ts.map +1 -1
- package/lib/browser/components/ChatInput.js +25 -1
- 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 +2 -3
- package/lib/browser/components/ChatToolRender.js.map +1 -1
- package/lib/browser/components/chat-history.module.less +1 -1
- package/lib/browser/components/components.module.less +20 -0
- package/lib/browser/context/llm-context.service.d.ts +18 -5
- package/lib/browser/context/llm-context.service.d.ts.map +1 -1
- package/lib/browser/context/llm-context.service.js +80 -47
- package/lib/browser/context/llm-context.service.js.map +1 -1
- package/lib/browser/layout/layout.module.less +4 -4
- package/lib/browser/mcp/tools/components/ExpandableFileList.d.ts +13 -0
- package/lib/browser/mcp/tools/components/ExpandableFileList.d.ts.map +1 -0
- package/lib/browser/mcp/tools/components/{SearchResult.js → ExpandableFileList.js} +29 -19
- package/lib/browser/mcp/tools/components/ExpandableFileList.js.map +1 -0
- package/lib/browser/mcp/tools/components/index.module.less +1 -0
- package/lib/browser/mcp/tools/createNewFileWithText.d.ts.map +1 -1
- package/lib/browser/mcp/tools/createNewFileWithText.js +1 -0
- package/lib/browser/mcp/tools/createNewFileWithText.js.map +1 -1
- package/lib/browser/mcp/tools/fileSearch.d.ts +1 -0
- package/lib/browser/mcp/tools/fileSearch.d.ts.map +1 -1
- package/lib/browser/mcp/tools/fileSearch.js +14 -5
- package/lib/browser/mcp/tools/fileSearch.js.map +1 -1
- package/lib/browser/mcp/tools/getDiagnosticsByPath.d.ts.map +1 -1
- package/lib/browser/mcp/tools/getDiagnosticsByPath.js +1 -0
- package/lib/browser/mcp/tools/getDiagnosticsByPath.js.map +1 -1
- package/lib/browser/mcp/tools/grepSearch.d.ts.map +1 -1
- package/lib/browser/mcp/tools/grepSearch.js +6 -3
- package/lib/browser/mcp/tools/grepSearch.js.map +1 -1
- package/lib/browser/mcp/tools/handlers/ListDir.d.ts +1 -0
- package/lib/browser/mcp/tools/handlers/ListDir.d.ts.map +1 -1
- package/lib/browser/mcp/tools/handlers/ListDir.js +3 -0
- package/lib/browser/mcp/tools/handlers/ListDir.js.map +1 -1
- package/lib/browser/mcp/tools/handlers/RunCommand.d.ts.map +1 -1
- package/lib/browser/mcp/tools/handlers/RunCommand.js +2 -0
- package/lib/browser/mcp/tools/handlers/RunCommand.js.map +1 -1
- package/lib/browser/mcp/tools/listDir.d.ts +1 -0
- package/lib/browser/mcp/tools/listDir.d.ts.map +1 -1
- package/lib/browser/mcp/tools/listDir.js +35 -4
- package/lib/browser/mcp/tools/listDir.js.map +1 -1
- package/lib/browser/mcp/tools/runTerminalCmd.d.ts.map +1 -1
- package/lib/browser/mcp/tools/runTerminalCmd.js +1 -0
- package/lib/browser/mcp/tools/runTerminalCmd.js.map +1 -1
- package/lib/browser/preferences/schema.d.ts.map +1 -1
- package/lib/browser/preferences/schema.js +0 -1
- package/lib/browser/preferences/schema.js.map +1 -1
- package/lib/common/llm-context.d.ts +13 -9
- package/lib/common/llm-context.d.ts.map +1 -1
- package/lib/common/llm-context.js.map +1 -1
- package/lib/common/prompts/context-prompt-provider.d.ts +4 -3
- package/lib/common/prompts/context-prompt-provider.d.ts.map +1 -1
- package/lib/common/prompts/context-prompt-provider.js +33 -22
- package/lib/common/prompts/context-prompt-provider.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 +3 -3
- package/lib/node/base-language-model.js.map +1 -1
- package/package.json +23 -23
- package/src/browser/ai-core.contribution.ts +27 -26
- package/src/browser/chat/chat-agent.service.ts +38 -7
- package/src/browser/chat/chat-model.ts +11 -6
- package/src/browser/chat/chat-proxy.service.ts +4 -2
- package/src/browser/chat/chat.module.less +1 -2
- package/src/browser/chat/chat.view.tsx +7 -70
- package/src/browser/components/ChatContext/index.tsx +2 -2
- package/src/browser/components/ChatInput.tsx +67 -3
- package/src/browser/components/ChatToolRender.tsx +1 -2
- package/src/browser/components/chat-history.module.less +1 -1
- package/src/browser/components/components.module.less +20 -0
- package/src/browser/context/llm-context.service.ts +93 -54
- package/src/browser/layout/layout.module.less +4 -4
- package/src/browser/mcp/tools/components/ExpandableFileList.tsx +133 -0
- package/src/browser/mcp/tools/components/index.module.less +1 -0
- package/src/browser/mcp/tools/createNewFileWithText.ts +1 -0
- package/src/browser/mcp/tools/fileSearch.ts +14 -4
- package/src/browser/mcp/tools/getDiagnosticsByPath.ts +1 -0
- package/src/browser/mcp/tools/grepSearch.ts +6 -3
- package/src/browser/mcp/tools/handlers/ListDir.ts +4 -0
- package/src/browser/mcp/tools/handlers/RunCommand.ts +2 -0
- package/src/browser/mcp/tools/listDir.ts +36 -5
- package/src/browser/mcp/tools/runTerminalCmd.ts +1 -0
- package/src/browser/preferences/schema.ts +0 -1
- package/src/common/llm-context.ts +10 -4
- package/src/common/prompts/context-prompt-provider.ts +38 -29
- package/src/node/base-language-model.ts +3 -1
- package/lib/browser/mcp/tools/components/SearchResult.d.ts +0 -11
- package/lib/browser/mcp/tools/components/SearchResult.d.ts.map +0 -1
- package/lib/browser/mcp/tools/components/SearchResult.js.map +0 -1
- package/src/browser/mcp/tools/components/SearchResult.tsx +0 -92
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import React, { useEffect, useMemo, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import { CommandService, LabelService, URI, path, useInjectable } from '@opensumi/ide-core-browser';
|
|
4
|
+
import { WorkbenchEditorService } from '@opensumi/ide-editor';
|
|
5
|
+
import { IWorkspaceService } from '@opensumi/ide-workspace';
|
|
6
|
+
|
|
7
|
+
import { IChatInternalService } from '../../../../common';
|
|
8
|
+
import { ChatInternalService } from '../../../chat/chat.internal.service';
|
|
9
|
+
|
|
10
|
+
import styles from './index.module.less';
|
|
11
|
+
|
|
12
|
+
interface FileInfo {
|
|
13
|
+
uri: string;
|
|
14
|
+
isDirectory: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface ExpandableFileListProps {
|
|
18
|
+
args: any;
|
|
19
|
+
toolCallId: string;
|
|
20
|
+
messageId: string;
|
|
21
|
+
toolName: string;
|
|
22
|
+
headerText?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const FileSearchToolComponent: React.FC<ExpandableFileListProps> = ({ args, toolCallId, messageId }) => (
|
|
26
|
+
<ExpandableFileList
|
|
27
|
+
args={args}
|
|
28
|
+
toolCallId={toolCallId}
|
|
29
|
+
messageId={messageId}
|
|
30
|
+
toolName='fileSearch'
|
|
31
|
+
headerText={`Searched files "${args.query}"`}
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
export const GrepSearchToolComponent: React.FC<ExpandableFileListProps> = ({ args, toolCallId, messageId }) => (
|
|
36
|
+
<ExpandableFileList
|
|
37
|
+
args={args}
|
|
38
|
+
toolCallId={toolCallId}
|
|
39
|
+
messageId={messageId}
|
|
40
|
+
toolName='grepSearch'
|
|
41
|
+
headerText={`Grepped codebase "${args.query}"`}
|
|
42
|
+
/>
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
export const ListDirToolComponent: React.FC<ExpandableFileListProps> = ({ args, toolCallId, messageId }) => (
|
|
46
|
+
<ExpandableFileList
|
|
47
|
+
args={args}
|
|
48
|
+
toolCallId={toolCallId}
|
|
49
|
+
messageId={messageId}
|
|
50
|
+
toolName='listDir'
|
|
51
|
+
headerText={`Listed directory "${args.relative_workspace_path}"`}
|
|
52
|
+
/>
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
const ExpandableFileList: React.FC<ExpandableFileListProps> = ({
|
|
56
|
+
args,
|
|
57
|
+
toolCallId,
|
|
58
|
+
toolName,
|
|
59
|
+
messageId,
|
|
60
|
+
headerText,
|
|
61
|
+
}) => {
|
|
62
|
+
const [isExpanded, setIsExpanded] = useState(false);
|
|
63
|
+
const labelService = useInjectable<LabelService>(LabelService);
|
|
64
|
+
const editorService = useInjectable<WorkbenchEditorService>(WorkbenchEditorService);
|
|
65
|
+
const workspaceService = useInjectable<IWorkspaceService>(IWorkspaceService);
|
|
66
|
+
const commandService = useInjectable<CommandService>(CommandService);
|
|
67
|
+
const workspaceRoot = useMemo(() => URI.parse(workspaceService.tryGetRoots()?.[0]?.uri), []);
|
|
68
|
+
|
|
69
|
+
const chatService = useInjectable<ChatInternalService>(IChatInternalService);
|
|
70
|
+
const [fileList, setFileList] = useState<FileInfo[]>([]);
|
|
71
|
+
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
const toDispose = chatService.sessionModel.history.onMessageAdditionalChange((additional) => {
|
|
74
|
+
setFileList(additional[toolCallId]?.files || []);
|
|
75
|
+
});
|
|
76
|
+
return () => {
|
|
77
|
+
toDispose.dispose();
|
|
78
|
+
};
|
|
79
|
+
}, []);
|
|
80
|
+
|
|
81
|
+
const handleFileClick = async (fileInfo: FileInfo) => {
|
|
82
|
+
// 处理文件点击跳转
|
|
83
|
+
if (!fileInfo.isDirectory) {
|
|
84
|
+
editorService.open(URI.parse(fileInfo.uri));
|
|
85
|
+
} else {
|
|
86
|
+
// 如果是目录,聚焦到文件树并展开该目录
|
|
87
|
+
const uri = URI.parse(fileInfo.uri);
|
|
88
|
+
commandService.executeCommand('filetree.location', uri);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const parsedFiles = useMemo(
|
|
93
|
+
() =>
|
|
94
|
+
fileList.map((file) => {
|
|
95
|
+
const uri = URI.parse(file.uri);
|
|
96
|
+
const iconClass = labelService.getIcon(uri, { isDirectory: file.isDirectory });
|
|
97
|
+
return {
|
|
98
|
+
iconClass,
|
|
99
|
+
name: uri.path.base,
|
|
100
|
+
path: path.relative(workspaceRoot.codeUri.fsPath, uri.path.dir.toString()),
|
|
101
|
+
uri: file.uri,
|
|
102
|
+
isDirectory: file.isDirectory,
|
|
103
|
+
};
|
|
104
|
+
}),
|
|
105
|
+
[fileList],
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
return (
|
|
109
|
+
<div className={styles.container}>
|
|
110
|
+
<div className={styles.header} onClick={() => setIsExpanded(!isExpanded)}>
|
|
111
|
+
<span style={{ transform: `rotate(${isExpanded ? '90deg' : '0deg'})` }}>▶</span>
|
|
112
|
+
<span>
|
|
113
|
+
{headerText} · {fileList.length} files
|
|
114
|
+
</span>
|
|
115
|
+
</div>
|
|
116
|
+
{isExpanded && (
|
|
117
|
+
<ul className={styles.fileList}>
|
|
118
|
+
{parsedFiles.map((file, index) => (
|
|
119
|
+
<li
|
|
120
|
+
key={index}
|
|
121
|
+
className={styles.fileItem}
|
|
122
|
+
onClick={() => handleFileClick({ uri: file.uri, isDirectory: file.isDirectory })}
|
|
123
|
+
>
|
|
124
|
+
<span className={file.iconClass}></span>
|
|
125
|
+
<span style={{ flex: 1 }}>{file.name}</span>
|
|
126
|
+
<span className={styles.filePath}>{file.path}</span>
|
|
127
|
+
</li>
|
|
128
|
+
))}
|
|
129
|
+
</ul>
|
|
130
|
+
)}
|
|
131
|
+
</div>
|
|
132
|
+
);
|
|
133
|
+
};
|
|
@@ -27,6 +27,7 @@ export class CreateNewFileWithTextTool implements MCPServerContribution {
|
|
|
27
27
|
getToolDefinition(): MCPToolDefinition {
|
|
28
28
|
return {
|
|
29
29
|
name: 'create_new_file_with_text',
|
|
30
|
+
label: 'Create File',
|
|
30
31
|
description:
|
|
31
32
|
'Creates a new file at the specified path within the project directory and populates it with the provided text. ' +
|
|
32
33
|
'Use this tool to generate new files in your project structure. ' +
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
|
|
3
3
|
import { Autowired } from '@opensumi/di';
|
|
4
|
+
import { getValidateInput } from '@opensumi/ide-addons/lib/browser/file-search.contribution';
|
|
4
5
|
import { Domain, URI } from '@opensumi/ide-core-common';
|
|
5
6
|
import { FileSearchServicePath, IFileSearchService } from '@opensumi/ide-file-search/lib/common';
|
|
6
7
|
import { IWorkspaceService } from '@opensumi/ide-workspace';
|
|
@@ -9,7 +10,7 @@ import { IChatInternalService } from '../../../common';
|
|
|
9
10
|
import { ChatInternalService } from '../../chat/chat.internal.service';
|
|
10
11
|
import { IMCPServerRegistry, MCPLogger, MCPServerContribution, MCPToolDefinition } from '../../types';
|
|
11
12
|
|
|
12
|
-
import { FileSearchToolComponent } from './components/
|
|
13
|
+
import { FileSearchToolComponent } from './components/ExpandableFileList';
|
|
13
14
|
|
|
14
15
|
const inputSchema = z.object({
|
|
15
16
|
query: z.string().describe('Fuzzy filename to search for'),
|
|
@@ -58,7 +59,7 @@ export class FileSearchTool implements MCPServerContribution {
|
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
// 使用 OpenSumi 的文件搜索 API
|
|
61
|
-
const searchPattern = args.query;
|
|
62
|
+
const searchPattern = this.normalizeQuery(args.query);
|
|
62
63
|
const searchResults = await this.fileSearchService.find(searchPattern, {
|
|
63
64
|
rootUris: [new URI(workspaceRoots[0].uri).codeUri.fsPath],
|
|
64
65
|
// TODO: 忽略配置
|
|
@@ -71,7 +72,10 @@ export class FileSearchTool implements MCPServerContribution {
|
|
|
71
72
|
|
|
72
73
|
const files = searchResults.slice(0, MAX_RESULTS).map((file) => {
|
|
73
74
|
const uri = URI.parse(file);
|
|
74
|
-
return
|
|
75
|
+
return {
|
|
76
|
+
uri: uri.codeUri.fsPath,
|
|
77
|
+
isDirectory: false, // 文件搜索结果都是文件
|
|
78
|
+
};
|
|
75
79
|
});
|
|
76
80
|
|
|
77
81
|
const messages = this.chatInternalService.sessionModel.history.getMessages();
|
|
@@ -87,7 +91,7 @@ export class FileSearchTool implements MCPServerContribution {
|
|
|
87
91
|
content: [
|
|
88
92
|
{
|
|
89
93
|
type: 'text',
|
|
90
|
-
text: `${files.join('\n')}\n${
|
|
94
|
+
text: `${files.map((f) => f.uri).join('\n')}\n${
|
|
91
95
|
searchResults.length > MAX_RESULTS
|
|
92
96
|
? `\nFound ${searchResults.length} files matching "${args.query}", only return the first ${MAX_RESULTS} results`
|
|
93
97
|
: ''
|
|
@@ -96,4 +100,10 @@ export class FileSearchTool implements MCPServerContribution {
|
|
|
96
100
|
],
|
|
97
101
|
};
|
|
98
102
|
}
|
|
103
|
+
|
|
104
|
+
private normalizeQuery(query: string): string {
|
|
105
|
+
const nonBlank = query.trim().replace(/\s/g, '');
|
|
106
|
+
const validated = getValidateInput(nonBlank);
|
|
107
|
+
return validated;
|
|
108
|
+
}
|
|
99
109
|
}
|
|
@@ -29,6 +29,7 @@ export class GetDiagnosticsByPathTool implements MCPServerContribution {
|
|
|
29
29
|
getToolDefinition(): MCPToolDefinition {
|
|
30
30
|
return {
|
|
31
31
|
name: 'get_diagnostics_by_path',
|
|
32
|
+
label: 'Get Diagnostics',
|
|
32
33
|
description:
|
|
33
34
|
'Retrieves diagnostic information (errors, warnings, etc.) from a specific file in the project. ' +
|
|
34
35
|
'Use this tool to get information about problems in any project file. ' +
|
|
@@ -10,7 +10,7 @@ import { IChatInternalService } from '../../../common';
|
|
|
10
10
|
import { ChatInternalService } from '../../chat/chat.internal.service';
|
|
11
11
|
import { IMCPServerRegistry, MCPLogger, MCPServerContribution, MCPToolDefinition } from '../../types';
|
|
12
12
|
|
|
13
|
-
import { GrepSearchToolComponent } from './components/
|
|
13
|
+
import { GrepSearchToolComponent } from './components/ExpandableFileList';
|
|
14
14
|
|
|
15
15
|
const inputSchema = z.object({
|
|
16
16
|
query: z.string().describe('The regex pattern to search for'),
|
|
@@ -90,7 +90,7 @@ export class GrepSearchTool implements MCPServerContribution {
|
|
|
90
90
|
return;
|
|
91
91
|
}
|
|
92
92
|
const results: string[] = [];
|
|
93
|
-
const files: string
|
|
93
|
+
const files: Array<{ uri: string; isDirectory: boolean }> = [];
|
|
94
94
|
for (const [fileUri, result] of this.searchService.searchResults.entries()) {
|
|
95
95
|
results.push(
|
|
96
96
|
`File: ${fileUri}\n${result
|
|
@@ -103,7 +103,10 @@ export class GrepSearchTool implements MCPServerContribution {
|
|
|
103
103
|
.map((r) => `Line: ${r.line}\nContent: ${r.lineText || r.renderLineText}`)
|
|
104
104
|
.join('\n')}`,
|
|
105
105
|
);
|
|
106
|
-
files.push(
|
|
106
|
+
files.push({
|
|
107
|
+
uri: fileUri,
|
|
108
|
+
isDirectory: false, // grep 搜索结果都是文件
|
|
109
|
+
});
|
|
107
110
|
}
|
|
108
111
|
deferred.resolve(results.join('\n\n'));
|
|
109
112
|
const messages = this.chatInternalService.sessionModel.history.getMessages();
|
|
@@ -56,6 +56,10 @@ export class ListDirHandler {
|
|
|
56
56
|
@Autowired(IFileServiceClient)
|
|
57
57
|
private readonly fileSystemService: IFileServiceClient;
|
|
58
58
|
|
|
59
|
+
getWorkspaceDir(): string {
|
|
60
|
+
return this.appConfig.workspaceDir;
|
|
61
|
+
}
|
|
62
|
+
|
|
59
63
|
async handler(args: { relativeWorkspacePath: string }) {
|
|
60
64
|
const { relativeWorkspacePath } = args;
|
|
61
65
|
if (!relativeWorkspacePath) {
|
|
@@ -49,6 +49,7 @@ export class RunCommandHandler {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
async handler(args: z.infer<typeof inputSchema> & { toolCallId: string }, logger: MCPLogger) {
|
|
52
|
+
logger.appendLine(`Executing command: ${args.command}`);
|
|
52
53
|
if (args.require_user_approval) {
|
|
53
54
|
const def = new Deferred<boolean>();
|
|
54
55
|
this.approvalDeferredMap.set(args.toolCallId, def);
|
|
@@ -89,6 +90,7 @@ export class RunCommandHandler {
|
|
|
89
90
|
content: result,
|
|
90
91
|
});
|
|
91
92
|
|
|
93
|
+
logger.appendLine(`Command ${args.command} finished with exit code: ${e.code}`);
|
|
92
94
|
terminalClient.term.writeln(
|
|
93
95
|
`\n${color.italic}> Command ${args.command} executed successfully. Terminal will close in ${
|
|
94
96
|
3000 / 1000
|
|
@@ -3,8 +3,11 @@ import { z } from 'zod';
|
|
|
3
3
|
import { Autowired } from '@opensumi/di';
|
|
4
4
|
import { Domain } from '@opensumi/ide-core-common';
|
|
5
5
|
|
|
6
|
+
import { IChatInternalService } from '../../../common';
|
|
7
|
+
import { ChatInternalService } from '../../chat/chat.internal.service';
|
|
6
8
|
import { IMCPServerRegistry, MCPLogger, MCPServerContribution, MCPToolDefinition } from '../../types';
|
|
7
9
|
|
|
10
|
+
import { ListDirToolComponent } from './components/ExpandableFileList';
|
|
8
11
|
import { ListDirHandler } from './handlers/ListDir';
|
|
9
12
|
|
|
10
13
|
const inputSchema = z
|
|
@@ -26,8 +29,12 @@ export class ListDirTool implements MCPServerContribution {
|
|
|
26
29
|
@Autowired(ListDirHandler)
|
|
27
30
|
private readonly listDirHandler: ListDirHandler;
|
|
28
31
|
|
|
32
|
+
@Autowired(IChatInternalService)
|
|
33
|
+
private readonly chatInternalService: ChatInternalService;
|
|
34
|
+
|
|
29
35
|
registerMCPServer(registry: IMCPServerRegistry): void {
|
|
30
36
|
registry.registerMCPTool(this.getToolDefinition());
|
|
37
|
+
registry.registerToolComponent('list_dir', ListDirToolComponent);
|
|
31
38
|
}
|
|
32
39
|
|
|
33
40
|
getToolDefinition(): MCPToolDefinition {
|
|
@@ -41,16 +48,40 @@ export class ListDirTool implements MCPServerContribution {
|
|
|
41
48
|
};
|
|
42
49
|
}
|
|
43
50
|
|
|
44
|
-
private async handler(args: z.infer<typeof inputSchema
|
|
51
|
+
private async handler(args: z.infer<typeof inputSchema> & { toolCallId: string }, logger: MCPLogger) {
|
|
45
52
|
const result = await this.listDirHandler.handler(args);
|
|
53
|
+
|
|
54
|
+
// 构建文件 URI 列表,用于前端渲染
|
|
55
|
+
const fileUris = result.files.map((file) => {
|
|
56
|
+
const filePath = `${this.listDirHandler.getWorkspaceDir()}/${result.directoryRelativeWorkspacePath}/${file.name}`;
|
|
57
|
+
return {
|
|
58
|
+
uri: filePath,
|
|
59
|
+
isDirectory: file.isDirectory,
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// 设置消息的附加数据
|
|
64
|
+
const messages = this.chatInternalService.sessionModel.history.getMessages();
|
|
65
|
+
this.chatInternalService.sessionModel.history.setMessageAdditional(messages[messages.length - 1].id, {
|
|
66
|
+
[args.toolCallId]: {
|
|
67
|
+
files: fileUris,
|
|
68
|
+
title: `Listed directory "${args.relativeWorkspacePath}"`,
|
|
69
|
+
details: result.files.map((file) => ({
|
|
70
|
+
type: file.isDirectory ? 'dir' : 'file',
|
|
71
|
+
name: file.name,
|
|
72
|
+
info: file.isDirectory ? `${file.numChildren ?? '?'} items` : `${file.size}KB, ${file.numLines} lines`,
|
|
73
|
+
lastModified: file.lastModified,
|
|
74
|
+
})),
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
logger.appendLine(`Listed ${fileUris.length} files in directory "${args.relativeWorkspacePath}"`);
|
|
79
|
+
|
|
46
80
|
return {
|
|
47
81
|
content: [
|
|
48
82
|
{
|
|
49
83
|
type: 'text',
|
|
50
|
-
text: `Contents of directory
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
${result.files
|
|
84
|
+
text: `Contents of directory "${args.relativeWorkspacePath}":\n${result.files
|
|
54
85
|
.map(
|
|
55
86
|
(file) =>
|
|
56
87
|
`[${file.isDirectory ? 'dir' : 'file'}] ${file.name} ${
|
|
@@ -32,6 +32,7 @@ export class RunTerminalCommandTool implements MCPServerContribution {
|
|
|
32
32
|
getToolDefinition(): MCPToolDefinition {
|
|
33
33
|
return {
|
|
34
34
|
name: 'run_terminal_cmd',
|
|
35
|
+
label: 'Run Command',
|
|
35
36
|
description:
|
|
36
37
|
"PROPOSE a command to run on behalf of the user.\nIf you have this tool, note that you DO have the ability to run commands directly on the USER's system.\n\nAdhere to these rules:\n1. Based on the contents of the conversation, you will be told if you are in the same shell as a previous step or a new shell.\n2. If in a new shell, you should `cd` to the right directory and do necessary setup in addition to running the command.\n3. If in the same shell, the state will persist, no need to do things like `cd` to the same directory.\n4. For ANY commands that would use a pager, you should append ` | cat` to the command (or whatever is appropriate). You MUST do this for: git, less, head, tail, more, etc.\n5. For commands that are long running/expected to run indefinitely until interruption, please run them in the background. To run jobs in the background, set `is_background` to true rather than changing the details of the command.\n6. Dont include any newlines in the command.",
|
|
37
38
|
inputSchema,
|
|
@@ -15,13 +15,13 @@ export interface LLMContextService {
|
|
|
15
15
|
*/
|
|
16
16
|
cleanFileContext(): void;
|
|
17
17
|
|
|
18
|
-
onDidContextFilesChangeEvent: Event<FileContext[]>;
|
|
18
|
+
onDidContextFilesChangeEvent: Event<{ viewed: FileContext[]; attached: FileContext[]; version: number }>;
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* 从 context 中移除文件
|
|
22
22
|
* @param uri URI
|
|
23
23
|
*/
|
|
24
|
-
removeFileFromContext(uri: URI): void;
|
|
24
|
+
removeFileFromContext(uri: URI, isManual?: boolean): void;
|
|
25
25
|
|
|
26
26
|
/** 导出为可序列化格式 */
|
|
27
27
|
serialize(): SerializedContext;
|
|
@@ -30,12 +30,18 @@ export interface LLMContextService {
|
|
|
30
30
|
export interface FileContext {
|
|
31
31
|
uri: URI;
|
|
32
32
|
selection?: [number, number];
|
|
33
|
-
isManual: boolean;
|
|
34
33
|
}
|
|
35
34
|
|
|
36
35
|
export const LLMContextServiceToken = Symbol('LLMContextService');
|
|
37
36
|
|
|
37
|
+
export interface AttachFileContext {
|
|
38
|
+
content: string;
|
|
39
|
+
lineErrors: string[];
|
|
40
|
+
path: string;
|
|
41
|
+
language: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
38
44
|
export interface SerializedContext {
|
|
39
45
|
recentlyViewFiles: string[];
|
|
40
|
-
attachedFiles: Array<
|
|
46
|
+
attachedFiles: Array<AttachFileContext>;
|
|
41
47
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Injectable } from '@opensumi/di';
|
|
2
|
-
import {
|
|
1
|
+
import { Autowired, Injectable } from '@opensumi/di';
|
|
2
|
+
import { WorkbenchEditorService } from '@opensumi/ide-editor/lib/common/editor';
|
|
3
3
|
|
|
4
4
|
import { SerializedContext } from '../llm-context';
|
|
5
5
|
|
|
@@ -10,37 +10,46 @@ export interface ChatAgentPromptProvider {
|
|
|
10
10
|
* 提供上下文提示
|
|
11
11
|
* @param context 上下文
|
|
12
12
|
*/
|
|
13
|
-
provideContextPrompt(context: SerializedContext, userMessage: string):
|
|
13
|
+
provideContextPrompt(context: SerializedContext, userMessage: string): string;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
@Injectable()
|
|
17
17
|
export class DefaultChatAgentPromptProvider implements ChatAgentPromptProvider {
|
|
18
|
-
|
|
18
|
+
@Autowired(WorkbenchEditorService)
|
|
19
|
+
protected readonly workbenchEditorService: WorkbenchEditorService;
|
|
20
|
+
|
|
21
|
+
provideContextPrompt(context: SerializedContext, userMessage: string): string {
|
|
22
|
+
const editor = this.workbenchEditorService.currentEditor;
|
|
23
|
+
const currentModel = editor?.currentDocumentModel;
|
|
19
24
|
return `
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
25
|
+
<additional_data>
|
|
26
|
+
Below are some potentially helpful/relevant pieces of information for figuring out to respond
|
|
27
|
+
<recently_viewed_files>
|
|
28
|
+
${context.recentlyViewFiles.map((file, idx) => ` ${idx + 1}: ${file}`).join('\n')}
|
|
29
|
+
</recently_viewed_files>
|
|
30
|
+
<attached_files>
|
|
31
|
+
${context.attachedFiles.map(
|
|
32
|
+
(file) =>
|
|
33
|
+
`
|
|
34
|
+
<file_contents>
|
|
35
|
+
\`\`\`${file.path}
|
|
36
|
+
${file.content}
|
|
37
|
+
\`\`\`
|
|
38
|
+
</file_contents>
|
|
39
|
+
<linter_errors>
|
|
40
|
+
${file.lineErrors.join('\n')}
|
|
41
|
+
</linter_errors>
|
|
42
|
+
`,
|
|
43
|
+
)}
|
|
44
|
+
</attached_files>
|
|
45
|
+
${currentModel ? `<current_opened_file>
|
|
46
|
+
\`\`\`${currentModel.languageId} ${currentModel.uri.toString()}
|
|
47
|
+
${currentModel.getText()}
|
|
48
|
+
\`\`\`
|
|
49
|
+
</current_opened_file>` : ''}
|
|
50
|
+
</additional_data>
|
|
51
|
+
<user_query>
|
|
52
|
+
${userMessage}
|
|
53
|
+
</user_query>`;
|
|
45
54
|
}
|
|
46
55
|
}
|
|
@@ -61,6 +61,7 @@ export abstract class BaseLanguageModel {
|
|
|
61
61
|
options.modelId,
|
|
62
62
|
options.providerOptions,
|
|
63
63
|
options.trimTexts,
|
|
64
|
+
options.system,
|
|
64
65
|
cancellationToken,
|
|
65
66
|
);
|
|
66
67
|
}
|
|
@@ -88,6 +89,7 @@ export abstract class BaseLanguageModel {
|
|
|
88
89
|
modelId?: string,
|
|
89
90
|
providerOptions?: Record<string, any>,
|
|
90
91
|
trimTexts?: [string, string],
|
|
92
|
+
systemPrompt?: string,
|
|
91
93
|
cancellationToken?: CancellationToken,
|
|
92
94
|
): Promise<any> {
|
|
93
95
|
try {
|
|
@@ -110,7 +112,6 @@ export abstract class BaseLanguageModel {
|
|
|
110
112
|
const modelInfo = modelId ? this.getModelInfo(modelId) : undefined;
|
|
111
113
|
const stream = streamText({
|
|
112
114
|
model: this.getModelIdentifier(provider, modelId),
|
|
113
|
-
maxTokens: 4096,
|
|
114
115
|
tools: aiTools,
|
|
115
116
|
messages,
|
|
116
117
|
abortSignal: abortController.signal,
|
|
@@ -119,6 +120,7 @@ export abstract class BaseLanguageModel {
|
|
|
119
120
|
temperature: modelInfo?.temperature || 0,
|
|
120
121
|
topP: modelInfo?.topP || 0.8,
|
|
121
122
|
topK: modelInfo?.topK || 1,
|
|
123
|
+
system: systemPrompt,
|
|
122
124
|
providerOptions,
|
|
123
125
|
});
|
|
124
126
|
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
interface SearchResultProps {
|
|
3
|
-
args: any;
|
|
4
|
-
toolCallId: string;
|
|
5
|
-
messageId: string;
|
|
6
|
-
toolName: string;
|
|
7
|
-
}
|
|
8
|
-
export declare const FileSearchToolComponent: React.FC<SearchResultProps>;
|
|
9
|
-
export declare const GrepSearchToolComponent: React.FC<SearchResultProps>;
|
|
10
|
-
export {};
|
|
11
|
-
//# sourceMappingURL=SearchResult.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SearchResult.d.ts","sourceRoot":"","sources":["../../../../../src/browser/mcp/tools/components/SearchResult.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAW5D,UAAU,iBAAiB;IACzB,IAAI,EAAE,GAAG,CAAC;IACV,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,uBAAuB,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAE/D,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAE/D,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SearchResult.js","sourceRoot":"","sources":["../../../../../src/browser/mcp/tools/components/SearchResult.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useMemo, useState } from 'react';
|
|
2
|
-
|
|
3
|
-
import { LabelService, URI, path, useInjectable } from '@opensumi/ide-core-browser';
|
|
4
|
-
import { WorkbenchEditorService } from '@opensumi/ide-editor';
|
|
5
|
-
import { IWorkspaceService } from '@opensumi/ide-workspace';
|
|
6
|
-
|
|
7
|
-
import { IChatInternalService } from '../../../../common';
|
|
8
|
-
import { ChatInternalService } from '../../../chat/chat.internal.service';
|
|
9
|
-
|
|
10
|
-
import styles from './index.module.less';
|
|
11
|
-
|
|
12
|
-
interface SearchResultProps {
|
|
13
|
-
args: any;
|
|
14
|
-
toolCallId: string;
|
|
15
|
-
messageId: string;
|
|
16
|
-
toolName: string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export const FileSearchToolComponent: React.FC<SearchResultProps> = ({ args, toolCallId, messageId }) => (
|
|
20
|
-
<SearchResult args={args} toolCallId={toolCallId} messageId={messageId} toolName='fileSearch' />
|
|
21
|
-
);
|
|
22
|
-
|
|
23
|
-
export const GrepSearchToolComponent: React.FC<SearchResultProps> = ({ args, toolCallId, messageId }) => (
|
|
24
|
-
<SearchResult args={args} toolCallId={toolCallId} messageId={messageId} toolName='grepSearch' />
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
const SearchResult: React.FC<SearchResultProps> = ({ args, toolCallId, toolName, messageId }) => {
|
|
28
|
-
const [isExpanded, setIsExpanded] = useState(false);
|
|
29
|
-
const labelService = useInjectable<LabelService>(LabelService);
|
|
30
|
-
const editorService = useInjectable<WorkbenchEditorService>(WorkbenchEditorService);
|
|
31
|
-
const workspaceService = useInjectable<IWorkspaceService>(IWorkspaceService);
|
|
32
|
-
const workspaceRoot = useMemo(() => URI.parse(workspaceService.tryGetRoots()?.[0]?.uri), []);
|
|
33
|
-
|
|
34
|
-
const chatService = useInjectable<ChatInternalService>(IChatInternalService);
|
|
35
|
-
const [files, setFiles] = useState<string[]>(
|
|
36
|
-
chatService.sessionModel.history.getMessageAdditional(messageId)?.[toolCallId]?.files || [],
|
|
37
|
-
);
|
|
38
|
-
useEffect(() => {
|
|
39
|
-
const toDispose = chatService.sessionModel.history.onMessageAdditionalChange((additional) => {
|
|
40
|
-
setFiles(additional[toolCallId]?.files || []);
|
|
41
|
-
});
|
|
42
|
-
return () => {
|
|
43
|
-
toDispose.dispose();
|
|
44
|
-
};
|
|
45
|
-
}, []);
|
|
46
|
-
|
|
47
|
-
const handleFileClick = (uri: URI) => {
|
|
48
|
-
// 处理文件点击跳转
|
|
49
|
-
editorService.open(uri);
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
const parsedFiles = useMemo(
|
|
53
|
-
() =>
|
|
54
|
-
files.map((file) => {
|
|
55
|
-
const uri = URI.parse(file);
|
|
56
|
-
const iconClass = labelService.getIcon(uri);
|
|
57
|
-
return {
|
|
58
|
-
iconClass,
|
|
59
|
-
name: uri.path.base,
|
|
60
|
-
path: path.relative(workspaceRoot.codeUri.fsPath, uri.path.dir.toString()),
|
|
61
|
-
};
|
|
62
|
-
}),
|
|
63
|
-
[files],
|
|
64
|
-
);
|
|
65
|
-
|
|
66
|
-
return (
|
|
67
|
-
<div className={styles.container}>
|
|
68
|
-
<div className={styles.header} onClick={() => setIsExpanded(!isExpanded)}>
|
|
69
|
-
<span style={{ transform: `rotate(${isExpanded ? '90deg' : '0deg'})` }}>▶</span>
|
|
70
|
-
<span>
|
|
71
|
-
{toolName === 'fileSearch' ? `Searched files "${args.query}"` : `Grepped codebase "${args.query}"`} ·{' '}
|
|
72
|
-
{files.length} files
|
|
73
|
-
</span>
|
|
74
|
-
</div>
|
|
75
|
-
{isExpanded && (
|
|
76
|
-
<ul className={styles.fileList}>
|
|
77
|
-
{parsedFiles.map((file, index) => (
|
|
78
|
-
<li
|
|
79
|
-
key={index}
|
|
80
|
-
className={styles.fileItem}
|
|
81
|
-
onClick={() => handleFileClick(URI.file(path.join(workspaceRoot.codeUri.fsPath, file.path, file.name)))}
|
|
82
|
-
>
|
|
83
|
-
<span className={file.iconClass}></span>
|
|
84
|
-
<span style={{ flex: 1 }}>{file.name}</span>
|
|
85
|
-
<span className={styles.filePath}>{file.path}</span>
|
|
86
|
-
</li>
|
|
87
|
-
))}
|
|
88
|
-
</ul>
|
|
89
|
-
)}
|
|
90
|
-
</div>
|
|
91
|
-
);
|
|
92
|
-
};
|