@opensumi/ide-ai-native 3.8.1-next-1740735826.0 → 3.8.1-next-1740965430.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 (73) hide show
  1. package/lib/browser/chat/chat-agent.service.d.ts +8 -0
  2. package/lib/browser/chat/chat-agent.service.d.ts.map +1 -1
  3. package/lib/browser/chat/chat-agent.service.js +34 -0
  4. package/lib/browser/chat/chat-agent.service.js.map +1 -1
  5. package/lib/browser/chat/chat-model.d.ts.map +1 -1
  6. package/lib/browser/chat/chat-model.js +3 -2
  7. package/lib/browser/chat/chat-model.js.map +1 -1
  8. package/lib/browser/chat/chat-proxy.service.d.ts.map +1 -1
  9. package/lib/browser/chat/chat-proxy.service.js +1 -1
  10. package/lib/browser/chat/chat-proxy.service.js.map +1 -1
  11. package/lib/browser/chat/chat.module.less +1 -2
  12. package/lib/browser/chat/chat.view.d.ts.map +1 -1
  13. package/lib/browser/chat/chat.view.js +6 -38
  14. package/lib/browser/chat/chat.view.js.map +1 -1
  15. package/lib/browser/components/ChatContext/index.js +2 -2
  16. package/lib/browser/components/ChatContext/index.js.map +1 -1
  17. package/lib/browser/components/ChatInput.d.ts.map +1 -1
  18. package/lib/browser/components/ChatInput.js +25 -1
  19. package/lib/browser/components/ChatInput.js.map +1 -1
  20. package/lib/browser/components/ChatToolRender.d.ts.map +1 -1
  21. package/lib/browser/components/ChatToolRender.js +2 -3
  22. package/lib/browser/components/ChatToolRender.js.map +1 -1
  23. package/lib/browser/components/chat-history.module.less +1 -1
  24. package/lib/browser/components/components.module.less +20 -0
  25. package/lib/browser/context/llm-context.service.d.ts +18 -5
  26. package/lib/browser/context/llm-context.service.d.ts.map +1 -1
  27. package/lib/browser/context/llm-context.service.js +80 -47
  28. package/lib/browser/context/llm-context.service.js.map +1 -1
  29. package/lib/browser/layout/layout.module.less +4 -4
  30. package/lib/browser/mcp/tools/components/index.module.less +1 -0
  31. package/lib/browser/mcp/tools/createNewFileWithText.d.ts.map +1 -1
  32. package/lib/browser/mcp/tools/createNewFileWithText.js +1 -0
  33. package/lib/browser/mcp/tools/createNewFileWithText.js.map +1 -1
  34. package/lib/browser/mcp/tools/getDiagnosticsByPath.d.ts.map +1 -1
  35. package/lib/browser/mcp/tools/getDiagnosticsByPath.js +1 -0
  36. package/lib/browser/mcp/tools/getDiagnosticsByPath.js.map +1 -1
  37. package/lib/browser/mcp/tools/handlers/RunCommand.d.ts.map +1 -1
  38. package/lib/browser/mcp/tools/handlers/RunCommand.js +2 -0
  39. package/lib/browser/mcp/tools/handlers/RunCommand.js.map +1 -1
  40. package/lib/browser/mcp/tools/runTerminalCmd.d.ts.map +1 -1
  41. package/lib/browser/mcp/tools/runTerminalCmd.js +1 -0
  42. package/lib/browser/mcp/tools/runTerminalCmd.js.map +1 -1
  43. package/lib/browser/preferences/schema.d.ts.map +1 -1
  44. package/lib/browser/preferences/schema.js +0 -1
  45. package/lib/browser/preferences/schema.js.map +1 -1
  46. package/lib/common/llm-context.d.ts +13 -9
  47. package/lib/common/llm-context.d.ts.map +1 -1
  48. package/lib/common/llm-context.js.map +1 -1
  49. package/lib/common/prompts/context-prompt-provider.d.ts +4 -3
  50. package/lib/common/prompts/context-prompt-provider.d.ts.map +1 -1
  51. package/lib/common/prompts/context-prompt-provider.js +33 -22
  52. package/lib/common/prompts/context-prompt-provider.js.map +1 -1
  53. package/package.json +23 -23
  54. package/src/browser/chat/chat-agent.service.ts +42 -3
  55. package/src/browser/chat/chat-model.ts +11 -6
  56. package/src/browser/chat/chat-proxy.service.ts +2 -1
  57. package/src/browser/chat/chat.module.less +1 -2
  58. package/src/browser/chat/chat.view.tsx +7 -70
  59. package/src/browser/components/ChatContext/index.tsx +2 -2
  60. package/src/browser/components/ChatInput.tsx +67 -4
  61. package/src/browser/components/ChatToolRender.tsx +1 -2
  62. package/src/browser/components/chat-history.module.less +1 -1
  63. package/src/browser/components/components.module.less +20 -0
  64. package/src/browser/context/llm-context.service.ts +93 -54
  65. package/src/browser/layout/layout.module.less +4 -4
  66. package/src/browser/mcp/tools/components/index.module.less +1 -0
  67. package/src/browser/mcp/tools/createNewFileWithText.ts +1 -0
  68. package/src/browser/mcp/tools/getDiagnosticsByPath.ts +1 -0
  69. package/src/browser/mcp/tools/handlers/RunCommand.ts +2 -0
  70. package/src/browser/mcp/tools/runTerminalCmd.ts +1 -0
  71. package/src/browser/preferences/schema.ts +0 -1
  72. package/src/common/llm-context.ts +10 -4
  73. package/src/common/prompts/context-prompt-provider.ts +38 -29
@@ -1,21 +1,31 @@
1
1
  import cls from 'classnames';
2
2
  import React, { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
3
3
 
4
- import { useInjectable, useLatest } from '@opensumi/ide-core-browser';
4
+ import { AINativeConfigService, useInjectable, useLatest } from '@opensumi/ide-core-browser';
5
5
  import { Icon, Popover, PopoverPosition, getIcon } from '@opensumi/ide-core-browser/lib/components';
6
6
  import { EnhanceIcon } from '@opensumi/ide-core-browser/lib/components/ai-native';
7
7
  import { InteractiveInput } from '@opensumi/ide-core-browser/lib/components/ai-native/interactive-input/index';
8
- import { ChatAgentViewServiceToken, ChatFeatureRegistryToken, localize, runWhenIdle } from '@opensumi/ide-core-common';
8
+ import {
9
+ ChatAgentViewServiceToken,
10
+ ChatFeatureRegistryToken,
11
+ MessageType,
12
+ localize,
13
+ runWhenIdle,
14
+ } from '@opensumi/ide-core-common';
15
+ import { CommandService } from '@opensumi/ide-core-common/lib/command';
9
16
  import { MonacoCommandRegistry } from '@opensumi/ide-editor/lib/browser/monaco-contrib/command/command.service';
17
+ import { IDialogService } from '@opensumi/ide-overlay';
10
18
 
11
- import { AT_SIGN_SYMBOL, IChatAgentService, SLASH_SYMBOL } from '../../common';
19
+ import { AT_SIGN_SYMBOL, IChatAgentService, SLASH_SYMBOL, TokenMCPServerProxyService } from '../../common';
12
20
  import { ChatAgentViewService } from '../chat/chat-agent.view.service';
13
21
  import { ChatSlashCommandItemModel } from '../chat/chat-model';
14
22
  import { ChatProxyService } from '../chat/chat-proxy.service';
15
23
  import { ChatFeatureRegistry } from '../chat/chat.feature.registry';
24
+ import { OPEN_MCP_CONFIG_COMMAND } from '../mcp/config/mcp-config.commands';
25
+ import { MCPServerProxyService } from '../mcp/mcp-server-proxy.service';
26
+ import { MCPToolsDialog } from '../mcp/mcp-tools-dialog.view';
16
27
  import { IChatSlashCommandItem } from '../types';
17
28
 
18
- import { ChatContext } from './ChatContext';
19
29
  import styles from './components.module.less';
20
30
 
21
31
  const INSTRUCTION_BOTTOM = 8;
@@ -195,12 +205,29 @@ export const ChatInput = React.forwardRef((props: IChatInputProps, ref) => {
195
205
  const [isExpand, setIsExpand] = useState(false);
196
206
  const [placeholder, setPlaceHolder] = useState(localize('aiNative.chat.input.placeholder.default'));
197
207
 
208
+ const dialogService = useInjectable<IDialogService>(IDialogService);
209
+ const aiNativeConfigService = useInjectable<AINativeConfigService>(AINativeConfigService);
210
+ const mcpServerProxyService = useInjectable<MCPServerProxyService>(TokenMCPServerProxyService);
198
211
  const monacoCommandRegistry = useInjectable<MonacoCommandRegistry>(MonacoCommandRegistry);
199
212
  const chatAgentService = useInjectable<IChatAgentService>(IChatAgentService);
200
213
  const chatFeatureRegistry = useInjectable<ChatFeatureRegistry>(ChatFeatureRegistryToken);
214
+ const commandService = useInjectable<CommandService>(CommandService);
201
215
 
202
216
  const currentAgentIdRef = useLatest(agentId);
203
217
 
218
+ const handleShowMCPConfig = React.useCallback(() => {
219
+ commandService.executeCommand(OPEN_MCP_CONFIG_COMMAND.id);
220
+ }, [commandService]);
221
+
222
+ const handleShowMCPTools = React.useCallback(async () => {
223
+ const tools = await mcpServerProxyService.getAllMCPTools();
224
+ dialogService.open({
225
+ message: <MCPToolsDialog tools={tools} />,
226
+ type: MessageType.Empty,
227
+ buttons: ['关闭'],
228
+ });
229
+ }, [mcpServerProxyService, dialogService]);
230
+
204
231
  useImperativeHandle(ref, () => ({
205
232
  setInputValue: (v: string) => {
206
233
  setValue(v);
@@ -462,6 +489,42 @@ export const ChatInput = React.forwardRef((props: IChatInputProps, ref) => {
462
489
  height={inputHeight}
463
490
  popoverPosition={PopoverPosition.left}
464
491
  />
492
+ <div className={styles.chat_input_footer}>
493
+ {aiNativeConfigService.capabilities.supportsMCP && (
494
+ <div className={styles.mcp_desc}>
495
+ <Popover
496
+ overlayClassName={styles.popover_icon}
497
+ id={'ai-chat-header-mcp-server'}
498
+ position={PopoverPosition.left}
499
+ title={'MCP Server'}
500
+ >
501
+ <EnhanceIcon
502
+ wrapperClassName={styles.action_btn}
503
+ className={'codicon codicon-server'}
504
+ onClick={handleShowMCPConfig}
505
+ tabIndex={0}
506
+ role='button'
507
+ ariaLabel={'MCP Server'}
508
+ />
509
+ </Popover>
510
+ <Popover
511
+ overlayClassName={styles.popover_icon}
512
+ id={'ai-chat-header-tools'}
513
+ position={PopoverPosition.left}
514
+ title={localize('aiNative.operate.tools.title')}
515
+ >
516
+ <EnhanceIcon
517
+ wrapperClassName={styles.action_btn}
518
+ className={getIcon('menubar-tool')}
519
+ onClick={handleShowMCPTools}
520
+ tabIndex={0}
521
+ role='button'
522
+ ariaLabel={localize('aiNative.operate.tools.title')}
523
+ />
524
+ </Popover>
525
+ </div>
526
+ )}
527
+ </div>
465
528
  </div>
466
529
  );
467
530
  });
@@ -67,13 +67,12 @@ export const ChatToolRender = (props: { value: IChatToolContent['content']; mess
67
67
  <div className={styles['chat-tool-render']}>
68
68
  <div className={styles['tool-header']} onClick={toggleExpand}>
69
69
  <div className={styles['tool-name']}>
70
- <span className={cls(styles['expand-icon'], { [styles.expanded]: isExpanded })}>▶</span>
70
+ <Icon iconClass={`codicon codicon-triangle-${isExpanded ? 'down' : 'right'}`} />
71
71
  {label}
72
72
  </div>
73
73
  {value.state && (
74
74
  <div className={styles['tool-state']}>
75
75
  <span className={styles['state-icon']}>{stateInfo.icon}</span>
76
- <span className={styles['state-label']}>{stateInfo.label}</span>
77
76
  </div>
78
77
  )}
79
78
  </div>
@@ -3,7 +3,7 @@
3
3
  align-items: center;
4
4
  justify-content: space-between;
5
5
  font-size: 13px;
6
- padding: 0 4px 0 12px;
6
+ padding: 0 0 0 12px;
7
7
  color: var(--editor-foreground);
8
8
  text-overflow: ellipsis;
9
9
  white-space: nowrap;
@@ -96,6 +96,7 @@
96
96
  .chat_input_container {
97
97
  position: relative;
98
98
  border-radius: 9px;
99
+ padding: 10px 0px 0px 0px;
99
100
  border: 1px solid var(--kt-input-border);
100
101
  background-color: var(--design-chatInput-background);
101
102
  &.active {
@@ -505,3 +506,22 @@
505
506
  }
506
507
  }
507
508
  }
509
+
510
+ .chat_input_footer {
511
+ padding: 0px 10px;
512
+ display: flex;
513
+ align-items: center;
514
+ font-size: 12px;
515
+
516
+ .model_selector {
517
+ display: flex;
518
+ font-size: 11px;
519
+ align-items: center;
520
+ }
521
+
522
+ .mcp_desc {
523
+ padding: 5px 0px;
524
+ display: flex;
525
+ align-items: center;
526
+ }
527
+ }
@@ -12,7 +12,7 @@ import {
12
12
  import { EditorSelectionChangeEvent } from '@opensumi/ide-editor/lib/browser/types';
13
13
  import { IMarkerService } from '@opensumi/ide-markers/lib/common/types';
14
14
 
15
- import { FileContext, LLMContextService, SerializedContext } from '../../common/llm-context';
15
+ import { AttachFileContext, FileContext, LLMContextService, SerializedContext } from '../../common/llm-context';
16
16
 
17
17
  @Injectable()
18
18
  export class LLMContextServiceImpl extends WithEventBus implements LLMContextService {
@@ -27,40 +27,68 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
27
27
 
28
28
  private isAutoCollecting = false;
29
29
 
30
- private contextFiles: FileContext[] = [];
30
+ private contextVersion = 0;
31
31
 
32
- private maxFiles: number = 10; // 上下文的最大长度限制
33
-
34
- private onDidContextFilesChangeEmitter = new Emitter<FileContext[]>();
32
+ private readonly maxAttachFilesLimit = 10;
33
+ private readonly maxViewFilesLimit = 20;
34
+ private readonly attachedFiles: FileContext[] = [];
35
+ private readonly recentlyViewFiles: FileContext[] = [];
36
+ private readonly onDidContextFilesChangeEmitter = new Emitter<{ viewed: FileContext[]; attached: FileContext[]; version: number }>();
35
37
  onDidContextFilesChangeEvent = this.onDidContextFilesChangeEmitter.event;
36
38
 
37
- addFileToContext(uri: URI, selection?: [number, number], isManual = true): void {
38
- this.removeFileFromContext(uri);
39
+ private addFileToList(file: FileContext, list: FileContext[], maxLimit: number) {
40
+ const existingIndex = list.findIndex((f) => f.uri.toString() === file.uri.toString());
41
+ if (existingIndex > -1) {
42
+ list.splice(existingIndex, 1);
43
+ }
44
+
45
+ list.push(file);
46
+ if (list.length > maxLimit) {
47
+ list.shift();
48
+ }
49
+ }
50
+
51
+ addFileToContext(uri: URI, selection?: [number, number], isManual = false): void {
52
+ if (!uri) {
53
+ return;
54
+ }
39
55
 
40
- this.contextFiles.push({ uri, selection, isManual });
56
+ const file = { uri, selection };
57
+ const targetList = isManual ? this.attachedFiles : this.recentlyViewFiles;
58
+ const maxLimit = isManual ? this.maxAttachFilesLimit : this.maxViewFilesLimit;
41
59
 
42
- if (this.contextFiles.length > this.maxFiles) {
43
- this.contextFiles.shift();
60
+ if (isManual) {
61
+ this.docModelManager.createModelReference(uri);
44
62
  }
45
63
 
64
+ this.addFileToList(file, targetList, maxLimit);
65
+ this.notifyContextChange();
66
+ }
67
+
68
+ private notifyContextChange(): void {
46
69
  this.onDidContextFilesChangeEmitter.fire(this.getAllContextFiles());
47
70
  }
48
71
 
49
72
  cleanFileContext() {
50
- this.contextFiles = [];
51
- this.onDidContextFilesChangeEmitter.fire(this.getAllContextFiles());
73
+ this.attachedFiles.length = 0;
74
+ this.notifyContextChange();
52
75
  }
53
76
 
54
77
  private getAllContextFiles() {
55
- return [...this.contextFiles];
78
+ return {
79
+ viewed: this.recentlyViewFiles,
80
+ attached: this.attachedFiles,
81
+ version: this.contextVersion++,
82
+ };
56
83
  }
57
84
 
58
- removeFileFromContext(uri: URI): void {
59
- const index = this.contextFiles.findIndex((file) => file.uri.toString() === uri.toString());
85
+ removeFileFromContext(uri: URI, isManual = false): void {
86
+ const targetList = isManual ? this.attachedFiles : this.recentlyViewFiles;
87
+ const index = targetList.findIndex((file) => file.uri.toString() === uri.toString());
60
88
  if (index > -1) {
61
- this.contextFiles.splice(index, 1);
62
- this.onDidContextFilesChangeEmitter.fire(this.getAllContextFiles());
89
+ targetList.splice(index, 1);
63
90
  }
91
+ this.notifyContextChange();
64
92
  }
65
93
 
66
94
  startAutoCollection(): void {
@@ -78,8 +106,7 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
78
106
  if (event.payload.uri.scheme !== 'file') {
79
107
  return;
80
108
  }
81
- // FIXME: 暂时不自动添加
82
- // this.addFileToContext(event.payload.uri);
109
+ this.addFileToContext(event.payload.uri, undefined, false);
83
110
  }),
84
111
  );
85
112
 
@@ -88,6 +115,8 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
88
115
  if (event.payload.scheme !== 'file') {
89
116
  return;
90
117
  }
118
+
119
+ this.removeFileFromContext(event.payload, false);
91
120
  }),
92
121
  );
93
122
 
@@ -109,11 +138,12 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
109
138
  ].sort() as [number, number];
110
139
 
111
140
  if (selection[0] === selection[1]) {
112
- this.addFileToContext(event.payload.editorUri, undefined);
141
+ this.addFileToContext(event.payload.editorUri, undefined, false);
113
142
  } else {
114
143
  this.addFileToContext(
115
144
  event.payload.editorUri,
116
145
  selection.sort((a, b) => a - b),
146
+ false,
117
147
  );
118
148
  }
119
149
  }
@@ -127,42 +157,51 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
127
157
 
128
158
  serialize(): SerializedContext {
129
159
  const files = this.getAllContextFiles();
130
- const recentlyViewFiles = files
131
- .filter((v) => !v.selection)
132
- .map((file) => {
133
- const relativePath = URI.file(this.appConfig.workspaceDir).relative(file.uri);
134
- if (relativePath) {
135
- return relativePath.toString();
136
- }
137
- return file.uri.parent.toString();
138
- })
139
- .filter(Boolean);
140
-
141
- const attachedFiles = files
142
- .filter((v) => v.selection)
143
- .map((file) => {
144
- const ref = this.docModelManager.getModelReference(file.uri);
145
- const content = ref!.instance.getText();
146
- const lineErrors = this.markerService
147
- .getManager()
148
- .getMarkers({
149
- resource: file.uri.toString(),
150
- severities: MarkerSeverity.Error,
151
- })
152
- .map((marker) => marker.message);
153
-
154
- return {
155
- content,
156
- lineErrors,
157
- path: URI.file(this.appConfig.workspaceDir).relative(file.uri)!.toString(),
158
- language: ref?.instance.languageId!,
159
- };
160
- })
161
- .filter(Boolean);
160
+ const workspaceRoot = URI.file(this.appConfig.workspaceDir);
162
161
 
163
162
  return {
164
- recentlyViewFiles,
165
- attachedFiles,
163
+ recentlyViewFiles: this.serializeRecentlyViewFiles(files.viewed, workspaceRoot),
164
+ attachedFiles: this.serializeAttachedFiles(files.attached, workspaceRoot),
166
165
  };
167
166
  }
167
+
168
+ private serializeRecentlyViewFiles(files: FileContext[], workspaceRoot: URI): string[] {
169
+ return files
170
+ .map((file) => workspaceRoot.relative(file.uri)?.toString() || file.uri.parent.toString())
171
+ .filter(Boolean);
172
+ }
173
+
174
+ private serializeAttachedFiles(files: FileContext[], workspaceRoot: URI): AttachFileContext[] {
175
+ return files
176
+ .map((file) => this.serializeAttachedFile(file, workspaceRoot))
177
+ .filter(Boolean) as unknown as AttachFileContext[];
178
+ }
179
+
180
+ private serializeAttachedFile(file: FileContext, workspaceRoot: URI) {
181
+ try {
182
+ const ref = this.docModelManager.getModelReference(file.uri);
183
+ if (!ref) {
184
+ return null;
185
+ }
186
+
187
+ return {
188
+ content: ref.instance.getText(),
189
+ lineErrors: this.getFileErrors(file.uri),
190
+ path: workspaceRoot.relative(file.uri)!.toString(),
191
+ language: ref.instance.languageId!,
192
+ };
193
+ } catch (e) {
194
+ return null;
195
+ }
196
+ }
197
+
198
+ private getFileErrors(uri: URI): string[] {
199
+ return this.markerService
200
+ .getManager()
201
+ .getMarkers({
202
+ resource: uri.toString(),
203
+ severities: MarkerSeverity.Error,
204
+ })
205
+ .map((marker) => marker.message);
206
+ }
168
207
  }
@@ -14,16 +14,16 @@
14
14
  padding: 8px 12px;
15
15
  min-width: initial;
16
16
  margin: 0;
17
-
18
- ::after {
19
- content: '';
20
- }
21
17
  }
22
18
 
23
19
  .rce-mbox-text {
24
20
  line-height: 18px;
25
21
  width: inherit;
26
22
  font-size: 12px;
23
+
24
+ &::after {
25
+ display: none;
26
+ }
27
27
  }
28
28
 
29
29
  .rce-smsg {
@@ -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. ' +
@@ -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. ' +
@@ -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
@@ -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,
@@ -148,7 +148,6 @@ export const aiNativePreferenceSchema: PreferenceSchema = {
148
148
  },
149
149
  [AINativeSettingSectionsId.SystemPrompt]: {
150
150
  type: 'string',
151
- default: '',
152
151
  description: localize('preference.ai.native.chat.system.prompt.description'),
153
152
  },
154
153
  },
@@ -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
  }