@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.
Files changed (110) hide show
  1. package/lib/browser/ai-core.contribution.d.ts.map +1 -1
  2. package/lib/browser/ai-core.contribution.js +22 -22
  3. package/lib/browser/ai-core.contribution.js.map +1 -1
  4. package/lib/browser/chat/chat-agent.service.d.ts +8 -0
  5. package/lib/browser/chat/chat-agent.service.d.ts.map +1 -1
  6. package/lib/browser/chat/chat-agent.service.js +32 -5
  7. package/lib/browser/chat/chat-agent.service.js.map +1 -1
  8. package/lib/browser/chat/chat-model.d.ts.map +1 -1
  9. package/lib/browser/chat/chat-model.js +3 -2
  10. package/lib/browser/chat/chat-model.js.map +1 -1
  11. package/lib/browser/chat/chat-proxy.service.d.ts.map +1 -1
  12. package/lib/browser/chat/chat-proxy.service.js +3 -1
  13. package/lib/browser/chat/chat-proxy.service.js.map +1 -1
  14. package/lib/browser/chat/chat.module.less +1 -2
  15. package/lib/browser/chat/chat.view.d.ts.map +1 -1
  16. package/lib/browser/chat/chat.view.js +6 -38
  17. package/lib/browser/chat/chat.view.js.map +1 -1
  18. package/lib/browser/components/ChatContext/index.js +2 -2
  19. package/lib/browser/components/ChatContext/index.js.map +1 -1
  20. package/lib/browser/components/ChatInput.d.ts.map +1 -1
  21. package/lib/browser/components/ChatInput.js +25 -1
  22. package/lib/browser/components/ChatInput.js.map +1 -1
  23. package/lib/browser/components/ChatToolRender.d.ts.map +1 -1
  24. package/lib/browser/components/ChatToolRender.js +2 -3
  25. package/lib/browser/components/ChatToolRender.js.map +1 -1
  26. package/lib/browser/components/chat-history.module.less +1 -1
  27. package/lib/browser/components/components.module.less +20 -0
  28. package/lib/browser/context/llm-context.service.d.ts +18 -5
  29. package/lib/browser/context/llm-context.service.d.ts.map +1 -1
  30. package/lib/browser/context/llm-context.service.js +80 -47
  31. package/lib/browser/context/llm-context.service.js.map +1 -1
  32. package/lib/browser/layout/layout.module.less +4 -4
  33. package/lib/browser/mcp/tools/components/ExpandableFileList.d.ts +13 -0
  34. package/lib/browser/mcp/tools/components/ExpandableFileList.d.ts.map +1 -0
  35. package/lib/browser/mcp/tools/components/{SearchResult.js → ExpandableFileList.js} +29 -19
  36. package/lib/browser/mcp/tools/components/ExpandableFileList.js.map +1 -0
  37. package/lib/browser/mcp/tools/components/index.module.less +1 -0
  38. package/lib/browser/mcp/tools/createNewFileWithText.d.ts.map +1 -1
  39. package/lib/browser/mcp/tools/createNewFileWithText.js +1 -0
  40. package/lib/browser/mcp/tools/createNewFileWithText.js.map +1 -1
  41. package/lib/browser/mcp/tools/fileSearch.d.ts +1 -0
  42. package/lib/browser/mcp/tools/fileSearch.d.ts.map +1 -1
  43. package/lib/browser/mcp/tools/fileSearch.js +14 -5
  44. package/lib/browser/mcp/tools/fileSearch.js.map +1 -1
  45. package/lib/browser/mcp/tools/getDiagnosticsByPath.d.ts.map +1 -1
  46. package/lib/browser/mcp/tools/getDiagnosticsByPath.js +1 -0
  47. package/lib/browser/mcp/tools/getDiagnosticsByPath.js.map +1 -1
  48. package/lib/browser/mcp/tools/grepSearch.d.ts.map +1 -1
  49. package/lib/browser/mcp/tools/grepSearch.js +6 -3
  50. package/lib/browser/mcp/tools/grepSearch.js.map +1 -1
  51. package/lib/browser/mcp/tools/handlers/ListDir.d.ts +1 -0
  52. package/lib/browser/mcp/tools/handlers/ListDir.d.ts.map +1 -1
  53. package/lib/browser/mcp/tools/handlers/ListDir.js +3 -0
  54. package/lib/browser/mcp/tools/handlers/ListDir.js.map +1 -1
  55. package/lib/browser/mcp/tools/handlers/RunCommand.d.ts.map +1 -1
  56. package/lib/browser/mcp/tools/handlers/RunCommand.js +2 -0
  57. package/lib/browser/mcp/tools/handlers/RunCommand.js.map +1 -1
  58. package/lib/browser/mcp/tools/listDir.d.ts +1 -0
  59. package/lib/browser/mcp/tools/listDir.d.ts.map +1 -1
  60. package/lib/browser/mcp/tools/listDir.js +35 -4
  61. package/lib/browser/mcp/tools/listDir.js.map +1 -1
  62. package/lib/browser/mcp/tools/runTerminalCmd.d.ts.map +1 -1
  63. package/lib/browser/mcp/tools/runTerminalCmd.js +1 -0
  64. package/lib/browser/mcp/tools/runTerminalCmd.js.map +1 -1
  65. package/lib/browser/preferences/schema.d.ts.map +1 -1
  66. package/lib/browser/preferences/schema.js +0 -1
  67. package/lib/browser/preferences/schema.js.map +1 -1
  68. package/lib/common/llm-context.d.ts +13 -9
  69. package/lib/common/llm-context.d.ts.map +1 -1
  70. package/lib/common/llm-context.js.map +1 -1
  71. package/lib/common/prompts/context-prompt-provider.d.ts +4 -3
  72. package/lib/common/prompts/context-prompt-provider.d.ts.map +1 -1
  73. package/lib/common/prompts/context-prompt-provider.js +33 -22
  74. package/lib/common/prompts/context-prompt-provider.js.map +1 -1
  75. package/lib/node/base-language-model.d.ts +1 -1
  76. package/lib/node/base-language-model.d.ts.map +1 -1
  77. package/lib/node/base-language-model.js +3 -3
  78. package/lib/node/base-language-model.js.map +1 -1
  79. package/package.json +23 -23
  80. package/src/browser/ai-core.contribution.ts +27 -26
  81. package/src/browser/chat/chat-agent.service.ts +38 -7
  82. package/src/browser/chat/chat-model.ts +11 -6
  83. package/src/browser/chat/chat-proxy.service.ts +4 -2
  84. package/src/browser/chat/chat.module.less +1 -2
  85. package/src/browser/chat/chat.view.tsx +7 -70
  86. package/src/browser/components/ChatContext/index.tsx +2 -2
  87. package/src/browser/components/ChatInput.tsx +67 -3
  88. package/src/browser/components/ChatToolRender.tsx +1 -2
  89. package/src/browser/components/chat-history.module.less +1 -1
  90. package/src/browser/components/components.module.less +20 -0
  91. package/src/browser/context/llm-context.service.ts +93 -54
  92. package/src/browser/layout/layout.module.less +4 -4
  93. package/src/browser/mcp/tools/components/ExpandableFileList.tsx +133 -0
  94. package/src/browser/mcp/tools/components/index.module.less +1 -0
  95. package/src/browser/mcp/tools/createNewFileWithText.ts +1 -0
  96. package/src/browser/mcp/tools/fileSearch.ts +14 -4
  97. package/src/browser/mcp/tools/getDiagnosticsByPath.ts +1 -0
  98. package/src/browser/mcp/tools/grepSearch.ts +6 -3
  99. package/src/browser/mcp/tools/handlers/ListDir.ts +4 -0
  100. package/src/browser/mcp/tools/handlers/RunCommand.ts +2 -0
  101. package/src/browser/mcp/tools/listDir.ts +36 -5
  102. package/src/browser/mcp/tools/runTerminalCmd.ts +1 -0
  103. package/src/browser/preferences/schema.ts +0 -1
  104. package/src/common/llm-context.ts +10 -4
  105. package/src/common/prompts/context-prompt-provider.ts +38 -29
  106. package/src/node/base-language-model.ts +3 -1
  107. package/lib/browser/mcp/tools/components/SearchResult.d.ts +0 -11
  108. package/lib/browser/mcp/tools/components/SearchResult.d.ts.map +0 -1
  109. package/lib/browser/mcp/tools/components/SearchResult.js.map +0 -1
  110. 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
+ };
@@ -154,6 +154,7 @@
154
154
  background-color: var(--design-chatInput-background);
155
155
  padding: 10px;
156
156
  border-radius: 4px;
157
+ margin: 10px 0px;
157
158
 
158
159
  .command_title {
159
160
  display: flex;
@@ -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/SearchResult';
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 uri.codeUri.fsPath;
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/SearchResult';
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(fileUri);
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>, logger: MCPLogger) {
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,
@@ -153,7 +153,6 @@ export const aiNativePreferenceSchema: PreferenceSchema = {
153
153
  },
154
154
  [AINativeSettingSectionsId.SystemPrompt]: {
155
155
  type: 'string',
156
- default: '',
157
156
  description: localize('preference.ai.native.chat.system.prompt.description'),
158
157
  },
159
158
  },
@@ -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<{ content: string; lineErrors: string[]; path: string; language: string }>;
46
+ attachedFiles: Array<AttachFileContext>;
41
47
  }
@@ -1,5 +1,5 @@
1
- import { Injectable } from '@opensumi/di';
2
- import { MaybePromise } from '@opensumi/ide-core-common/lib/utils';
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): MaybePromise<string>;
13
+ provideContextPrompt(context: SerializedContext, userMessage: string): string;
14
14
  }
15
15
 
16
16
  @Injectable()
17
17
  export class DefaultChatAgentPromptProvider implements ChatAgentPromptProvider {
18
- provideContextPrompt(context: SerializedContext, userMessage: string): MaybePromise<string> {
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
- <additional_data>
21
- Below are some potentially helpful/relevant pieces of information for figuring out to respond
22
- <recently_viewed_files>
23
- ${context.recentlyViewFiles.map((file, idx) => `${idx + 1} : ${file}`)}
24
- </recently_viewed_files>
25
- <attached_files>
26
- ${context.attachedFiles.map(
27
- (file) =>
28
- `
29
- <file_contents>
30
- \`\`\`${file.language} ${file.path}
31
- ${file.content}
32
- \`\`\`
33
- </file_contents>
34
- <linter_errors>
35
- ${file.lineErrors.join('\n')}
36
- </linter_errors>
37
- `,
38
- )}
39
-
40
- </attached_files>
41
- </additional_data>
42
- <user_query>
43
- ${userMessage}
44
- </user_query>`;
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
- };