@opensumi/ide-ai-native 3.8.1-next-1741080291.0 → 3.8.1-next-1741092802.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/browser/ai-core.contribution.d.ts.map +1 -1
- package/lib/browser/ai-core.contribution.js +22 -22
- package/lib/browser/ai-core.contribution.js.map +1 -1
- package/lib/browser/chat/chat-agent.service.d.ts +8 -0
- package/lib/browser/chat/chat-agent.service.d.ts.map +1 -1
- package/lib/browser/chat/chat-agent.service.js +32 -5
- package/lib/browser/chat/chat-agent.service.js.map +1 -1
- package/lib/browser/chat/chat-model.d.ts.map +1 -1
- package/lib/browser/chat/chat-model.js +3 -2
- package/lib/browser/chat/chat-model.js.map +1 -1
- package/lib/browser/chat/chat-proxy.service.d.ts.map +1 -1
- package/lib/browser/chat/chat-proxy.service.js +3 -1
- package/lib/browser/chat/chat-proxy.service.js.map +1 -1
- package/lib/browser/chat/chat.module.less +1 -2
- package/lib/browser/chat/chat.view.d.ts.map +1 -1
- package/lib/browser/chat/chat.view.js +6 -38
- package/lib/browser/chat/chat.view.js.map +1 -1
- package/lib/browser/components/ChatContext/index.js +2 -2
- package/lib/browser/components/ChatContext/index.js.map +1 -1
- package/lib/browser/components/ChatInput.d.ts.map +1 -1
- package/lib/browser/components/ChatInput.js +25 -1
- package/lib/browser/components/ChatInput.js.map +1 -1
- package/lib/browser/components/ChatToolRender.d.ts.map +1 -1
- package/lib/browser/components/ChatToolRender.js +2 -3
- package/lib/browser/components/ChatToolRender.js.map +1 -1
- package/lib/browser/components/chat-history.module.less +1 -1
- package/lib/browser/components/components.module.less +20 -0
- package/lib/browser/context/llm-context.service.d.ts +18 -5
- package/lib/browser/context/llm-context.service.d.ts.map +1 -1
- package/lib/browser/context/llm-context.service.js +80 -47
- package/lib/browser/context/llm-context.service.js.map +1 -1
- package/lib/browser/layout/layout.module.less +4 -4
- package/lib/browser/mcp/tools/components/ExpandableFileList.d.ts +13 -0
- package/lib/browser/mcp/tools/components/ExpandableFileList.d.ts.map +1 -0
- package/lib/browser/mcp/tools/components/{SearchResult.js → ExpandableFileList.js} +29 -19
- package/lib/browser/mcp/tools/components/ExpandableFileList.js.map +1 -0
- package/lib/browser/mcp/tools/components/index.module.less +1 -0
- 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/fileSearch.d.ts +1 -0
- package/lib/browser/mcp/tools/fileSearch.d.ts.map +1 -1
- package/lib/browser/mcp/tools/fileSearch.js +14 -5
- 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 +1 -0
- package/lib/browser/mcp/tools/getDiagnosticsByPath.js.map +1 -1
- package/lib/browser/mcp/tools/grepSearch.d.ts.map +1 -1
- package/lib/browser/mcp/tools/grepSearch.js +6 -3
- package/lib/browser/mcp/tools/grepSearch.js.map +1 -1
- package/lib/browser/mcp/tools/handlers/ListDir.d.ts +1 -0
- package/lib/browser/mcp/tools/handlers/ListDir.d.ts.map +1 -1
- package/lib/browser/mcp/tools/handlers/ListDir.js +3 -0
- package/lib/browser/mcp/tools/handlers/ListDir.js.map +1 -1
- package/lib/browser/mcp/tools/handlers/RunCommand.d.ts.map +1 -1
- package/lib/browser/mcp/tools/handlers/RunCommand.js +2 -0
- package/lib/browser/mcp/tools/handlers/RunCommand.js.map +1 -1
- package/lib/browser/mcp/tools/listDir.d.ts +1 -0
- package/lib/browser/mcp/tools/listDir.d.ts.map +1 -1
- package/lib/browser/mcp/tools/listDir.js +35 -4
- package/lib/browser/mcp/tools/listDir.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/preferences/schema.d.ts.map +1 -1
- package/lib/browser/preferences/schema.js +0 -1
- package/lib/browser/preferences/schema.js.map +1 -1
- package/lib/common/llm-context.d.ts +13 -9
- 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 +4 -3
- package/lib/common/prompts/context-prompt-provider.d.ts.map +1 -1
- package/lib/common/prompts/context-prompt-provider.js +33 -22
- package/lib/common/prompts/context-prompt-provider.js.map +1 -1
- package/lib/node/base-language-model.d.ts +1 -1
- package/lib/node/base-language-model.d.ts.map +1 -1
- package/lib/node/base-language-model.js +3 -3
- package/lib/node/base-language-model.js.map +1 -1
- package/package.json +23 -23
- package/src/browser/ai-core.contribution.ts +27 -26
- package/src/browser/chat/chat-agent.service.ts +38 -7
- package/src/browser/chat/chat-model.ts +11 -6
- package/src/browser/chat/chat-proxy.service.ts +4 -2
- package/src/browser/chat/chat.module.less +1 -2
- package/src/browser/chat/chat.view.tsx +7 -70
- package/src/browser/components/ChatContext/index.tsx +2 -2
- package/src/browser/components/ChatInput.tsx +67 -3
- package/src/browser/components/ChatToolRender.tsx +1 -2
- package/src/browser/components/chat-history.module.less +1 -1
- package/src/browser/components/components.module.less +20 -0
- package/src/browser/context/llm-context.service.ts +93 -54
- package/src/browser/layout/layout.module.less +4 -4
- package/src/browser/mcp/tools/components/ExpandableFileList.tsx +133 -0
- package/src/browser/mcp/tools/components/index.module.less +1 -0
- package/src/browser/mcp/tools/createNewFileWithText.ts +1 -0
- package/src/browser/mcp/tools/fileSearch.ts +14 -4
- package/src/browser/mcp/tools/getDiagnosticsByPath.ts +1 -0
- package/src/browser/mcp/tools/grepSearch.ts +6 -3
- package/src/browser/mcp/tools/handlers/ListDir.ts +4 -0
- package/src/browser/mcp/tools/handlers/RunCommand.ts +2 -0
- package/src/browser/mcp/tools/listDir.ts +36 -5
- package/src/browser/mcp/tools/runTerminalCmd.ts +1 -0
- package/src/browser/preferences/schema.ts +0 -1
- package/src/common/llm-context.ts +10 -4
- package/src/common/prompts/context-prompt-provider.ts +38 -29
- package/src/node/base-language-model.ts +3 -1
- package/lib/browser/mcp/tools/components/SearchResult.d.ts +0 -11
- package/lib/browser/mcp/tools/components/SearchResult.d.ts.map +0 -1
- package/lib/browser/mcp/tools/components/SearchResult.js.map +0 -1
- package/src/browser/mcp/tools/components/SearchResult.tsx +0 -92
|
@@ -279,7 +279,6 @@
|
|
|
279
279
|
}
|
|
280
280
|
}
|
|
281
281
|
|
|
282
|
-
|
|
283
282
|
.chat_tips_container {
|
|
284
283
|
display: flex;
|
|
285
284
|
align-items: center;
|
|
@@ -290,6 +289,6 @@
|
|
|
290
289
|
}
|
|
291
290
|
|
|
292
291
|
.chat_history {
|
|
293
|
-
width: calc(100% -
|
|
292
|
+
width: calc(100% - 40px);
|
|
294
293
|
color: var(--design-text-foreground);
|
|
295
294
|
}
|
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
AINativeConfigService,
|
|
6
6
|
CommandService,
|
|
7
7
|
getIcon,
|
|
8
|
-
useEventEffect,
|
|
9
8
|
useInjectable,
|
|
10
9
|
useUpdateOnEvent,
|
|
11
10
|
} from '@opensumi/ide-core-browser';
|
|
@@ -42,8 +41,6 @@ import {
|
|
|
42
41
|
IChatMessageStructure,
|
|
43
42
|
TokenMCPServerProxyService,
|
|
44
43
|
} from '../../common';
|
|
45
|
-
import { LLMContextService, LLMContextServiceToken } from '../../common/llm-context';
|
|
46
|
-
import { ChatAgentPromptProvider } from '../../common/prompts/context-prompt-provider';
|
|
47
44
|
import { ChatContext } from '../components/ChatContext';
|
|
48
45
|
import { CodeBlockWrapperInput } from '../components/ChatEditor';
|
|
49
46
|
import ChatHistory, { IChatHistoryItem } from '../components/ChatHistory';
|
|
@@ -82,18 +79,12 @@ export const AIChatView = () => {
|
|
|
82
79
|
const chatAgentService = useInjectable<IChatAgentService>(IChatAgentService);
|
|
83
80
|
const chatFeatureRegistry = useInjectable<ChatFeatureRegistry>(ChatFeatureRegistryToken);
|
|
84
81
|
const chatRenderRegistry = useInjectable<ChatRenderRegistry>(ChatRenderRegistryToken);
|
|
85
|
-
const contextService = useInjectable<LLMContextService>(LLMContextServiceToken);
|
|
86
|
-
const promptProvider = useInjectable<ChatAgentPromptProvider>(ChatAgentPromptProvider);
|
|
87
|
-
const mcpServerProxyService = useInjectable<MCPServerProxyService>(TokenMCPServerProxyService);
|
|
88
82
|
|
|
89
83
|
const layoutService = useInjectable<IMainLayoutService>(IMainLayoutService);
|
|
90
84
|
const msgHistoryManager = aiChatService.sessionModel.history;
|
|
91
85
|
const containerRef = React.useRef<HTMLDivElement>(null);
|
|
92
86
|
const autoScroll = React.useRef<boolean>(true);
|
|
93
87
|
const chatInputRef = React.useRef<{ setInputValue: (v: string) => void } | null>(null);
|
|
94
|
-
const dialogService = useInjectable<IDialogService>(IDialogService);
|
|
95
|
-
const aiNativeConfigService = useInjectable<AINativeConfigService>(AINativeConfigService);
|
|
96
|
-
const commandService = useInjectable<CommandService>(CommandService);
|
|
97
88
|
|
|
98
89
|
const [shortcutCommands, setShortcutCommands] = React.useState<ChatSlashCommandItemModel[]>([]);
|
|
99
90
|
|
|
@@ -115,8 +106,6 @@ export const AIChatView = () => {
|
|
|
115
106
|
const [defaultAgentId, setDefaultAgentId] = React.useState<string>('');
|
|
116
107
|
const [command, setCommand] = React.useState('');
|
|
117
108
|
const [theme, setTheme] = React.useState<string | null>(null);
|
|
118
|
-
const [mcpToolsCount, setMcpToolsCount] = React.useState<number>(0);
|
|
119
|
-
const [mcpServersCount, setMcpServersCount] = React.useState<number>(0);
|
|
120
109
|
|
|
121
110
|
React.useEffect(() => {
|
|
122
111
|
const featureSlashCommands = chatFeatureRegistry.getAllShortcutSlashCommand();
|
|
@@ -537,10 +526,7 @@ export const AIChatView = () => {
|
|
|
537
526
|
const { message, agentId, command, reportExtra } = value;
|
|
538
527
|
const { actionType, actionSource } = reportExtra || {};
|
|
539
528
|
|
|
540
|
-
const
|
|
541
|
-
const fullMessage = await promptProvider.provideContextPrompt(context, message);
|
|
542
|
-
|
|
543
|
-
const request = aiChatService.createRequest(fullMessage, agentId!, command);
|
|
529
|
+
const request = aiChatService.createRequest(message, agentId!, command);
|
|
544
530
|
if (!request) {
|
|
545
531
|
return;
|
|
546
532
|
}
|
|
@@ -689,32 +675,6 @@ export const AIChatView = () => {
|
|
|
689
675
|
};
|
|
690
676
|
}, [aiChatService.sessionModel]);
|
|
691
677
|
|
|
692
|
-
useEventEffect(
|
|
693
|
-
mcpServerProxyService.onChangeMCPServers,
|
|
694
|
-
() => {
|
|
695
|
-
mcpServerProxyService.getAllMCPTools().then((tools) => {
|
|
696
|
-
setMcpToolsCount(tools.length);
|
|
697
|
-
});
|
|
698
|
-
mcpServerProxyService.$getServers().then((servers) => {
|
|
699
|
-
setMcpServersCount(servers.length);
|
|
700
|
-
});
|
|
701
|
-
},
|
|
702
|
-
[mcpServerProxyService],
|
|
703
|
-
);
|
|
704
|
-
|
|
705
|
-
const handleShowMCPTools = React.useCallback(async () => {
|
|
706
|
-
const tools = await mcpServerProxyService.getAllMCPTools();
|
|
707
|
-
dialogService.open({
|
|
708
|
-
message: <MCPToolsDialog tools={tools} />,
|
|
709
|
-
type: MessageType.Empty,
|
|
710
|
-
buttons: ['关闭'],
|
|
711
|
-
});
|
|
712
|
-
}, [mcpServerProxyService, dialogService]);
|
|
713
|
-
|
|
714
|
-
const handleShowMCPConfig = React.useCallback(() => {
|
|
715
|
-
commandService.executeCommand(OPEN_MCP_CONFIG_COMMAND.id);
|
|
716
|
-
}, [commandService]);
|
|
717
|
-
|
|
718
678
|
return (
|
|
719
679
|
<div id={styles.ai_chat_view}>
|
|
720
680
|
<div className={styles.header_container}>
|
|
@@ -754,18 +714,6 @@ export const AIChatView = () => {
|
|
|
754
714
|
</Popover>
|
|
755
715
|
))}
|
|
756
716
|
</div>
|
|
757
|
-
<div className={styles.header_operate_right}>
|
|
758
|
-
{aiNativeConfigService.capabilities.supportsMCP && (
|
|
759
|
-
<>
|
|
760
|
-
<div className={styles.tag} onClick={handleShowMCPConfig}>
|
|
761
|
-
{`MCP Servers: ${mcpServersCount}`}
|
|
762
|
-
</div>
|
|
763
|
-
<div className={styles.tag} onClick={handleShowMCPTools}>
|
|
764
|
-
{`MCP Tools: ${mcpToolsCount}`}
|
|
765
|
-
</div>
|
|
766
|
-
</>
|
|
767
|
-
)}
|
|
768
|
-
</div>
|
|
769
717
|
</div>
|
|
770
718
|
<ChatInputWrapperRender
|
|
771
719
|
onSend={(value, agentId, command) =>
|
|
@@ -808,6 +756,8 @@ export function DefaultChatViewHeader({
|
|
|
808
756
|
const aiNativeConfigService = useInjectable<AINativeConfigService>(AINativeConfigService);
|
|
809
757
|
const mcpServerProxyService = useInjectable<MCPServerProxyService>(TokenMCPServerProxyService);
|
|
810
758
|
const aiChatService = useInjectable<ChatInternalService>(IChatInternalService);
|
|
759
|
+
const commandService = useInjectable<CommandService>(CommandService);
|
|
760
|
+
|
|
811
761
|
const [historyList, setHistoryList] = React.useState<IChatHistoryItem[]>([]);
|
|
812
762
|
const [currentTitle, setCurrentTitle] = React.useState<string>('');
|
|
813
763
|
const handleNewChat = React.useCallback(() => {
|
|
@@ -828,6 +778,10 @@ export function DefaultChatViewHeader({
|
|
|
828
778
|
[aiChatService],
|
|
829
779
|
);
|
|
830
780
|
|
|
781
|
+
const handleShowMCPConfig = React.useCallback(() => {
|
|
782
|
+
commandService.executeCommand(OPEN_MCP_CONFIG_COMMAND.id);
|
|
783
|
+
}, [commandService]);
|
|
784
|
+
|
|
831
785
|
const handleShowMCPTools = React.useCallback(async () => {
|
|
832
786
|
const tools = await mcpServerProxyService.getAllMCPTools();
|
|
833
787
|
dialogService.open({
|
|
@@ -916,23 +870,6 @@ export function DefaultChatViewHeader({
|
|
|
916
870
|
ariaLabel={localize('aiNative.operate.clear.title')}
|
|
917
871
|
/>
|
|
918
872
|
</Popover>
|
|
919
|
-
{aiNativeConfigService.capabilities.supportsMCP && (
|
|
920
|
-
<Popover
|
|
921
|
-
overlayClassName={styles.popover_icon}
|
|
922
|
-
id={'ai-chat-header-tools'}
|
|
923
|
-
position={PopoverPosition.left}
|
|
924
|
-
title={localize('aiNative.operate.tools.title')}
|
|
925
|
-
>
|
|
926
|
-
<EnhanceIcon
|
|
927
|
-
wrapperClassName={styles.action_btn}
|
|
928
|
-
className={getIcon('menubar-tool')}
|
|
929
|
-
onClick={handleShowMCPTools}
|
|
930
|
-
tabIndex={0}
|
|
931
|
-
role='button'
|
|
932
|
-
ariaLabel={localize('aiNative.operate.tools.title')}
|
|
933
|
-
/>
|
|
934
|
-
</Popover>
|
|
935
|
-
)}
|
|
936
873
|
<Popover
|
|
937
874
|
overlayClassName={styles.popover_icon}
|
|
938
875
|
id={'ai-chat-header-close'}
|
|
@@ -39,7 +39,7 @@ export const ChatContext = memo(() => {
|
|
|
39
39
|
50,
|
|
40
40
|
)((files) => {
|
|
41
41
|
if (files) {
|
|
42
|
-
updateAddedFiles(files);
|
|
42
|
+
updateAddedFiles([...files.attached]);
|
|
43
43
|
}
|
|
44
44
|
}, contextService);
|
|
45
45
|
|
|
@@ -57,7 +57,7 @@ export const ChatContext = memo(() => {
|
|
|
57
57
|
}, []);
|
|
58
58
|
|
|
59
59
|
const onDidDeselect = useCallback((uri: URI) => {
|
|
60
|
-
contextService.removeFileFromContext(uri);
|
|
60
|
+
contextService.removeFileFromContext(uri, true);
|
|
61
61
|
}, []);
|
|
62
62
|
|
|
63
63
|
const onDidClickFile = useCallback((uri: URI) => {
|
|
@@ -1,18 +1,29 @@
|
|
|
1
1
|
import cls from 'classnames';
|
|
2
2
|
import React, { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
|
|
3
3
|
|
|
4
|
-
import { useInjectable, useLatest } from '@opensumi/ide-core-browser';
|
|
4
|
+
import { AINativeConfigService, useInjectable, useLatest } from '@opensumi/ide-core-browser';
|
|
5
5
|
import { Icon, Popover, PopoverPosition, getIcon } from '@opensumi/ide-core-browser/lib/components';
|
|
6
6
|
import { EnhanceIcon } from '@opensumi/ide-core-browser/lib/components/ai-native';
|
|
7
7
|
import { InteractiveInput } from '@opensumi/ide-core-browser/lib/components/ai-native/interactive-input/index';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
ChatAgentViewServiceToken,
|
|
10
|
+
ChatFeatureRegistryToken,
|
|
11
|
+
MessageType,
|
|
12
|
+
localize,
|
|
13
|
+
runWhenIdle,
|
|
14
|
+
} from '@opensumi/ide-core-common';
|
|
15
|
+
import { CommandService } from '@opensumi/ide-core-common/lib/command';
|
|
9
16
|
import { MonacoCommandRegistry } from '@opensumi/ide-editor/lib/browser/monaco-contrib/command/command.service';
|
|
17
|
+
import { IDialogService } from '@opensumi/ide-overlay';
|
|
10
18
|
|
|
11
|
-
import { AT_SIGN_SYMBOL, IChatAgentService, SLASH_SYMBOL } from '../../common';
|
|
19
|
+
import { AT_SIGN_SYMBOL, IChatAgentService, SLASH_SYMBOL, TokenMCPServerProxyService } from '../../common';
|
|
12
20
|
import { ChatAgentViewService } from '../chat/chat-agent.view.service';
|
|
13
21
|
import { ChatSlashCommandItemModel } from '../chat/chat-model';
|
|
14
22
|
import { ChatProxyService } from '../chat/chat-proxy.service';
|
|
15
23
|
import { ChatFeatureRegistry } from '../chat/chat.feature.registry';
|
|
24
|
+
import { OPEN_MCP_CONFIG_COMMAND } from '../mcp/config/mcp-config.commands';
|
|
25
|
+
import { MCPServerProxyService } from '../mcp/mcp-server-proxy.service';
|
|
26
|
+
import { MCPToolsDialog } from '../mcp/mcp-tools-dialog.view';
|
|
16
27
|
import { IChatSlashCommandItem } from '../types';
|
|
17
28
|
|
|
18
29
|
import styles from './components.module.less';
|
|
@@ -194,12 +205,29 @@ export const ChatInput = React.forwardRef((props: IChatInputProps, ref) => {
|
|
|
194
205
|
const [isExpand, setIsExpand] = useState(false);
|
|
195
206
|
const [placeholder, setPlaceHolder] = useState(localize('aiNative.chat.input.placeholder.default'));
|
|
196
207
|
|
|
208
|
+
const dialogService = useInjectable<IDialogService>(IDialogService);
|
|
209
|
+
const aiNativeConfigService = useInjectable<AINativeConfigService>(AINativeConfigService);
|
|
210
|
+
const mcpServerProxyService = useInjectable<MCPServerProxyService>(TokenMCPServerProxyService);
|
|
197
211
|
const monacoCommandRegistry = useInjectable<MonacoCommandRegistry>(MonacoCommandRegistry);
|
|
198
212
|
const chatAgentService = useInjectable<IChatAgentService>(IChatAgentService);
|
|
199
213
|
const chatFeatureRegistry = useInjectable<ChatFeatureRegistry>(ChatFeatureRegistryToken);
|
|
214
|
+
const commandService = useInjectable<CommandService>(CommandService);
|
|
200
215
|
|
|
201
216
|
const currentAgentIdRef = useLatest(agentId);
|
|
202
217
|
|
|
218
|
+
const handleShowMCPConfig = React.useCallback(() => {
|
|
219
|
+
commandService.executeCommand(OPEN_MCP_CONFIG_COMMAND.id);
|
|
220
|
+
}, [commandService]);
|
|
221
|
+
|
|
222
|
+
const handleShowMCPTools = React.useCallback(async () => {
|
|
223
|
+
const tools = await mcpServerProxyService.getAllMCPTools();
|
|
224
|
+
dialogService.open({
|
|
225
|
+
message: <MCPToolsDialog tools={tools} />,
|
|
226
|
+
type: MessageType.Empty,
|
|
227
|
+
buttons: [localize('dialog.file.close')],
|
|
228
|
+
});
|
|
229
|
+
}, [mcpServerProxyService, dialogService]);
|
|
230
|
+
|
|
203
231
|
useImperativeHandle(ref, () => ({
|
|
204
232
|
setInputValue: (v: string) => {
|
|
205
233
|
setValue(v);
|
|
@@ -461,6 +489,42 @@ export const ChatInput = React.forwardRef((props: IChatInputProps, ref) => {
|
|
|
461
489
|
height={inputHeight}
|
|
462
490
|
popoverPosition={PopoverPosition.left}
|
|
463
491
|
/>
|
|
492
|
+
<div className={styles.chat_input_footer}>
|
|
493
|
+
{aiNativeConfigService.capabilities.supportsMCP && (
|
|
494
|
+
<div className={styles.mcp_desc}>
|
|
495
|
+
<Popover
|
|
496
|
+
overlayClassName={styles.popover_icon}
|
|
497
|
+
id={'ai-chat-header-mcp-server'}
|
|
498
|
+
position={PopoverPosition.left}
|
|
499
|
+
title={'MCP Server'}
|
|
500
|
+
>
|
|
501
|
+
<EnhanceIcon
|
|
502
|
+
wrapperClassName={styles.action_btn}
|
|
503
|
+
className={'codicon codicon-server'}
|
|
504
|
+
onClick={handleShowMCPConfig}
|
|
505
|
+
tabIndex={0}
|
|
506
|
+
role='button'
|
|
507
|
+
ariaLabel={'MCP Server'}
|
|
508
|
+
/>
|
|
509
|
+
</Popover>
|
|
510
|
+
<Popover
|
|
511
|
+
overlayClassName={styles.popover_icon}
|
|
512
|
+
id={'ai-chat-header-tools'}
|
|
513
|
+
position={PopoverPosition.left}
|
|
514
|
+
title={localize('aiNative.operate.tools.title')}
|
|
515
|
+
>
|
|
516
|
+
<EnhanceIcon
|
|
517
|
+
wrapperClassName={styles.action_btn}
|
|
518
|
+
className={getIcon('menubar-tool')}
|
|
519
|
+
onClick={handleShowMCPTools}
|
|
520
|
+
tabIndex={0}
|
|
521
|
+
role='button'
|
|
522
|
+
ariaLabel={localize('aiNative.operate.tools.title')}
|
|
523
|
+
/>
|
|
524
|
+
</Popover>
|
|
525
|
+
</div>
|
|
526
|
+
)}
|
|
527
|
+
</div>
|
|
464
528
|
</div>
|
|
465
529
|
);
|
|
466
530
|
});
|
|
@@ -67,13 +67,12 @@ export const ChatToolRender = (props: { value: IChatToolContent['content']; mess
|
|
|
67
67
|
<div className={styles['chat-tool-render']}>
|
|
68
68
|
<div className={styles['tool-header']} onClick={toggleExpand}>
|
|
69
69
|
<div className={styles['tool-name']}>
|
|
70
|
-
<
|
|
70
|
+
<Icon iconClass={`codicon codicon-triangle-${isExpanded ? 'down' : 'right'}`} />
|
|
71
71
|
{label}
|
|
72
72
|
</div>
|
|
73
73
|
{value.state && (
|
|
74
74
|
<div className={styles['tool-state']}>
|
|
75
75
|
<span className={styles['state-icon']}>{stateInfo.icon}</span>
|
|
76
|
-
<span className={styles['state-label']}>{stateInfo.label}</span>
|
|
77
76
|
</div>
|
|
78
77
|
)}
|
|
79
78
|
</div>
|
|
@@ -96,6 +96,7 @@
|
|
|
96
96
|
.chat_input_container {
|
|
97
97
|
position: relative;
|
|
98
98
|
border-radius: 9px;
|
|
99
|
+
padding: 10px 0px 0px 0px;
|
|
99
100
|
border: 1px solid var(--kt-input-border);
|
|
100
101
|
background-color: var(--design-chatInput-background);
|
|
101
102
|
&.active {
|
|
@@ -505,3 +506,22 @@
|
|
|
505
506
|
}
|
|
506
507
|
}
|
|
507
508
|
}
|
|
509
|
+
|
|
510
|
+
.chat_input_footer {
|
|
511
|
+
padding: 0px 10px;
|
|
512
|
+
display: flex;
|
|
513
|
+
align-items: center;
|
|
514
|
+
font-size: 12px;
|
|
515
|
+
|
|
516
|
+
.model_selector {
|
|
517
|
+
display: flex;
|
|
518
|
+
font-size: 11px;
|
|
519
|
+
align-items: center;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
.mcp_desc {
|
|
523
|
+
padding: 5px 0px;
|
|
524
|
+
display: flex;
|
|
525
|
+
align-items: center;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
import { EditorSelectionChangeEvent } from '@opensumi/ide-editor/lib/browser/types';
|
|
13
13
|
import { IMarkerService } from '@opensumi/ide-markers/lib/common/types';
|
|
14
14
|
|
|
15
|
-
import { FileContext, LLMContextService, SerializedContext } from '../../common/llm-context';
|
|
15
|
+
import { AttachFileContext, FileContext, LLMContextService, SerializedContext } from '../../common/llm-context';
|
|
16
16
|
|
|
17
17
|
@Injectable()
|
|
18
18
|
export class LLMContextServiceImpl extends WithEventBus implements LLMContextService {
|
|
@@ -27,40 +27,68 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
|
|
|
27
27
|
|
|
28
28
|
private isAutoCollecting = false;
|
|
29
29
|
|
|
30
|
-
private
|
|
30
|
+
private contextVersion = 0;
|
|
31
31
|
|
|
32
|
-
private
|
|
33
|
-
|
|
34
|
-
private
|
|
32
|
+
private readonly maxAttachFilesLimit = 10;
|
|
33
|
+
private readonly maxViewFilesLimit = 20;
|
|
34
|
+
private readonly attachedFiles: FileContext[] = [];
|
|
35
|
+
private readonly recentlyViewFiles: FileContext[] = [];
|
|
36
|
+
private readonly onDidContextFilesChangeEmitter = new Emitter<{ viewed: FileContext[]; attached: FileContext[]; version: number }>();
|
|
35
37
|
onDidContextFilesChangeEvent = this.onDidContextFilesChangeEmitter.event;
|
|
36
38
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
private addFileToList(file: FileContext, list: FileContext[], maxLimit: number) {
|
|
40
|
+
const existingIndex = list.findIndex((f) => f.uri.toString() === file.uri.toString());
|
|
41
|
+
if (existingIndex > -1) {
|
|
42
|
+
list.splice(existingIndex, 1);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
list.push(file);
|
|
46
|
+
if (list.length > maxLimit) {
|
|
47
|
+
list.shift();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
addFileToContext(uri: URI, selection?: [number, number], isManual = false): void {
|
|
52
|
+
if (!uri) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
39
55
|
|
|
40
|
-
|
|
56
|
+
const file = { uri, selection };
|
|
57
|
+
const targetList = isManual ? this.attachedFiles : this.recentlyViewFiles;
|
|
58
|
+
const maxLimit = isManual ? this.maxAttachFilesLimit : this.maxViewFilesLimit;
|
|
41
59
|
|
|
42
|
-
if (
|
|
43
|
-
this.
|
|
60
|
+
if (isManual) {
|
|
61
|
+
this.docModelManager.createModelReference(uri);
|
|
44
62
|
}
|
|
45
63
|
|
|
64
|
+
this.addFileToList(file, targetList, maxLimit);
|
|
65
|
+
this.notifyContextChange();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private notifyContextChange(): void {
|
|
46
69
|
this.onDidContextFilesChangeEmitter.fire(this.getAllContextFiles());
|
|
47
70
|
}
|
|
48
71
|
|
|
49
72
|
cleanFileContext() {
|
|
50
|
-
this.
|
|
51
|
-
this.
|
|
73
|
+
this.attachedFiles.length = 0;
|
|
74
|
+
this.notifyContextChange();
|
|
52
75
|
}
|
|
53
76
|
|
|
54
77
|
private getAllContextFiles() {
|
|
55
|
-
return
|
|
78
|
+
return {
|
|
79
|
+
viewed: this.recentlyViewFiles,
|
|
80
|
+
attached: this.attachedFiles,
|
|
81
|
+
version: this.contextVersion++,
|
|
82
|
+
};
|
|
56
83
|
}
|
|
57
84
|
|
|
58
|
-
removeFileFromContext(uri: URI): void {
|
|
59
|
-
const
|
|
85
|
+
removeFileFromContext(uri: URI, isManual = false): void {
|
|
86
|
+
const targetList = isManual ? this.attachedFiles : this.recentlyViewFiles;
|
|
87
|
+
const index = targetList.findIndex((file) => file.uri.toString() === uri.toString());
|
|
60
88
|
if (index > -1) {
|
|
61
|
-
|
|
62
|
-
this.onDidContextFilesChangeEmitter.fire(this.getAllContextFiles());
|
|
89
|
+
targetList.splice(index, 1);
|
|
63
90
|
}
|
|
91
|
+
this.notifyContextChange();
|
|
64
92
|
}
|
|
65
93
|
|
|
66
94
|
startAutoCollection(): void {
|
|
@@ -78,8 +106,7 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
|
|
|
78
106
|
if (event.payload.uri.scheme !== 'file') {
|
|
79
107
|
return;
|
|
80
108
|
}
|
|
81
|
-
|
|
82
|
-
// this.addFileToContext(event.payload.uri);
|
|
109
|
+
this.addFileToContext(event.payload.uri, undefined, false);
|
|
83
110
|
}),
|
|
84
111
|
);
|
|
85
112
|
|
|
@@ -88,6 +115,8 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
|
|
|
88
115
|
if (event.payload.scheme !== 'file') {
|
|
89
116
|
return;
|
|
90
117
|
}
|
|
118
|
+
|
|
119
|
+
this.removeFileFromContext(event.payload, false);
|
|
91
120
|
}),
|
|
92
121
|
);
|
|
93
122
|
|
|
@@ -109,11 +138,12 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
|
|
|
109
138
|
].sort() as [number, number];
|
|
110
139
|
|
|
111
140
|
if (selection[0] === selection[1]) {
|
|
112
|
-
this.addFileToContext(event.payload.editorUri, undefined);
|
|
141
|
+
this.addFileToContext(event.payload.editorUri, undefined, false);
|
|
113
142
|
} else {
|
|
114
143
|
this.addFileToContext(
|
|
115
144
|
event.payload.editorUri,
|
|
116
145
|
selection.sort((a, b) => a - b),
|
|
146
|
+
false,
|
|
117
147
|
);
|
|
118
148
|
}
|
|
119
149
|
}
|
|
@@ -127,42 +157,51 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
|
|
|
127
157
|
|
|
128
158
|
serialize(): SerializedContext {
|
|
129
159
|
const files = this.getAllContextFiles();
|
|
130
|
-
const
|
|
131
|
-
.filter((v) => !v.selection)
|
|
132
|
-
.map((file) => {
|
|
133
|
-
const relativePath = URI.file(this.appConfig.workspaceDir).relative(file.uri);
|
|
134
|
-
if (relativePath) {
|
|
135
|
-
return relativePath.toString();
|
|
136
|
-
}
|
|
137
|
-
return file.uri.parent.toString();
|
|
138
|
-
})
|
|
139
|
-
.filter(Boolean);
|
|
140
|
-
|
|
141
|
-
const attachedFiles = files
|
|
142
|
-
.filter((v) => v.selection)
|
|
143
|
-
.map((file) => {
|
|
144
|
-
const ref = this.docModelManager.getModelReference(file.uri);
|
|
145
|
-
const content = ref!.instance.getText();
|
|
146
|
-
const lineErrors = this.markerService
|
|
147
|
-
.getManager()
|
|
148
|
-
.getMarkers({
|
|
149
|
-
resource: file.uri.toString(),
|
|
150
|
-
severities: MarkerSeverity.Error,
|
|
151
|
-
})
|
|
152
|
-
.map((marker) => marker.message);
|
|
153
|
-
|
|
154
|
-
return {
|
|
155
|
-
content,
|
|
156
|
-
lineErrors,
|
|
157
|
-
path: URI.file(this.appConfig.workspaceDir).relative(file.uri)!.toString(),
|
|
158
|
-
language: ref?.instance.languageId!,
|
|
159
|
-
};
|
|
160
|
-
})
|
|
161
|
-
.filter(Boolean);
|
|
160
|
+
const workspaceRoot = URI.file(this.appConfig.workspaceDir);
|
|
162
161
|
|
|
163
162
|
return {
|
|
164
|
-
recentlyViewFiles,
|
|
165
|
-
attachedFiles,
|
|
163
|
+
recentlyViewFiles: this.serializeRecentlyViewFiles(files.viewed, workspaceRoot),
|
|
164
|
+
attachedFiles: this.serializeAttachedFiles(files.attached, workspaceRoot),
|
|
166
165
|
};
|
|
167
166
|
}
|
|
167
|
+
|
|
168
|
+
private serializeRecentlyViewFiles(files: FileContext[], workspaceRoot: URI): string[] {
|
|
169
|
+
return files
|
|
170
|
+
.map((file) => workspaceRoot.relative(file.uri)?.toString() || file.uri.parent.toString())
|
|
171
|
+
.filter(Boolean);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
private serializeAttachedFiles(files: FileContext[], workspaceRoot: URI): AttachFileContext[] {
|
|
175
|
+
return files
|
|
176
|
+
.map((file) => this.serializeAttachedFile(file, workspaceRoot))
|
|
177
|
+
.filter(Boolean) as unknown as AttachFileContext[];
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private serializeAttachedFile(file: FileContext, workspaceRoot: URI) {
|
|
181
|
+
try {
|
|
182
|
+
const ref = this.docModelManager.getModelReference(file.uri);
|
|
183
|
+
if (!ref) {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return {
|
|
188
|
+
content: ref.instance.getText(),
|
|
189
|
+
lineErrors: this.getFileErrors(file.uri),
|
|
190
|
+
path: workspaceRoot.relative(file.uri)!.toString(),
|
|
191
|
+
language: ref.instance.languageId!,
|
|
192
|
+
};
|
|
193
|
+
} catch (e) {
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
private getFileErrors(uri: URI): string[] {
|
|
199
|
+
return this.markerService
|
|
200
|
+
.getManager()
|
|
201
|
+
.getMarkers({
|
|
202
|
+
resource: uri.toString(),
|
|
203
|
+
severities: MarkerSeverity.Error,
|
|
204
|
+
})
|
|
205
|
+
.map((marker) => marker.message);
|
|
206
|
+
}
|
|
168
207
|
}
|
|
@@ -14,16 +14,16 @@
|
|
|
14
14
|
padding: 8px 12px;
|
|
15
15
|
min-width: initial;
|
|
16
16
|
margin: 0;
|
|
17
|
-
|
|
18
|
-
::after {
|
|
19
|
-
content: '';
|
|
20
|
-
}
|
|
21
17
|
}
|
|
22
18
|
|
|
23
19
|
.rce-mbox-text {
|
|
24
20
|
line-height: 18px;
|
|
25
21
|
width: inherit;
|
|
26
22
|
font-size: 12px;
|
|
23
|
+
|
|
24
|
+
&::after {
|
|
25
|
+
display: none;
|
|
26
|
+
}
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
.rce-smsg {
|