@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.
Files changed (117) hide show
  1. package/lib/browser/chat/chat-agent.service.d.ts +1 -1
  2. package/lib/browser/chat/chat-agent.service.d.ts.map +1 -1
  3. package/lib/browser/chat/chat-agent.service.js +7 -7
  4. package/lib/browser/chat/chat-agent.service.js.map +1 -1
  5. package/lib/browser/chat/chat.view.d.ts.map +1 -1
  6. package/lib/browser/chat/chat.view.js +69 -31
  7. package/lib/browser/chat/chat.view.js.map +1 -1
  8. package/lib/browser/components/ChatEditor.d.ts +11 -2
  9. package/lib/browser/components/ChatEditor.d.ts.map +1 -1
  10. package/lib/browser/components/ChatEditor.js +60 -6
  11. package/lib/browser/components/ChatEditor.js.map +1 -1
  12. package/lib/browser/components/ChatHistory.d.ts.map +1 -1
  13. package/lib/browser/components/ChatHistory.js +15 -15
  14. package/lib/browser/components/ChatHistory.js.map +1 -1
  15. package/lib/browser/components/ChatMentionInput.d.ts +25 -0
  16. package/lib/browser/components/ChatMentionInput.d.ts.map +1 -0
  17. package/lib/browser/components/ChatMentionInput.js +229 -0
  18. package/lib/browser/components/ChatMentionInput.js.map +1 -0
  19. package/lib/browser/components/ChatThinking.d.ts +1 -1
  20. package/lib/browser/components/ChatThinking.d.ts.map +1 -1
  21. package/lib/browser/components/ChatThinking.js +8 -2
  22. package/lib/browser/components/ChatThinking.js.map +1 -1
  23. package/lib/browser/components/change-list.module.less +2 -0
  24. package/lib/browser/components/{ChatContext/ContextSelector.d.ts → chat-context/context-selector.d.ts} +1 -1
  25. package/lib/browser/components/chat-context/context-selector.d.ts.map +1 -0
  26. package/lib/browser/components/{ChatContext/ContextSelector.js → chat-context/context-selector.js} +1 -1
  27. package/lib/browser/components/chat-context/context-selector.js.map +1 -0
  28. package/lib/browser/components/chat-context/index.d.ts.map +1 -0
  29. package/lib/browser/components/{ChatContext → chat-context}/index.js +2 -2
  30. package/lib/browser/components/chat-context/index.js.map +1 -0
  31. package/lib/browser/components/chat-history.module.less +33 -16
  32. package/lib/browser/components/components.module.less +39 -3
  33. package/lib/browser/components/mention-input/mention-input.d.ts +5 -0
  34. package/lib/browser/components/mention-input/mention-input.d.ts.map +1 -0
  35. package/lib/browser/components/mention-input/mention-input.js +763 -0
  36. package/lib/browser/components/mention-input/mention-input.js.map +1 -0
  37. package/lib/browser/components/mention-input/mention-input.module.less +333 -0
  38. package/lib/browser/components/mention-input/mention-item.d.ts +10 -0
  39. package/lib/browser/components/mention-input/mention-item.d.ts.map +1 -0
  40. package/lib/browser/components/mention-input/mention-item.js +16 -0
  41. package/lib/browser/components/mention-input/mention-item.js.map +1 -0
  42. package/lib/browser/components/mention-input/mention-panel.d.ts +15 -0
  43. package/lib/browser/components/mention-input/mention-panel.d.ts.map +1 -0
  44. package/lib/browser/components/mention-input/mention-panel.js +49 -0
  45. package/lib/browser/components/mention-input/mention-panel.js.map +1 -0
  46. package/lib/browser/components/mention-input/types.d.ts +78 -0
  47. package/lib/browser/components/mention-input/types.d.ts.map +1 -0
  48. package/lib/browser/components/mention-input/types.js +16 -0
  49. package/lib/browser/components/mention-input/types.js.map +1 -0
  50. package/lib/browser/context/llm-context.service.d.ts +10 -2
  51. package/lib/browser/context/llm-context.service.d.ts.map +1 -1
  52. package/lib/browser/context/llm-context.service.js +76 -2
  53. package/lib/browser/context/llm-context.service.js.map +1 -1
  54. package/lib/browser/mcp/config/components/mcp-config.module.less +61 -30
  55. package/lib/browser/mcp/config/components/mcp-config.view.d.ts.map +1 -1
  56. package/lib/browser/mcp/config/components/mcp-config.view.js +17 -19
  57. package/lib/browser/mcp/config/components/mcp-config.view.js.map +1 -1
  58. package/lib/browser/mcp/config/components/mcp-server-form.js +1 -1
  59. package/lib/browser/mcp/config/components/mcp-server-form.js.map +1 -1
  60. package/lib/browser/mcp/config/components/mcp-server-form.module.less +3 -0
  61. package/lib/browser/mcp/mcp-server-proxy.service.d.ts +1 -0
  62. package/lib/browser/mcp/mcp-server-proxy.service.d.ts.map +1 -1
  63. package/lib/common/index.d.ts +2 -1
  64. package/lib/common/index.d.ts.map +1 -1
  65. package/lib/common/index.js +1 -1
  66. package/lib/common/llm-context.d.ts +15 -1
  67. package/lib/common/llm-context.d.ts.map +1 -1
  68. package/lib/common/llm-context.js.map +1 -1
  69. package/lib/common/prompts/context-prompt-provider.d.ts +12 -2
  70. package/lib/common/prompts/context-prompt-provider.d.ts.map +1 -1
  71. package/lib/common/prompts/context-prompt-provider.js +95 -30
  72. package/lib/common/prompts/context-prompt-provider.js.map +1 -1
  73. package/lib/common/types.d.ts +1 -1
  74. package/lib/common/types.d.ts.map +1 -1
  75. package/lib/common/utils.d.ts +1 -0
  76. package/lib/common/utils.d.ts.map +1 -1
  77. package/lib/common/utils.js +9 -1
  78. package/lib/common/utils.js.map +1 -1
  79. package/lib/node/mcp/sumi-mcp-server.d.ts +3 -3
  80. package/lib/node/mcp/sumi-mcp-server.d.ts.map +1 -1
  81. package/lib/node/mcp/sumi-mcp-server.js +11 -7
  82. package/lib/node/mcp/sumi-mcp-server.js.map +1 -1
  83. package/package.json +23 -23
  84. package/src/browser/chat/chat-agent.service.ts +7 -7
  85. package/src/browser/chat/chat.view.tsx +81 -24
  86. package/src/browser/components/ChatEditor.tsx +128 -9
  87. package/src/browser/components/ChatHistory.tsx +16 -30
  88. package/src/browser/components/ChatMentionInput.tsx +276 -0
  89. package/src/browser/components/ChatThinking.tsx +10 -4
  90. package/src/browser/components/change-list.module.less +2 -0
  91. package/src/browser/components/{ChatContext → chat-context}/index.tsx +1 -1
  92. package/src/browser/components/chat-history.module.less +33 -16
  93. package/src/browser/components/components.module.less +39 -3
  94. package/src/browser/components/mention-input/mention-input.module.less +333 -0
  95. package/src/browser/components/mention-input/mention-input.tsx +952 -0
  96. package/src/browser/components/mention-input/mention-item.tsx +24 -0
  97. package/src/browser/components/mention-input/mention-panel.tsx +89 -0
  98. package/src/browser/components/mention-input/types.ts +84 -0
  99. package/src/browser/context/llm-context.service.ts +85 -3
  100. package/src/browser/mcp/config/components/mcp-config.module.less +61 -30
  101. package/src/browser/mcp/config/components/mcp-config.view.tsx +49 -32
  102. package/src/browser/mcp/config/components/mcp-server-form.module.less +3 -0
  103. package/src/browser/mcp/config/components/mcp-server-form.tsx +1 -1
  104. package/src/common/index.ts +2 -2
  105. package/src/common/llm-context.ts +16 -1
  106. package/src/common/prompts/context-prompt-provider.ts +130 -36
  107. package/src/common/types.ts +1 -1
  108. package/src/common/utils.ts +8 -0
  109. package/src/node/mcp/sumi-mcp-server.ts +11 -7
  110. package/lib/browser/components/ChatContext/ContextSelector.d.ts.map +0 -1
  111. package/lib/browser/components/ChatContext/ContextSelector.js.map +0 -1
  112. package/lib/browser/components/ChatContext/index.d.ts.map +0 -1
  113. package/lib/browser/components/ChatContext/index.js.map +0 -1
  114. /package/lib/browser/components/{ChatContext → chat-context}/index.d.ts +0 -0
  115. /package/lib/browser/components/{ChatContext → chat-context}/style.module.less +0 -0
  116. /package/src/browser/components/{ChatContext/ContextSelector.tsx → chat-context/context-selector.tsx} +0 -0
  117. /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 { AppConfig, getIcon, useInjectable, useUpdateOnEvent } from '@opensumi/ide-core-browser';
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 relationId={relationId} text={message} agentId={visibleAgentId} command={command} />
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 (value: IChatMessageStructure) => {
642
- const { message, command, reportExtra } = value;
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 agentId = value.agentId ? value.agentId : ChatProxyService.AGENT_ID;
645
- return handleAgentReply({ message, agentId, command, reportExtra });
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={(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
- }
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(latestUserMessage ? latestUserMessage.content.slice(0, MAX_TITLE_LENGTH) : '');
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 = messages.length > 0 ? messages[0].content.slice(0, MAX_TITLE_LENGTH) : '';
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 { IClipboardService, getIcon, useInjectable, uuid } from '@opensumi/ide-core-browser';
6
- import { Popover } from '@opensumi/ide-core-browser/lib/components';
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
- renderedContent.push(
197
- <span className={styles.code_inline} key={index}>
198
- {text}
199
- </span>,
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 content={text} renderText={renderText} relationId={relationId} agentId={agentId} />
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 content={txt} relationId={relationId} agentId={agentId} command={command} />
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['dm-chat-history-item-content']}>
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={`dm-chat-history-item-title-${item.id}`} className={styles['dm-chat-history-item-title']}>
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['dm-chat-history-item-title']}
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['dm-chat-history-item-actions']}>
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['dm-chat-history-item-actions-delete'], getIcon('delete'))}
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
- style={{ width: '100%', maxWidth: '100%' }}
228
+ className={styles.chat_history_search}
241
229
  value={searchValue}
242
230
  onChange={handleSearchChange}
243
231
  />
244
- <div className={styles['dm-chat-history-list']}>
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['dm-chat-history-time']}>{group.key}</div>
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['dm-chat-history-header'], className)}>
261
- <div className={styles['dm-chat-history-header-title']}>
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['dm-chat-history-header-actions']}>
252
+ <div className={styles.chat_history_header_actions}>
265
253
  <Popover
266
- id='dm-chat-history-header-actions-history'
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['dm-chat-history-header-actions-history']}
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['dm-chat-history-header-actions-new'], getIcon('plus'))}
274
+ className={cls(styles.chat_history_header_actions_new, getIcon('plus'))}
289
275
  onClick={handleNewChat}
290
276
  />
291
277
  </Popover>