@opensumi/ide-ai-native 3.8.3-next-1741752385.0 → 3.8.3-next-1741763229.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-model.d.ts +2 -2
- package/lib/browser/chat/chat-model.d.ts.map +1 -1
- package/lib/browser/chat/chat-model.js +18 -1
- package/lib/browser/chat/chat-model.js.map +1 -1
- package/lib/browser/chat/chat.view.d.ts.map +1 -1
- package/lib/browser/chat/chat.view.js +49 -18
- package/lib/browser/chat/chat.view.js.map +1 -1
- package/lib/browser/components/ChatEditor.d.ts +5 -2
- package/lib/browser/components/ChatEditor.d.ts.map +1 -1
- package/lib/browser/components/ChatEditor.js +45 -6
- package/lib/browser/components/ChatEditor.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 +221 -0
- package/lib/browser/components/ChatMentionInput.js.map +1 -0
- package/lib/browser/components/ChatReply.d.ts.map +1 -1
- package/lib/browser/components/ChatReply.js +35 -17
- package/lib/browser/components/ChatReply.js.map +1 -1
- package/lib/browser/components/ChatThinking.js +1 -1
- package/lib/browser/components/ChatThinking.js.map +1 -1
- package/lib/browser/components/WelcomeMsg.js +1 -1
- package/lib/browser/components/WelcomeMsg.js.map +1 -1
- 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/components.module.less +43 -0
- 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 +753 -0
- package/lib/browser/components/mention-input/mention-input.js.map +1 -0
- package/lib/browser/components/mention-input/mention-input.module.less +327 -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 +76 -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 +71 -2
- package/lib/browser/context/llm-context.service.js.map +1 -1
- package/lib/browser/contrib/inline-completions/prompt/matcher.js +2 -2
- package/lib/browser/contrib/inline-completions/prompt/similarSnippets.d.ts +1 -1
- package/lib/browser/contrib/inline-completions/prompt/similarSnippets.js +2 -2
- package/lib/browser/contrib/intelligent-completions/view/default.d.ts.map +1 -1
- package/lib/browser/contrib/intelligent-completions/view/default.js.map +1 -1
- package/lib/browser/mcp/config/components/mcp-config.view.d.ts.map +1 -1
- package/lib/browser/mcp/config/components/mcp-config.view.js +28 -18
- package/lib/browser/mcp/config/components/mcp-config.view.js.map +1 -1
- package/lib/browser/mcp/config/components/mcp-server-form.d.ts.map +1 -1
- package/lib/browser/mcp/config/components/mcp-server-form.js +33 -25
- package/lib/browser/mcp/config/components/mcp-server-form.js.map +1 -1
- package/lib/browser/mcp/mcp-server.feature.registry.js +1 -1
- package/lib/browser/mcp/mcp-server.feature.registry.js.map +1 -1
- package/lib/browser/mcp/tools/components/ExpandableFileList.d.ts.map +1 -1
- package/lib/browser/mcp/tools/components/ExpandableFileList.js +3 -1
- package/lib/browser/mcp/tools/components/ExpandableFileList.js.map +1 -1
- package/lib/browser/mcp/tools/components/Terminal.d.ts.map +1 -1
- package/lib/browser/mcp/tools/components/Terminal.js +6 -5
- package/lib/browser/mcp/tools/components/Terminal.js.map +1 -1
- package/lib/browser/mcp/tools/components/computeAnsiLogString.d.ts +4 -0
- package/lib/browser/mcp/tools/components/computeAnsiLogString.d.ts.map +1 -0
- package/lib/browser/mcp/tools/components/computeAnsiLogString.js +22 -0
- package/lib/browser/mcp/tools/components/computeAnsiLogString.js.map +1 -0
- package/lib/browser/mcp/tools/components/filterEraseMultipleLine.d.ts +18 -0
- package/lib/browser/mcp/tools/components/filterEraseMultipleLine.d.ts.map +1 -0
- package/lib/browser/mcp/tools/components/filterEraseMultipleLine.js +69 -0
- package/lib/browser/mcp/tools/components/filterEraseMultipleLine.js.map +1 -0
- package/lib/browser/mcp/tools/components/index.module.less +8 -5
- package/lib/browser/mcp/tools/createNewFileWithText.d.ts.map +1 -1
- package/lib/browser/mcp/tools/createNewFileWithText.js +1 -0
- package/lib/browser/mcp/tools/createNewFileWithText.js.map +1 -1
- package/lib/browser/mcp/tools/editFile.d.ts.map +1 -1
- package/lib/browser/mcp/tools/editFile.js +1 -0
- package/lib/browser/mcp/tools/editFile.js.map +1 -1
- package/lib/browser/mcp/tools/fileSearch.d.ts.map +1 -1
- package/lib/browser/mcp/tools/fileSearch.js +1 -0
- package/lib/browser/mcp/tools/fileSearch.js.map +1 -1
- package/lib/browser/mcp/tools/getDiagnosticsByPath.d.ts.map +1 -1
- package/lib/browser/mcp/tools/getDiagnosticsByPath.js +2 -1
- package/lib/browser/mcp/tools/getDiagnosticsByPath.js.map +1 -1
- package/lib/browser/mcp/tools/getOpenEditorFileDiagnostics.d.ts.map +1 -1
- package/lib/browser/mcp/tools/getOpenEditorFileDiagnostics.js +2 -0
- package/lib/browser/mcp/tools/getOpenEditorFileDiagnostics.js.map +1 -1
- package/lib/browser/mcp/tools/grepSearch.d.ts.map +1 -1
- package/lib/browser/mcp/tools/grepSearch.js +1 -0
- package/lib/browser/mcp/tools/grepSearch.js.map +1 -1
- package/lib/browser/mcp/tools/listDir.d.ts.map +1 -1
- package/lib/browser/mcp/tools/listDir.js +1 -0
- package/lib/browser/mcp/tools/listDir.js.map +1 -1
- package/lib/browser/mcp/tools/readFile.d.ts.map +1 -1
- package/lib/browser/mcp/tools/readFile.js +1 -0
- package/lib/browser/mcp/tools/readFile.js.map +1 -1
- package/lib/browser/mcp/tools/runTerminalCmd.d.ts.map +1 -1
- package/lib/browser/mcp/tools/runTerminalCmd.js +1 -0
- package/lib/browser/mcp/tools/runTerminalCmd.js.map +1 -1
- package/lib/browser/types.d.ts +1 -0
- package/lib/browser/types.d.ts.map +1 -1
- package/lib/browser/widget/inline-diff/inline-diff-manager.d.ts.map +1 -1
- package/lib/browser/widget/inline-diff/inline-diff-manager.js.map +1 -1
- package/lib/browser/widget/inline-stream-diff/live-preview.decoration.d.ts.map +1 -1
- package/lib/browser/widget/inline-stream-diff/live-preview.decoration.js +10 -5
- package/lib/browser/widget/inline-stream-diff/live-preview.decoration.js.map +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 +94 -28
- package/lib/common/prompts/context-prompt-provider.js.map +1 -1
- package/lib/node/base-language-model.d.ts.map +1 -1
- package/lib/node/base-language-model.js +6 -0
- package/lib/node/base-language-model.js.map +1 -1
- package/package.json +24 -23
- package/src/browser/chat/chat-agent.service.ts +7 -7
- package/src/browser/chat/chat-model.ts +19 -2
- package/src/browser/chat/chat.view.tsx +63 -20
- package/src/browser/components/ChatEditor.tsx +72 -9
- package/src/browser/components/ChatMentionInput.tsx +268 -0
- package/src/browser/components/ChatReply.tsx +61 -18
- package/src/browser/components/ChatThinking.tsx +1 -1
- package/src/browser/components/WelcomeMsg.tsx +1 -1
- package/src/browser/components/{ChatContext → chat-context}/index.tsx +1 -1
- package/src/browser/components/components.module.less +43 -0
- package/src/browser/components/mention-input/mention-input.module.less +327 -0
- package/src/browser/components/mention-input/mention-input.tsx +943 -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 +82 -0
- package/src/browser/context/llm-context.service.ts +81 -3
- package/src/browser/contrib/inline-completions/prompt/matcher.ts +2 -2
- package/src/browser/contrib/inline-completions/prompt/similarSnippets.ts +2 -2
- package/src/browser/contrib/intelligent-completions/view/default.ts +0 -1
- package/src/browser/mcp/config/components/mcp-config.view.tsx +23 -12
- package/src/browser/mcp/config/components/mcp-server-form.tsx +68 -54
- package/src/browser/mcp/mcp-server.feature.registry.ts +1 -1
- package/src/browser/mcp/tools/components/ExpandableFileList.tsx +4 -1
- package/src/browser/mcp/tools/components/Terminal.tsx +4 -6
- package/src/browser/mcp/tools/components/computeAnsiLogString.ts +24 -0
- package/src/browser/mcp/tools/components/filterEraseMultipleLine.ts +71 -0
- package/src/browser/mcp/tools/components/index.module.less +8 -5
- package/src/browser/mcp/tools/createNewFileWithText.ts +1 -0
- package/src/browser/mcp/tools/editFile.ts +1 -0
- package/src/browser/mcp/tools/fileSearch.ts +1 -0
- package/src/browser/mcp/tools/getDiagnosticsByPath.ts +2 -1
- package/src/browser/mcp/tools/getOpenEditorFileDiagnostics.ts +2 -0
- package/src/browser/mcp/tools/grepSearch.ts +1 -0
- package/src/browser/mcp/tools/listDir.ts +1 -0
- package/src/browser/mcp/tools/readFile.ts +1 -0
- package/src/browser/mcp/tools/runTerminalCmd.ts +1 -0
- package/src/browser/types.ts +1 -0
- package/src/browser/widget/inline-diff/inline-diff-manager.tsx +0 -1
- package/src/browser/widget/inline-stream-diff/live-preview.decoration.tsx +9 -5
- package/src/common/llm-context.ts +16 -1
- package/src/common/prompts/context-prompt-provider.ts +126 -32
- package/src/node/base-language-model.ts +5 -0
- 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
|
@@ -59,7 +59,7 @@ export class ChatAgentService extends Disposable implements IChatAgentService {
|
|
|
59
59
|
private readonly aiReporter: IAIReporter;
|
|
60
60
|
|
|
61
61
|
@Autowired(LLMContextServiceToken)
|
|
62
|
-
protected readonly
|
|
62
|
+
protected readonly llmContextService: LLMContextService;
|
|
63
63
|
|
|
64
64
|
@Autowired(ChatAgentPromptProvider)
|
|
65
65
|
protected readonly promptProvider: ChatAgentPromptProvider;
|
|
@@ -74,7 +74,7 @@ export class ChatAgentService extends Disposable implements IChatAgentService {
|
|
|
74
74
|
super();
|
|
75
75
|
this.addDispose(this._onDidChangeAgents);
|
|
76
76
|
this.addDispose(
|
|
77
|
-
this.
|
|
77
|
+
this.llmContextService.onDidContextFilesChangeEvent((event) => {
|
|
78
78
|
if (event.version !== this.contextVersion) {
|
|
79
79
|
this.contextVersion = event.version;
|
|
80
80
|
this.shouldUpdateContext = true;
|
|
@@ -152,9 +152,9 @@ export class ChatAgentService extends Disposable implements IChatAgentService {
|
|
|
152
152
|
if (!this.initialUserMessageMap.has(request.sessionId)) {
|
|
153
153
|
this.initialUserMessageMap.set(request.sessionId, request.message);
|
|
154
154
|
const rawMessage = request.message;
|
|
155
|
-
request.message = this.provideContextMessage(rawMessage, request.sessionId);
|
|
155
|
+
request.message = await this.provideContextMessage(rawMessage, request.sessionId);
|
|
156
156
|
} else if (this.shouldUpdateContext || request.regenerate || history.length === 0) {
|
|
157
|
-
request.message = this.provideContextMessage(request.message, request.sessionId);
|
|
157
|
+
request.message = await this.provideContextMessage(request.message, request.sessionId);
|
|
158
158
|
this.shouldUpdateContext = false;
|
|
159
159
|
}
|
|
160
160
|
|
|
@@ -162,9 +162,9 @@ export class ChatAgentService extends Disposable implements IChatAgentService {
|
|
|
162
162
|
return result;
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
-
private provideContextMessage(message: string, sessionId: string) {
|
|
166
|
-
const context = this.
|
|
167
|
-
const fullMessage = this.promptProvider.provideContextPrompt(context, message);
|
|
165
|
+
private async provideContextMessage(message: string, sessionId: string) {
|
|
166
|
+
const context = await this.llmContextService.serialize();
|
|
167
|
+
const fullMessage = await this.promptProvider.provideContextPrompt(context, message);
|
|
168
168
|
this.aiReporter.send({
|
|
169
169
|
msgType: AIServiceType.Chat,
|
|
170
170
|
actionType: ActionTypeEnum.ContextEnhance,
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
IChatComponent,
|
|
7
7
|
IChatMarkdownContent,
|
|
8
8
|
IChatProgress,
|
|
9
|
+
IChatReasoning,
|
|
9
10
|
IChatToolContent,
|
|
10
11
|
IChatTreeData,
|
|
11
12
|
uuid,
|
|
@@ -33,7 +34,8 @@ export type IChatProgressResponseContent =
|
|
|
33
34
|
| IChatAsyncContent
|
|
34
35
|
| IChatTreeData
|
|
35
36
|
| IChatComponent
|
|
36
|
-
| IChatToolContent
|
|
37
|
+
| IChatToolContent
|
|
38
|
+
| IChatReasoning;
|
|
37
39
|
|
|
38
40
|
export class ChatResponseModel extends Disposable {
|
|
39
41
|
#responseParts: IChatProgressResponseContent[] = [];
|
|
@@ -131,6 +133,18 @@ export class ChatResponseModel extends Disposable {
|
|
|
131
133
|
};
|
|
132
134
|
}
|
|
133
135
|
|
|
136
|
+
this.#updateResponseText();
|
|
137
|
+
} else if (progress.kind === 'reasoning') {
|
|
138
|
+
const lastResponsePart = this.#responseParts[responsePartLength];
|
|
139
|
+
if (!lastResponsePart || lastResponsePart.kind !== 'reasoning') {
|
|
140
|
+
// 去掉开头的 <think> 标签
|
|
141
|
+
this.#responseParts.push({ content: progress.content.replace(/^<think>/, ''), kind: 'reasoning' });
|
|
142
|
+
} else {
|
|
143
|
+
this.#responseParts[responsePartLength] = {
|
|
144
|
+
content: lastResponsePart.content + progress.content,
|
|
145
|
+
kind: 'reasoning',
|
|
146
|
+
};
|
|
147
|
+
}
|
|
134
148
|
this.#updateResponseText();
|
|
135
149
|
} else if (progress.kind === 'asyncContent') {
|
|
136
150
|
// Add a new resolving part
|
|
@@ -181,6 +195,9 @@ export class ChatResponseModel extends Disposable {
|
|
|
181
195
|
if (part.kind === 'toolCall') {
|
|
182
196
|
return part.content.function.name;
|
|
183
197
|
}
|
|
198
|
+
if (part.kind === 'reasoning') {
|
|
199
|
+
return '';
|
|
200
|
+
}
|
|
184
201
|
return part.content.value;
|
|
185
202
|
})
|
|
186
203
|
.join('\n\n');
|
|
@@ -387,7 +404,7 @@ export class ChatModel extends Disposable implements IChatModel {
|
|
|
387
404
|
|
|
388
405
|
const { kind } = progress;
|
|
389
406
|
|
|
390
|
-
const basicKind = ['content', 'markdownContent', 'asyncContent', 'treeData', 'component', 'toolCall'];
|
|
407
|
+
const basicKind = ['content', 'markdownContent', 'asyncContent', 'treeData', 'component', 'toolCall', 'reasoning'];
|
|
391
408
|
|
|
392
409
|
if (basicKind.includes(kind)) {
|
|
393
410
|
request.response.updateContent(progress, quiet);
|
|
@@ -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 {
|
|
@@ -31,13 +38,14 @@ import { IMessageService } from '@opensumi/ide-overlay';
|
|
|
31
38
|
|
|
32
39
|
import 'react-chat-elements/dist/main.css';
|
|
33
40
|
import { AI_CHAT_VIEW_ID, IChatAgentService, IChatInternalService, IChatMessageStructure } from '../../common';
|
|
41
|
+
import { LLMContextService, LLMContextServiceToken } from '../../common/llm-context';
|
|
34
42
|
import { CodeBlockData } from '../../common/types';
|
|
35
43
|
import { FileChange, FileListDisplay } from '../components/ChangeList';
|
|
36
|
-
import { ChatContext } from '../components/ChatContext';
|
|
37
44
|
import { CodeBlockWrapperInput } from '../components/ChatEditor';
|
|
38
45
|
import ChatHistory, { IChatHistoryItem } from '../components/ChatHistory';
|
|
39
46
|
import { ChatInput } from '../components/ChatInput';
|
|
40
47
|
import { ChatMarkdown } from '../components/ChatMarkdown';
|
|
48
|
+
import { ChatMentionInput } from '../components/ChatMentionInput';
|
|
41
49
|
import { ChatNotify, ChatReply } from '../components/ChatReply';
|
|
42
50
|
import { SlashCustomRender } from '../components/SlashCustomRender';
|
|
43
51
|
import { MessageData, createMessageByAI, createMessageByUser } from '../components/utils';
|
|
@@ -105,6 +113,8 @@ export const AIChatView = () => {
|
|
|
105
113
|
const chatFeatureRegistry = useInjectable<ChatFeatureRegistry>(ChatFeatureRegistryToken);
|
|
106
114
|
const chatRenderRegistry = useInjectable<ChatRenderRegistry>(ChatRenderRegistryToken);
|
|
107
115
|
const mcpServerRegistry = useInjectable<IMCPServerRegistry>(TokenMCPServerRegistry);
|
|
116
|
+
const aiNativeConfigService = useInjectable<AINativeConfigService>(AINativeConfigService);
|
|
117
|
+
const llmContextService = useInjectable<LLMContextService>(LLMContextServiceToken);
|
|
108
118
|
|
|
109
119
|
const layoutService = useInjectable<IMainLayoutService>(IMainLayoutService);
|
|
110
120
|
const msgHistoryManager = aiChatService.sessionModel.history;
|
|
@@ -114,6 +124,7 @@ export const AIChatView = () => {
|
|
|
114
124
|
const editorService = useInjectable<WorkbenchEditorService>(WorkbenchEditorService);
|
|
115
125
|
const appConfig = useInjectable<AppConfig>(AppConfig);
|
|
116
126
|
const applyService = useInjectable<BaseApplyService>(BaseApplyService);
|
|
127
|
+
const labelService = useInjectable<LabelService>(LabelService);
|
|
117
128
|
const [shortcutCommands, setShortcutCommands] = React.useState<ChatSlashCommandItemModel[]>([]);
|
|
118
129
|
|
|
119
130
|
const [changeList, setChangeList] = React.useState<FileChange[]>(getFileChanges(applyService.getSessionCodeBlocks()));
|
|
@@ -184,6 +195,9 @@ export const AIChatView = () => {
|
|
|
184
195
|
if (chatRenderRegistry.chatInputRender) {
|
|
185
196
|
return chatRenderRegistry.chatInputRender;
|
|
186
197
|
}
|
|
198
|
+
if (aiNativeConfigService.capabilities.supportsMCP) {
|
|
199
|
+
return ChatMentionInput;
|
|
200
|
+
}
|
|
187
201
|
return ChatInput;
|
|
188
202
|
}, [chatRenderRegistry.chatInputRender]);
|
|
189
203
|
|
|
@@ -262,7 +276,7 @@ export const AIChatView = () => {
|
|
|
262
276
|
if (loading) {
|
|
263
277
|
return;
|
|
264
278
|
}
|
|
265
|
-
await handleSend(message);
|
|
279
|
+
await handleSend(message.message, message.agentId, message.command);
|
|
266
280
|
} else {
|
|
267
281
|
if (message.agentId) {
|
|
268
282
|
setAgentId(message.agentId);
|
|
@@ -349,6 +363,7 @@ export const AIChatView = () => {
|
|
|
349
363
|
text={message}
|
|
350
364
|
agentId={visibleAgentId}
|
|
351
365
|
command={command}
|
|
366
|
+
labelService={labelService}
|
|
352
367
|
/>
|
|
353
368
|
),
|
|
354
369
|
},
|
|
@@ -454,7 +469,13 @@ export const AIChatView = () => {
|
|
|
454
469
|
text: ChatUserRoleRender ? (
|
|
455
470
|
<ChatUserRoleRender content={message} agentId={visibleAgentId} command={command} />
|
|
456
471
|
) : (
|
|
457
|
-
<CodeBlockWrapperInput
|
|
472
|
+
<CodeBlockWrapperInput
|
|
473
|
+
labelService={labelService}
|
|
474
|
+
relationId={relationId}
|
|
475
|
+
text={message}
|
|
476
|
+
agentId={visibleAgentId}
|
|
477
|
+
command={command}
|
|
478
|
+
/>
|
|
458
479
|
),
|
|
459
480
|
},
|
|
460
481
|
styles.chat_message_code,
|
|
@@ -638,11 +659,44 @@ export const AIChatView = () => {
|
|
|
638
659
|
);
|
|
639
660
|
|
|
640
661
|
const handleSend = React.useCallback(
|
|
641
|
-
async (
|
|
642
|
-
const
|
|
662
|
+
async (message: string, agentId?: string, command?: string) => {
|
|
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
|
+
}
|
|
643
687
|
|
|
644
|
-
const
|
|
645
|
-
|
|
688
|
+
const folderPattern = /\{\{@folder:(.*?)\}\}/g;
|
|
689
|
+
const folderMatches = processedContent.match(folderPattern);
|
|
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 });
|
|
646
700
|
},
|
|
647
701
|
[handleAgentReply],
|
|
648
702
|
);
|
|
@@ -759,7 +813,6 @@ export const AIChatView = () => {
|
|
|
759
813
|
</div>
|
|
760
814
|
) : null}
|
|
761
815
|
<div className={styles.chat_input_wrap}>
|
|
762
|
-
<ChatContext />
|
|
763
816
|
<div className={styles.header_operate}>
|
|
764
817
|
<div className={styles.header_operate_left}>
|
|
765
818
|
{shortcutCommands.map((command) => (
|
|
@@ -790,17 +843,7 @@ export const AIChatView = () => {
|
|
|
790
843
|
/>
|
|
791
844
|
)}
|
|
792
845
|
<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
|
-
}
|
|
846
|
+
onSend={handleSend}
|
|
804
847
|
disabled={loading}
|
|
805
848
|
enableOptions={true}
|
|
806
849
|
theme={theme}
|
|
@@ -2,14 +2,15 @@ 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 { IClipboardService, LabelService, getIcon, useInjectable, uuid } from '@opensumi/ide-core-browser';
|
|
6
|
+
import { Icon, 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,
|
|
13
14
|
localize,
|
|
14
15
|
runWhenIdle,
|
|
15
16
|
} from '@opensumi/ide-core-common';
|
|
@@ -139,16 +140,26 @@ const CodeBlock = ({
|
|
|
139
140
|
renderText,
|
|
140
141
|
agentId = '',
|
|
141
142
|
command = '',
|
|
143
|
+
labelService,
|
|
142
144
|
}: {
|
|
143
145
|
content?: string;
|
|
144
146
|
relationId: string;
|
|
145
147
|
renderText?: (t: string) => React.ReactNode;
|
|
146
148
|
agentId?: string;
|
|
147
149
|
command?: string;
|
|
150
|
+
labelService?: LabelService;
|
|
148
151
|
}) => {
|
|
149
152
|
const rgInlineCode = /`([^`]+)`/g;
|
|
150
153
|
const rgBlockCode = /```([^]+?)```/g;
|
|
151
154
|
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
|
+
);
|
|
152
163
|
|
|
153
164
|
const renderCodeEditor = (content: string) => {
|
|
154
165
|
const language = content.split('\n')[0].trim().toLowerCase();
|
|
@@ -193,11 +204,47 @@ const CodeBlock = ({
|
|
|
193
204
|
renderedContent.push(text);
|
|
194
205
|
}
|
|
195
206
|
} else {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
)
|
|
207
|
+
// 处理文件和文件夹标记
|
|
208
|
+
const processedText = text;
|
|
209
|
+
const fileMatches = [...text.matchAll(rgAttachedFile)];
|
|
210
|
+
const folderMatches = [...text.matchAll(rgAttachedFolder)];
|
|
211
|
+
if (fileMatches.length || folderMatches.length) {
|
|
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
|
+
}
|
|
201
248
|
}
|
|
202
249
|
});
|
|
203
250
|
} else {
|
|
@@ -216,15 +263,23 @@ export const CodeBlockWrapper = ({
|
|
|
216
263
|
renderText,
|
|
217
264
|
relationId,
|
|
218
265
|
agentId,
|
|
266
|
+
labelService,
|
|
219
267
|
}: {
|
|
220
268
|
text?: string;
|
|
221
269
|
relationId: string;
|
|
222
270
|
renderText?: (t: string) => React.ReactNode;
|
|
223
271
|
agentId?: string;
|
|
272
|
+
labelService?: LabelService;
|
|
224
273
|
}) => (
|
|
225
274
|
<div className={styles.ai_chat_code_wrapper}>
|
|
226
275
|
<div className={styles.render_text}>
|
|
227
|
-
<CodeBlock
|
|
276
|
+
<CodeBlock
|
|
277
|
+
content={text}
|
|
278
|
+
labelService={labelService}
|
|
279
|
+
renderText={renderText}
|
|
280
|
+
relationId={relationId}
|
|
281
|
+
agentId={agentId}
|
|
282
|
+
/>
|
|
228
283
|
</div>
|
|
229
284
|
</div>
|
|
230
285
|
);
|
|
@@ -234,11 +289,13 @@ export const CodeBlockWrapperInput = ({
|
|
|
234
289
|
relationId,
|
|
235
290
|
agentId,
|
|
236
291
|
command,
|
|
292
|
+
labelService,
|
|
237
293
|
}: {
|
|
238
294
|
text: string;
|
|
239
295
|
relationId: string;
|
|
240
296
|
agentId?: string;
|
|
241
297
|
command?: string;
|
|
298
|
+
labelService?: LabelService;
|
|
242
299
|
}) => {
|
|
243
300
|
const chatFeatureRegistry = useInjectable<ChatFeatureRegistry>(ChatFeatureRegistryToken);
|
|
244
301
|
const [tag, setTag] = useState<string>('');
|
|
@@ -271,7 +328,13 @@ export const CodeBlockWrapperInput = ({
|
|
|
271
328
|
</div>
|
|
272
329
|
)}
|
|
273
330
|
{command && <div className={styles.tag}>/ {command}</div>}
|
|
274
|
-
<CodeBlock
|
|
331
|
+
<CodeBlock
|
|
332
|
+
content={txt}
|
|
333
|
+
labelService={labelService}
|
|
334
|
+
relationId={relationId}
|
|
335
|
+
agentId={agentId}
|
|
336
|
+
command={command}
|
|
337
|
+
/>
|
|
275
338
|
</div>
|
|
276
339
|
</div>
|
|
277
340
|
);
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import { LabelService, RecentFilesManager, useInjectable } from '@opensumi/ide-core-browser';
|
|
4
|
+
import { getIcon } from '@opensumi/ide-core-browser/lib/components';
|
|
5
|
+
import { URI, localize } from '@opensumi/ide-core-common';
|
|
6
|
+
import { CommandService } from '@opensumi/ide-core-common/lib/command';
|
|
7
|
+
import { WorkbenchEditorService } from '@opensumi/ide-editor';
|
|
8
|
+
import { FileSearchServicePath, IFileSearchService } from '@opensumi/ide-file-search';
|
|
9
|
+
import { IWorkspaceService } from '@opensumi/ide-workspace';
|
|
10
|
+
|
|
11
|
+
import { IChatInternalService } from '../../common';
|
|
12
|
+
import { ChatInternalService } from '../chat/chat.internal.service';
|
|
13
|
+
import { OPEN_MCP_CONFIG_COMMAND } from '../mcp/config/mcp-config.commands';
|
|
14
|
+
|
|
15
|
+
import styles from './components.module.less';
|
|
16
|
+
import { MentionInput } from './mention-input/mention-input';
|
|
17
|
+
import { FooterButtonPosition, FooterConfig, MentionItem, MentionType } from './mention-input/types';
|
|
18
|
+
|
|
19
|
+
export interface IChatMentionInputProps {
|
|
20
|
+
onSend: (value: string, agentId?: string, command?: string, option?: { model: string; [key: string]: any }) => void;
|
|
21
|
+
onValueChange?: (value: string) => void;
|
|
22
|
+
onExpand?: (value: boolean) => void;
|
|
23
|
+
placeholder?: string;
|
|
24
|
+
enableOptions?: boolean;
|
|
25
|
+
disabled?: boolean;
|
|
26
|
+
sendBtnClassName?: string;
|
|
27
|
+
defaultHeight?: number;
|
|
28
|
+
value?: string;
|
|
29
|
+
autoFocus?: boolean;
|
|
30
|
+
theme?: string | null;
|
|
31
|
+
setTheme: (theme: string | null) => void;
|
|
32
|
+
agentId: string;
|
|
33
|
+
setAgentId: (id: string) => void;
|
|
34
|
+
defaultAgentId?: string;
|
|
35
|
+
command: string;
|
|
36
|
+
setCommand: (command: string) => void;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// 指令命令激活组件
|
|
40
|
+
export const ChatMentionInput = React.forwardRef((props: IChatMentionInputProps) => {
|
|
41
|
+
const { onSend, disabled = false } = props;
|
|
42
|
+
|
|
43
|
+
const [value, setValue] = useState(props.value || '');
|
|
44
|
+
const aiChatService = useInjectable<ChatInternalService>(IChatInternalService);
|
|
45
|
+
const commandService = useInjectable<CommandService>(CommandService);
|
|
46
|
+
const searchService = useInjectable<IFileSearchService>(FileSearchServicePath);
|
|
47
|
+
const recentFilesManager = useInjectable<RecentFilesManager>(RecentFilesManager);
|
|
48
|
+
const workspaceService = useInjectable<IWorkspaceService>(IWorkspaceService);
|
|
49
|
+
const editorService = useInjectable<WorkbenchEditorService>(WorkbenchEditorService);
|
|
50
|
+
const labelService = useInjectable<LabelService>(LabelService);
|
|
51
|
+
|
|
52
|
+
const handleShowMCPConfig = React.useCallback(() => {
|
|
53
|
+
commandService.executeCommand(OPEN_MCP_CONFIG_COMMAND.id);
|
|
54
|
+
}, [commandService]);
|
|
55
|
+
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
if (props.value !== value) {
|
|
58
|
+
setValue(props.value || '');
|
|
59
|
+
}
|
|
60
|
+
}, [props.value]);
|
|
61
|
+
|
|
62
|
+
// 默认菜单项
|
|
63
|
+
const defaultMenuItems: MentionItem[] = [
|
|
64
|
+
// {
|
|
65
|
+
// id: 'code',
|
|
66
|
+
// type: 'code',
|
|
67
|
+
// text: 'Code',
|
|
68
|
+
// icon: getIcon('codebraces'),
|
|
69
|
+
// getHighestLevelItems: () => [],
|
|
70
|
+
// getItems: async (searchText: string) => {
|
|
71
|
+
// const currentEditor = editorService.currentEditor;
|
|
72
|
+
// if (!currentEditor) {
|
|
73
|
+
// return [];
|
|
74
|
+
// }
|
|
75
|
+
// const currentDocumentModel = currentEditor.currentDocumentModel;
|
|
76
|
+
// if (!currentDocumentModel) {
|
|
77
|
+
// return [];
|
|
78
|
+
// }
|
|
79
|
+
// const symbols = await commandService.executeCommand('_executeFormatDocumentProvider', currentDocumentModel.uri.codeUri);
|
|
80
|
+
// return [];
|
|
81
|
+
// },
|
|
82
|
+
// },
|
|
83
|
+
{
|
|
84
|
+
id: MentionType.FILE,
|
|
85
|
+
type: MentionType.FILE,
|
|
86
|
+
text: 'File',
|
|
87
|
+
icon: getIcon('file'),
|
|
88
|
+
getHighestLevelItems: () => {
|
|
89
|
+
const currentEditor = editorService.currentEditor;
|
|
90
|
+
const currentUri = currentEditor?.currentUri;
|
|
91
|
+
if (!currentUri) {
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
return [
|
|
95
|
+
{
|
|
96
|
+
id: currentUri.codeUri.fsPath,
|
|
97
|
+
type: MentionType.FILE,
|
|
98
|
+
text: currentUri.displayName,
|
|
99
|
+
value: currentUri.codeUri.fsPath,
|
|
100
|
+
description: `(${localize('aiNative.chat.defaultContextFile')})`,
|
|
101
|
+
contextId: currentUri.codeUri.fsPath,
|
|
102
|
+
icon: labelService.getIcon(currentUri),
|
|
103
|
+
},
|
|
104
|
+
];
|
|
105
|
+
},
|
|
106
|
+
getItems: async (searchText: string) => {
|
|
107
|
+
if (!searchText) {
|
|
108
|
+
const recentFile = await recentFilesManager.getMostRecentlyOpenedFiles();
|
|
109
|
+
return Promise.all(
|
|
110
|
+
recentFile.map(async (file) => {
|
|
111
|
+
const uri = new URI(file);
|
|
112
|
+
return {
|
|
113
|
+
id: uri.codeUri.fsPath,
|
|
114
|
+
type: MentionType.FILE,
|
|
115
|
+
text: uri.displayName,
|
|
116
|
+
value: uri.codeUri.fsPath,
|
|
117
|
+
description: (await workspaceService.asRelativePath(uri.parent))?.path || '',
|
|
118
|
+
contextId: uri.codeUri.fsPath,
|
|
119
|
+
icon: labelService.getIcon(uri),
|
|
120
|
+
};
|
|
121
|
+
}),
|
|
122
|
+
);
|
|
123
|
+
} else {
|
|
124
|
+
const rootUris = (await workspaceService.roots).map((root) => new URI(root.uri).codeUri.fsPath.toString());
|
|
125
|
+
const results = await searchService.find(searchText, {
|
|
126
|
+
rootUris,
|
|
127
|
+
useGitIgnore: true,
|
|
128
|
+
noIgnoreParent: true,
|
|
129
|
+
fuzzyMatch: true,
|
|
130
|
+
limit: 10,
|
|
131
|
+
});
|
|
132
|
+
return Promise.all(
|
|
133
|
+
results.map(async (file) => {
|
|
134
|
+
const uri = new URI(file);
|
|
135
|
+
return {
|
|
136
|
+
id: uri.codeUri.fsPath,
|
|
137
|
+
type: MentionType.FILE,
|
|
138
|
+
text: uri.displayName,
|
|
139
|
+
value: uri.codeUri.fsPath,
|
|
140
|
+
description: (await workspaceService.asRelativePath(uri.parent))?.path || '',
|
|
141
|
+
contextId: uri.codeUri.fsPath,
|
|
142
|
+
icon: labelService.getIcon(uri),
|
|
143
|
+
};
|
|
144
|
+
}),
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
id: MentionType.FOLDER,
|
|
151
|
+
type: MentionType.FOLDER,
|
|
152
|
+
text: 'Folder',
|
|
153
|
+
icon: getIcon('folder'),
|
|
154
|
+
getHighestLevelItems: () => {
|
|
155
|
+
const currentEditor = editorService.currentEditor;
|
|
156
|
+
const currentFolderUri = currentEditor?.currentUri?.parent;
|
|
157
|
+
if (!currentFolderUri) {
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
return [
|
|
161
|
+
{
|
|
162
|
+
id: currentFolderUri.codeUri.fsPath,
|
|
163
|
+
type: MentionType.FOLDER,
|
|
164
|
+
text: currentFolderUri.displayName,
|
|
165
|
+
value: currentFolderUri.codeUri.fsPath,
|
|
166
|
+
description: `(${localize('aiNative.chat.defaultContextFolder')})`,
|
|
167
|
+
contextId: currentFolderUri.codeUri.fsPath,
|
|
168
|
+
icon: getIcon('folder'),
|
|
169
|
+
},
|
|
170
|
+
];
|
|
171
|
+
},
|
|
172
|
+
getItems: async (searchText: string) => {
|
|
173
|
+
if (!searchText) {
|
|
174
|
+
const recentFile = await recentFilesManager.getMostRecentlyOpenedFiles();
|
|
175
|
+
const recentFolder = Array.from(new Set(recentFile.map((file) => new URI(file).parent.codeUri.fsPath)));
|
|
176
|
+
return Promise.all(
|
|
177
|
+
recentFolder.map(async (folder) => {
|
|
178
|
+
const uri = new URI(folder);
|
|
179
|
+
const relativePath = await workspaceService.asRelativePath(uri);
|
|
180
|
+
return {
|
|
181
|
+
id: uri.codeUri.fsPath,
|
|
182
|
+
type: MentionType.FOLDER,
|
|
183
|
+
text: uri.displayName,
|
|
184
|
+
value: uri.codeUri.fsPath,
|
|
185
|
+
description: relativePath?.root ? relativePath.path : '',
|
|
186
|
+
contextId: uri.codeUri.fsPath,
|
|
187
|
+
icon: getIcon('folder'),
|
|
188
|
+
};
|
|
189
|
+
}),
|
|
190
|
+
);
|
|
191
|
+
} else {
|
|
192
|
+
const rootUris = (await workspaceService.roots).map((root) => new URI(root.uri).codeUri.fsPath.toString());
|
|
193
|
+
const results = await searchService.find(searchText, {
|
|
194
|
+
rootUris,
|
|
195
|
+
useGitIgnore: true,
|
|
196
|
+
noIgnoreParent: true,
|
|
197
|
+
fuzzyMatch: true,
|
|
198
|
+
limit: 10,
|
|
199
|
+
onlyFolders: true,
|
|
200
|
+
});
|
|
201
|
+
return Promise.all(
|
|
202
|
+
results.map(async (folder) => {
|
|
203
|
+
const uri = new URI(folder);
|
|
204
|
+
return {
|
|
205
|
+
id: uri.codeUri.fsPath,
|
|
206
|
+
type: MentionType.FOLDER,
|
|
207
|
+
text: uri.displayName,
|
|
208
|
+
value: uri.codeUri.fsPath,
|
|
209
|
+
description: (await workspaceService.asRelativePath(uri.parent))?.path || '',
|
|
210
|
+
contextId: uri.codeUri.fsPath,
|
|
211
|
+
icon: getIcon('folder'),
|
|
212
|
+
};
|
|
213
|
+
}),
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
];
|
|
219
|
+
|
|
220
|
+
const defaultMentionInputFooterOptions: FooterConfig = useMemo(
|
|
221
|
+
() => ({
|
|
222
|
+
modelOptions: [
|
|
223
|
+
{ label: 'QWQ 32B', value: 'qwq-32b' },
|
|
224
|
+
{ label: 'DeepSeek R1', value: 'deepseek-r1' },
|
|
225
|
+
],
|
|
226
|
+
defaultModel: 'deepseek-r1',
|
|
227
|
+
buttons: [
|
|
228
|
+
{
|
|
229
|
+
id: 'mcp-server',
|
|
230
|
+
icon: 'mcp',
|
|
231
|
+
title: 'MCP Server',
|
|
232
|
+
onClick: handleShowMCPConfig,
|
|
233
|
+
position: FooterButtonPosition.LEFT,
|
|
234
|
+
},
|
|
235
|
+
],
|
|
236
|
+
showModelSelector: true,
|
|
237
|
+
}),
|
|
238
|
+
[handleShowMCPConfig],
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
const handleStop = useCallback(() => {
|
|
242
|
+
aiChatService.cancelRequest();
|
|
243
|
+
}, []);
|
|
244
|
+
|
|
245
|
+
const handleSend = useCallback(
|
|
246
|
+
async (content: string, option?: { model: string; [key: string]: any }) => {
|
|
247
|
+
if (disabled) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
onSend(content, undefined, undefined, option);
|
|
251
|
+
},
|
|
252
|
+
[onSend, editorService, disabled],
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
return (
|
|
256
|
+
<div className={styles.chat_input_container}>
|
|
257
|
+
<MentionInput
|
|
258
|
+
mentionItems={defaultMenuItems}
|
|
259
|
+
onSend={handleSend}
|
|
260
|
+
onStop={handleStop}
|
|
261
|
+
loading={disabled}
|
|
262
|
+
labelService={labelService}
|
|
263
|
+
placeholder={localize('aiNative.chat.input.placeholder.default')}
|
|
264
|
+
footerConfig={defaultMentionInputFooterOptions}
|
|
265
|
+
/>
|
|
266
|
+
</div>
|
|
267
|
+
);
|
|
268
|
+
});
|