@opensumi/ide-ai-native 3.8.1-next-1740475512.0 → 3.8.1-next-1740556231.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 (206) 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 +23 -11
  4. package/lib/browser/ai-core.contribution.js.map +1 -1
  5. package/lib/browser/chat/chat-manager.service.d.ts +1 -5
  6. package/lib/browser/chat/chat-manager.service.d.ts.map +1 -1
  7. package/lib/browser/chat/chat-manager.service.js +13 -17
  8. package/lib/browser/chat/chat-manager.service.js.map +1 -1
  9. package/lib/browser/chat/chat-model.d.ts +0 -2
  10. package/lib/browser/chat/chat-model.d.ts.map +1 -1
  11. package/lib/browser/chat/chat-model.js +2 -8
  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 +2 -1
  18. package/lib/browser/chat/chat.view.d.ts.map +1 -1
  19. package/lib/browser/chat/chat.view.js +9 -6
  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 +1 -25
  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 +3 -2
  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 +0 -20
  35. package/lib/browser/context/llm-context.service.d.ts +5 -16
  36. package/lib/browser/context/llm-context.service.d.ts.map +1 -1
  37. package/lib/browser/context/llm-context.service.js +47 -78
  38. package/lib/browser/context/llm-context.service.js.map +1 -1
  39. package/lib/browser/index.d.ts.map +1 -1
  40. package/lib/browser/index.js +0 -4
  41. package/lib/browser/index.js.map +1 -1
  42. package/lib/browser/layout/layout.module.less +4 -4
  43. package/lib/browser/mcp/base-apply.service.d.ts +31 -40
  44. package/lib/browser/mcp/base-apply.service.d.ts.map +1 -1
  45. package/lib/browser/mcp/base-apply.service.js +233 -167
  46. package/lib/browser/mcp/base-apply.service.js.map +1 -1
  47. package/lib/browser/mcp/mcp-server-proxy.service.d.ts +0 -6
  48. package/lib/browser/mcp/mcp-server-proxy.service.d.ts.map +1 -1
  49. package/lib/browser/mcp/mcp-server-proxy.service.js +1 -10
  50. package/lib/browser/mcp/mcp-server-proxy.service.js.map +1 -1
  51. package/lib/browser/mcp/mcp-server.feature.registry.d.ts.map +1 -1
  52. package/lib/browser/mcp/mcp-server.feature.registry.js +2 -3
  53. package/lib/browser/mcp/mcp-server.feature.registry.js.map +1 -1
  54. package/lib/browser/mcp/tools/components/EditFile.d.ts.map +1 -1
  55. package/lib/browser/mcp/tools/components/EditFile.js +55 -41
  56. package/lib/browser/mcp/tools/components/EditFile.js.map +1 -1
  57. package/lib/browser/mcp/tools/components/index.module.less +22 -4
  58. package/lib/browser/mcp/tools/createNewFileWithText.d.ts.map +1 -1
  59. package/lib/browser/mcp/tools/createNewFileWithText.js +0 -1
  60. package/lib/browser/mcp/tools/createNewFileWithText.js.map +1 -1
  61. package/lib/browser/mcp/tools/editFile.js +1 -1
  62. package/lib/browser/mcp/tools/editFile.js.map +1 -1
  63. package/lib/browser/mcp/tools/getDiagnosticsByPath.d.ts.map +1 -1
  64. package/lib/browser/mcp/tools/getDiagnosticsByPath.js +0 -1
  65. package/lib/browser/mcp/tools/getDiagnosticsByPath.js.map +1 -1
  66. package/lib/browser/mcp/tools/handlers/EditFile.d.ts +5 -1
  67. package/lib/browser/mcp/tools/handlers/EditFile.d.ts.map +1 -1
  68. package/lib/browser/mcp/tools/handlers/EditFile.js +4 -4
  69. package/lib/browser/mcp/tools/handlers/EditFile.js.map +1 -1
  70. package/lib/browser/mcp/tools/handlers/RunCommand.d.ts.map +1 -1
  71. package/lib/browser/mcp/tools/handlers/RunCommand.js +0 -2
  72. package/lib/browser/mcp/tools/handlers/RunCommand.js.map +1 -1
  73. package/lib/browser/mcp/tools/runTerminalCmd.d.ts.map +1 -1
  74. package/lib/browser/mcp/tools/runTerminalCmd.js +0 -1
  75. package/lib/browser/mcp/tools/runTerminalCmd.js.map +1 -1
  76. package/lib/browser/model/msg-history-manager.d.ts +1 -0
  77. package/lib/browser/model/msg-history-manager.d.ts.map +1 -1
  78. package/lib/browser/model/msg-history-manager.js +12 -2
  79. package/lib/browser/model/msg-history-manager.js.map +1 -1
  80. package/lib/browser/preferences/schema.d.ts.map +1 -1
  81. package/lib/browser/preferences/schema.js +0 -16
  82. package/lib/browser/preferences/schema.js.map +1 -1
  83. package/lib/browser/types.d.ts +1 -1
  84. package/lib/browser/types.d.ts.map +1 -1
  85. package/lib/browser/widget/inline-diff/inline-diff-manager.d.ts +6 -0
  86. package/lib/browser/widget/inline-diff/inline-diff-manager.d.ts.map +1 -0
  87. package/lib/browser/widget/inline-diff/inline-diff-manager.js +27 -0
  88. package/lib/browser/widget/inline-diff/inline-diff-manager.js.map +1 -0
  89. package/lib/browser/widget/inline-diff/inline-diff-widget.module.less +12 -0
  90. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts +2 -0
  91. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts.map +1 -1
  92. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js +11 -4
  93. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js.map +1 -1
  94. package/lib/common/index.d.ts +1 -8
  95. package/lib/common/index.d.ts.map +1 -1
  96. package/lib/common/index.js +1 -3
  97. package/lib/common/index.js.map +1 -1
  98. package/lib/common/llm-context.d.ts +9 -12
  99. package/lib/common/llm-context.d.ts.map +1 -1
  100. package/lib/common/llm-context.js.map +1 -1
  101. package/lib/common/mcp-server-manager.d.ts +1 -17
  102. package/lib/common/mcp-server-manager.d.ts.map +1 -1
  103. package/lib/common/mcp-server-manager.js.map +1 -1
  104. package/lib/common/prompts/context-prompt-provider.d.ts +3 -2
  105. package/lib/common/prompts/context-prompt-provider.d.ts.map +1 -1
  106. package/lib/common/prompts/context-prompt-provider.js +22 -21
  107. package/lib/common/prompts/context-prompt-provider.js.map +1 -1
  108. package/lib/common/tool-invocation-registry.d.ts +2 -2
  109. package/lib/common/tool-invocation-registry.d.ts.map +1 -1
  110. package/lib/common/tool-invocation-registry.js +1 -1
  111. package/lib/common/tool-invocation-registry.js.map +1 -1
  112. package/lib/common/types.d.ts +17 -6
  113. package/lib/common/types.d.ts.map +1 -1
  114. package/lib/common/types.js.map +1 -1
  115. package/lib/common/utils.d.ts.map +1 -1
  116. package/lib/common/utils.js +1 -2
  117. package/lib/common/utils.js.map +1 -1
  118. package/lib/node/base-language-model.d.ts +1 -1
  119. package/lib/node/base-language-model.d.ts.map +1 -1
  120. package/lib/node/base-language-model.js +54 -3
  121. package/lib/node/base-language-model.js.map +1 -1
  122. package/lib/node/mcp/sumi-mcp-server.d.ts +3 -17
  123. package/lib/node/mcp/sumi-mcp-server.d.ts.map +1 -1
  124. package/lib/node/mcp/sumi-mcp-server.js +6 -59
  125. package/lib/node/mcp/sumi-mcp-server.js.map +1 -1
  126. package/lib/node/mcp-server-manager-impl.d.ts +3 -4
  127. package/lib/node/mcp-server-manager-impl.d.ts.map +1 -1
  128. package/lib/node/mcp-server-manager-impl.js +6 -26
  129. package/lib/node/mcp-server-manager-impl.js.map +1 -1
  130. package/lib/node/mcp-server.d.ts +16 -5
  131. package/lib/node/mcp-server.d.ts.map +1 -1
  132. package/lib/node/mcp-server.js +6 -12
  133. package/lib/node/mcp-server.js.map +1 -1
  134. package/lib/node/openai/openai-language-model.d.ts +3 -4
  135. package/lib/node/openai/openai-language-model.d.ts.map +1 -1
  136. package/lib/node/openai/openai-language-model.js +2 -3
  137. package/lib/node/openai/openai-language-model.js.map +1 -1
  138. package/package.json +27 -27
  139. package/src/browser/ai-core.contribution.ts +29 -14
  140. package/src/browser/chat/chat-manager.service.ts +13 -17
  141. package/src/browser/chat/chat-model.ts +3 -18
  142. package/src/browser/chat/chat.internal.service.ts +4 -0
  143. package/src/browser/chat/chat.module.less +2 -1
  144. package/src/browser/chat/chat.view.tsx +26 -10
  145. package/src/browser/components/ChatContext/index.tsx +2 -2
  146. package/src/browser/components/ChatHistory.tsx +21 -15
  147. package/src/browser/components/ChatInput.tsx +4 -67
  148. package/src/browser/components/ChatToolRender.tsx +2 -1
  149. package/src/browser/components/{chat-history.css → chat-history.module.less} +1 -1
  150. package/src/browser/components/components.module.less +0 -20
  151. package/src/browser/context/llm-context.service.ts +54 -90
  152. package/src/browser/index.ts +0 -4
  153. package/src/browser/layout/layout.module.less +4 -4
  154. package/src/browser/mcp/base-apply.service.ts +266 -213
  155. package/src/browser/mcp/mcp-server-proxy.service.ts +2 -14
  156. package/src/browser/mcp/mcp-server.feature.registry.ts +2 -3
  157. package/src/browser/mcp/tools/components/EditFile.tsx +82 -60
  158. package/src/browser/mcp/tools/components/index.module.less +22 -4
  159. package/src/browser/mcp/tools/createNewFileWithText.ts +0 -1
  160. package/src/browser/mcp/tools/editFile.ts +2 -2
  161. package/src/browser/mcp/tools/getDiagnosticsByPath.ts +0 -1
  162. package/src/browser/mcp/tools/handlers/EditFile.ts +4 -4
  163. package/src/browser/mcp/tools/handlers/RunCommand.ts +0 -2
  164. package/src/browser/mcp/tools/runTerminalCmd.ts +0 -1
  165. package/src/browser/model/msg-history-manager.ts +12 -2
  166. package/src/browser/preferences/schema.ts +0 -16
  167. package/src/browser/types.ts +1 -1
  168. package/src/browser/widget/inline-diff/inline-diff-manager.tsx +38 -0
  169. package/src/browser/widget/inline-diff/inline-diff-widget.module.less +12 -0
  170. package/src/browser/widget/inline-stream-diff/inline-stream-diff.handler.tsx +13 -4
  171. package/src/common/index.ts +1 -7
  172. package/src/common/llm-context.ts +4 -10
  173. package/src/common/mcp-server-manager.ts +1 -17
  174. package/src/common/prompts/context-prompt-provider.ts +28 -26
  175. package/src/common/tool-invocation-registry.ts +2 -2
  176. package/src/common/types.ts +20 -6
  177. package/src/common/utils.ts +1 -3
  178. package/src/node/base-language-model.ts +63 -1
  179. package/src/node/mcp/sumi-mcp-server.ts +9 -67
  180. package/src/node/mcp-server-manager-impl.ts +9 -30
  181. package/src/node/mcp-server.ts +14 -11
  182. package/src/node/openai/openai-language-model.ts +4 -7
  183. package/lib/browser/mcp/config/components/mcp-config.module.less +0 -178
  184. package/lib/browser/mcp/config/components/mcp-config.view.d.ts +0 -3
  185. package/lib/browser/mcp/config/components/mcp-config.view.d.ts.map +0 -1
  186. package/lib/browser/mcp/config/components/mcp-config.view.js +0 -150
  187. package/lib/browser/mcp/config/components/mcp-config.view.js.map +0 -1
  188. package/lib/browser/mcp/config/components/mcp-server-form.d.ts +0 -16
  189. package/lib/browser/mcp/config/components/mcp-server-form.d.ts.map +0 -1
  190. package/lib/browser/mcp/config/components/mcp-server-form.js +0 -84
  191. package/lib/browser/mcp/config/components/mcp-server-form.js.map +0 -1
  192. package/lib/browser/mcp/config/components/mcp-server-form.module.less +0 -78
  193. package/lib/browser/mcp/config/mcp-config.commands.d.ts +0 -10
  194. package/lib/browser/mcp/config/mcp-config.commands.d.ts.map +0 -1
  195. package/lib/browser/mcp/config/mcp-config.commands.js +0 -35
  196. package/lib/browser/mcp/config/mcp-config.commands.js.map +0 -1
  197. package/lib/browser/mcp/config/mcp-config.contribution.d.ts +0 -16
  198. package/lib/browser/mcp/config/mcp-config.contribution.d.ts.map +0 -1
  199. package/lib/browser/mcp/config/mcp-config.contribution.js +0 -62
  200. package/lib/browser/mcp/config/mcp-config.contribution.js.map +0 -1
  201. package/src/browser/mcp/config/components/mcp-config.module.less +0 -178
  202. package/src/browser/mcp/config/components/mcp-config.view.tsx +0 -215
  203. package/src/browser/mcp/config/components/mcp-server-form.module.less +0 -78
  204. package/src/browser/mcp/config/components/mcp-server-form.tsx +0 -144
  205. package/src/browser/mcp/config/mcp-config.commands.ts +0 -29
  206. package/src/browser/mcp/config/mcp-config.contribution.ts +0 -65
@@ -1,16 +1,22 @@
1
1
  import { createPatch } from 'diff';
2
2
 
3
3
  import { Autowired } from '@opensumi/di';
4
- import { AppConfig, ChatMessageRole, IMarker, MarkerSeverity, OnEvent, WithEventBus } from '@opensumi/ide-core-browser';
4
+ import { AppConfig, IChatProgress, IMarker, MarkerSeverity, OnEvent, WithEventBus } from '@opensumi/ide-core-browser';
5
5
  import { WorkbenchEditorService } from '@opensumi/ide-editor';
6
- import { EditorGroupCloseEvent } from '@opensumi/ide-editor/lib/browser';
6
+ import {
7
+ EditorGroupCloseEvent,
8
+ EditorGroupOpenEvent,
9
+ RegisterEditorSideComponentEvent,
10
+ } from '@opensumi/ide-editor/lib/browser';
7
11
  import { IMarkerService } from '@opensumi/ide-markers';
8
- import { Position, Range, Selection, SelectionDirection } from '@opensumi/ide-monaco';
9
- import { observableValue, transaction } from '@opensumi/ide-monaco/lib/common/observable';
10
- import { Deferred, URI, path } from '@opensumi/ide-utils';
12
+ import { ICodeEditor, Position, Range, Selection, SelectionDirection } from '@opensumi/ide-monaco';
13
+ import { Deferred, Emitter, URI, path } from '@opensumi/ide-utils';
14
+ import { SumiReadableStream } from '@opensumi/ide-utils/lib/stream';
11
15
 
12
16
  import { IChatInternalService } from '../../common';
17
+ import { CodeBlockData, CodeBlockStatus } from '../../common/types';
13
18
  import { ChatInternalService } from '../chat/chat.internal.service';
19
+ import { InlineChatController } from '../widget/inline-chat/inline-chat-controller';
14
20
  import {
15
21
  BaseInlineDiffPreviewer,
16
22
  InlineDiffController,
@@ -41,6 +47,9 @@ export abstract class BaseApplyService extends WithEventBus {
41
47
  @Autowired(IMarkerService)
42
48
  private readonly markerService: IMarkerService;
43
49
 
50
+ private onCodeBlockUpdateEmitter = new Emitter<CodeBlockData>();
51
+ public onCodeBlockUpdate = this.onCodeBlockUpdateEmitter.event;
52
+
44
53
  constructor() {
45
54
  super();
46
55
  this.addDispose(
@@ -52,23 +61,32 @@ export abstract class BaseApplyService extends WithEventBus {
52
61
  this.chatInternalService.onRegenerateRequest(() => {
53
62
  const messages = this.chatInternalService.sessionModel.history.getMessages();
54
63
  const messageId = messages[messages.length - 1].id;
55
- messageId && this.disposeApplyForMessage(messageId);
64
+ const codeBlockMap = this.getMessageCodeBlocks(messageId);
65
+ if (!codeBlockMap) {
66
+ return;
67
+ }
68
+ Object.values(codeBlockMap).forEach((blockData) => {
69
+ this.cancelApply(blockData);
70
+ });
56
71
  }),
57
72
  );
58
73
  }
59
74
 
60
- public readonly codeBlockMapObservable = observableValue<Map<string, CodeBlockData>>(this, new Map());
75
+ private getMessageCodeBlocks(
76
+ messageId: string,
77
+ sessionId?: string,
78
+ ): { [toolCallId: string]: CodeBlockData } | undefined {
79
+ sessionId = sessionId || this.chatInternalService.sessionModel.sessionId;
80
+ const sessionModel = this.chatInternalService.getSession(sessionId);
81
+ if (!sessionModel) {
82
+ throw new Error(`Session ${sessionId} not found`);
83
+ }
84
+ const message = sessionModel.history.getMessageAdditional(messageId);
85
+ return message?.codeBlockMap;
86
+ }
61
87
 
62
88
  private activePreviewer: BaseInlineDiffPreviewer<InlineStreamDiffHandler> | undefined;
63
89
 
64
- private pendingApplyParams:
65
- | {
66
- relativePath: string;
67
- newContent: string;
68
- range?: Range;
69
- }
70
- | undefined;
71
-
72
90
  @OnEvent(EditorGroupCloseEvent)
73
91
  onEditorGroupClose(event: EditorGroupCloseEvent) {
74
92
  if (this.activePreviewer?.getNode()?.uri.path.toString() === event.payload.resource.uri.path.toString()) {
@@ -77,187 +95,195 @@ export abstract class BaseApplyService extends WithEventBus {
77
95
  }
78
96
  }
79
97
 
80
- /**
81
- * Get the code block data by relative or absolute path of the last assistant message
82
- */
83
- getCodeBlock(relativeOrAbsolutePath: string, messageId?: string): CodeBlockData | undefined {
84
- if (!relativeOrAbsolutePath) {
85
- return undefined;
98
+ @OnEvent(EditorGroupOpenEvent)
99
+ async onEditorGroupOpen(event: EditorGroupOpenEvent) {
100
+ if (!this.chatInternalService.sessionModel.history.getMessages().length) {
101
+ return;
102
+ }
103
+ const relativePath = path.relative(this.appConfig.workspaceDir, event.payload.resource.uri.path.toString());
104
+ const filePendingApplies = Object.values(
105
+ this.getMessageCodeBlocks(this.chatInternalService.sessionModel.history.lastMessageId!) || {},
106
+ ).filter((block) => block.relativePath === relativePath && block.status === 'pending');
107
+ // TODO: 刷新后重新应用,事件无法恢复 & 恢复继续请求,需要改造成批量apply形式
108
+ // TODO: 暂时只支持 pending 串行的 apply,后续支持批量apply后统一accept
109
+ if (filePendingApplies.length > 0) {
110
+ this.renderApplyResult(filePendingApplies[0], filePendingApplies[0].updatedCode!);
86
111
  }
87
- const blockId = this.generateBlockId(relativeOrAbsolutePath, messageId);
88
- return this.codeBlockMapObservable.get().get(blockId);
89
112
  }
90
113
 
91
- getCodeBlockById(id: string): CodeBlockData | undefined {
92
- return this.codeBlockMapObservable.get().get(id);
114
+ getUriPendingCodeBlock(uri: URI): CodeBlockData | undefined {
115
+ const messageId = this.chatInternalService.sessionModel.history.lastMessageId;
116
+ if (!messageId) {
117
+ return undefined;
118
+ }
119
+ const codeBlockMap = this.getMessageCodeBlocks(messageId);
120
+ if (!codeBlockMap) {
121
+ return undefined;
122
+ }
123
+ return Object.values(codeBlockMap).find(
124
+ (block) =>
125
+ block.relativePath === path.relative(this.appConfig.workspaceDir, uri.path.toString()) &&
126
+ block.status === 'pending',
127
+ );
93
128
  }
94
129
 
95
- protected updateCodeBlock(codeBlock: CodeBlockData) {
96
- const codeBlockMap = new Map(this.codeBlockMapObservable.get());
97
- codeBlockMap.set(codeBlock.id, codeBlock);
98
- transaction((tx) => {
99
- this.codeBlockMapObservable.set(codeBlockMap, tx);
100
- });
130
+ getCodeBlock(toolCallId: string, messageId?: string): CodeBlockData | undefined {
131
+ messageId = messageId || this.chatInternalService.sessionModel.history.lastMessageId;
132
+ if (!messageId) {
133
+ throw new Error('Message ID is required');
134
+ }
135
+ const codeBlockMap = this.getMessageCodeBlocks(messageId);
136
+ if (!codeBlockMap) {
137
+ return undefined;
138
+ }
139
+ return codeBlockMap[toolCallId];
101
140
  }
102
141
 
103
- /**
104
- * Register a new code block and return its unique ID
105
- */
106
- registerCodeBlock(relativePath: string, content: string): string {
107
- const blockId = this.generateBlockId(relativePath);
108
-
109
- if (!this.codeBlockMapObservable.get().has(blockId)) {
110
- this.codeBlockMapObservable.get().set(blockId, {
111
- id: blockId,
112
- content,
113
- relativePath,
114
- status: 'generating',
115
- iterationCount: 0,
116
- createdAt: Date.now(),
117
- });
142
+ protected updateCodeBlock(codeBlock: CodeBlockData, messageId?: string) {
143
+ messageId = messageId || this.chatInternalService.sessionModel.history.lastMessageId;
144
+ if (!messageId) {
145
+ throw new Error('Message ID is required');
118
146
  }
119
-
120
- return blockId;
147
+ const codeBlockMap = this.getMessageCodeBlocks(messageId);
148
+ if (!codeBlockMap) {
149
+ throw new Error('Code block not found');
150
+ }
151
+ codeBlockMap[codeBlock.toolCallId] = codeBlock;
152
+ this.chatInternalService.sessionModel.history.setMessageAdditional(messageId, {
153
+ codeBlockMap,
154
+ });
155
+ this.onCodeBlockUpdateEmitter.fire(codeBlock);
121
156
  }
122
157
 
123
- initToolCallId(blockId: string, toolCallId: string): void {
124
- const blockData = this.getCodeBlockById(blockId);
125
- if (blockData && !blockData.initToolCallId) {
126
- blockData.initToolCallId = toolCallId;
158
+ registerCodeBlock(relativePath: string, content: string, toolCallId: string): CodeBlockData {
159
+ const lastMessageId = this.chatInternalService.sessionModel.history.lastMessageId!;
160
+ const savedCodeBlockMap = this.getMessageCodeBlocks(lastMessageId) || {};
161
+ const newBlock: CodeBlockData = {
162
+ codeEdit: content,
163
+ relativePath,
164
+ status: 'generating' as CodeBlockStatus,
165
+ iterationCount: 1,
166
+ version: 1,
167
+ createdAt: Date.now(),
168
+ toolCallId,
169
+ };
170
+ const samePathCodeBlocks = Object.values(savedCodeBlockMap).filter((block) => block.relativePath === relativePath);
171
+ if (samePathCodeBlocks.length > 0) {
172
+ newBlock.version = samePathCodeBlocks.length;
173
+ for (const block of samePathCodeBlocks.sort((a, b) => b.version - a.version)) {
174
+ // 如果连续的上一个同文件apply结果存在LintError,则iterationCount++
175
+ if (block.relativePath === relativePath && block.applyResult?.diagnosticInfos?.length) {
176
+ newBlock.iterationCount++;
177
+ } else {
178
+ break;
179
+ }
180
+ }
127
181
  }
182
+ savedCodeBlockMap[toolCallId] = newBlock;
183
+ this.chatInternalService.sessionModel.history.setMessageAdditional(lastMessageId, {
184
+ codeBlockMap: savedCodeBlockMap,
185
+ });
186
+ this.onCodeBlockUpdateEmitter.fire(newBlock);
187
+ return newBlock;
128
188
  }
129
189
 
130
190
  /**
131
191
  * Apply changes of a code block
132
192
  */
133
- async apply(relativePath: string, newContent: string, instructions?: string): Promise<CodeBlockData> {
134
- const blockData = this.getCodeBlock(relativePath);
135
- if (!blockData) {
136
- throw new Error('Code block not found');
137
- }
193
+ async apply(codeBlock: CodeBlockData): Promise<CodeBlockData> {
138
194
  try {
139
- if (++blockData.iterationCount > 3) {
140
- throw new Error('Max iteration count exceeded');
195
+ if (codeBlock.iterationCount > 3) {
196
+ throw new Error('Lint error max iteration count exceeded');
141
197
  }
142
- blockData.status = 'generating';
143
- blockData.content = newContent;
144
- this.updateCodeBlock(blockData);
145
- const applyDiffResult = await this.doApply(relativePath, newContent, instructions);
146
- blockData.applyResult = applyDiffResult;
147
- this.updateCodeBlock(blockData);
148
- return blockData;
198
+ const fastApplyFileResult = await this.doApply(codeBlock);
199
+ if (!fastApplyFileResult.stream && !fastApplyFileResult.result) {
200
+ throw new Error('No apply content provided');
201
+ }
202
+
203
+ // trigger diffPreivewer & return expected diff result directly
204
+ const applyResult = await this.renderApplyResult(
205
+ codeBlock,
206
+ (fastApplyFileResult.result || fastApplyFileResult.stream)!,
207
+ fastApplyFileResult.range,
208
+ );
209
+ if (applyResult) {
210
+ // 用户实际接受的 apply 结果
211
+ codeBlock.applyResult = applyResult;
212
+ this.updateCodeBlock(codeBlock);
213
+ }
214
+
215
+ return codeBlock;
149
216
  } catch (err) {
150
- blockData.status = 'failed';
151
- this.updateCodeBlock(blockData);
217
+ codeBlock.status = 'failed';
218
+ this.updateCodeBlock(codeBlock);
152
219
  throw err;
153
220
  }
154
221
  }
155
222
 
156
- async reRenderPendingApply() {
157
- if (!this.pendingApplyParams) {
158
- throw new Error('No pending apply params');
159
- }
160
- const result = await this.renderApplyResult(
161
- this.pendingApplyParams.relativePath,
162
- this.pendingApplyParams.newContent,
163
- this.pendingApplyParams.range,
164
- );
165
- if (result) {
166
- const blockData = this.getCodeBlock(this.pendingApplyParams.relativePath)!;
167
- blockData.applyResult = result;
168
- this.updateCodeBlock(blockData);
169
- }
170
- }
171
-
172
223
  async renderApplyResult(
173
- relativePath: string,
174
- newContent: string,
224
+ codeBlock: CodeBlockData,
225
+ updatedContentOrStream: string | SumiReadableStream<IChatProgress>,
175
226
  range?: Range,
176
227
  ): Promise<{ diff: string; diagnosticInfos: IMarker[] } | undefined> {
177
- // 用户可能会关闭编辑器,所以需要缓存参数
178
- this.pendingApplyParams = {
179
- relativePath,
180
- newContent,
181
- range,
182
- };
183
- const blockData = this.getCodeBlock(relativePath);
184
- if (!blockData) {
185
- throw new Error('Code block not found');
186
- }
228
+ const { relativePath } = codeBlock;
187
229
  const openResult = await this.editorService.open(URI.file(path.join(this.appConfig.workspaceDir, relativePath)));
188
230
  if (!openResult) {
189
231
  throw new Error('Failed to open editor');
190
232
  }
191
233
  const editor = openResult.group.codeEditor.monacoEditor;
192
234
  const inlineDiffController = InlineDiffController.get(editor)!;
193
- blockData.status = 'pending';
194
- this.updateCodeBlock(blockData);
195
-
196
- range = range || editor.getModel()?.getFullModelRange()!;
197
- // Create diff previewer
198
- const previewer = inlineDiffController.createDiffPreviewer(
199
- editor,
200
- Selection.fromRange(range, SelectionDirection.LTR),
201
- {
202
- disposeWhenEditorClosed: true,
203
- renderRemovedWidgetImmediately: true,
204
- },
205
- ) as LiveInlineDiffPreviewer;
206
- this.activePreviewer = previewer;
235
+ codeBlock.status = 'pending';
236
+ // 强刷展示 manager 视图
237
+ this.eventBus.fire(new RegisterEditorSideComponentEvent());
238
+ this.updateCodeBlock(codeBlock);
207
239
 
208
240
  const fullOriginalContent = editor.getModel()!.getValue();
209
- const savedContent = editor.getModel()!.getValueInRange(range);
210
- const deferred = new Deferred<{ diff: string; diagnosticInfos: IMarker[] }>();
211
- if (newContent === savedContent) {
212
- blockData.status = 'success';
213
- deferred.resolve();
241
+ range = range || editor.getModel()?.getFullModelRange()!;
242
+ // const savedRangeContent = editor.getModel()!.getValueInRange(range);
243
+
244
+ if (typeof updatedContentOrStream === 'string') {
245
+ // Create diff previewer
246
+ const previewer = inlineDiffController.createDiffPreviewer(
247
+ editor,
248
+ Selection.fromRange(range, SelectionDirection.LTR),
249
+ {
250
+ disposeWhenEditorClosed: true,
251
+ renderRemovedWidgetImmediately: true,
252
+ },
253
+ ) as LiveInlineDiffPreviewer;
254
+ // TODO: 支持多个diffPreviewer
255
+ this.activePreviewer = previewer;
256
+ codeBlock.updatedCode = updatedContentOrStream;
257
+ previewer.setValue(updatedContentOrStream);
214
258
  } else {
215
- previewer.setValue(newContent);
259
+ const controller = new InlineChatController();
260
+ controller.mountReadable(updatedContentOrStream);
261
+ const inlineDiffHandler = InlineDiffController.get(editor)!;
262
+
263
+ this.activePreviewer = inlineDiffHandler.showPreviewerByStream(editor, {
264
+ crossSelection: Selection.fromRange(range, SelectionDirection.LTR),
265
+ chatResponse: controller,
266
+ previewerOptions: {
267
+ disposeWhenEditorClosed: true,
268
+ renderRemovedWidgetImmediately: false,
269
+ },
270
+ }) as LiveInlineDiffPreviewer;
216
271
  this.addDispose(
217
- this.inlineDiffService.onPartialEdit((event) => {
218
- // TODO 支持自动保存
219
- if (event.totalPartialEditCount === event.resolvedPartialEditCount) {
220
- if (event.acceptPartialEditCount > 0) {
221
- blockData.status = 'success';
222
- const appliedResult = editor.getModel()!.getValue();
223
- const diffResult = createPatch(relativePath, fullOriginalContent, appliedResult)
224
- .split('\n')
225
- .slice(4)
226
- .join('\n');
227
- const rangesFromDiffHunk = diffResult
228
- .split('\n')
229
- .map((line) => {
230
- if (line.startsWith('@@')) {
231
- const [, , , start, end] = line.match(/@@ -(\d+),(\d+) \+(\d+),(\d+) @@/)!;
232
- return new Range(parseInt(start, 10), 0, parseInt(end, 10), 0);
233
- }
234
- return null;
235
- })
236
- .filter((range) => range !== null);
237
- const diagnosticInfos = this.getdiagnosticInfos(editor.getModel()!.uri.toString(), rangesFromDiffHunk);
238
- // 移除开头的几个固定信息,避免浪费 tokens
239
- deferred.resolve({
240
- diff: diffResult,
241
- diagnosticInfos,
242
- });
243
- } else {
244
- // 用户全部取消
245
- blockData.status = 'cancelled';
246
- deferred.resolve();
247
- }
248
- }
272
+ this.activePreviewer.getNode()!.onDiffFinished((diffModel) => {
273
+ codeBlock.updatedCode = diffModel.newFullRangeTextLines.join('\n');
274
+ this.updateCodeBlock(codeBlock);
249
275
  }),
250
276
  );
251
277
  }
252
- return deferred.promise;
278
+
279
+ return this.listenPartialEdit(editor, codeBlock, fullOriginalContent);
253
280
  }
254
281
 
255
282
  /**
256
283
  * Cancel an ongoing apply operation
257
284
  */
258
- cancelApply(relativePath: string): void {
259
- const blockData = this.getCodeBlock(relativePath);
260
- if (blockData && (blockData.status === 'generating' || blockData.status === 'pending')) {
285
+ cancelApply(blockData: CodeBlockData): void {
286
+ if (blockData.status === 'generating' || blockData.status === 'pending') {
261
287
  if (this.activePreviewer) {
262
288
  this.activePreviewer.getNode()?.livePreviewDiffDecorationModel.discardUnProcessed();
263
289
  this.activePreviewer.dispose();
@@ -267,62 +293,105 @@ export abstract class BaseApplyService extends WithEventBus {
267
293
  }
268
294
  }
269
295
 
296
+ // TODO: 目前的设计下,有一个工具 apply 没返回,是不会触发下一个的(cursor 是会全部自动 apply 的),所以这个方法目前还没有必要
270
297
  cancelAllApply(): void {
271
- this.codeBlockMapObservable.get().forEach((blockData) => {
272
- if (blockData.status === 'generating' || blockData.status === 'pending') {
273
- this.cancelApply(blockData.relativePath);
274
- }
298
+ const messageId = this.chatInternalService.sessionModel.history.lastMessageId!;
299
+ const codeBlockMap = this.getMessageCodeBlocks(messageId);
300
+ if (!codeBlockMap) {
301
+ return;
302
+ }
303
+ Object.values(codeBlockMap).forEach((blockData) => {
304
+ this.cancelApply(blockData);
275
305
  });
276
306
  }
277
307
 
278
- disposeApplyForMessage(messageId: string): void {
279
- this.codeBlockMapObservable.get().forEach((blockData) => {
280
- if (blockData.id.endsWith(':' + messageId)) {
281
- if (blockData.status === 'generating') {
282
- this.cancelApply(blockData.relativePath);
283
- }
284
- this.codeBlockMapObservable.get().delete(blockData.id);
285
- }
286
- });
308
+ revealApplyPosition(blockData: CodeBlockData): void {
309
+ const hunkInfo = blockData.applyResult?.diff.split('\n').find((line) => line.startsWith('@@'));
310
+ let startLine = 0;
311
+ let endLine = 0;
312
+ if (hunkInfo) {
313
+ // 取改动后的区间
314
+ const [, , , start, end] = hunkInfo.match(/@@ -(\d+),(\d+) \+(\d+),(\d+) @@/)!;
315
+ startLine = parseInt(start, 10) - 1;
316
+ endLine = parseInt(end, 10) - 1;
317
+ }
318
+ this.editorService.open(URI.file(path.join(this.appConfig.workspaceDir, blockData.relativePath)));
319
+ const editor = this.editorService.currentEditor;
320
+ if (editor) {
321
+ editor.setSelection(new Selection(startLine, 0, endLine, 0));
322
+ }
287
323
  }
288
324
 
289
- revealApplyPosition(blockId: string): void {
290
- const blockData = this.codeBlockMapObservable.get().get(blockId);
291
- if (blockData) {
292
- const hunkInfo = blockData.applyResult?.diff.split('\n').find((line) => line.startsWith('@@'));
293
- let startLine = 0;
294
- let endLine = 0;
295
- if (hunkInfo) {
296
- // 取改动后的区间
297
- const [, , , start, end] = hunkInfo.match(/@@ -(\d+),(\d+) \+(\d+),(\d+) @@/)!;
298
- startLine = parseInt(start, 10) - 1;
299
- endLine = parseInt(end, 10) - 1;
300
- }
301
- this.editorService.open(URI.file(path.join(this.appConfig.workspaceDir, blockData.relativePath)));
302
- const editor = this.editorService.currentEditor;
303
- if (editor) {
304
- editor.setSelection(new Selection(startLine, 0, endLine, 0));
305
- }
325
+ processAll(uri: URI, type: 'accept' | 'reject'): void {
326
+ const codeBlock = this.getUriPendingCodeBlock(uri);
327
+ if (!codeBlock) {
328
+ throw new Error('No pending code block found');
306
329
  }
330
+ const decorationModel = this.activePreviewer?.getNode()?.livePreviewDiffDecorationModel;
331
+ if (!decorationModel) {
332
+ throw new Error('No active previewer found');
333
+ }
334
+ if (type === 'accept') {
335
+ decorationModel.acceptUnProcessed();
336
+ } else {
337
+ decorationModel.discardUnProcessed();
338
+ }
339
+ this.editorService.save(uri);
340
+ codeBlock.status = type === 'accept' ? 'success' : 'cancelled';
341
+ this.updateCodeBlock(codeBlock);
307
342
  }
308
343
 
309
- protected abstract doApply(
310
- relativePath: string,
311
- newContent: string,
312
- instructions?: string,
313
- ): Promise<{ diff: string; diagnosticInfos: IMarker[] } | undefined>;
314
-
315
- protected generateBlockId(absoluteOrRelativePath: string, messageId?: string): string {
316
- if (!absoluteOrRelativePath.startsWith('/')) {
317
- absoluteOrRelativePath = path.join(this.appConfig.workspaceDir, absoluteOrRelativePath);
318
- }
319
- const sessionId = this.chatInternalService.sessionModel.sessionId;
320
- const messages = this.chatInternalService.sessionModel.history.getMessages();
321
- messageId = messageId || messages[messages.length - 1].id;
322
- return `${sessionId}:${absoluteOrRelativePath}:${messageId || '-'}`;
344
+ protected listenPartialEdit(editor: ICodeEditor, codeBlock: CodeBlockData, fullOriginalContent: string) {
345
+ const deferred = new Deferred<{ diff: string; diagnosticInfos: IMarker[] }>();
346
+ const toDispose = this.inlineDiffService.onPartialEdit((event) => {
347
+ // TODO 支持自动保存
348
+ if (event.totalPartialEditCount === event.resolvedPartialEditCount) {
349
+ if (event.acceptPartialEditCount > 0) {
350
+ codeBlock.status = 'success';
351
+ const appliedResult = editor.getModel()!.getValue();
352
+ const diffResult = createPatch(codeBlock.relativePath, fullOriginalContent, appliedResult)
353
+ .split('\n')
354
+ .slice(4)
355
+ .join('\n');
356
+ const rangesFromDiffHunk = diffResult
357
+ .split('\n')
358
+ .map((line) => {
359
+ if (line.startsWith('@@')) {
360
+ const [, , , start, end] = line.match(/@@ -(\d+),(\d+) \+(\d+),(\d+) @@/)!;
361
+ return new Range(parseInt(start, 10), 0, parseInt(end, 10), 0);
362
+ }
363
+ return null;
364
+ })
365
+ .filter((range) => range !== null);
366
+ const diagnosticInfos = this.getDiagnosticInfos(editor.getModel()!.uri.toString(), rangesFromDiffHunk);
367
+ // 移除开头的几个固定信息,避免浪费 tokens
368
+ deferred.resolve({
369
+ diff: diffResult,
370
+ diagnosticInfos,
371
+ });
372
+ } else {
373
+ // 用户全部取消
374
+ codeBlock.status = 'cancelled';
375
+ deferred.resolve();
376
+ }
377
+ toDispose.dispose();
378
+ }
379
+ });
380
+ return deferred.promise;
323
381
  }
324
382
 
325
- protected getdiagnosticInfos(uri: string, ranges: Range[]) {
383
+ /**
384
+ * Apply changes of a code block, return stream to render inline diff in stream mode, result to render inline diff directly
385
+ * range is optional, if not provided, the result will be applied to the the full file
386
+ */
387
+ protected abstract doApply(codeBlock: CodeBlockData): Promise<{
388
+ range?: Range;
389
+ stream?: SumiReadableStream<IChatProgress, Error>;
390
+ result?: string;
391
+ }>;
392
+
393
+ // TODO: 支持使用内存中的document获取诊断信息,实现并行apply accept
394
+ protected getDiagnosticInfos(uri: string, ranges: Range[]) {
326
395
  const markers = this.markerService.getManager().getMarkers({ resource: uri });
327
396
  return markers.filter(
328
397
  (marker) =>
@@ -331,19 +400,3 @@ export abstract class BaseApplyService extends WithEventBus {
331
400
  );
332
401
  }
333
402
  }
334
-
335
- export interface CodeBlockData {
336
- id: string;
337
- initToolCallId?: string;
338
- content: string;
339
- relativePath: string;
340
- status: CodeBlockStatus;
341
- iterationCount: number;
342
- createdAt: number;
343
- applyResult?: {
344
- diff: string;
345
- diagnosticInfos: IMarker[];
346
- };
347
- }
348
-
349
- export type CodeBlockStatus = 'generating' | 'pending' | 'success' | 'rejected' | 'failed' | 'cancelled';
@@ -4,7 +4,7 @@ import { Autowired, Injectable } from '@opensumi/di';
4
4
  import { ILogger } from '@opensumi/ide-core-browser';
5
5
  import { Emitter, Event } from '@opensumi/ide-core-common';
6
6
 
7
- import { BUILTIN_MCP_SERVER_NAME, ISumiMCPServerBackend, SumiMCPServerProxyServicePath } from '../../common';
7
+ import { ISumiMCPServerBackend, SumiMCPServerProxyServicePath } from '../../common';
8
8
  import { IMCPServerProxyService } from '../../common/types';
9
9
  import { IMCPServerRegistry, TokenMCPServerRegistry } from '../types';
10
10
 
@@ -35,7 +35,7 @@ export class MCPServerProxyService implements IMCPServerProxyService {
35
35
  name: tool.name,
36
36
  description: tool.description,
37
37
  inputSchema: zodToJsonSchema(tool.inputSchema),
38
- providerName: BUILTIN_MCP_SERVER_NAME,
38
+ providerName: 'sumi-builtin',
39
39
  }),
40
40
  );
41
41
 
@@ -52,16 +52,4 @@ export class MCPServerProxyService implements IMCPServerProxyService {
52
52
  async getAllMCPTools() {
53
53
  return this.sumiMCPServerProxyService.getAllMCPTools();
54
54
  }
55
-
56
- async $getServers() {
57
- return this.sumiMCPServerProxyService.getServers();
58
- }
59
-
60
- async $startServer(serverName: string) {
61
- await this.sumiMCPServerProxyService.startServer(serverName);
62
- }
63
-
64
- async $stopServer(serverName: string) {
65
- await this.sumiMCPServerProxyService.stopServer(serverName);
66
- }
67
55
  }
@@ -2,7 +2,6 @@
2
2
  import { Autowired, Injectable } from '@opensumi/di';
3
3
  import { ILogger } from '@opensumi/ide-core-common';
4
4
 
5
- import { BUILTIN_MCP_SERVER_NAME } from '../../common';
6
5
  import { getToolName } from '../../common/utils';
7
6
  import { IMCPServerRegistry, IMCPServerToolComponentProps, MCPLogger, MCPToolDefinition } from '../types';
8
7
 
@@ -26,7 +25,7 @@ export class MCPServerRegistry implements IMCPServerRegistry {
26
25
  return new LoggerAdapter(this.baseLogger);
27
26
  }
28
27
 
29
- getMCPTool(name: string, serverName = BUILTIN_MCP_SERVER_NAME): MCPToolDefinition | undefined {
28
+ getMCPTool(name: string, serverName = 'sumi-builtin'): MCPToolDefinition | undefined {
30
29
  return this.tools.find((tool) => getToolName(tool.name, serverName) === name);
31
30
  }
32
31
 
@@ -37,7 +36,7 @@ export class MCPServerRegistry implements IMCPServerRegistry {
37
36
  registerToolComponent(
38
37
  name: string,
39
38
  component: React.FC<IMCPServerToolComponentProps>,
40
- serverName = BUILTIN_MCP_SERVER_NAME,
39
+ serverName = 'sumi-builtin',
41
40
  ): void {
42
41
  this.toolComponents[getToolName(name, serverName)] = component;
43
42
  }