@opensumi/ide-ai-native 3.8.1-next-1740556231.0 → 3.8.1-next-1740571693.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/browser/ai-core.contextkeys.d.ts +1 -1
- package/lib/browser/ai-core.contextkeys.d.ts.map +1 -1
- package/lib/browser/ai-core.contextkeys.js +1 -1
- package/lib/browser/ai-core.contextkeys.js.map +1 -1
- package/lib/browser/ai-core.contribution.d.ts +1 -4
- package/lib/browser/ai-core.contribution.d.ts.map +1 -1
- package/lib/browser/ai-core.contribution.js +11 -23
- package/lib/browser/ai-core.contribution.js.map +1 -1
- package/lib/browser/chat/chat-manager.service.d.ts +0 -1
- package/lib/browser/chat/chat-manager.service.d.ts.map +1 -1
- package/lib/browser/chat/chat-manager.service.js +0 -13
- package/lib/browser/chat/chat-manager.service.js.map +1 -1
- package/lib/browser/chat/chat.internal.service.d.ts +0 -1
- package/lib/browser/chat/chat.internal.service.d.ts.map +1 -1
- package/lib/browser/chat/chat.internal.service.js +0 -3
- package/lib/browser/chat/chat.internal.service.js.map +1 -1
- package/lib/browser/chat/chat.view.d.ts.map +1 -1
- package/lib/browser/chat/chat.view.js +30 -1
- package/lib/browser/chat/chat.view.js.map +1 -1
- package/lib/browser/components/ChatHistory.d.ts +1 -0
- package/lib/browser/components/ChatHistory.d.ts.map +1 -1
- package/lib/browser/components/ChatHistory.js +14 -14
- package/lib/browser/components/ChatHistory.js.map +1 -1
- package/lib/browser/contrib/inline-completions/inline-completions.controller.js +1 -1
- package/lib/browser/contrib/inline-completions/inline-completions.controller.js.map +1 -1
- package/lib/browser/contrib/intelligent-completions/index.d.ts +2 -1
- package/lib/browser/contrib/intelligent-completions/index.d.ts.map +1 -1
- package/lib/browser/contrib/intelligent-completions/index.js +4 -1
- package/lib/browser/contrib/intelligent-completions/index.js.map +1 -1
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.js +2 -2
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.js.map +1 -1
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.d.ts.map +1 -1
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.js +5 -4
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.js.map +1 -1
- package/lib/browser/contrib/intelligent-completions/view/code-edits-previewer.d.ts.map +1 -1
- package/lib/browser/contrib/intelligent-completions/view/code-edits-previewer.js +4 -2
- package/lib/browser/contrib/intelligent-completions/view/code-edits-previewer.js.map +1 -1
- package/lib/browser/contrib/intelligent-completions/view/default.d.ts.map +1 -1
- package/lib/browser/contrib/intelligent-completions/view/default.js +17 -11
- package/lib/browser/contrib/intelligent-completions/view/default.js.map +1 -1
- package/lib/browser/index.d.ts.map +1 -1
- package/lib/browser/index.js +4 -0
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/mcp/base-apply.service.d.ts +40 -31
- package/lib/browser/mcp/base-apply.service.d.ts.map +1 -1
- package/lib/browser/mcp/base-apply.service.js +167 -233
- package/lib/browser/mcp/base-apply.service.js.map +1 -1
- package/lib/browser/mcp/config/components/mcp-config.module.less +178 -0
- package/lib/browser/mcp/config/components/mcp-config.view.d.ts +3 -0
- package/lib/browser/mcp/config/components/mcp-config.view.d.ts.map +1 -0
- package/lib/browser/mcp/config/components/mcp-config.view.js +150 -0
- package/lib/browser/mcp/config/components/mcp-config.view.js.map +1 -0
- package/lib/browser/mcp/config/components/mcp-server-form.d.ts +16 -0
- package/lib/browser/mcp/config/components/mcp-server-form.d.ts.map +1 -0
- package/lib/browser/mcp/config/components/mcp-server-form.js +84 -0
- package/lib/browser/mcp/config/components/mcp-server-form.js.map +1 -0
- package/lib/browser/mcp/config/components/mcp-server-form.module.less +78 -0
- package/lib/browser/mcp/config/mcp-config.commands.d.ts +10 -0
- package/lib/browser/mcp/config/mcp-config.commands.d.ts.map +1 -0
- package/lib/browser/mcp/config/mcp-config.commands.js +35 -0
- package/lib/browser/mcp/config/mcp-config.commands.js.map +1 -0
- package/lib/browser/mcp/config/mcp-config.contribution.d.ts +16 -0
- package/lib/browser/mcp/config/mcp-config.contribution.d.ts.map +1 -0
- package/lib/browser/mcp/config/mcp-config.contribution.js +62 -0
- package/lib/browser/mcp/config/mcp-config.contribution.js.map +1 -0
- package/lib/browser/mcp/mcp-server-proxy.service.d.ts +6 -0
- package/lib/browser/mcp/mcp-server-proxy.service.d.ts.map +1 -1
- package/lib/browser/mcp/mcp-server-proxy.service.js +10 -1
- package/lib/browser/mcp/mcp-server-proxy.service.js.map +1 -1
- package/lib/browser/mcp/mcp-server.feature.registry.d.ts.map +1 -1
- package/lib/browser/mcp/mcp-server.feature.registry.js +3 -2
- package/lib/browser/mcp/mcp-server.feature.registry.js.map +1 -1
- package/lib/browser/mcp/tools/components/EditFile.d.ts.map +1 -1
- package/lib/browser/mcp/tools/components/EditFile.js +41 -55
- package/lib/browser/mcp/tools/components/EditFile.js.map +1 -1
- package/lib/browser/mcp/tools/components/index.module.less +3 -22
- package/lib/browser/mcp/tools/editFile.js +1 -1
- package/lib/browser/mcp/tools/editFile.js.map +1 -1
- package/lib/browser/mcp/tools/handlers/EditFile.d.ts +1 -5
- package/lib/browser/mcp/tools/handlers/EditFile.d.ts.map +1 -1
- package/lib/browser/mcp/tools/handlers/EditFile.js +4 -4
- package/lib/browser/mcp/tools/handlers/EditFile.js.map +1 -1
- package/lib/browser/model/msg-history-manager.d.ts +0 -1
- package/lib/browser/model/msg-history-manager.d.ts.map +1 -1
- package/lib/browser/model/msg-history-manager.js +2 -12
- package/lib/browser/model/msg-history-manager.js.map +1 -1
- package/lib/browser/preferences/schema.d.ts.map +1 -1
- package/lib/browser/preferences/schema.js +16 -0
- package/lib/browser/preferences/schema.js.map +1 -1
- package/lib/browser/types.d.ts +1 -1
- package/lib/browser/types.d.ts.map +1 -1
- package/lib/browser/widget/inline-diff/inline-diff-widget.module.less +0 -12
- package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts +0 -2
- package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts.map +1 -1
- package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js +4 -11
- package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js.map +1 -1
- package/lib/common/index.d.ts +8 -1
- package/lib/common/index.d.ts.map +1 -1
- package/lib/common/index.js +3 -1
- package/lib/common/index.js.map +1 -1
- package/lib/common/mcp-server-manager.d.ts +17 -1
- package/lib/common/mcp-server-manager.d.ts.map +1 -1
- package/lib/common/mcp-server-manager.js.map +1 -1
- package/lib/common/tool-invocation-registry.d.ts +2 -2
- package/lib/common/tool-invocation-registry.d.ts.map +1 -1
- package/lib/common/tool-invocation-registry.js +1 -1
- package/lib/common/tool-invocation-registry.js.map +1 -1
- package/lib/common/types.d.ts +6 -17
- package/lib/common/types.d.ts.map +1 -1
- package/lib/common/types.js.map +1 -1
- package/lib/common/utils.d.ts.map +1 -1
- package/lib/common/utils.js +2 -1
- package/lib/common/utils.js.map +1 -1
- package/lib/node/base-language-model.d.ts +1 -1
- package/lib/node/base-language-model.d.ts.map +1 -1
- package/lib/node/base-language-model.js +8 -58
- package/lib/node/base-language-model.js.map +1 -1
- package/lib/node/mcp/sumi-mcp-server.d.ts +17 -3
- package/lib/node/mcp/sumi-mcp-server.d.ts.map +1 -1
- package/lib/node/mcp/sumi-mcp-server.js +59 -6
- package/lib/node/mcp/sumi-mcp-server.js.map +1 -1
- package/lib/node/mcp-server-manager-impl.d.ts +4 -3
- package/lib/node/mcp-server-manager-impl.d.ts.map +1 -1
- package/lib/node/mcp-server-manager-impl.js +26 -6
- package/lib/node/mcp-server-manager-impl.js.map +1 -1
- package/lib/node/mcp-server.d.ts +5 -16
- package/lib/node/mcp-server.d.ts.map +1 -1
- package/lib/node/mcp-server.js +12 -6
- package/lib/node/mcp-server.js.map +1 -1
- package/lib/node/openai/openai-language-model.d.ts +4 -3
- package/lib/node/openai/openai-language-model.d.ts.map +1 -1
- package/lib/node/openai/openai-language-model.js +3 -2
- package/lib/node/openai/openai-language-model.js.map +1 -1
- package/package.json +27 -27
- package/src/browser/ai-core.contextkeys.ts +3 -3
- package/src/browser/ai-core.contribution.ts +14 -29
- package/src/browser/chat/chat-manager.service.ts +0 -12
- package/src/browser/chat/chat.internal.service.ts +0 -4
- package/src/browser/chat/chat.view.tsx +47 -0
- package/src/browser/components/ChatHistory.tsx +15 -21
- package/src/browser/contrib/inline-completions/inline-completions.controller.ts +1 -1
- package/src/browser/contrib/intelligent-completions/index.ts +5 -1
- package/src/browser/contrib/intelligent-completions/intelligent-completions.contribution.ts +3 -3
- package/src/browser/contrib/intelligent-completions/intelligent-completions.controller.ts +6 -5
- package/src/browser/contrib/intelligent-completions/view/code-edits-previewer.ts +4 -2
- package/src/browser/contrib/intelligent-completions/view/default.ts +27 -19
- package/src/browser/index.ts +4 -0
- package/src/browser/mcp/base-apply.service.ts +213 -266
- package/src/browser/mcp/config/components/mcp-config.module.less +178 -0
- package/src/browser/mcp/config/components/mcp-config.view.tsx +215 -0
- package/src/browser/mcp/config/components/mcp-server-form.module.less +78 -0
- package/src/browser/mcp/config/components/mcp-server-form.tsx +144 -0
- package/src/browser/mcp/config/mcp-config.commands.ts +29 -0
- package/src/browser/mcp/config/mcp-config.contribution.ts +65 -0
- package/src/browser/mcp/mcp-server-proxy.service.ts +14 -2
- package/src/browser/mcp/mcp-server.feature.registry.ts +3 -2
- package/src/browser/mcp/tools/components/EditFile.tsx +60 -82
- package/src/browser/mcp/tools/components/index.module.less +3 -22
- package/src/browser/mcp/tools/editFile.ts +2 -2
- package/src/browser/mcp/tools/handlers/EditFile.ts +4 -4
- package/src/browser/model/msg-history-manager.ts +2 -12
- package/src/browser/preferences/schema.ts +16 -0
- package/src/browser/types.ts +1 -1
- package/src/browser/widget/inline-diff/inline-diff-widget.module.less +0 -12
- package/src/browser/widget/inline-stream-diff/inline-stream-diff.handler.tsx +4 -13
- package/src/common/index.ts +7 -1
- package/src/common/mcp-server-manager.ts +17 -1
- package/src/common/tool-invocation-registry.ts +2 -2
- package/src/common/types.ts +6 -20
- package/src/common/utils.ts +3 -1
- package/src/node/base-language-model.ts +8 -67
- package/src/node/mcp/sumi-mcp-server.ts +67 -9
- package/src/node/mcp-server-manager-impl.ts +30 -9
- package/src/node/mcp-server.ts +11 -14
- package/src/node/openai/openai-language-model.ts +7 -4
- package/lib/browser/widget/inline-diff/inline-diff-manager.d.ts +0 -6
- package/lib/browser/widget/inline-diff/inline-diff-manager.d.ts.map +0 -1
- package/lib/browser/widget/inline-diff/inline-diff-manager.js +0 -27
- package/lib/browser/widget/inline-diff/inline-diff-manager.js.map +0 -1
- package/src/browser/widget/inline-diff/inline-diff-manager.tsx +0 -38
- /package/lib/browser/components/{chat-history.module.less → chat-history.css} +0 -0
- /package/src/browser/components/{chat-history.module.less → chat-history.css} +0 -0
|
@@ -1,22 +1,16 @@
|
|
|
1
1
|
import { createPatch } from 'diff';
|
|
2
2
|
|
|
3
3
|
import { Autowired } from '@opensumi/di';
|
|
4
|
-
import { AppConfig,
|
|
4
|
+
import { AppConfig, ChatMessageRole, IMarker, MarkerSeverity, OnEvent, WithEventBus } from '@opensumi/ide-core-browser';
|
|
5
5
|
import { WorkbenchEditorService } from '@opensumi/ide-editor';
|
|
6
|
-
import {
|
|
7
|
-
EditorGroupCloseEvent,
|
|
8
|
-
EditorGroupOpenEvent,
|
|
9
|
-
RegisterEditorSideComponentEvent,
|
|
10
|
-
} from '@opensumi/ide-editor/lib/browser';
|
|
6
|
+
import { EditorGroupCloseEvent } from '@opensumi/ide-editor/lib/browser';
|
|
11
7
|
import { IMarkerService } from '@opensumi/ide-markers';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
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';
|
|
15
11
|
|
|
16
12
|
import { IChatInternalService } from '../../common';
|
|
17
|
-
import { CodeBlockData, CodeBlockStatus } from '../../common/types';
|
|
18
13
|
import { ChatInternalService } from '../chat/chat.internal.service';
|
|
19
|
-
import { InlineChatController } from '../widget/inline-chat/inline-chat-controller';
|
|
20
14
|
import {
|
|
21
15
|
BaseInlineDiffPreviewer,
|
|
22
16
|
InlineDiffController,
|
|
@@ -47,9 +41,6 @@ export abstract class BaseApplyService extends WithEventBus {
|
|
|
47
41
|
@Autowired(IMarkerService)
|
|
48
42
|
private readonly markerService: IMarkerService;
|
|
49
43
|
|
|
50
|
-
private onCodeBlockUpdateEmitter = new Emitter<CodeBlockData>();
|
|
51
|
-
public onCodeBlockUpdate = this.onCodeBlockUpdateEmitter.event;
|
|
52
|
-
|
|
53
44
|
constructor() {
|
|
54
45
|
super();
|
|
55
46
|
this.addDispose(
|
|
@@ -61,32 +52,23 @@ export abstract class BaseApplyService extends WithEventBus {
|
|
|
61
52
|
this.chatInternalService.onRegenerateRequest(() => {
|
|
62
53
|
const messages = this.chatInternalService.sessionModel.history.getMessages();
|
|
63
54
|
const messageId = messages[messages.length - 1].id;
|
|
64
|
-
|
|
65
|
-
if (!codeBlockMap) {
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
Object.values(codeBlockMap).forEach((blockData) => {
|
|
69
|
-
this.cancelApply(blockData);
|
|
70
|
-
});
|
|
55
|
+
messageId && this.disposeApplyForMessage(messageId);
|
|
71
56
|
}),
|
|
72
57
|
);
|
|
73
58
|
}
|
|
74
59
|
|
|
75
|
-
|
|
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
|
-
}
|
|
60
|
+
public readonly codeBlockMapObservable = observableValue<Map<string, CodeBlockData>>(this, new Map());
|
|
87
61
|
|
|
88
62
|
private activePreviewer: BaseInlineDiffPreviewer<InlineStreamDiffHandler> | undefined;
|
|
89
63
|
|
|
64
|
+
private pendingApplyParams:
|
|
65
|
+
| {
|
|
66
|
+
relativePath: string;
|
|
67
|
+
newContent: string;
|
|
68
|
+
range?: Range;
|
|
69
|
+
}
|
|
70
|
+
| undefined;
|
|
71
|
+
|
|
90
72
|
@OnEvent(EditorGroupCloseEvent)
|
|
91
73
|
onEditorGroupClose(event: EditorGroupCloseEvent) {
|
|
92
74
|
if (this.activePreviewer?.getNode()?.uri.path.toString() === event.payload.resource.uri.path.toString()) {
|
|
@@ -95,195 +77,187 @@ export abstract class BaseApplyService extends WithEventBus {
|
|
|
95
77
|
}
|
|
96
78
|
}
|
|
97
79
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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!);
|
|
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;
|
|
111
86
|
}
|
|
87
|
+
const blockId = this.generateBlockId(relativeOrAbsolutePath, messageId);
|
|
88
|
+
return this.codeBlockMapObservable.get().get(blockId);
|
|
112
89
|
}
|
|
113
90
|
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
);
|
|
91
|
+
getCodeBlockById(id: string): CodeBlockData | undefined {
|
|
92
|
+
return this.codeBlockMapObservable.get().get(id);
|
|
128
93
|
}
|
|
129
94
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
if (!codeBlockMap) {
|
|
137
|
-
return undefined;
|
|
138
|
-
}
|
|
139
|
-
return codeBlockMap[toolCallId];
|
|
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
|
+
});
|
|
140
101
|
}
|
|
141
102
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if (!
|
|
149
|
-
|
|
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
|
+
});
|
|
150
118
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
codeBlockMap,
|
|
154
|
-
});
|
|
155
|
-
this.onCodeBlockUpdateEmitter.fire(codeBlock);
|
|
119
|
+
|
|
120
|
+
return blockId;
|
|
156
121
|
}
|
|
157
122
|
|
|
158
|
-
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
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
|
-
}
|
|
123
|
+
initToolCallId(blockId: string, toolCallId: string): void {
|
|
124
|
+
const blockData = this.getCodeBlockById(blockId);
|
|
125
|
+
if (blockData && !blockData.initToolCallId) {
|
|
126
|
+
blockData.initToolCallId = toolCallId;
|
|
181
127
|
}
|
|
182
|
-
savedCodeBlockMap[toolCallId] = newBlock;
|
|
183
|
-
this.chatInternalService.sessionModel.history.setMessageAdditional(lastMessageId, {
|
|
184
|
-
codeBlockMap: savedCodeBlockMap,
|
|
185
|
-
});
|
|
186
|
-
this.onCodeBlockUpdateEmitter.fire(newBlock);
|
|
187
|
-
return newBlock;
|
|
188
128
|
}
|
|
189
129
|
|
|
190
130
|
/**
|
|
191
131
|
* Apply changes of a code block
|
|
192
132
|
*/
|
|
193
|
-
async apply(
|
|
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
|
+
}
|
|
194
138
|
try {
|
|
195
|
-
if (
|
|
196
|
-
throw new Error('
|
|
197
|
-
}
|
|
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);
|
|
139
|
+
if (++blockData.iterationCount > 3) {
|
|
140
|
+
throw new Error('Max iteration count exceeded');
|
|
213
141
|
}
|
|
214
|
-
|
|
215
|
-
|
|
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;
|
|
216
149
|
} catch (err) {
|
|
217
|
-
|
|
218
|
-
this.updateCodeBlock(
|
|
150
|
+
blockData.status = 'failed';
|
|
151
|
+
this.updateCodeBlock(blockData);
|
|
219
152
|
throw err;
|
|
220
153
|
}
|
|
221
154
|
}
|
|
222
155
|
|
|
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
|
+
|
|
223
172
|
async renderApplyResult(
|
|
224
|
-
|
|
225
|
-
|
|
173
|
+
relativePath: string,
|
|
174
|
+
newContent: string,
|
|
226
175
|
range?: Range,
|
|
227
176
|
): Promise<{ diff: string; diagnosticInfos: IMarker[] } | undefined> {
|
|
228
|
-
|
|
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
|
+
}
|
|
229
187
|
const openResult = await this.editorService.open(URI.file(path.join(this.appConfig.workspaceDir, relativePath)));
|
|
230
188
|
if (!openResult) {
|
|
231
189
|
throw new Error('Failed to open editor');
|
|
232
190
|
}
|
|
233
191
|
const editor = openResult.group.codeEditor.monacoEditor;
|
|
234
192
|
const inlineDiffController = InlineDiffController.get(editor)!;
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
this.eventBus.fire(new RegisterEditorSideComponentEvent());
|
|
238
|
-
this.updateCodeBlock(codeBlock);
|
|
193
|
+
blockData.status = 'pending';
|
|
194
|
+
this.updateCodeBlock(blockData);
|
|
239
195
|
|
|
240
|
-
const fullOriginalContent = editor.getModel()!.getValue();
|
|
241
196
|
range = range || editor.getModel()?.getFullModelRange()!;
|
|
242
|
-
//
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
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;
|
|
207
|
+
|
|
208
|
+
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();
|
|
258
214
|
} else {
|
|
259
|
-
|
|
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;
|
|
215
|
+
previewer.setValue(newContent);
|
|
271
216
|
this.addDispose(
|
|
272
|
-
this.
|
|
273
|
-
|
|
274
|
-
|
|
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
|
+
}
|
|
275
249
|
}),
|
|
276
250
|
);
|
|
277
251
|
}
|
|
278
|
-
|
|
279
|
-
return this.listenPartialEdit(editor, codeBlock, fullOriginalContent);
|
|
252
|
+
return deferred.promise;
|
|
280
253
|
}
|
|
281
254
|
|
|
282
255
|
/**
|
|
283
256
|
* Cancel an ongoing apply operation
|
|
284
257
|
*/
|
|
285
|
-
cancelApply(
|
|
286
|
-
|
|
258
|
+
cancelApply(relativePath: string): void {
|
|
259
|
+
const blockData = this.getCodeBlock(relativePath);
|
|
260
|
+
if (blockData && (blockData.status === 'generating' || blockData.status === 'pending')) {
|
|
287
261
|
if (this.activePreviewer) {
|
|
288
262
|
this.activePreviewer.getNode()?.livePreviewDiffDecorationModel.discardUnProcessed();
|
|
289
263
|
this.activePreviewer.dispose();
|
|
@@ -293,105 +267,62 @@ export abstract class BaseApplyService extends WithEventBus {
|
|
|
293
267
|
}
|
|
294
268
|
}
|
|
295
269
|
|
|
296
|
-
// TODO: 目前的设计下,有一个工具 apply 没返回,是不会触发下一个的(cursor 是会全部自动 apply 的),所以这个方法目前还没有必要
|
|
297
270
|
cancelAllApply(): void {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
}
|
|
303
|
-
Object.values(codeBlockMap).forEach((blockData) => {
|
|
304
|
-
this.cancelApply(blockData);
|
|
271
|
+
this.codeBlockMapObservable.get().forEach((blockData) => {
|
|
272
|
+
if (blockData.status === 'generating' || blockData.status === 'pending') {
|
|
273
|
+
this.cancelApply(blockData.relativePath);
|
|
274
|
+
}
|
|
305
275
|
});
|
|
306
276
|
}
|
|
307
277
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
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
|
-
}
|
|
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
|
+
});
|
|
323
287
|
}
|
|
324
288
|
|
|
325
|
-
|
|
326
|
-
const
|
|
327
|
-
if (
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
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
|
+
}
|
|
338
306
|
}
|
|
339
|
-
this.editorService.save(uri);
|
|
340
|
-
codeBlock.status = type === 'accept' ? 'success' : 'cancelled';
|
|
341
|
-
this.updateCodeBlock(codeBlock);
|
|
342
307
|
}
|
|
343
308
|
|
|
344
|
-
protected
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
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;
|
|
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 || '-'}`;
|
|
381
323
|
}
|
|
382
324
|
|
|
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[]) {
|
|
325
|
+
protected getdiagnosticInfos(uri: string, ranges: Range[]) {
|
|
395
326
|
const markers = this.markerService.getManager().getMarkers({ resource: uri });
|
|
396
327
|
return markers.filter(
|
|
397
328
|
(marker) =>
|
|
@@ -400,3 +331,19 @@ export abstract class BaseApplyService extends WithEventBus {
|
|
|
400
331
|
);
|
|
401
332
|
}
|
|
402
333
|
}
|
|
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';
|