@opensumi/ide-ai-native 3.8.3-next-1741917543.0 → 3.8.3-next-1741920696.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 +69 -31
- package/lib/browser/chat/chat.view.js.map +1 -1
- package/lib/browser/components/ChatEditor.d.ts +11 -2
- package/lib/browser/components/ChatEditor.d.ts.map +1 -1
- package/lib/browser/components/ChatEditor.js +60 -6
- package/lib/browser/components/ChatEditor.js.map +1 -1
- package/lib/browser/components/ChatHistory.d.ts.map +1 -1
- package/lib/browser/components/ChatHistory.js +15 -15
- package/lib/browser/components/ChatHistory.js.map +1 -1
- package/lib/browser/components/ChatMentionInput.d.ts +25 -0
- package/lib/browser/components/ChatMentionInput.d.ts.map +1 -0
- package/lib/browser/components/ChatMentionInput.js +229 -0
- package/lib/browser/components/ChatMentionInput.js.map +1 -0
- package/lib/browser/components/ChatThinking.d.ts +1 -1
- package/lib/browser/components/ChatThinking.d.ts.map +1 -1
- package/lib/browser/components/ChatThinking.js +8 -2
- package/lib/browser/components/ChatThinking.js.map +1 -1
- package/lib/browser/components/change-list.module.less +2 -0
- package/lib/browser/components/{ChatContext/ContextSelector.d.ts → chat-context/context-selector.d.ts} +1 -1
- package/lib/browser/components/chat-context/context-selector.d.ts.map +1 -0
- package/lib/browser/components/{ChatContext/ContextSelector.js → chat-context/context-selector.js} +1 -1
- package/lib/browser/components/chat-context/context-selector.js.map +1 -0
- package/lib/browser/components/chat-context/index.d.ts.map +1 -0
- package/lib/browser/components/{ChatContext → chat-context}/index.js +2 -2
- package/lib/browser/components/chat-context/index.js.map +1 -0
- package/lib/browser/components/chat-history.module.less +33 -16
- package/lib/browser/components/components.module.less +39 -3
- package/lib/browser/components/mention-input/mention-input.d.ts +5 -0
- package/lib/browser/components/mention-input/mention-input.d.ts.map +1 -0
- package/lib/browser/components/mention-input/mention-input.js +763 -0
- package/lib/browser/components/mention-input/mention-input.js.map +1 -0
- package/lib/browser/components/mention-input/mention-input.module.less +333 -0
- package/lib/browser/components/mention-input/mention-item.d.ts +10 -0
- package/lib/browser/components/mention-input/mention-item.d.ts.map +1 -0
- package/lib/browser/components/mention-input/mention-item.js +16 -0
- package/lib/browser/components/mention-input/mention-item.js.map +1 -0
- package/lib/browser/components/mention-input/mention-panel.d.ts +15 -0
- package/lib/browser/components/mention-input/mention-panel.d.ts.map +1 -0
- package/lib/browser/components/mention-input/mention-panel.js +49 -0
- package/lib/browser/components/mention-input/mention-panel.js.map +1 -0
- package/lib/browser/components/mention-input/types.d.ts +78 -0
- package/lib/browser/components/mention-input/types.d.ts.map +1 -0
- package/lib/browser/components/mention-input/types.js +16 -0
- package/lib/browser/components/mention-input/types.js.map +1 -0
- package/lib/browser/context/llm-context.service.d.ts +10 -2
- package/lib/browser/context/llm-context.service.d.ts.map +1 -1
- package/lib/browser/context/llm-context.service.js +76 -2
- package/lib/browser/context/llm-context.service.js.map +1 -1
- package/lib/browser/mcp/config/components/mcp-config.module.less +61 -30
- package/lib/browser/mcp/config/components/mcp-config.view.d.ts.map +1 -1
- package/lib/browser/mcp/config/components/mcp-config.view.js +17 -19
- package/lib/browser/mcp/config/components/mcp-config.view.js.map +1 -1
- package/lib/browser/mcp/config/components/mcp-server-form.js +1 -1
- package/lib/browser/mcp/config/components/mcp-server-form.js.map +1 -1
- package/lib/browser/mcp/config/components/mcp-server-form.module.less +3 -0
- package/lib/browser/mcp/mcp-server-proxy.service.d.ts +1 -0
- package/lib/browser/mcp/mcp-server-proxy.service.d.ts.map +1 -1
- package/lib/common/index.d.ts +2 -1
- package/lib/common/index.d.ts.map +1 -1
- package/lib/common/index.js +1 -1
- package/lib/common/llm-context.d.ts +15 -1
- 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 +12 -2
- package/lib/common/prompts/context-prompt-provider.d.ts.map +1 -1
- package/lib/common/prompts/context-prompt-provider.js +95 -30
- package/lib/common/prompts/context-prompt-provider.js.map +1 -1
- package/lib/common/types.d.ts +1 -1
- package/lib/common/types.d.ts.map +1 -1
- package/lib/common/utils.d.ts +1 -0
- package/lib/common/utils.d.ts.map +1 -1
- package/lib/common/utils.js +9 -1
- package/lib/common/utils.js.map +1 -1
- package/lib/node/mcp/sumi-mcp-server.d.ts +3 -3
- package/lib/node/mcp/sumi-mcp-server.d.ts.map +1 -1
- package/lib/node/mcp/sumi-mcp-server.js +11 -7
- package/lib/node/mcp/sumi-mcp-server.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 +81 -24
- package/src/browser/components/ChatEditor.tsx +128 -9
- package/src/browser/components/ChatHistory.tsx +16 -30
- package/src/browser/components/ChatMentionInput.tsx +276 -0
- package/src/browser/components/ChatThinking.tsx +10 -4
- package/src/browser/components/change-list.module.less +2 -0
- package/src/browser/components/{ChatContext → chat-context}/index.tsx +1 -1
- package/src/browser/components/chat-history.module.less +33 -16
- package/src/browser/components/components.module.less +39 -3
- package/src/browser/components/mention-input/mention-input.module.less +333 -0
- package/src/browser/components/mention-input/mention-input.tsx +952 -0
- package/src/browser/components/mention-input/mention-item.tsx +24 -0
- package/src/browser/components/mention-input/mention-panel.tsx +89 -0
- package/src/browser/components/mention-input/types.ts +84 -0
- package/src/browser/context/llm-context.service.ts +85 -3
- package/src/browser/mcp/config/components/mcp-config.module.less +61 -30
- package/src/browser/mcp/config/components/mcp-config.view.tsx +49 -32
- package/src/browser/mcp/config/components/mcp-server-form.module.less +3 -0
- package/src/browser/mcp/config/components/mcp-server-form.tsx +1 -1
- package/src/common/index.ts +2 -2
- package/src/common/llm-context.ts +16 -1
- package/src/common/prompts/context-prompt-provider.ts +130 -36
- package/src/common/types.ts +1 -1
- package/src/common/utils.ts +8 -0
- package/src/node/mcp/sumi-mcp-server.ts +11 -7
- package/lib/browser/components/ChatContext/ContextSelector.d.ts.map +0 -1
- package/lib/browser/components/ChatContext/ContextSelector.js.map +0 -1
- package/lib/browser/components/ChatContext/index.d.ts.map +0 -1
- package/lib/browser/components/ChatContext/index.js.map +0 -1
- /package/lib/browser/components/{ChatContext → chat-context}/index.d.ts +0 -0
- /package/lib/browser/components/{ChatContext → chat-context}/style.module.less +0 -0
- /package/src/browser/components/{ChatContext/ContextSelector.tsx → chat-context/context-selector.tsx} +0 -0
- /package/src/browser/components/{ChatContext → chat-context}/style.module.less +0 -0
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { MessageList } from 'react-chat-elements';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
AINativeConfigService,
|
|
6
|
+
AppConfig,
|
|
7
|
+
LabelService,
|
|
8
|
+
getIcon,
|
|
9
|
+
useInjectable,
|
|
10
|
+
useUpdateOnEvent,
|
|
11
|
+
} from '@opensumi/ide-core-browser';
|
|
5
12
|
import { Popover, PopoverPosition } from '@opensumi/ide-core-browser/lib/components';
|
|
6
13
|
import { EnhanceIcon } from '@opensumi/ide-core-browser/lib/components/ai-native';
|
|
7
14
|
import {
|
|
@@ -14,6 +21,7 @@ import {
|
|
|
14
21
|
ChatMessageRole,
|
|
15
22
|
ChatRenderRegistryToken,
|
|
16
23
|
ChatServiceToken,
|
|
24
|
+
CommandService,
|
|
17
25
|
Disposable,
|
|
18
26
|
DisposableCollection,
|
|
19
27
|
IAIReporter,
|
|
@@ -28,16 +36,19 @@ import {
|
|
|
28
36
|
import { WorkbenchEditorService } from '@opensumi/ide-editor';
|
|
29
37
|
import { IMainLayoutService } from '@opensumi/ide-main-layout';
|
|
30
38
|
import { IMessageService } from '@opensumi/ide-overlay';
|
|
31
|
-
|
|
32
39
|
import 'react-chat-elements/dist/main.css';
|
|
40
|
+
import { IWorkspaceService } from '@opensumi/ide-workspace';
|
|
41
|
+
|
|
33
42
|
import { AI_CHAT_VIEW_ID, IChatAgentService, IChatInternalService, IChatMessageStructure } from '../../common';
|
|
43
|
+
import { LLMContextService, LLMContextServiceToken } from '../../common/llm-context';
|
|
34
44
|
import { CodeBlockData } from '../../common/types';
|
|
45
|
+
import { cleanAttachedTextWrapper } from '../../common/utils';
|
|
35
46
|
import { FileChange, FileListDisplay } from '../components/ChangeList';
|
|
36
|
-
import { ChatContext } from '../components/ChatContext';
|
|
37
47
|
import { CodeBlockWrapperInput } from '../components/ChatEditor';
|
|
38
48
|
import ChatHistory, { IChatHistoryItem } from '../components/ChatHistory';
|
|
39
49
|
import { ChatInput } from '../components/ChatInput';
|
|
40
50
|
import { ChatMarkdown } from '../components/ChatMarkdown';
|
|
51
|
+
import { ChatMentionInput } from '../components/ChatMentionInput';
|
|
41
52
|
import { ChatNotify, ChatReply } from '../components/ChatReply';
|
|
42
53
|
import { SlashCustomRender } from '../components/SlashCustomRender';
|
|
43
54
|
import { MessageData, createMessageByAI, createMessageByUser } from '../components/utils';
|
|
@@ -105,6 +116,8 @@ export const AIChatView = () => {
|
|
|
105
116
|
const chatFeatureRegistry = useInjectable<ChatFeatureRegistry>(ChatFeatureRegistryToken);
|
|
106
117
|
const chatRenderRegistry = useInjectable<ChatRenderRegistry>(ChatRenderRegistryToken);
|
|
107
118
|
const mcpServerRegistry = useInjectable<IMCPServerRegistry>(TokenMCPServerRegistry);
|
|
119
|
+
const aiNativeConfigService = useInjectable<AINativeConfigService>(AINativeConfigService);
|
|
120
|
+
const llmContextService = useInjectable<LLMContextService>(LLMContextServiceToken);
|
|
108
121
|
|
|
109
122
|
const layoutService = useInjectable<IMainLayoutService>(IMainLayoutService);
|
|
110
123
|
const msgHistoryManager = aiChatService.sessionModel.history;
|
|
@@ -114,6 +127,9 @@ export const AIChatView = () => {
|
|
|
114
127
|
const editorService = useInjectable<WorkbenchEditorService>(WorkbenchEditorService);
|
|
115
128
|
const appConfig = useInjectable<AppConfig>(AppConfig);
|
|
116
129
|
const applyService = useInjectable<BaseApplyService>(BaseApplyService);
|
|
130
|
+
const labelService = useInjectable<LabelService>(LabelService);
|
|
131
|
+
const workspaceService = useInjectable<IWorkspaceService>(IWorkspaceService);
|
|
132
|
+
const commandService = useInjectable<CommandService>(CommandService);
|
|
117
133
|
const [shortcutCommands, setShortcutCommands] = React.useState<ChatSlashCommandItemModel[]>([]);
|
|
118
134
|
|
|
119
135
|
const [changeList, setChangeList] = React.useState<FileChange[]>(getFileChanges(applyService.getSessionCodeBlocks()));
|
|
@@ -184,6 +200,9 @@ export const AIChatView = () => {
|
|
|
184
200
|
if (chatRenderRegistry.chatInputRender) {
|
|
185
201
|
return chatRenderRegistry.chatInputRender;
|
|
186
202
|
}
|
|
203
|
+
if (aiNativeConfigService.capabilities.supportsMCP) {
|
|
204
|
+
return ChatMentionInput;
|
|
205
|
+
}
|
|
187
206
|
return ChatInput;
|
|
188
207
|
}, [chatRenderRegistry.chatInputRender]);
|
|
189
208
|
|
|
@@ -262,7 +281,7 @@ export const AIChatView = () => {
|
|
|
262
281
|
if (loading) {
|
|
263
282
|
return;
|
|
264
283
|
}
|
|
265
|
-
await handleSend(message);
|
|
284
|
+
await handleSend(message.message, message.agentId, message.command);
|
|
266
285
|
} else {
|
|
267
286
|
if (message.agentId) {
|
|
268
287
|
setAgentId(message.agentId);
|
|
@@ -349,6 +368,9 @@ export const AIChatView = () => {
|
|
|
349
368
|
text={message}
|
|
350
369
|
agentId={visibleAgentId}
|
|
351
370
|
command={command}
|
|
371
|
+
labelService={labelService}
|
|
372
|
+
workspaceService={workspaceService}
|
|
373
|
+
commandService={commandService}
|
|
352
374
|
/>
|
|
353
375
|
),
|
|
354
376
|
},
|
|
@@ -454,7 +476,15 @@ export const AIChatView = () => {
|
|
|
454
476
|
text: ChatUserRoleRender ? (
|
|
455
477
|
<ChatUserRoleRender content={message} agentId={visibleAgentId} command={command} />
|
|
456
478
|
) : (
|
|
457
|
-
<CodeBlockWrapperInput
|
|
479
|
+
<CodeBlockWrapperInput
|
|
480
|
+
labelService={labelService}
|
|
481
|
+
relationId={relationId}
|
|
482
|
+
text={message}
|
|
483
|
+
agentId={visibleAgentId}
|
|
484
|
+
command={command}
|
|
485
|
+
workspaceService={workspaceService}
|
|
486
|
+
commandService={commandService}
|
|
487
|
+
/>
|
|
458
488
|
),
|
|
459
489
|
},
|
|
460
490
|
styles.chat_message_code,
|
|
@@ -634,15 +664,50 @@ export const AIChatView = () => {
|
|
|
634
664
|
msgId,
|
|
635
665
|
});
|
|
636
666
|
},
|
|
637
|
-
[chatRenderRegistry, chatRenderRegistry.chatUserRoleRender, msgHistoryManager, scrollToBottom],
|
|
667
|
+
[chatRenderRegistry, chatRenderRegistry.chatUserRoleRender, msgHistoryManager, scrollToBottom, loading],
|
|
638
668
|
);
|
|
639
669
|
|
|
640
670
|
const handleSend = React.useCallback(
|
|
641
|
-
async (
|
|
642
|
-
const
|
|
671
|
+
async (message: string, agentId?: string, command?: string) => {
|
|
672
|
+
const reportExtra = {
|
|
673
|
+
actionSource: ActionSourceEnum.Chat,
|
|
674
|
+
actionType: ActionTypeEnum.Send,
|
|
675
|
+
};
|
|
676
|
+
agentId = agentId ? agentId : ChatProxyService.AGENT_ID;
|
|
677
|
+
// 提取并替换 {{@file:xxx}} 中的文件内容
|
|
678
|
+
let processedContent = message;
|
|
679
|
+
const filePattern = /\{\{@file:(.*?)\}\}/g;
|
|
680
|
+
const fileMatches = message.match(filePattern);
|
|
681
|
+
let isCleanContext = false;
|
|
682
|
+
if (fileMatches) {
|
|
683
|
+
for (const match of fileMatches) {
|
|
684
|
+
const filePath = match.replace(/\{\{@file:(.*?)\}\}/, '$1');
|
|
685
|
+
if (filePath && !isCleanContext) {
|
|
686
|
+
isCleanContext = true;
|
|
687
|
+
llmContextService.cleanFileContext();
|
|
688
|
+
}
|
|
689
|
+
const fileUri = new URI(filePath);
|
|
690
|
+
llmContextService.addFileToContext(fileUri, undefined, true);
|
|
691
|
+
const relativePath = (await workspaceService.asRelativePath(fileUri))?.path || fileUri.displayName;
|
|
692
|
+
// 获取文件内容
|
|
693
|
+
// 替换占位符,后续支持自定义渲染时可替换为自定义渲染标签
|
|
694
|
+
processedContent = processedContent.replace(match, `\`<attached_file>${relativePath}\``);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
643
697
|
|
|
644
|
-
const
|
|
645
|
-
|
|
698
|
+
const folderPattern = /\{\{@folder:(.*?)\}\}/g;
|
|
699
|
+
const folderMatches = processedContent.match(folderPattern);
|
|
700
|
+
if (folderMatches) {
|
|
701
|
+
for (const match of folderMatches) {
|
|
702
|
+
const folderPath = match.replace(/\{\{@folder:(.*?)\}\}/, '$1');
|
|
703
|
+
const folderUri = new URI(folderPath);
|
|
704
|
+
llmContextService.addFolderToContext(folderUri);
|
|
705
|
+
const relativePath = (await workspaceService.asRelativePath(folderUri))?.path || folderUri.displayName;
|
|
706
|
+
// 替换占位符,后续支持自定义渲染时可替换为自定义渲染标签
|
|
707
|
+
processedContent = processedContent.replace(match, `\`<attached_folder>${relativePath}\``);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
return handleAgentReply({ message: processedContent, agentId, command, reportExtra });
|
|
646
711
|
},
|
|
647
712
|
[handleAgentReply],
|
|
648
713
|
);
|
|
@@ -759,7 +824,6 @@ export const AIChatView = () => {
|
|
|
759
824
|
</div>
|
|
760
825
|
) : null}
|
|
761
826
|
<div className={styles.chat_input_wrap}>
|
|
762
|
-
<ChatContext />
|
|
763
827
|
<div className={styles.header_operate}>
|
|
764
828
|
<div className={styles.header_operate_left}>
|
|
765
829
|
{shortcutCommands.map((command) => (
|
|
@@ -790,17 +854,7 @@ export const AIChatView = () => {
|
|
|
790
854
|
/>
|
|
791
855
|
)}
|
|
792
856
|
<ChatInputWrapperRender
|
|
793
|
-
onSend={
|
|
794
|
-
handleSend({
|
|
795
|
-
message: value,
|
|
796
|
-
agentId,
|
|
797
|
-
command,
|
|
798
|
-
reportExtra: {
|
|
799
|
-
actionSource: ActionSourceEnum.Chat,
|
|
800
|
-
actionType: ActionTypeEnum.Send,
|
|
801
|
-
},
|
|
802
|
-
})
|
|
803
|
-
}
|
|
857
|
+
onSend={handleSend}
|
|
804
858
|
disabled={loading}
|
|
805
859
|
enableOptions={true}
|
|
806
860
|
theme={theme}
|
|
@@ -857,12 +911,15 @@ export function DefaultChatViewHeader({
|
|
|
857
911
|
const getHistoryList = () => {
|
|
858
912
|
const currentMessages = aiChatService.sessionModel.history.getMessages();
|
|
859
913
|
const latestUserMessage = currentMessages.findLast((m) => m.role === ChatMessageRole.User);
|
|
860
|
-
setCurrentTitle(
|
|
914
|
+
setCurrentTitle(
|
|
915
|
+
latestUserMessage ? cleanAttachedTextWrapper(latestUserMessage.content).slice(0, MAX_TITLE_LENGTH) : '',
|
|
916
|
+
);
|
|
861
917
|
setHistoryList(
|
|
862
918
|
aiChatService.getSessions().map((session) => {
|
|
863
919
|
const history = session.history;
|
|
864
920
|
const messages = history.getMessages();
|
|
865
|
-
const title =
|
|
921
|
+
const title =
|
|
922
|
+
messages.length > 0 ? cleanAttachedTextWrapper(messages[0].content).slice(0, MAX_TITLE_LENGTH) : '';
|
|
866
923
|
const updatedAt = messages.length > 0 ? messages[messages.length - 1].replyStartTime || 0 : 0;
|
|
867
924
|
// const loading = session.requests[session.requests.length - 1]?.response.isComplete;
|
|
868
925
|
return {
|
|
@@ -2,14 +2,24 @@ 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 {
|
|
6
|
-
|
|
5
|
+
import {
|
|
6
|
+
EDITOR_COMMANDS,
|
|
7
|
+
FILE_COMMANDS,
|
|
8
|
+
IClipboardService,
|
|
9
|
+
LabelService,
|
|
10
|
+
getIcon,
|
|
11
|
+
useInjectable,
|
|
12
|
+
uuid,
|
|
13
|
+
} from '@opensumi/ide-core-browser';
|
|
14
|
+
import { Icon, Popover } from '@opensumi/ide-core-browser/lib/components';
|
|
7
15
|
import { EnhanceIcon } from '@opensumi/ide-core-browser/lib/components/ai-native';
|
|
8
16
|
import {
|
|
9
17
|
ActionSourceEnum,
|
|
10
18
|
ActionTypeEnum,
|
|
11
19
|
ChatFeatureRegistryToken,
|
|
20
|
+
CommandService,
|
|
12
21
|
IAIReporter,
|
|
22
|
+
URI,
|
|
13
23
|
localize,
|
|
14
24
|
runWhenIdle,
|
|
15
25
|
} from '@opensumi/ide-core-common';
|
|
@@ -22,6 +32,9 @@ import { ChatFeatureRegistry } from '../chat/chat.feature.registry';
|
|
|
22
32
|
|
|
23
33
|
import styles from './components.module.less';
|
|
24
34
|
import { highLightLanguageSupport } from './highLight';
|
|
35
|
+
import { MentionType } from './mention-input/types';
|
|
36
|
+
|
|
37
|
+
import type { IWorkspaceService } from '@opensumi/ide-workspace';
|
|
25
38
|
|
|
26
39
|
import './highlightTheme.less';
|
|
27
40
|
|
|
@@ -139,16 +152,56 @@ const CodeBlock = ({
|
|
|
139
152
|
renderText,
|
|
140
153
|
agentId = '',
|
|
141
154
|
command = '',
|
|
155
|
+
labelService,
|
|
156
|
+
commandService,
|
|
157
|
+
workspaceService,
|
|
142
158
|
}: {
|
|
143
159
|
content?: string;
|
|
144
160
|
relationId: string;
|
|
145
161
|
renderText?: (t: string) => React.ReactNode;
|
|
146
162
|
agentId?: string;
|
|
147
163
|
command?: string;
|
|
164
|
+
labelService?: LabelService;
|
|
165
|
+
commandService?: CommandService;
|
|
166
|
+
workspaceService?: IWorkspaceService;
|
|
148
167
|
}) => {
|
|
149
168
|
const rgInlineCode = /`([^`]+)`/g;
|
|
150
169
|
const rgBlockCode = /```([^]+?)```/g;
|
|
151
170
|
const rgBlockCodeBefore = /```([^]+)?/g;
|
|
171
|
+
const rgAttachedFile = /<attached_file>(.*)/g;
|
|
172
|
+
const rgAttachedFolder = /<attached_folder>(.*)/g;
|
|
173
|
+
const handleAttachmentClick = useCallback(
|
|
174
|
+
async (text: string, type: MentionType) => {
|
|
175
|
+
const roots = await workspaceService?.roots;
|
|
176
|
+
let uri;
|
|
177
|
+
if (!roots) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
for (const root of roots) {
|
|
181
|
+
uri = new URI(root.uri).resolve(text);
|
|
182
|
+
try {
|
|
183
|
+
await commandService?.executeCommand(FILE_COMMANDS.REVEAL_IN_EXPLORER.id, uri);
|
|
184
|
+
if (type === MentionType.FILE) {
|
|
185
|
+
await commandService?.executeCommand(EDITOR_COMMANDS.OPEN_RESOURCE.id, uri);
|
|
186
|
+
}
|
|
187
|
+
break;
|
|
188
|
+
} catch {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
[commandService, workspaceService],
|
|
194
|
+
);
|
|
195
|
+
const renderAttachment = (text: string, isFolder = false, key: string) => (
|
|
196
|
+
<span
|
|
197
|
+
className={styles.attachment}
|
|
198
|
+
key={key}
|
|
199
|
+
onClick={() => handleAttachmentClick(text, isFolder ? MentionType.FOLDER : MentionType.FILE)}
|
|
200
|
+
>
|
|
201
|
+
<Icon iconClass={isFolder ? getIcon('folder') : labelService?.getIcon(new URI(text || 'file'))} />
|
|
202
|
+
<span className={styles.attachment_text}>{text}</span>
|
|
203
|
+
</span>
|
|
204
|
+
);
|
|
152
205
|
|
|
153
206
|
const renderCodeEditor = (content: string) => {
|
|
154
207
|
const language = content.split('\n')[0].trim().toLowerCase();
|
|
@@ -193,11 +246,49 @@ const CodeBlock = ({
|
|
|
193
246
|
renderedContent.push(text);
|
|
194
247
|
}
|
|
195
248
|
} else {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
)
|
|
249
|
+
// 处理文件和文件夹标记
|
|
250
|
+
const processedText = text;
|
|
251
|
+
const fileMatches = [...text.matchAll(rgAttachedFile)];
|
|
252
|
+
const folderMatches = [...text.matchAll(rgAttachedFolder)];
|
|
253
|
+
if (fileMatches.length || folderMatches.length) {
|
|
254
|
+
let lastIndex = 0;
|
|
255
|
+
const fragments: (string | React.ReactNode)[] = [];
|
|
256
|
+
|
|
257
|
+
// 通用处理函数
|
|
258
|
+
const processMatches = (matches: RegExpMatchArray[], isFolder: boolean) => {
|
|
259
|
+
matches.forEach((match, matchIndex) => {
|
|
260
|
+
if (match.index !== undefined) {
|
|
261
|
+
const spanText = processedText.slice(lastIndex, match.index);
|
|
262
|
+
if (spanText) {
|
|
263
|
+
fragments.push(
|
|
264
|
+
<span key={`${index}-${matchIndex}-${isFolder ? 'folder' : 'file'}`}>{spanText}</span>,
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
fragments.push(
|
|
268
|
+
renderAttachment(
|
|
269
|
+
match[1],
|
|
270
|
+
isFolder,
|
|
271
|
+
`${index}-tag-${matchIndex}-${isFolder ? 'folder' : 'file'}`,
|
|
272
|
+
),
|
|
273
|
+
);
|
|
274
|
+
lastIndex = match.index + match[0].length;
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
// 处理文件标记
|
|
280
|
+
processMatches(fileMatches, false);
|
|
281
|
+
processMatches(folderMatches, true);
|
|
282
|
+
|
|
283
|
+
fragments.push(processedText.slice(lastIndex));
|
|
284
|
+
renderedContent.push(...fragments);
|
|
285
|
+
} else {
|
|
286
|
+
renderedContent.push(
|
|
287
|
+
<span className={styles.code_inline} key={index}>
|
|
288
|
+
{text}
|
|
289
|
+
</span>,
|
|
290
|
+
);
|
|
291
|
+
}
|
|
201
292
|
}
|
|
202
293
|
});
|
|
203
294
|
} else {
|
|
@@ -216,15 +307,29 @@ export const CodeBlockWrapper = ({
|
|
|
216
307
|
renderText,
|
|
217
308
|
relationId,
|
|
218
309
|
agentId,
|
|
310
|
+
labelService,
|
|
311
|
+
commandService,
|
|
312
|
+
workspaceService,
|
|
219
313
|
}: {
|
|
220
314
|
text?: string;
|
|
221
315
|
relationId: string;
|
|
222
316
|
renderText?: (t: string) => React.ReactNode;
|
|
223
317
|
agentId?: string;
|
|
318
|
+
labelService?: LabelService;
|
|
319
|
+
commandService?: CommandService;
|
|
320
|
+
workspaceService?: IWorkspaceService;
|
|
224
321
|
}) => (
|
|
225
322
|
<div className={styles.ai_chat_code_wrapper}>
|
|
226
323
|
<div className={styles.render_text}>
|
|
227
|
-
<CodeBlock
|
|
324
|
+
<CodeBlock
|
|
325
|
+
content={text}
|
|
326
|
+
labelService={labelService}
|
|
327
|
+
renderText={renderText}
|
|
328
|
+
relationId={relationId}
|
|
329
|
+
agentId={agentId}
|
|
330
|
+
commandService={commandService}
|
|
331
|
+
workspaceService={workspaceService}
|
|
332
|
+
/>
|
|
228
333
|
</div>
|
|
229
334
|
</div>
|
|
230
335
|
);
|
|
@@ -234,11 +339,17 @@ export const CodeBlockWrapperInput = ({
|
|
|
234
339
|
relationId,
|
|
235
340
|
agentId,
|
|
236
341
|
command,
|
|
342
|
+
labelService,
|
|
343
|
+
workspaceService,
|
|
344
|
+
commandService,
|
|
237
345
|
}: {
|
|
238
346
|
text: string;
|
|
239
347
|
relationId: string;
|
|
240
348
|
agentId?: string;
|
|
241
349
|
command?: string;
|
|
350
|
+
labelService?: LabelService;
|
|
351
|
+
workspaceService?: IWorkspaceService;
|
|
352
|
+
commandService?: CommandService;
|
|
242
353
|
}) => {
|
|
243
354
|
const chatFeatureRegistry = useInjectable<ChatFeatureRegistry>(ChatFeatureRegistryToken);
|
|
244
355
|
const [tag, setTag] = useState<string>('');
|
|
@@ -271,7 +382,15 @@ export const CodeBlockWrapperInput = ({
|
|
|
271
382
|
</div>
|
|
272
383
|
)}
|
|
273
384
|
{command && <div className={styles.tag}>/ {command}</div>}
|
|
274
|
-
<CodeBlock
|
|
385
|
+
<CodeBlock
|
|
386
|
+
content={txt}
|
|
387
|
+
labelService={labelService}
|
|
388
|
+
relationId={relationId}
|
|
389
|
+
agentId={agentId}
|
|
390
|
+
command={command}
|
|
391
|
+
workspaceService={workspaceService}
|
|
392
|
+
commandService={commandService}
|
|
393
|
+
/>
|
|
275
394
|
</div>
|
|
276
395
|
</div>
|
|
277
396
|
);
|
|
@@ -163,25 +163,22 @@ const ChatHistory: FC<IChatHistoryProps> = memo(
|
|
|
163
163
|
(item: IChatHistoryItem) => (
|
|
164
164
|
<div
|
|
165
165
|
key={item.id}
|
|
166
|
-
className={cls(
|
|
167
|
-
styles['dm-chat-history-item'],
|
|
168
|
-
item.id === currentId ? styles['dm-chat-history-item-selected'] : '',
|
|
169
|
-
)}
|
|
166
|
+
className={cls(styles.chat_history_item, item.id === currentId ? styles.chat_history_item_selected : '')}
|
|
170
167
|
onClick={() => handleHistoryItemSelect(item)}
|
|
171
168
|
>
|
|
172
|
-
<div className={styles
|
|
169
|
+
<div className={styles.chat_history_item_content}>
|
|
173
170
|
{item.loading ? (
|
|
174
171
|
<Loading />
|
|
175
172
|
) : (
|
|
176
173
|
<Icon icon='message' style={{ width: '16px', height: '16px', marginRight: 4 }} />
|
|
177
174
|
)}
|
|
178
175
|
{!historyTitleEditable?.[item.id] ? (
|
|
179
|
-
<span id={`
|
|
176
|
+
<span id={`chat-history-item-title-${item.id}`} className={styles.chat_history_item_title}>
|
|
180
177
|
{item.title}
|
|
181
178
|
</span>
|
|
182
179
|
) : (
|
|
183
180
|
<Input
|
|
184
|
-
className={styles
|
|
181
|
+
className={styles.chat_history_item_title}
|
|
185
182
|
defaultValue={item.title}
|
|
186
183
|
ref={inputRef}
|
|
187
184
|
onPressEnter={(e: any) => {
|
|
@@ -191,18 +188,9 @@ const ChatHistory: FC<IChatHistoryProps> = memo(
|
|
|
191
188
|
/>
|
|
192
189
|
)}
|
|
193
190
|
</div>
|
|
194
|
-
<div className={styles
|
|
195
|
-
{/* <EditOutlined
|
|
196
|
-
title={localize('aiNative.operate.chatHistory.edit')}
|
|
197
|
-
style={{ marginRight: 8 }}
|
|
198
|
-
onClick={(e) => {
|
|
199
|
-
e.preventDefault();
|
|
200
|
-
e.stopPropagation();
|
|
201
|
-
handleTitleEdit(item);
|
|
202
|
-
}}
|
|
203
|
-
/> */}
|
|
191
|
+
<div className={styles.chat_history_item_actions}>
|
|
204
192
|
<EnhanceIcon
|
|
205
|
-
className={cls(styles
|
|
193
|
+
className={cls(styles.chat_history_item_actions_delete, getIcon('delete'))}
|
|
206
194
|
onClick={(e) => {
|
|
207
195
|
e.preventDefault();
|
|
208
196
|
e.stopPropagation();
|
|
@@ -237,14 +225,14 @@ const ChatHistory: FC<IChatHistoryProps> = memo(
|
|
|
237
225
|
<div>
|
|
238
226
|
<Input
|
|
239
227
|
placeholder={localize('aiNative.operate.chatHistory.searchPlaceholder')}
|
|
240
|
-
|
|
228
|
+
className={styles.chat_history_search}
|
|
241
229
|
value={searchValue}
|
|
242
230
|
onChange={handleSearchChange}
|
|
243
231
|
/>
|
|
244
|
-
<div className={styles
|
|
232
|
+
<div className={styles.chat_history_list}>
|
|
245
233
|
{groupedHistoryList.map((group) => (
|
|
246
234
|
<div key={group.key} style={{ padding: '4px' }}>
|
|
247
|
-
<div className={styles
|
|
235
|
+
<div className={styles.chat_history_time}>{group.key}</div>
|
|
248
236
|
{group.items.map(renderHistoryItem)}
|
|
249
237
|
</div>
|
|
250
238
|
))}
|
|
@@ -257,13 +245,13 @@ const ChatHistory: FC<IChatHistoryProps> = memo(
|
|
|
257
245
|
const getPopupContainer = useCallback((triggerNode: HTMLElement) => triggerNode.parentElement!, []);
|
|
258
246
|
|
|
259
247
|
return (
|
|
260
|
-
<div className={cls(styles
|
|
261
|
-
<div className={styles
|
|
248
|
+
<div className={cls(styles.chat_history_header, className)}>
|
|
249
|
+
<div className={styles.chat_history_header_title}>
|
|
262
250
|
<span>{title}</span>
|
|
263
251
|
</div>
|
|
264
|
-
<div className={styles
|
|
252
|
+
<div className={styles.chat_history_header_actions}>
|
|
265
253
|
<Popover
|
|
266
|
-
id='
|
|
254
|
+
id='chat-history-header-actions-history'
|
|
267
255
|
content={renderHistory()}
|
|
268
256
|
trigger={PopoverTriggerType.click}
|
|
269
257
|
position={PopoverPosition.bottomRight}
|
|
@@ -271,12 +259,10 @@ const ChatHistory: FC<IChatHistoryProps> = memo(
|
|
|
271
259
|
getPopupContainer={getPopupContainer}
|
|
272
260
|
>
|
|
273
261
|
<div
|
|
274
|
-
className={styles
|
|
262
|
+
className={styles.chat_history_header_actions_history}
|
|
275
263
|
title={localize('aiNative.operate.chatHistory.title')}
|
|
276
264
|
>
|
|
277
|
-
<EnhanceIcon
|
|
278
|
-
className={cls(styles['dm-chat-history-header-actions-history'], 'codicon codicon-history')}
|
|
279
|
-
/>
|
|
265
|
+
<EnhanceIcon className={cls(styles.chat_history_header_actions_history, 'codicon codicon-history')} />
|
|
280
266
|
</div>
|
|
281
267
|
</Popover>
|
|
282
268
|
<Popover
|
|
@@ -285,7 +271,7 @@ const ChatHistory: FC<IChatHistoryProps> = memo(
|
|
|
285
271
|
title={localize('aiNative.operate.newChat.title')}
|
|
286
272
|
>
|
|
287
273
|
<EnhanceIcon
|
|
288
|
-
className={cls(styles
|
|
274
|
+
className={cls(styles.chat_history_header_actions_new, getIcon('plus'))}
|
|
289
275
|
onClick={handleNewChat}
|
|
290
276
|
/>
|
|
291
277
|
</Popover>
|