@opensumi/ide-ai-native 3.8.3-next-1741763229.0 → 3.8.3-next-1741763277.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/chat/chat-agent.service.d.ts +1 -1
- package/lib/browser/chat/chat-agent.service.d.ts.map +1 -1
- package/lib/browser/chat/chat-agent.service.js +7 -7
- package/lib/browser/chat/chat-agent.service.js.map +1 -1
- package/lib/browser/chat/chat.view.d.ts.map +1 -1
- package/lib/browser/chat/chat.view.js +18 -49
- package/lib/browser/chat/chat.view.js.map +1 -1
- package/lib/browser/components/{chat-context/context-selector.d.ts → ChatContext/ContextSelector.d.ts} +1 -1
- package/lib/browser/components/ChatContext/ContextSelector.d.ts.map +1 -0
- package/lib/browser/components/{chat-context/context-selector.js → ChatContext/ContextSelector.js} +1 -1
- package/lib/browser/components/ChatContext/ContextSelector.js.map +1 -0
- package/lib/browser/components/ChatContext/index.d.ts.map +1 -0
- package/lib/browser/components/{chat-context → ChatContext}/index.js +2 -2
- package/lib/browser/components/ChatContext/index.js.map +1 -0
- package/lib/browser/components/ChatEditor.d.ts +2 -5
- package/lib/browser/components/ChatEditor.d.ts.map +1 -1
- package/lib/browser/components/ChatEditor.js +6 -45
- package/lib/browser/components/ChatEditor.js.map +1 -1
- package/lib/browser/components/components.module.less +0 -19
- package/lib/browser/context/llm-context.service.d.ts +2 -10
- package/lib/browser/context/llm-context.service.d.ts.map +1 -1
- package/lib/browser/context/llm-context.service.js +2 -71
- package/lib/browser/context/llm-context.service.js.map +1 -1
- package/lib/common/llm-context.d.ts +1 -15
- package/lib/common/llm-context.d.ts.map +1 -1
- package/lib/common/llm-context.js.map +1 -1
- package/lib/common/prompts/context-prompt-provider.d.ts +2 -12
- package/lib/common/prompts/context-prompt-provider.d.ts.map +1 -1
- package/lib/common/prompts/context-prompt-provider.js +30 -94
- package/lib/common/prompts/context-prompt-provider.js.map +1 -1
- package/package.json +23 -23
- package/src/browser/chat/chat-agent.service.ts +7 -7
- package/src/browser/chat/chat.view.tsx +20 -63
- package/src/browser/components/{chat-context → ChatContext}/index.tsx +1 -1
- package/src/browser/components/ChatEditor.tsx +9 -72
- package/src/browser/components/components.module.less +0 -19
- package/src/browser/context/llm-context.service.ts +3 -81
- package/src/common/llm-context.ts +1 -16
- package/src/common/prompts/context-prompt-provider.ts +36 -126
- package/lib/browser/components/ChatMentionInput.d.ts +0 -25
- package/lib/browser/components/ChatMentionInput.d.ts.map +0 -1
- package/lib/browser/components/ChatMentionInput.js +0 -221
- package/lib/browser/components/ChatMentionInput.js.map +0 -1
- package/lib/browser/components/chat-context/context-selector.d.ts.map +0 -1
- package/lib/browser/components/chat-context/context-selector.js.map +0 -1
- package/lib/browser/components/chat-context/index.d.ts.map +0 -1
- package/lib/browser/components/chat-context/index.js.map +0 -1
- package/lib/browser/components/mention-input/mention-input.d.ts +0 -5
- package/lib/browser/components/mention-input/mention-input.d.ts.map +0 -1
- package/lib/browser/components/mention-input/mention-input.js +0 -753
- package/lib/browser/components/mention-input/mention-input.js.map +0 -1
- package/lib/browser/components/mention-input/mention-input.module.less +0 -327
- package/lib/browser/components/mention-input/mention-item.d.ts +0 -10
- package/lib/browser/components/mention-input/mention-item.d.ts.map +0 -1
- package/lib/browser/components/mention-input/mention-item.js +0 -16
- package/lib/browser/components/mention-input/mention-item.js.map +0 -1
- package/lib/browser/components/mention-input/mention-panel.d.ts +0 -15
- package/lib/browser/components/mention-input/mention-panel.d.ts.map +0 -1
- package/lib/browser/components/mention-input/mention-panel.js +0 -49
- package/lib/browser/components/mention-input/mention-panel.js.map +0 -1
- package/lib/browser/components/mention-input/types.d.ts +0 -76
- package/lib/browser/components/mention-input/types.d.ts.map +0 -1
- package/lib/browser/components/mention-input/types.js +0 -16
- package/lib/browser/components/mention-input/types.js.map +0 -1
- package/src/browser/components/ChatMentionInput.tsx +0 -268
- package/src/browser/components/mention-input/mention-input.module.less +0 -327
- package/src/browser/components/mention-input/mention-input.tsx +0 -943
- package/src/browser/components/mention-input/mention-item.tsx +0 -24
- package/src/browser/components/mention-input/mention-panel.tsx +0 -89
- package/src/browser/components/mention-input/types.ts +0 -82
- /package/lib/browser/components/{chat-context → ChatContext}/index.d.ts +0 -0
- /package/lib/browser/components/{chat-context → ChatContext}/style.module.less +0 -0
- /package/src/browser/components/{chat-context/context-selector.tsx → ChatContext/ContextSelector.tsx} +0 -0
- /package/src/browser/components/{chat-context → ChatContext}/style.module.less +0 -0
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { MessageList } from 'react-chat-elements';
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
AINativeConfigService,
|
|
6
|
-
AppConfig,
|
|
7
|
-
LabelService,
|
|
8
|
-
getIcon,
|
|
9
|
-
useInjectable,
|
|
10
|
-
useUpdateOnEvent,
|
|
11
|
-
} from '@opensumi/ide-core-browser';
|
|
4
|
+
import { AppConfig, getIcon, useInjectable, useUpdateOnEvent } from '@opensumi/ide-core-browser';
|
|
12
5
|
import { Popover, PopoverPosition } from '@opensumi/ide-core-browser/lib/components';
|
|
13
6
|
import { EnhanceIcon } from '@opensumi/ide-core-browser/lib/components/ai-native';
|
|
14
7
|
import {
|
|
@@ -38,14 +31,13 @@ import { IMessageService } from '@opensumi/ide-overlay';
|
|
|
38
31
|
|
|
39
32
|
import 'react-chat-elements/dist/main.css';
|
|
40
33
|
import { AI_CHAT_VIEW_ID, IChatAgentService, IChatInternalService, IChatMessageStructure } from '../../common';
|
|
41
|
-
import { LLMContextService, LLMContextServiceToken } from '../../common/llm-context';
|
|
42
34
|
import { CodeBlockData } from '../../common/types';
|
|
43
35
|
import { FileChange, FileListDisplay } from '../components/ChangeList';
|
|
36
|
+
import { ChatContext } from '../components/ChatContext';
|
|
44
37
|
import { CodeBlockWrapperInput } from '../components/ChatEditor';
|
|
45
38
|
import ChatHistory, { IChatHistoryItem } from '../components/ChatHistory';
|
|
46
39
|
import { ChatInput } from '../components/ChatInput';
|
|
47
40
|
import { ChatMarkdown } from '../components/ChatMarkdown';
|
|
48
|
-
import { ChatMentionInput } from '../components/ChatMentionInput';
|
|
49
41
|
import { ChatNotify, ChatReply } from '../components/ChatReply';
|
|
50
42
|
import { SlashCustomRender } from '../components/SlashCustomRender';
|
|
51
43
|
import { MessageData, createMessageByAI, createMessageByUser } from '../components/utils';
|
|
@@ -113,8 +105,6 @@ export const AIChatView = () => {
|
|
|
113
105
|
const chatFeatureRegistry = useInjectable<ChatFeatureRegistry>(ChatFeatureRegistryToken);
|
|
114
106
|
const chatRenderRegistry = useInjectable<ChatRenderRegistry>(ChatRenderRegistryToken);
|
|
115
107
|
const mcpServerRegistry = useInjectable<IMCPServerRegistry>(TokenMCPServerRegistry);
|
|
116
|
-
const aiNativeConfigService = useInjectable<AINativeConfigService>(AINativeConfigService);
|
|
117
|
-
const llmContextService = useInjectable<LLMContextService>(LLMContextServiceToken);
|
|
118
108
|
|
|
119
109
|
const layoutService = useInjectable<IMainLayoutService>(IMainLayoutService);
|
|
120
110
|
const msgHistoryManager = aiChatService.sessionModel.history;
|
|
@@ -124,7 +114,6 @@ export const AIChatView = () => {
|
|
|
124
114
|
const editorService = useInjectable<WorkbenchEditorService>(WorkbenchEditorService);
|
|
125
115
|
const appConfig = useInjectable<AppConfig>(AppConfig);
|
|
126
116
|
const applyService = useInjectable<BaseApplyService>(BaseApplyService);
|
|
127
|
-
const labelService = useInjectable<LabelService>(LabelService);
|
|
128
117
|
const [shortcutCommands, setShortcutCommands] = React.useState<ChatSlashCommandItemModel[]>([]);
|
|
129
118
|
|
|
130
119
|
const [changeList, setChangeList] = React.useState<FileChange[]>(getFileChanges(applyService.getSessionCodeBlocks()));
|
|
@@ -195,9 +184,6 @@ export const AIChatView = () => {
|
|
|
195
184
|
if (chatRenderRegistry.chatInputRender) {
|
|
196
185
|
return chatRenderRegistry.chatInputRender;
|
|
197
186
|
}
|
|
198
|
-
if (aiNativeConfigService.capabilities.supportsMCP) {
|
|
199
|
-
return ChatMentionInput;
|
|
200
|
-
}
|
|
201
187
|
return ChatInput;
|
|
202
188
|
}, [chatRenderRegistry.chatInputRender]);
|
|
203
189
|
|
|
@@ -276,7 +262,7 @@ export const AIChatView = () => {
|
|
|
276
262
|
if (loading) {
|
|
277
263
|
return;
|
|
278
264
|
}
|
|
279
|
-
await handleSend(message
|
|
265
|
+
await handleSend(message);
|
|
280
266
|
} else {
|
|
281
267
|
if (message.agentId) {
|
|
282
268
|
setAgentId(message.agentId);
|
|
@@ -363,7 +349,6 @@ export const AIChatView = () => {
|
|
|
363
349
|
text={message}
|
|
364
350
|
agentId={visibleAgentId}
|
|
365
351
|
command={command}
|
|
366
|
-
labelService={labelService}
|
|
367
352
|
/>
|
|
368
353
|
),
|
|
369
354
|
},
|
|
@@ -469,13 +454,7 @@ export const AIChatView = () => {
|
|
|
469
454
|
text: ChatUserRoleRender ? (
|
|
470
455
|
<ChatUserRoleRender content={message} agentId={visibleAgentId} command={command} />
|
|
471
456
|
) : (
|
|
472
|
-
<CodeBlockWrapperInput
|
|
473
|
-
labelService={labelService}
|
|
474
|
-
relationId={relationId}
|
|
475
|
-
text={message}
|
|
476
|
-
agentId={visibleAgentId}
|
|
477
|
-
command={command}
|
|
478
|
-
/>
|
|
457
|
+
<CodeBlockWrapperInput relationId={relationId} text={message} agentId={visibleAgentId} command={command} />
|
|
479
458
|
),
|
|
480
459
|
},
|
|
481
460
|
styles.chat_message_code,
|
|
@@ -659,44 +638,11 @@ export const AIChatView = () => {
|
|
|
659
638
|
);
|
|
660
639
|
|
|
661
640
|
const handleSend = React.useCallback(
|
|
662
|
-
async (
|
|
663
|
-
const reportExtra =
|
|
664
|
-
actionSource: ActionSourceEnum.Chat,
|
|
665
|
-
actionType: ActionTypeEnum.Send,
|
|
666
|
-
};
|
|
667
|
-
agentId = agentId ? agentId : ChatProxyService.AGENT_ID;
|
|
668
|
-
// 提取并替换 {{@file:xxx}} 中的文件内容
|
|
669
|
-
let processedContent = message;
|
|
670
|
-
const filePattern = /\{\{@file:(.*?)\}\}/g;
|
|
671
|
-
const fileMatches = message.match(filePattern);
|
|
672
|
-
let isCleanContext = false;
|
|
673
|
-
if (fileMatches) {
|
|
674
|
-
for (const match of fileMatches) {
|
|
675
|
-
const filePath = match.replace(/\{\{@file:(.*?)\}\}/, '$1');
|
|
676
|
-
if (filePath && !isCleanContext) {
|
|
677
|
-
isCleanContext = true;
|
|
678
|
-
llmContextService.cleanFileContext();
|
|
679
|
-
}
|
|
680
|
-
const fileUri = new URI(filePath);
|
|
681
|
-
llmContextService.addFileToContext(fileUri, undefined, true);
|
|
682
|
-
// 获取文件内容
|
|
683
|
-
// 替换占位符,后续支持自定义渲染时可替换为自定义渲染标签
|
|
684
|
-
processedContent = processedContent.replace(match, `\`<attached_file>${fileUri.displayName}\``);
|
|
685
|
-
}
|
|
686
|
-
}
|
|
641
|
+
async (value: IChatMessageStructure) => {
|
|
642
|
+
const { message, command, reportExtra } = value;
|
|
687
643
|
|
|
688
|
-
const
|
|
689
|
-
|
|
690
|
-
if (folderMatches) {
|
|
691
|
-
for (const match of folderMatches) {
|
|
692
|
-
const folderPath = match.replace(/\{\{@folder:(.*?)\}\}/, '$1');
|
|
693
|
-
const folderUri = new URI(folderPath);
|
|
694
|
-
llmContextService.addFolderToContext(folderUri);
|
|
695
|
-
// 替换占位符,后续支持自定义渲染时可替换为自定义渲染标签
|
|
696
|
-
processedContent = processedContent.replace(match, `\`<attached_folder>${folderUri.displayName}\``);
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
return handleAgentReply({ message: processedContent, agentId, command, reportExtra });
|
|
644
|
+
const agentId = value.agentId ? value.agentId : ChatProxyService.AGENT_ID;
|
|
645
|
+
return handleAgentReply({ message, agentId, command, reportExtra });
|
|
700
646
|
},
|
|
701
647
|
[handleAgentReply],
|
|
702
648
|
);
|
|
@@ -813,6 +759,7 @@ export const AIChatView = () => {
|
|
|
813
759
|
</div>
|
|
814
760
|
) : null}
|
|
815
761
|
<div className={styles.chat_input_wrap}>
|
|
762
|
+
<ChatContext />
|
|
816
763
|
<div className={styles.header_operate}>
|
|
817
764
|
<div className={styles.header_operate_left}>
|
|
818
765
|
{shortcutCommands.map((command) => (
|
|
@@ -843,7 +790,17 @@ export const AIChatView = () => {
|
|
|
843
790
|
/>
|
|
844
791
|
)}
|
|
845
792
|
<ChatInputWrapperRender
|
|
846
|
-
onSend={
|
|
793
|
+
onSend={(value, agentId, command) =>
|
|
794
|
+
handleSend({
|
|
795
|
+
message: value,
|
|
796
|
+
agentId,
|
|
797
|
+
command,
|
|
798
|
+
reportExtra: {
|
|
799
|
+
actionSource: ActionSourceEnum.Chat,
|
|
800
|
+
actionType: ActionTypeEnum.Send,
|
|
801
|
+
},
|
|
802
|
+
})
|
|
803
|
+
}
|
|
847
804
|
disabled={loading}
|
|
848
805
|
enableOptions={true}
|
|
849
806
|
theme={theme}
|
|
@@ -15,7 +15,7 @@ import { WorkbenchEditorService } from '@opensumi/ide-editor/lib/browser/types';
|
|
|
15
15
|
|
|
16
16
|
import { FileContext, LLMContextService, LLMContextServiceToken } from '../../../common/llm-context';
|
|
17
17
|
|
|
18
|
-
import { ContextSelector } from './
|
|
18
|
+
import { ContextSelector } from './ContextSelector';
|
|
19
19
|
import styles from './style.module.less';
|
|
20
20
|
|
|
21
21
|
const getCollapsedHeight = () => ({ height: 0, opacity: 0 });
|
|
@@ -2,15 +2,14 @@ import capitalize from 'lodash/capitalize';
|
|
|
2
2
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
3
3
|
import Highlight from 'react-highlight';
|
|
4
4
|
|
|
5
|
-
import { IClipboardService,
|
|
6
|
-
import {
|
|
5
|
+
import { IClipboardService, getIcon, useInjectable, uuid } from '@opensumi/ide-core-browser';
|
|
6
|
+
import { Popover } from '@opensumi/ide-core-browser/lib/components';
|
|
7
7
|
import { EnhanceIcon } from '@opensumi/ide-core-browser/lib/components/ai-native';
|
|
8
8
|
import {
|
|
9
9
|
ActionSourceEnum,
|
|
10
10
|
ActionTypeEnum,
|
|
11
11
|
ChatFeatureRegistryToken,
|
|
12
12
|
IAIReporter,
|
|
13
|
-
URI,
|
|
14
13
|
localize,
|
|
15
14
|
runWhenIdle,
|
|
16
15
|
} from '@opensumi/ide-core-common';
|
|
@@ -140,26 +139,16 @@ const CodeBlock = ({
|
|
|
140
139
|
renderText,
|
|
141
140
|
agentId = '',
|
|
142
141
|
command = '',
|
|
143
|
-
labelService,
|
|
144
142
|
}: {
|
|
145
143
|
content?: string;
|
|
146
144
|
relationId: string;
|
|
147
145
|
renderText?: (t: string) => React.ReactNode;
|
|
148
146
|
agentId?: string;
|
|
149
147
|
command?: string;
|
|
150
|
-
labelService?: LabelService;
|
|
151
148
|
}) => {
|
|
152
149
|
const rgInlineCode = /`([^`]+)`/g;
|
|
153
150
|
const rgBlockCode = /```([^]+?)```/g;
|
|
154
151
|
const rgBlockCodeBefore = /```([^]+)?/g;
|
|
155
|
-
const rgAttachedFile = /<attached_file>(.*)/g;
|
|
156
|
-
const rgAttachedFolder = /<attached_folder>(.*)/g;
|
|
157
|
-
const renderAttachment = (text: string, isFolder = false, key: string) => (
|
|
158
|
-
<span className={styles.attachment} key={key}>
|
|
159
|
-
<Icon iconClass={isFolder ? getIcon('folder') : labelService?.getIcon(new URI(text || 'file'))} />
|
|
160
|
-
<span className={styles.attachment_text}>{text}</span>
|
|
161
|
-
</span>
|
|
162
|
-
);
|
|
163
152
|
|
|
164
153
|
const renderCodeEditor = (content: string) => {
|
|
165
154
|
const language = content.split('\n')[0].trim().toLowerCase();
|
|
@@ -204,47 +193,11 @@ const CodeBlock = ({
|
|
|
204
193
|
renderedContent.push(text);
|
|
205
194
|
}
|
|
206
195
|
} else {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
let lastIndex = 0;
|
|
213
|
-
const fragments: (string | React.ReactNode)[] = [];
|
|
214
|
-
|
|
215
|
-
// 处理文件标记
|
|
216
|
-
fileMatches.forEach((match, matchIndex) => {
|
|
217
|
-
if (match.index !== undefined) {
|
|
218
|
-
const spanText = processedText.slice(lastIndex, match.index);
|
|
219
|
-
if (spanText) {
|
|
220
|
-
fragments.push(<span key={`${index}-${matchIndex}`}>{spanText}</span>);
|
|
221
|
-
}
|
|
222
|
-
fragments.push(renderAttachment(match[1], false, `${index}-tag-${matchIndex}`));
|
|
223
|
-
lastIndex = match.index + match[0].length;
|
|
224
|
-
}
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
// 处理文件夹标记
|
|
228
|
-
folderMatches.forEach((match, matchIndex) => {
|
|
229
|
-
if (match.index !== undefined) {
|
|
230
|
-
const spanText = processedText.slice(lastIndex, match.index);
|
|
231
|
-
if (spanText) {
|
|
232
|
-
fragments.push(<span key={`${index}-${matchIndex}`}>{spanText}</span>);
|
|
233
|
-
}
|
|
234
|
-
fragments.push(renderAttachment(match[1], true, `${index}-tag-${matchIndex}`));
|
|
235
|
-
lastIndex = match.index + match[0].length;
|
|
236
|
-
}
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
fragments.push(processedText.slice(lastIndex));
|
|
240
|
-
renderedContent.push(...fragments);
|
|
241
|
-
} else {
|
|
242
|
-
renderedContent.push(
|
|
243
|
-
<span className={styles.code_inline} key={index}>
|
|
244
|
-
{text}
|
|
245
|
-
</span>,
|
|
246
|
-
);
|
|
247
|
-
}
|
|
196
|
+
renderedContent.push(
|
|
197
|
+
<span className={styles.code_inline} key={index}>
|
|
198
|
+
{text}
|
|
199
|
+
</span>,
|
|
200
|
+
);
|
|
248
201
|
}
|
|
249
202
|
});
|
|
250
203
|
} else {
|
|
@@ -263,23 +216,15 @@ export const CodeBlockWrapper = ({
|
|
|
263
216
|
renderText,
|
|
264
217
|
relationId,
|
|
265
218
|
agentId,
|
|
266
|
-
labelService,
|
|
267
219
|
}: {
|
|
268
220
|
text?: string;
|
|
269
221
|
relationId: string;
|
|
270
222
|
renderText?: (t: string) => React.ReactNode;
|
|
271
223
|
agentId?: string;
|
|
272
|
-
labelService?: LabelService;
|
|
273
224
|
}) => (
|
|
274
225
|
<div className={styles.ai_chat_code_wrapper}>
|
|
275
226
|
<div className={styles.render_text}>
|
|
276
|
-
<CodeBlock
|
|
277
|
-
content={text}
|
|
278
|
-
labelService={labelService}
|
|
279
|
-
renderText={renderText}
|
|
280
|
-
relationId={relationId}
|
|
281
|
-
agentId={agentId}
|
|
282
|
-
/>
|
|
227
|
+
<CodeBlock content={text} renderText={renderText} relationId={relationId} agentId={agentId} />
|
|
283
228
|
</div>
|
|
284
229
|
</div>
|
|
285
230
|
);
|
|
@@ -289,13 +234,11 @@ export const CodeBlockWrapperInput = ({
|
|
|
289
234
|
relationId,
|
|
290
235
|
agentId,
|
|
291
236
|
command,
|
|
292
|
-
labelService,
|
|
293
237
|
}: {
|
|
294
238
|
text: string;
|
|
295
239
|
relationId: string;
|
|
296
240
|
agentId?: string;
|
|
297
241
|
command?: string;
|
|
298
|
-
labelService?: LabelService;
|
|
299
242
|
}) => {
|
|
300
243
|
const chatFeatureRegistry = useInjectable<ChatFeatureRegistry>(ChatFeatureRegistryToken);
|
|
301
244
|
const [tag, setTag] = useState<string>('');
|
|
@@ -328,13 +271,7 @@ export const CodeBlockWrapperInput = ({
|
|
|
328
271
|
</div>
|
|
329
272
|
)}
|
|
330
273
|
{command && <div className={styles.tag}>/ {command}</div>}
|
|
331
|
-
<CodeBlock
|
|
332
|
-
content={txt}
|
|
333
|
-
labelService={labelService}
|
|
334
|
-
relationId={relationId}
|
|
335
|
-
agentId={agentId}
|
|
336
|
-
command={command}
|
|
337
|
-
/>
|
|
274
|
+
<CodeBlock content={txt} relationId={relationId} agentId={agentId} command={command} />
|
|
338
275
|
</div>
|
|
339
276
|
</div>
|
|
340
277
|
);
|
|
@@ -519,7 +519,6 @@
|
|
|
519
519
|
display: flex;
|
|
520
520
|
font-size: 11px;
|
|
521
521
|
align-items: center;
|
|
522
|
-
min-width: 150px;
|
|
523
522
|
}
|
|
524
523
|
|
|
525
524
|
.mcp_desc {
|
|
@@ -566,21 +565,3 @@
|
|
|
566
565
|
color: var(--descriptionForeground);
|
|
567
566
|
}
|
|
568
567
|
}
|
|
569
|
-
|
|
570
|
-
.attachment {
|
|
571
|
-
display: inline-flex;
|
|
572
|
-
align-items: center;
|
|
573
|
-
padding: 0 4px;
|
|
574
|
-
margin: 0 2px;
|
|
575
|
-
background: var(--badge-background);
|
|
576
|
-
color: var(--badge-foreground);
|
|
577
|
-
border-radius: 3px;
|
|
578
|
-
vertical-align: middle;
|
|
579
|
-
font-size: 12px;
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
.attachment_text {
|
|
583
|
-
line-height: 20px;
|
|
584
|
-
vertical-align: middle;
|
|
585
|
-
font-size: 12px;
|
|
586
|
-
}
|
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
IEditorDocumentModelService,
|
|
11
11
|
} from '@opensumi/ide-editor/lib/browser/doc-model/types';
|
|
12
12
|
import { EditorSelectionChangeEvent } from '@opensumi/ide-editor/lib/browser/types';
|
|
13
|
-
import { FileType, IFileServiceClient } from '@opensumi/ide-file-service';
|
|
14
13
|
import { IMarkerService } from '@opensumi/ide-markers/lib/common/types';
|
|
15
14
|
import { Range } from '@opensumi/ide-monaco';
|
|
16
15
|
|
|
@@ -27,18 +26,13 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
|
|
|
27
26
|
@Autowired(IMarkerService)
|
|
28
27
|
protected readonly markerService: IMarkerService;
|
|
29
28
|
|
|
30
|
-
@Autowired(IFileServiceClient)
|
|
31
|
-
protected readonly fileService: IFileServiceClient;
|
|
32
|
-
|
|
33
29
|
private isAutoCollecting = false;
|
|
34
30
|
|
|
35
31
|
private contextVersion = 0;
|
|
36
32
|
|
|
37
33
|
private readonly maxAttachFilesLimit = 10;
|
|
38
|
-
private readonly maxAttachFoldersLimit = 10;
|
|
39
34
|
private readonly maxViewFilesLimit = 20;
|
|
40
|
-
private attachedFiles: FileContext[] = [];
|
|
41
|
-
private attachedFolders: FileContext[] = [];
|
|
35
|
+
private readonly attachedFiles: FileContext[] = [];
|
|
42
36
|
private readonly recentlyViewFiles: FileContext[] = [];
|
|
43
37
|
private readonly onDidContextFilesChangeEmitter = new Emitter<{
|
|
44
38
|
viewed: FileContext[];
|
|
@@ -59,18 +53,6 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
|
|
|
59
53
|
}
|
|
60
54
|
}
|
|
61
55
|
|
|
62
|
-
private addFolderToList(folder: FileContext, list: FileContext[], maxLimit: number) {
|
|
63
|
-
const existingIndex = list.findIndex((f) => f.uri.toString() === folder.uri.toString());
|
|
64
|
-
if (existingIndex > -1) {
|
|
65
|
-
list.splice(existingIndex, 1);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
list.push(folder);
|
|
69
|
-
if (list.length > maxLimit) {
|
|
70
|
-
list.shift();
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
56
|
addFileToContext(uri: URI, selection?: [number, number], isManual = false): void {
|
|
75
57
|
if (!uri) {
|
|
76
58
|
return;
|
|
@@ -88,24 +70,12 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
|
|
|
88
70
|
this.notifyContextChange();
|
|
89
71
|
}
|
|
90
72
|
|
|
91
|
-
addFolderToContext(uri: URI): void {
|
|
92
|
-
if (!uri) {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const file = { uri };
|
|
97
|
-
|
|
98
|
-
this.addFolderToList(file, this.attachedFolders, this.maxAttachFoldersLimit);
|
|
99
|
-
this.notifyContextChange();
|
|
100
|
-
}
|
|
101
|
-
|
|
102
73
|
private notifyContextChange(): void {
|
|
103
74
|
this.onDidContextFilesChangeEmitter.fire(this.getAllContextFiles());
|
|
104
75
|
}
|
|
105
76
|
|
|
106
77
|
cleanFileContext() {
|
|
107
|
-
this.attachedFiles =
|
|
108
|
-
this.attachedFolders = [];
|
|
78
|
+
this.attachedFiles.length = 0;
|
|
109
79
|
this.notifyContextChange();
|
|
110
80
|
}
|
|
111
81
|
|
|
@@ -113,7 +83,6 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
|
|
|
113
83
|
return {
|
|
114
84
|
viewed: this.recentlyViewFiles,
|
|
115
85
|
attached: this.attachedFiles,
|
|
116
|
-
attachedFolders: this.attachedFolders,
|
|
117
86
|
version: this.contextVersion++,
|
|
118
87
|
};
|
|
119
88
|
}
|
|
@@ -191,63 +160,16 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
|
|
|
191
160
|
this.dispose();
|
|
192
161
|
}
|
|
193
162
|
|
|
194
|
-
|
|
163
|
+
serialize(): SerializedContext {
|
|
195
164
|
const files = this.getAllContextFiles();
|
|
196
165
|
const workspaceRoot = URI.file(this.appConfig.workspaceDir);
|
|
197
166
|
|
|
198
167
|
return {
|
|
199
168
|
recentlyViewFiles: this.serializeRecentlyViewFiles(files.viewed, workspaceRoot),
|
|
200
169
|
attachedFiles: this.serializeAttachedFiles(files.attached, workspaceRoot),
|
|
201
|
-
attachedFolders: await this.serializeAttachedFolders(files.attachedFolders, workspaceRoot),
|
|
202
170
|
};
|
|
203
171
|
}
|
|
204
172
|
|
|
205
|
-
private async serializeAttachedFolders(folders: FileContext[], workspaceRoot: URI): Promise<string[]> {
|
|
206
|
-
// 去重
|
|
207
|
-
const folderPath = Array.from(new Set(folders.map((folder) => folder.uri.toString())));
|
|
208
|
-
return Promise.all(
|
|
209
|
-
folderPath.map(async (folder) => {
|
|
210
|
-
const folderUri = new URI(folder);
|
|
211
|
-
const root = workspaceRoot.relative(folderUri)?.toString() || '/';
|
|
212
|
-
return `\`\`\`\n${root}\n${(await this.getPartiaFolderStructure(folderUri.codeUri.fsPath))
|
|
213
|
-
.map((line) => `- ${line}`)
|
|
214
|
-
.join('\n')}\n\`\`\`\n`;
|
|
215
|
-
}),
|
|
216
|
-
);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
private async getPartiaFolderStructure(folder: string, level = 2): Promise<string[]> {
|
|
220
|
-
const result: string[] = [];
|
|
221
|
-
const stat = await this.fileService.getFileStat(folder);
|
|
222
|
-
|
|
223
|
-
for (const child of stat?.children || []) {
|
|
224
|
-
const relativePath = new URI(folder).relative(new URI(child.uri))!.toString();
|
|
225
|
-
|
|
226
|
-
if (child.isSymbolicLink) {
|
|
227
|
-
// 处理软链接
|
|
228
|
-
const target = await this.fileService.getFileStat(child.realUri || child.uri);
|
|
229
|
-
if (target) {
|
|
230
|
-
result.push(`${relativePath} -> ${target} (symbolic link)`);
|
|
231
|
-
} else {
|
|
232
|
-
result.push(`${relativePath} (broken symbolic link)`);
|
|
233
|
-
}
|
|
234
|
-
continue;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
if (child.type === FileType.Directory) {
|
|
238
|
-
result.push(`${relativePath}/`);
|
|
239
|
-
if (level > 1) {
|
|
240
|
-
const subDirStructure = await this.getPartiaFolderStructure(child.uri, level - 1);
|
|
241
|
-
result.push(...subDirStructure.map((subEntry) => `${relativePath}/${subEntry}`));
|
|
242
|
-
}
|
|
243
|
-
} else if (child.type === FileType.File) {
|
|
244
|
-
result.push(relativePath);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
return result;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
173
|
private serializeRecentlyViewFiles(files: FileContext[], workspaceRoot: URI): string[] {
|
|
252
174
|
return files
|
|
253
175
|
.map((file) => workspaceRoot.relative(file.uri)?.toString() || file.uri.parent.toString())
|
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
import { Event, URI } from '@opensumi/ide-core-common/lib/utils';
|
|
2
2
|
|
|
3
3
|
export interface LLMContextService {
|
|
4
|
-
/**
|
|
5
|
-
* 开始自动收集
|
|
6
|
-
*/
|
|
7
4
|
startAutoCollection(): void;
|
|
8
5
|
|
|
9
|
-
/**
|
|
10
|
-
* 停止自动收集
|
|
11
|
-
*/
|
|
12
6
|
stopAutoCollection(): void;
|
|
13
7
|
|
|
14
8
|
/**
|
|
@@ -16,19 +10,11 @@ export interface LLMContextService {
|
|
|
16
10
|
*/
|
|
17
11
|
addFileToContext(uri: URI, selection?: [number, number], isManual?: boolean): void;
|
|
18
12
|
|
|
19
|
-
/**
|
|
20
|
-
* 添加文件夹到 context 中
|
|
21
|
-
*/
|
|
22
|
-
addFolderToContext(uri: URI, isManual?: boolean): void;
|
|
23
|
-
|
|
24
13
|
/**
|
|
25
14
|
* 清除上下文
|
|
26
15
|
*/
|
|
27
16
|
cleanFileContext(): void;
|
|
28
17
|
|
|
29
|
-
/**
|
|
30
|
-
* 上下文文件变化事件
|
|
31
|
-
*/
|
|
32
18
|
onDidContextFilesChangeEvent: Event<{ viewed: FileContext[]; attached: FileContext[]; version: number }>;
|
|
33
19
|
|
|
34
20
|
/**
|
|
@@ -38,7 +24,7 @@ export interface LLMContextService {
|
|
|
38
24
|
removeFileFromContext(uri: URI, isManual?: boolean): void;
|
|
39
25
|
|
|
40
26
|
/** 导出为可序列化格式 */
|
|
41
|
-
serialize():
|
|
27
|
+
serialize(): SerializedContext;
|
|
42
28
|
}
|
|
43
29
|
|
|
44
30
|
export interface FileContext {
|
|
@@ -58,5 +44,4 @@ export interface AttachFileContext {
|
|
|
58
44
|
export interface SerializedContext {
|
|
59
45
|
recentlyViewFiles: string[];
|
|
60
46
|
attachedFiles: Array<AttachFileContext>;
|
|
61
|
-
attachedFolders: string[];
|
|
62
47
|
}
|