@opensumi/ide-ai-native 3.8.1-next-1740571693.0 → 3.8.1-next-1740725107.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 (127) hide show
  1. package/lib/browser/ai-core.contribution.d.ts +4 -1
  2. package/lib/browser/ai-core.contribution.d.ts.map +1 -1
  3. package/lib/browser/ai-core.contribution.js +20 -1
  4. package/lib/browser/ai-core.contribution.js.map +1 -1
  5. package/lib/browser/chat/chat-manager.service.d.ts +6 -0
  6. package/lib/browser/chat/chat-manager.service.d.ts.map +1 -1
  7. package/lib/browser/chat/chat-manager.service.js +31 -1
  8. package/lib/browser/chat/chat-manager.service.js.map +1 -1
  9. package/lib/browser/chat/chat-model.d.ts +2 -0
  10. package/lib/browser/chat/chat-model.d.ts.map +1 -1
  11. package/lib/browser/chat/chat-model.js +8 -2
  12. package/lib/browser/chat/chat-model.js.map +1 -1
  13. package/lib/browser/chat/chat.internal.service.d.ts +1 -0
  14. package/lib/browser/chat/chat.internal.service.d.ts.map +1 -1
  15. package/lib/browser/chat/chat.internal.service.js +3 -0
  16. package/lib/browser/chat/chat.internal.service.js.map +1 -1
  17. package/lib/browser/chat/chat.module.less +1 -2
  18. package/lib/browser/chat/chat.view.d.ts.map +1 -1
  19. package/lib/browser/chat/chat.view.js +6 -38
  20. package/lib/browser/chat/chat.view.js.map +1 -1
  21. package/lib/browser/components/ChatContext/index.js +2 -2
  22. package/lib/browser/components/ChatContext/index.js.map +1 -1
  23. package/lib/browser/components/ChatHistory.d.ts +0 -1
  24. package/lib/browser/components/ChatHistory.d.ts.map +1 -1
  25. package/lib/browser/components/ChatHistory.js +14 -14
  26. package/lib/browser/components/ChatHistory.js.map +1 -1
  27. package/lib/browser/components/ChatInput.d.ts.map +1 -1
  28. package/lib/browser/components/ChatInput.js +25 -1
  29. package/lib/browser/components/ChatInput.js.map +1 -1
  30. package/lib/browser/components/ChatToolRender.d.ts.map +1 -1
  31. package/lib/browser/components/ChatToolRender.js +2 -3
  32. package/lib/browser/components/ChatToolRender.js.map +1 -1
  33. package/lib/browser/components/{chat-history.css → chat-history.module.less} +1 -1
  34. package/lib/browser/components/components.module.less +20 -0
  35. package/lib/browser/context/llm-context.service.d.ts +16 -5
  36. package/lib/browser/context/llm-context.service.d.ts.map +1 -1
  37. package/lib/browser/context/llm-context.service.js +78 -47
  38. package/lib/browser/context/llm-context.service.js.map +1 -1
  39. package/lib/browser/layout/layout.module.less +4 -4
  40. package/lib/browser/mcp/base-apply.service.d.ts +31 -40
  41. package/lib/browser/mcp/base-apply.service.d.ts.map +1 -1
  42. package/lib/browser/mcp/base-apply.service.js +233 -167
  43. package/lib/browser/mcp/base-apply.service.js.map +1 -1
  44. package/lib/browser/mcp/tools/components/EditFile.d.ts.map +1 -1
  45. package/lib/browser/mcp/tools/components/EditFile.js +55 -41
  46. package/lib/browser/mcp/tools/components/EditFile.js.map +1 -1
  47. package/lib/browser/mcp/tools/components/index.module.less +23 -3
  48. package/lib/browser/mcp/tools/createNewFileWithText.d.ts.map +1 -1
  49. package/lib/browser/mcp/tools/createNewFileWithText.js +1 -0
  50. package/lib/browser/mcp/tools/createNewFileWithText.js.map +1 -1
  51. package/lib/browser/mcp/tools/editFile.js +1 -1
  52. package/lib/browser/mcp/tools/editFile.js.map +1 -1
  53. package/lib/browser/mcp/tools/getDiagnosticsByPath.d.ts.map +1 -1
  54. package/lib/browser/mcp/tools/getDiagnosticsByPath.js +1 -0
  55. package/lib/browser/mcp/tools/getDiagnosticsByPath.js.map +1 -1
  56. package/lib/browser/mcp/tools/handlers/EditFile.d.ts +5 -1
  57. package/lib/browser/mcp/tools/handlers/EditFile.d.ts.map +1 -1
  58. package/lib/browser/mcp/tools/handlers/EditFile.js +4 -4
  59. package/lib/browser/mcp/tools/handlers/EditFile.js.map +1 -1
  60. package/lib/browser/mcp/tools/handlers/RunCommand.d.ts.map +1 -1
  61. package/lib/browser/mcp/tools/handlers/RunCommand.js +2 -0
  62. package/lib/browser/mcp/tools/handlers/RunCommand.js.map +1 -1
  63. package/lib/browser/mcp/tools/runTerminalCmd.d.ts.map +1 -1
  64. package/lib/browser/mcp/tools/runTerminalCmd.js +1 -0
  65. package/lib/browser/mcp/tools/runTerminalCmd.js.map +1 -1
  66. package/lib/browser/model/msg-history-manager.d.ts +1 -0
  67. package/lib/browser/model/msg-history-manager.d.ts.map +1 -1
  68. package/lib/browser/model/msg-history-manager.js +12 -2
  69. package/lib/browser/model/msg-history-manager.js.map +1 -1
  70. package/lib/browser/types.d.ts +1 -1
  71. package/lib/browser/types.d.ts.map +1 -1
  72. package/lib/browser/widget/inline-diff/inline-diff-manager.d.ts +6 -0
  73. package/lib/browser/widget/inline-diff/inline-diff-manager.d.ts.map +1 -0
  74. package/lib/browser/widget/inline-diff/inline-diff-manager.js +27 -0
  75. package/lib/browser/widget/inline-diff/inline-diff-manager.js.map +1 -0
  76. package/lib/browser/widget/inline-diff/inline-diff-widget.module.less +12 -0
  77. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts +2 -0
  78. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts.map +1 -1
  79. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js +11 -4
  80. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js.map +1 -1
  81. package/lib/common/llm-context.d.ts +12 -9
  82. package/lib/common/llm-context.d.ts.map +1 -1
  83. package/lib/common/llm-context.js.map +1 -1
  84. package/lib/common/prompts/context-prompt-provider.d.ts +4 -3
  85. package/lib/common/prompts/context-prompt-provider.d.ts.map +1 -1
  86. package/lib/common/prompts/context-prompt-provider.js +34 -22
  87. package/lib/common/prompts/context-prompt-provider.js.map +1 -1
  88. package/lib/common/types.d.ts +17 -0
  89. package/lib/common/types.d.ts.map +1 -1
  90. package/lib/common/types.js.map +1 -1
  91. package/lib/node/base-language-model.d.ts +1 -1
  92. package/lib/node/base-language-model.d.ts.map +1 -1
  93. package/lib/node/base-language-model.js +54 -3
  94. package/lib/node/base-language-model.js.map +1 -1
  95. package/package.json +23 -23
  96. package/src/browser/ai-core.contribution.ts +25 -1
  97. package/src/browser/chat/chat-manager.service.ts +29 -1
  98. package/src/browser/chat/chat-model.ts +18 -3
  99. package/src/browser/chat/chat.internal.service.ts +4 -0
  100. package/src/browser/chat/chat.module.less +1 -2
  101. package/src/browser/chat/chat.view.tsx +7 -70
  102. package/src/browser/components/ChatContext/index.tsx +2 -2
  103. package/src/browser/components/ChatHistory.tsx +21 -15
  104. package/src/browser/components/ChatInput.tsx +67 -4
  105. package/src/browser/components/ChatToolRender.tsx +1 -2
  106. package/src/browser/components/{chat-history.css → chat-history.module.less} +1 -1
  107. package/src/browser/components/components.module.less +20 -0
  108. package/src/browser/context/llm-context.service.ts +90 -54
  109. package/src/browser/layout/layout.module.less +4 -4
  110. package/src/browser/mcp/base-apply.service.ts +266 -213
  111. package/src/browser/mcp/tools/components/EditFile.tsx +82 -60
  112. package/src/browser/mcp/tools/components/index.module.less +23 -3
  113. package/src/browser/mcp/tools/createNewFileWithText.ts +1 -0
  114. package/src/browser/mcp/tools/editFile.ts +2 -2
  115. package/src/browser/mcp/tools/getDiagnosticsByPath.ts +1 -0
  116. package/src/browser/mcp/tools/handlers/EditFile.ts +4 -4
  117. package/src/browser/mcp/tools/handlers/RunCommand.ts +2 -0
  118. package/src/browser/mcp/tools/runTerminalCmd.ts +1 -0
  119. package/src/browser/model/msg-history-manager.ts +12 -2
  120. package/src/browser/types.ts +1 -1
  121. package/src/browser/widget/inline-diff/inline-diff-manager.tsx +38 -0
  122. package/src/browser/widget/inline-diff/inline-diff-widget.module.less +12 -0
  123. package/src/browser/widget/inline-stream-diff/inline-stream-diff.handler.tsx +13 -4
  124. package/src/common/llm-context.ts +10 -4
  125. package/src/common/prompts/context-prompt-provider.ts +39 -29
  126. package/src/common/types.ts +20 -0
  127. package/src/node/base-language-model.ts +63 -1
@@ -1,5 +1,5 @@
1
1
  import cls from 'classnames';
2
- import React, { useEffect, useMemo } from 'react';
2
+ import React, { useEffect, useMemo, useState } from 'react';
3
3
 
4
4
  import { Icon, Popover } from '@opensumi/ide-components';
5
5
  import {
@@ -10,7 +10,6 @@ import {
10
10
  Uri,
11
11
  detectModeId,
12
12
  path,
13
- useAutorun,
14
13
  useInjectable,
15
14
  } from '@opensumi/ide-core-browser';
16
15
  import { Loading } from '@opensumi/ide-core-browser/lib/components/ai-native';
@@ -18,61 +17,24 @@ import { ILanguageService } from '@opensumi/monaco-editor-core/esm/vs/editor/com
18
17
  import { IModelService } from '@opensumi/monaco-editor-core/esm/vs/editor/common/services/model';
19
18
  import { StandaloneServices } from '@opensumi/monaco-editor-core/esm/vs/editor/standalone/browser/standaloneServices';
20
19
 
20
+ import { CodeBlockData } from '../../../../common/types';
21
21
  import { ChatMarkdown } from '../../../components/ChatMarkdown';
22
22
  import { IMCPServerToolComponentProps } from '../../../types';
23
- import { BaseApplyService, CodeBlockData } from '../../base-apply.service';
23
+ import { BaseApplyService } from '../../base-apply.service';
24
24
 
25
25
  import styles from './index.module.less';
26
26
 
27
- const renderStatus = (codeBlockData: CodeBlockData) => {
28
- const status = codeBlockData.status;
29
- switch (status) {
30
- case 'generating':
31
- return <Loading />;
32
- case 'pending':
33
- return (
34
- <Popover title={status} id={'edit-file-tool-status-pending'}>
35
- <Icon iconClass='codicon codicon-circle-large' />
36
- </Popover>
37
- );
38
- case 'success':
39
- return (
40
- <Popover title={status} id={'edit-file-tool-status-success'}>
41
- <Icon iconClass='codicon codicon-check-all' />
42
- </Popover>
43
- );
44
- case 'failed':
45
- return (
46
- <Popover title={status} id={'edit-file-tool-status-failed'}>
47
- <Icon iconClass='codicon codicon-error' color='var(--vscode-input-errorForeground)' />
48
- </Popover>
49
- );
50
- case 'cancelled':
51
- return (
52
- <Popover title={status} id={'edit-file-tool-status-cancelled'}>
53
- <Icon iconClass='codicon codicon-close' color='var(--vscode-input-placeholderForeground)' />
54
- </Popover>
55
- );
56
- default:
57
- return null;
58
- }
59
- };
60
-
61
27
  export const EditFileToolComponent = (props: IMCPServerToolComponentProps) => {
62
28
  const { args, messageId, toolCallId } = props;
29
+ const [mode, setMode] = useState<'code' | 'diff'>('code');
63
30
  const labelService = useInjectable(LabelService);
64
31
  const appConfig = useInjectable<AppConfig>(AppConfig);
65
32
  const applyService = useInjectable<BaseApplyService>(BaseApplyService);
66
33
  const { target_file = '', code_edit, instructions } = args || {};
67
34
  const absolutePath = path.join(appConfig.workspaceDir, target_file);
68
-
69
- const codeBlockData = applyService.getCodeBlock(absolutePath, messageId);
70
-
71
- useAutorun(applyService.codeBlockMapObservable);
72
-
73
- if (toolCallId && codeBlockData) {
74
- applyService.initToolCallId(codeBlockData.id, toolCallId);
75
- }
35
+ const [codeBlockData, setCodeBlockData] = useState<CodeBlockData | undefined>(
36
+ applyService.getCodeBlock(toolCallId, messageId),
37
+ );
76
38
 
77
39
  const icon = useMemo(() => {
78
40
  if (!target_file) {
@@ -91,40 +53,66 @@ export const EditFileToolComponent = (props: IMCPServerToolComponentProps) => {
91
53
  return detectedModeId;
92
54
  }, [target_file, absolutePath]);
93
55
 
56
+ useEffect(() => {
57
+ const disposable = applyService.onCodeBlockUpdate((codeBlockData) => {
58
+ setCodeBlockData({ ...codeBlockData });
59
+ });
60
+ return () => {
61
+ disposable.dispose();
62
+ };
63
+ }, []);
64
+
94
65
  // 多次迭代时,仅在首处tool组件中展示
95
- if (!args || !codeBlockData || (toolCallId && toolCallId !== codeBlockData.initToolCallId)) {
66
+ // FIXME: 这个优化有必要吗?每次都展示也挺好?
67
+ if (!args || !codeBlockData) {
96
68
  return null;
97
69
  }
98
70
 
99
71
  return [
100
72
  instructions && <p>{instructions}</p>,
101
- <div className={styles['edit-file-tool']} key={`edit-file-tool-${codeBlockData.id}`}>
73
+ <div className={styles['edit-file-tool']} key={'edit-file-tool'}>
102
74
  <div
103
75
  className={cls(styles['edit-file-tool-header'], {
104
76
  clickable: codeBlockData.status === 'pending' || codeBlockData.status === 'success',
105
77
  })}
106
78
  onClick={() => {
107
79
  if (codeBlockData.status === 'pending') {
108
- applyService.reRenderPendingApply();
80
+ applyService.renderApplyResult(codeBlockData, codeBlockData.updatedCode!);
109
81
  } else if (codeBlockData.status === 'success') {
110
- applyService.revealApplyPosition(codeBlockData.id);
82
+ applyService.revealApplyPosition(codeBlockData);
111
83
  }
112
84
  }}
113
85
  >
114
- {icon && <span className={icon}></span>}
115
- <span className={styles['edit-file-tool-file-name']}>{target_file}</span>
116
- {codeBlockData.iterationCount > 1 && (
117
- <span className={styles['edit-file-tool-iteration-count']}>{codeBlockData.iterationCount}/3</span>
118
- )}
119
- {renderStatus(codeBlockData)}
86
+ <div className={styles.left}>
87
+ {icon && <span className={icon}></span>}
88
+ <span className={styles['edit-file-tool-file-name']}>{target_file}</span>
89
+ {codeBlockData.iterationCount > 1 && (
90
+ <span className={styles['edit-file-tool-iteration-count']}>{codeBlockData.iterationCount}/3</span>
91
+ )}
92
+ {renderStatus(codeBlockData)}
93
+ </div>
94
+ <div className={styles.right}>
95
+ <Popover title={'Show Code'} id={'edit-file-tool-show-code'}>
96
+ <Icon iconClass='codicon codicon-file-code' onClick={() => setMode('code')} />
97
+ </Popover>
98
+ {codeBlockData.applyResult?.diff && (
99
+ <Popover title={'Show Diff'} id={'edit-file-tool-show-diff'}>
100
+ <Icon iconClass='codicon codicon-diff-multiple' onClick={() => setMode('diff')} />
101
+ </Popover>
102
+ )}
103
+ </div>
120
104
  </div>
121
- <ChatMarkdown markdown={`\`\`\`${languageId || ''}\n${code_edit}\n\`\`\``} hideInsert={true} />
105
+ <ChatMarkdown
106
+ markdown={
107
+ mode === 'code'
108
+ ? `\`\`\`${languageId || ''}\n${code_edit}\n\`\`\``
109
+ : `\`\`\`diff\n${codeBlockData.applyResult?.diff}\n\`\`\``
110
+ }
111
+ hideInsert={true}
112
+ />
122
113
  </div>,
123
114
  codeBlockData.applyResult && codeBlockData.applyResult.diagnosticInfos.length > 0 && (
124
- <div
125
- className={styles['edit-file-tool-diagnostic-errors']}
126
- key={`edit-file-tool-diagnostic-errors-${codeBlockData.id}`}
127
- >
115
+ <div className={styles['edit-file-tool-diagnostic-errors']} key={'edit-file-tool-diagnostic-errors'}>
128
116
  <div className={styles['title']}>Found Lints:</div>
129
117
  {codeBlockData.applyResult?.diagnosticInfos.map((info) => (
130
118
  <div
@@ -142,3 +130,37 @@ export const EditFileToolComponent = (props: IMCPServerToolComponentProps) => {
142
130
  ),
143
131
  ];
144
132
  };
133
+
134
+ const renderStatus = (codeBlockData: CodeBlockData) => {
135
+ const status = codeBlockData.status;
136
+ switch (status) {
137
+ case 'generating':
138
+ return <Loading />;
139
+ case 'pending':
140
+ return (
141
+ <Popover title='Pending' id={'edit-file-tool-status-pending'}>
142
+ <Icon iconClass='codicon codicon-circle-large' />
143
+ </Popover>
144
+ );
145
+ case 'success':
146
+ return (
147
+ <Popover title='Success' id={'edit-file-tool-status-success'}>
148
+ <Icon iconClass='codicon codicon-check-all' />
149
+ </Popover>
150
+ );
151
+ case 'failed':
152
+ return (
153
+ <Popover title='Failed' id={'edit-file-tool-status-failed'}>
154
+ <Icon iconClass='codicon codicon-error' style={{ color: 'var(--debugConsole-errorForeground)' }} />
155
+ </Popover>
156
+ );
157
+ case 'cancelled':
158
+ return (
159
+ <Popover title='Cancelled' id={'edit-file-tool-status-cancelled'}>
160
+ <Icon iconClass='codicon codicon-close' style={{ color: 'var(--input-placeholderForeground)' }} />
161
+ </Popover>
162
+ );
163
+ default:
164
+ return null;
165
+ }
166
+ };
@@ -1,15 +1,14 @@
1
1
  .edit-file-tool-header {
2
2
  display: flex;
3
3
  align-items: center;
4
+ justify-content: space-between;
4
5
  padding: 2px 8px;
5
6
  border-bottom: 1px solid var(--vscode-commandCenter-inactiveBorder);
6
7
  background-color: var(--design-block-background);
7
8
  font-size: 10px;
8
9
  margin-bottom: -4px;
9
10
  border-radius: 8px 8px 0 0;
10
- > span {
11
- margin-right: 4px;
12
- }
11
+ white-space: nowrap;
13
12
  :global(span.codicon) {
14
13
  font-size: 12px;
15
14
  }
@@ -18,6 +17,26 @@
18
17
  align-items: center;
19
18
  justify-content: center;
20
19
  }
20
+ .left,
21
+ .right {
22
+ display: flex;
23
+ align-items: center;
24
+ }
25
+ &::after {
26
+ display: none;
27
+ }
28
+ .left {
29
+ > span {
30
+ margin-right: 4px;
31
+ }
32
+ }
33
+ .right > div {
34
+ margin-left: 4px;
35
+ }
36
+ }
37
+ .edit-file-tool-file-name {
38
+ text-overflow: ellipsis;
39
+ overflow: hidden;
21
40
  }
22
41
  .edit-file-tool {
23
42
  border: 1px solid var(--vscode-commandCenter-inactiveBorder);
@@ -135,6 +154,7 @@
135
154
  background-color: var(--design-chatInput-background);
136
155
  padding: 10px;
137
156
  border-radius: 4px;
157
+ margin: 10px 0px;
138
158
 
139
159
  .command_title {
140
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. ' +
@@ -69,8 +69,8 @@ You should specify the following arguments before the others: [target_file]`,
69
69
  };
70
70
  }
71
71
 
72
- private async handler(args: z.infer<typeof inputSchema>, logger: MCPLogger) {
73
- const result = await this.editFileHandler.handler(args.targetFile, args.codeEdit, args.instructions);
72
+ private async handler(args: z.infer<typeof inputSchema> & { toolCallId: string }, logger: MCPLogger) {
73
+ const result = await this.editFileHandler.handler(args, args.toolCallId);
74
74
  return {
75
75
  content: [
76
76
  {
@@ -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. ' +
@@ -12,10 +12,10 @@ export class EditFileHandler {
12
12
  @Autowired(BaseApplyService)
13
13
  private applyService: BaseApplyService;
14
14
 
15
- async handler(relativePath: string, updateContent: string, instructions?: string) {
16
- // TODO: ignore file
17
- this.applyService.registerCodeBlock(relativePath, updateContent);
18
- const blockData = await this.applyService.apply(relativePath, updateContent, instructions);
15
+ async handler(params: { targetFile: string; codeEdit: string; instructions?: string }, toolCallId: string) {
16
+ const { targetFile, codeEdit } = params;
17
+ const block = this.applyService.registerCodeBlock(targetFile, codeEdit, toolCallId);
18
+ const blockData = await this.applyService.apply(block);
19
19
  return blockData;
20
20
  }
21
21
  }
@@ -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,
@@ -66,6 +66,11 @@ export class MsgHistoryManager extends Disposable {
66
66
  return this.startIndex;
67
67
  }
68
68
 
69
+ public get lastMessageId(): string | undefined {
70
+ const list = this.messageList;
71
+ return list[list.length - 1]?.id;
72
+ }
73
+
69
74
  public getMessages(maxTokens?: number): IHistoryChatMessage[] {
70
75
  if (maxTokens && this.totalTokens > maxTokens) {
71
76
  while (this.totalTokens > maxTokens) {
@@ -109,9 +114,14 @@ export class MsgHistoryManager extends Disposable {
109
114
  return;
110
115
  }
111
116
 
112
- this.messageAdditionalMap.set(id, additional);
117
+ const oldAdditional = this.messageAdditionalMap.get(id) || {};
118
+ const newAdditional = {
119
+ ...oldAdditional,
120
+ ...additional,
121
+ };
113
122
 
114
- this._onMessageAdditionalChange.fire(additional);
123
+ this.messageAdditionalMap.set(id, newAdditional);
124
+ this._onMessageAdditionalChange.fire(newAdditional);
115
125
  }
116
126
 
117
127
  public getMessageAdditional(id: string): Record<string, any> {
@@ -368,7 +368,7 @@ export interface IMCPServerToolComponentProps {
368
368
  result?: any;
369
369
  index?: number;
370
370
  messageId?: string;
371
- toolCallId?: string;
371
+ toolCallId: string;
372
372
  }
373
373
 
374
374
  export interface IMCPServerRegistry {
@@ -0,0 +1,38 @@
1
+ import React, { useEffect, useState } from 'react';
2
+
3
+ import { Button } from '@opensumi/ide-components';
4
+ import { localize, useInjectable } from '@opensumi/ide-core-browser';
5
+ import { IResource } from '@opensumi/ide-editor';
6
+
7
+ import { BaseApplyService } from '../../mcp/base-apply.service';
8
+
9
+ import styles from './inline-diff-widget.module.less';
10
+
11
+ export const InlineDiffManager: React.FC<{ resource: IResource }> = (props) => {
12
+ const applyService = useInjectable<BaseApplyService>(BaseApplyService);
13
+ const [show, setShow] = useState(true);
14
+ useEffect(() => {
15
+ applyService.onCodeBlockUpdate((codeBlock) => {
16
+ setShow(codeBlock.status === 'pending');
17
+ });
18
+ }, []);
19
+ return (
20
+ <div className={styles.inlineDiffManager} style={{ display: show ? 'flex' : 'none' }}>
21
+ <Button
22
+ onClick={() => {
23
+ applyService.processAll(props.resource.uri, 'accept');
24
+ }}
25
+ >
26
+ {localize('aiNative.inlineDiff.acceptAll')}
27
+ </Button>
28
+ <Button
29
+ type='ghost'
30
+ onClick={() => {
31
+ applyService.processAll(props.resource.uri, 'reject');
32
+ }}
33
+ >
34
+ {localize('aiNative.inlineDiff.rejectAll')}
35
+ </Button>
36
+ </div>
37
+ );
38
+ };
@@ -19,3 +19,15 @@
19
19
  display: flex;
20
20
  position: relative;
21
21
  }
22
+
23
+ .inlineDiffManager {
24
+ display: flex;
25
+ padding: 12px 16px;
26
+ justify-content: center;
27
+ position: absolute;
28
+ bottom: 0;
29
+ left: 50%;
30
+ transform: translateX(-50%);
31
+ gap: 12px;
32
+ z-index: 999;
33
+ }
@@ -52,6 +52,9 @@ export class InlineStreamDiffHandler extends Disposable implements IInlineDiffPr
52
52
  protected readonly _onDidEditChange = this.registerDispose(new Emitter<void>());
53
53
  public readonly onDidEditChange: Event<void> = this._onDidEditChange.event;
54
54
 
55
+ protected readonly onDiffFinishedEmitter = this.registerDispose(new Emitter<IComputeDiffData>());
56
+ public readonly onDiffFinished: Event<IComputeDiffData> = this.onDiffFinishedEmitter.event;
57
+
55
58
  public previewerOptions: IDiffPreviewerOptions;
56
59
 
57
60
  private originalModel: ITextModel;
@@ -445,6 +448,8 @@ export class InlineStreamDiffHandler extends Disposable implements IInlineDiffPr
445
448
  this.diffModel.set(currentDiffModel, tx);
446
449
  });
447
450
 
451
+ this.onDiffFinishedEmitter.fire(currentDiffModel);
452
+
448
453
  if (this.originalModel.id === this.monacoEditor.getModel()?.id) {
449
454
  this.renderDiffEdits(currentDiffModel);
450
455
  }
@@ -471,10 +476,13 @@ export class InlineStreamDiffHandler extends Disposable implements IInlineDiffPr
471
476
  }
472
477
 
473
478
  public pushRateFinallyDiffStack(diffModel: IComputeDiffData): void {
474
- // 可能存在 rate editor controller 处理完之后接口层流式才结束
475
- if (this.isEditing === false) {
476
- this.finallyRender(diffModel);
477
- }
479
+ transaction((tx) => {
480
+ this.finallyDiffModel.set(diffModel, tx);
481
+ // 可能存在 rate editor controller 处理完之后接口层流式才结束
482
+ if (this.isEditing === false) {
483
+ this.finallyRender(diffModel);
484
+ }
485
+ });
478
486
  }
479
487
 
480
488
  public finallyRender(diffModel: IComputeDiffData): void {
@@ -487,6 +495,7 @@ export class InlineStreamDiffHandler extends Disposable implements IInlineDiffPr
487
495
  return;
488
496
  }
489
497
 
498
+ this.onDiffFinishedEmitter.fire(diffModel);
490
499
  this.renderPartialEditWidgets(diffModel);
491
500
  this.renderDiffEdits(diffModel);
492
501
  this.pushStackElement();
@@ -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[] }>;
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/browser/types';
3
3
 
4
4
  import { SerializedContext } from '../llm-context';
5
5
 
@@ -10,37 +10,47 @@ 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;
24
+ currentModel
19
25
  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>`;
26
+ <additional_data>
27
+ Below are some potentially helpful/relevant pieces of information for figuring out to respond
28
+ <recently_viewed_files>
29
+ ${context.recentlyViewFiles.map((file, idx) => ` ${idx + 1}: ${file}`).join('\n')}
30
+ </recently_viewed_files>
31
+ <attached_files>
32
+ ${context.attachedFiles.map(
33
+ (file) =>
34
+ `
35
+ <file_contents>
36
+ \`\`\`${file.language} ${file.path}
37
+ ${file.content}
38
+ \`\`\`
39
+ </file_contents>
40
+ <linter_errors>
41
+ ${file.lineErrors.join('\n')}
42
+ </linter_errors>
43
+ `,
44
+ )}
45
+ </attached_files>
46
+ ${currentModel ? `<current_opened_file>
47
+ \`\`\`${currentModel.languageId} ${currentModel.uri.toString()}
48
+ ${currentModel.getText()}
49
+ \`\`\`
50
+ </current_opened_file>` : ''}
51
+ </additional_data>
52
+ <user_query>
53
+ ${userMessage}
54
+ </user_query>`;
45
55
  }
46
56
  }
@@ -1,3 +1,5 @@
1
+ import { IMarker } from '@opensumi/ide-core-browser';
2
+
1
3
  export enum NearestCodeBlockType {
2
4
  Block = 'block',
3
5
  Line = 'line',
@@ -46,3 +48,21 @@ export interface MCPTool {
46
48
  inputSchema: any;
47
49
  providerName: string;
48
50
  }
51
+
52
+ export interface CodeBlockData {
53
+ toolCallId: string;
54
+ codeEdit: string;
55
+ updatedCode?: string;
56
+ relativePath: string;
57
+ status: CodeBlockStatus;
58
+ iterationCount: number;
59
+ createdAt: number;
60
+ version: number;
61
+ instructions?: string;
62
+ applyResult?: {
63
+ diff: string;
64
+ diagnosticInfos: IMarker[];
65
+ };
66
+ }
67
+
68
+ export type CodeBlockStatus = 'generating' | 'pending' | 'success' | 'rejected' | 'failed' | 'cancelled';