@opensumi/ide-ai-native 3.8.1-next-1740571693.0 → 3.8.1-next-1740725107.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 (127) hide show
  1. package/lib/browser/ai-core.contribution.d.ts +4 -1
  2. package/lib/browser/ai-core.contribution.d.ts.map +1 -1
  3. package/lib/browser/ai-core.contribution.js +20 -1
  4. package/lib/browser/ai-core.contribution.js.map +1 -1
  5. package/lib/browser/chat/chat-manager.service.d.ts +6 -0
  6. package/lib/browser/chat/chat-manager.service.d.ts.map +1 -1
  7. package/lib/browser/chat/chat-manager.service.js +31 -1
  8. package/lib/browser/chat/chat-manager.service.js.map +1 -1
  9. package/lib/browser/chat/chat-model.d.ts +2 -0
  10. package/lib/browser/chat/chat-model.d.ts.map +1 -1
  11. package/lib/browser/chat/chat-model.js +8 -2
  12. package/lib/browser/chat/chat-model.js.map +1 -1
  13. package/lib/browser/chat/chat.internal.service.d.ts +1 -0
  14. package/lib/browser/chat/chat.internal.service.d.ts.map +1 -1
  15. package/lib/browser/chat/chat.internal.service.js +3 -0
  16. package/lib/browser/chat/chat.internal.service.js.map +1 -1
  17. package/lib/browser/chat/chat.module.less +1 -2
  18. package/lib/browser/chat/chat.view.d.ts.map +1 -1
  19. package/lib/browser/chat/chat.view.js +6 -38
  20. package/lib/browser/chat/chat.view.js.map +1 -1
  21. package/lib/browser/components/ChatContext/index.js +2 -2
  22. package/lib/browser/components/ChatContext/index.js.map +1 -1
  23. package/lib/browser/components/ChatHistory.d.ts +0 -1
  24. package/lib/browser/components/ChatHistory.d.ts.map +1 -1
  25. package/lib/browser/components/ChatHistory.js +14 -14
  26. package/lib/browser/components/ChatHistory.js.map +1 -1
  27. package/lib/browser/components/ChatInput.d.ts.map +1 -1
  28. package/lib/browser/components/ChatInput.js +25 -1
  29. package/lib/browser/components/ChatInput.js.map +1 -1
  30. package/lib/browser/components/ChatToolRender.d.ts.map +1 -1
  31. package/lib/browser/components/ChatToolRender.js +2 -3
  32. package/lib/browser/components/ChatToolRender.js.map +1 -1
  33. package/lib/browser/components/{chat-history.css → chat-history.module.less} +1 -1
  34. package/lib/browser/components/components.module.less +20 -0
  35. package/lib/browser/context/llm-context.service.d.ts +16 -5
  36. package/lib/browser/context/llm-context.service.d.ts.map +1 -1
  37. package/lib/browser/context/llm-context.service.js +78 -47
  38. package/lib/browser/context/llm-context.service.js.map +1 -1
  39. package/lib/browser/layout/layout.module.less +4 -4
  40. package/lib/browser/mcp/base-apply.service.d.ts +31 -40
  41. package/lib/browser/mcp/base-apply.service.d.ts.map +1 -1
  42. package/lib/browser/mcp/base-apply.service.js +233 -167
  43. package/lib/browser/mcp/base-apply.service.js.map +1 -1
  44. package/lib/browser/mcp/tools/components/EditFile.d.ts.map +1 -1
  45. package/lib/browser/mcp/tools/components/EditFile.js +55 -41
  46. package/lib/browser/mcp/tools/components/EditFile.js.map +1 -1
  47. package/lib/browser/mcp/tools/components/index.module.less +23 -3
  48. package/lib/browser/mcp/tools/createNewFileWithText.d.ts.map +1 -1
  49. package/lib/browser/mcp/tools/createNewFileWithText.js +1 -0
  50. package/lib/browser/mcp/tools/createNewFileWithText.js.map +1 -1
  51. package/lib/browser/mcp/tools/editFile.js +1 -1
  52. package/lib/browser/mcp/tools/editFile.js.map +1 -1
  53. package/lib/browser/mcp/tools/getDiagnosticsByPath.d.ts.map +1 -1
  54. package/lib/browser/mcp/tools/getDiagnosticsByPath.js +1 -0
  55. package/lib/browser/mcp/tools/getDiagnosticsByPath.js.map +1 -1
  56. package/lib/browser/mcp/tools/handlers/EditFile.d.ts +5 -1
  57. package/lib/browser/mcp/tools/handlers/EditFile.d.ts.map +1 -1
  58. package/lib/browser/mcp/tools/handlers/EditFile.js +4 -4
  59. package/lib/browser/mcp/tools/handlers/EditFile.js.map +1 -1
  60. package/lib/browser/mcp/tools/handlers/RunCommand.d.ts.map +1 -1
  61. package/lib/browser/mcp/tools/handlers/RunCommand.js +2 -0
  62. package/lib/browser/mcp/tools/handlers/RunCommand.js.map +1 -1
  63. package/lib/browser/mcp/tools/runTerminalCmd.d.ts.map +1 -1
  64. package/lib/browser/mcp/tools/runTerminalCmd.js +1 -0
  65. package/lib/browser/mcp/tools/runTerminalCmd.js.map +1 -1
  66. package/lib/browser/model/msg-history-manager.d.ts +1 -0
  67. package/lib/browser/model/msg-history-manager.d.ts.map +1 -1
  68. package/lib/browser/model/msg-history-manager.js +12 -2
  69. package/lib/browser/model/msg-history-manager.js.map +1 -1
  70. package/lib/browser/types.d.ts +1 -1
  71. package/lib/browser/types.d.ts.map +1 -1
  72. package/lib/browser/widget/inline-diff/inline-diff-manager.d.ts +6 -0
  73. package/lib/browser/widget/inline-diff/inline-diff-manager.d.ts.map +1 -0
  74. package/lib/browser/widget/inline-diff/inline-diff-manager.js +27 -0
  75. package/lib/browser/widget/inline-diff/inline-diff-manager.js.map +1 -0
  76. package/lib/browser/widget/inline-diff/inline-diff-widget.module.less +12 -0
  77. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts +2 -0
  78. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts.map +1 -1
  79. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js +11 -4
  80. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js.map +1 -1
  81. package/lib/common/llm-context.d.ts +12 -9
  82. package/lib/common/llm-context.d.ts.map +1 -1
  83. package/lib/common/llm-context.js.map +1 -1
  84. package/lib/common/prompts/context-prompt-provider.d.ts +4 -3
  85. package/lib/common/prompts/context-prompt-provider.d.ts.map +1 -1
  86. package/lib/common/prompts/context-prompt-provider.js +34 -22
  87. package/lib/common/prompts/context-prompt-provider.js.map +1 -1
  88. package/lib/common/types.d.ts +17 -0
  89. package/lib/common/types.d.ts.map +1 -1
  90. package/lib/common/types.js.map +1 -1
  91. package/lib/node/base-language-model.d.ts +1 -1
  92. package/lib/node/base-language-model.d.ts.map +1 -1
  93. package/lib/node/base-language-model.js +54 -3
  94. package/lib/node/base-language-model.js.map +1 -1
  95. package/package.json +23 -23
  96. package/src/browser/ai-core.contribution.ts +25 -1
  97. package/src/browser/chat/chat-manager.service.ts +29 -1
  98. package/src/browser/chat/chat-model.ts +18 -3
  99. package/src/browser/chat/chat.internal.service.ts +4 -0
  100. package/src/browser/chat/chat.module.less +1 -2
  101. package/src/browser/chat/chat.view.tsx +7 -70
  102. package/src/browser/components/ChatContext/index.tsx +2 -2
  103. package/src/browser/components/ChatHistory.tsx +21 -15
  104. package/src/browser/components/ChatInput.tsx +67 -4
  105. package/src/browser/components/ChatToolRender.tsx +1 -2
  106. package/src/browser/components/{chat-history.css → chat-history.module.less} +1 -1
  107. package/src/browser/components/components.module.less +20 -0
  108. package/src/browser/context/llm-context.service.ts +90 -54
  109. package/src/browser/layout/layout.module.less +4 -4
  110. package/src/browser/mcp/base-apply.service.ts +266 -213
  111. package/src/browser/mcp/tools/components/EditFile.tsx +82 -60
  112. package/src/browser/mcp/tools/components/index.module.less +23 -3
  113. package/src/browser/mcp/tools/createNewFileWithText.ts +1 -0
  114. package/src/browser/mcp/tools/editFile.ts +2 -2
  115. package/src/browser/mcp/tools/getDiagnosticsByPath.ts +1 -0
  116. package/src/browser/mcp/tools/handlers/EditFile.ts +4 -4
  117. package/src/browser/mcp/tools/handlers/RunCommand.ts +2 -0
  118. package/src/browser/mcp/tools/runTerminalCmd.ts +1 -0
  119. package/src/browser/model/msg-history-manager.ts +12 -2
  120. package/src/browser/types.ts +1 -1
  121. package/src/browser/widget/inline-diff/inline-diff-manager.tsx +38 -0
  122. package/src/browser/widget/inline-diff/inline-diff-widget.module.less +12 -0
  123. package/src/browser/widget/inline-stream-diff/inline-stream-diff.handler.tsx +13 -4
  124. package/src/common/llm-context.ts +10 -4
  125. package/src/common/prompts/context-prompt-provider.ts +39 -29
  126. package/src/common/types.ts +20 -0
  127. package/src/node/base-language-model.ts +63 -1
@@ -9,10 +9,13 @@ import {
9
9
  IStorage,
10
10
  STORAGE_NAMESPACE,
11
11
  StorageProvider,
12
+ debounce,
12
13
  } from '@opensumi/ide-core-common';
13
14
  import { ChatMessageRole, IChatMessage, IHistoryChatMessage } from '@opensumi/ide-core-common/lib/types/ai-native';
14
15
 
15
16
  import { IChatAgentService, IChatFollowup, IChatRequestMessage, IChatResponseErrorDetails } from '../../common';
17
+ import { LLMContextService, LLMContextServiceToken } from '../../common/llm-context';
18
+ import { ChatAgentPromptProvider } from '../../common/prompts/context-prompt-provider';
16
19
  import { MsgHistoryManager } from '../model/msg-history-manager';
17
20
 
18
21
  import { ChatModel, ChatRequestModel, ChatResponseModel, IChatProgressResponseContent } from './chat-model';
@@ -49,6 +52,12 @@ export class ChatManagerService extends Disposable {
49
52
  @Autowired(StorageProvider)
50
53
  private storageProvider: StorageProvider;
51
54
 
55
+ @Autowired(ChatAgentPromptProvider)
56
+ protected readonly promptProvider: ChatAgentPromptProvider;
57
+
58
+ @Autowired(LLMContextServiceToken)
59
+ protected readonly contextService: LLMContextService;
60
+
52
61
  private _chatStorage: IStorage;
53
62
 
54
63
  protected fromJSON(data: ISessionModel[]) {
@@ -89,6 +98,7 @@ export class ChatManagerService extends Disposable {
89
98
  const savedSessions = this.fromJSON(sessionsModelData);
90
99
  savedSessions.forEach((session) => {
91
100
  this.#sessionModels.set(session.sessionId, session);
101
+ this.listenSession(session);
92
102
  });
93
103
  await this.storageInitEmitter.fireAndAwait();
94
104
  }
@@ -98,11 +108,20 @@ export class ChatManagerService extends Disposable {
98
108
  }
99
109
 
100
110
  startSession() {
101
- const model = new ChatModel();
111
+ const model = new ChatModel({
112
+ provideContext: this.provideContextPrompt.bind(this),
113
+ });
102
114
  this.#sessionModels.set(model.sessionId, model);
115
+ this.listenSession(model);
103
116
  return model;
104
117
  }
105
118
 
119
+ private provideContextPrompt(message: string) {
120
+ const context = this.contextService.serialize();
121
+ const fullMessage = this.promptProvider.provideContextPrompt(context, message);
122
+ return fullMessage;
123
+ }
124
+
106
125
  getSession(sessionId: string): ChatModel | undefined {
107
126
  return this.#sessionModels.get(sessionId);
108
127
  }
@@ -196,6 +215,15 @@ export class ChatManagerService extends Disposable {
196
215
  }
197
216
  }
198
217
 
218
+ protected listenSession(session: ChatModel) {
219
+ this.addDispose(
220
+ session.history.onMessageAdditionalChange(() => {
221
+ this.saveSessions();
222
+ }),
223
+ );
224
+ }
225
+
226
+ @debounce(1000)
199
227
  protected saveSessions() {
200
228
  this._chatStorage.set('sessionModels', this.getSessions());
201
229
  }
@@ -274,13 +274,22 @@ export class ChatRequestModel implements IChatRequestModel {
274
274
  export class ChatModel extends Disposable implements IChatModel {
275
275
  private static requestIdPool = 0;
276
276
 
277
- constructor(initParams?: { sessionId?: string; history?: MsgHistoryManager; requests?: ChatRequestModel[] }) {
277
+ private provideContextPrompt?: (string) => string;
278
+
279
+ constructor(initParams?: {
280
+ sessionId?: string;
281
+ history?: MsgHistoryManager;
282
+ requests?: ChatRequestModel[];
283
+ provideContext?: (msg: string) => string;
284
+ }) {
278
285
  super();
279
286
  this.#sessionId = initParams?.sessionId ?? uuid();
280
287
  this.history = initParams?.history ?? new MsgHistoryManager();
281
288
  if (initParams?.requests) {
282
289
  this.#requests = new Map(initParams.requests.map((r) => [r.requestId, r]));
283
290
  }
291
+
292
+ this.provideContextPrompt = initParams?.provideContext;
284
293
  }
285
294
 
286
295
  #sessionId: string;
@@ -300,9 +309,15 @@ export class ChatModel extends Disposable implements IChatModel {
300
309
  readonly history: MsgHistoryManager;
301
310
 
302
311
  addRequest(message: IChatRequestMessage): ChatRequestModel {
312
+ const msg = message;
313
+ // first msg
314
+ if (this.provideContextPrompt) {
315
+ msg.prompt = this.provideContextPrompt(msg.prompt);
316
+ }
317
+
303
318
  const requestId = `${this.sessionId}_request_${ChatModel.requestIdPool++}`;
304
- const response = new ChatResponseModel(requestId, this, message.agentId);
305
- const request = new ChatRequestModel(requestId, this, message, response);
319
+ const response = new ChatResponseModel(requestId, this, msg.agentId);
320
+ const request = new ChatRequestModel(requestId, this, msg, response);
306
321
 
307
322
  this.#requests.set(requestId, request);
308
323
  return request;
@@ -94,6 +94,10 @@ export class ChatInternalService extends Disposable {
94
94
  return this.chatManagerService.getSessions();
95
95
  }
96
96
 
97
+ getSession(sessionId: string) {
98
+ return this.chatManagerService.getSession(sessionId);
99
+ }
100
+
97
101
  activateSession(sessionId: string) {
98
102
  const targetSession = this.chatManagerService.getSession(sessionId);
99
103
  if (!targetSession) {
@@ -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% - 60px);
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,17 +79,11 @@ 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 chatInputRef = React.useRef<{ setInputValue: (v: string) => void } | null>(null);
93
- const dialogService = useInjectable<IDialogService>(IDialogService);
94
- const aiNativeConfigService = useInjectable<AINativeConfigService>(AINativeConfigService);
95
- const commandService = useInjectable<CommandService>(CommandService);
96
87
 
97
88
  const [shortcutCommands, setShortcutCommands] = React.useState<ChatSlashCommandItemModel[]>([]);
98
89
 
@@ -114,8 +105,6 @@ export const AIChatView = () => {
114
105
  const [defaultAgentId, setDefaultAgentId] = React.useState<string>('');
115
106
  const [command, setCommand] = React.useState('');
116
107
  const [theme, setTheme] = React.useState<string | null>(null);
117
- const [mcpToolsCount, setMcpToolsCount] = React.useState<number>(0);
118
- const [mcpServersCount, setMcpServersCount] = React.useState<number>(0);
119
108
 
120
109
  React.useEffect(() => {
121
110
  const featureSlashCommands = chatFeatureRegistry.getAllShortcutSlashCommand();
@@ -515,10 +504,7 @@ export const AIChatView = () => {
515
504
  const { message, agentId, command, reportExtra } = value;
516
505
  const { actionType, actionSource } = reportExtra || {};
517
506
 
518
- const context = contextService.serialize();
519
- const fullMessage = await promptProvider.provideContextPrompt(context, message);
520
-
521
- const request = aiChatService.createRequest(fullMessage, agentId!, command);
507
+ const request = aiChatService.createRequest(message, agentId!, command);
522
508
  if (!request) {
523
509
  return;
524
510
  }
@@ -667,32 +653,6 @@ export const AIChatView = () => {
667
653
  };
668
654
  }, [aiChatService.sessionModel]);
669
655
 
670
- useEventEffect(
671
- mcpServerProxyService.onChangeMCPServers,
672
- () => {
673
- mcpServerProxyService.getAllMCPTools().then((tools) => {
674
- setMcpToolsCount(tools.length);
675
- });
676
- mcpServerProxyService.$getServers().then((servers) => {
677
- setMcpServersCount(servers.length);
678
- });
679
- },
680
- [mcpServerProxyService],
681
- );
682
-
683
- const handleShowMCPTools = React.useCallback(async () => {
684
- const tools = await mcpServerProxyService.getAllMCPTools();
685
- dialogService.open({
686
- message: <MCPToolsDialog tools={tools} />,
687
- type: MessageType.Empty,
688
- buttons: ['关闭'],
689
- });
690
- }, [mcpServerProxyService, dialogService]);
691
-
692
- const handleShowMCPConfig = React.useCallback(() => {
693
- commandService.executeCommand(OPEN_MCP_CONFIG_COMMAND.id);
694
- }, [commandService]);
695
-
696
656
  return (
697
657
  <div id={styles.ai_chat_view}>
698
658
  <div className={styles.header_container}>
@@ -732,18 +692,6 @@ export const AIChatView = () => {
732
692
  </Popover>
733
693
  ))}
734
694
  </div>
735
- <div className={styles.header_operate_right}>
736
- {aiNativeConfigService.capabilities.supportsMCP && (
737
- <>
738
- <div className={styles.tag} onClick={handleShowMCPConfig}>
739
- {`MCP Servers: ${mcpServersCount}`}
740
- </div>
741
- <div className={styles.tag} onClick={handleShowMCPTools}>
742
- {`MCP Tools: ${mcpToolsCount}`}
743
- </div>
744
- </>
745
- )}
746
- </div>
747
695
  </div>
748
696
  <ChatInputWrapperRender
749
697
  onSend={(value, agentId, command) =>
@@ -786,6 +734,8 @@ export function DefaultChatViewHeader({
786
734
  const aiNativeConfigService = useInjectable<AINativeConfigService>(AINativeConfigService);
787
735
  const mcpServerProxyService = useInjectable<MCPServerProxyService>(TokenMCPServerProxyService);
788
736
  const aiChatService = useInjectable<ChatInternalService>(IChatInternalService);
737
+ const commandService = useInjectable<CommandService>(CommandService);
738
+
789
739
  const [historyList, setHistoryList] = React.useState<IChatHistoryItem[]>([]);
790
740
  const [currentTitle, setCurrentTitle] = React.useState<string>('');
791
741
  const handleNewChat = React.useCallback(() => {
@@ -806,6 +756,10 @@ export function DefaultChatViewHeader({
806
756
  [aiChatService],
807
757
  );
808
758
 
759
+ const handleShowMCPConfig = React.useCallback(() => {
760
+ commandService.executeCommand(OPEN_MCP_CONFIG_COMMAND.id);
761
+ }, [commandService]);
762
+
809
763
  const handleShowMCPTools = React.useCallback(async () => {
810
764
  const tools = await mcpServerProxyService.getAllMCPTools();
811
765
  dialogService.open({
@@ -894,23 +848,6 @@ export function DefaultChatViewHeader({
894
848
  ariaLabel={localize('aiNative.operate.clear.title')}
895
849
  />
896
850
  </Popover>
897
- {aiNativeConfigService.capabilities.supportsMCP && (
898
- <Popover
899
- overlayClassName={styles.popover_icon}
900
- id={'ai-chat-header-tools'}
901
- position={PopoverPosition.left}
902
- title={localize('aiNative.operate.tools.title')}
903
- >
904
- <EnhanceIcon
905
- wrapperClassName={styles.action_btn}
906
- className={getIcon('menubar-tool')}
907
- onClick={handleShowMCPTools}
908
- tabIndex={0}
909
- role='button'
910
- ariaLabel={localize('aiNative.operate.tools.title')}
911
- />
912
- </Popover>
913
- )}
914
851
  <Popover
915
852
  overlayClassName={styles.popover_icon}
916
853
  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) => {
@@ -2,10 +2,11 @@ import cls from 'classnames';
2
2
  import React, { FC, memo, useCallback, useEffect, useRef, useState } from 'react';
3
3
 
4
4
  import { Icon, Input, Loading, Popover, PopoverPosition, PopoverTriggerType, getIcon } from '@opensumi/ide-components';
5
- import './chat-history.css';
6
5
  import { localize } from '@opensumi/ide-core-browser';
7
6
  import { EnhanceIcon } from '@opensumi/ide-core-browser/lib/components/ai-native';
8
7
 
8
+ import styles from './chat-history.module.less';
9
+
9
10
  export interface IChatHistoryItem {
10
11
  id: string;
11
12
  title: string;
@@ -162,22 +163,25 @@ const ChatHistory: FC<IChatHistoryProps> = memo(
162
163
  (item: IChatHistoryItem) => (
163
164
  <div
164
165
  key={item.id}
165
- className={cls('dm-chat-history-item', item.id === currentId ? 'dm-chat-history-item-selected' : '')}
166
+ className={cls(
167
+ styles['dm-chat-history-item'],
168
+ item.id === currentId ? styles['dm-chat-history-item-selected'] : '',
169
+ )}
166
170
  onClick={() => handleHistoryItemSelect(item)}
167
171
  >
168
- <div className='dm-chat-history-item-content'>
172
+ <div className={styles['dm-chat-history-item-content']}>
169
173
  {item.loading ? (
170
174
  <Loading />
171
175
  ) : (
172
176
  <Icon icon='message' style={{ width: '16px', height: '16px', marginRight: 4 }} />
173
177
  )}
174
178
  {!historyTitleEditable?.[item.id] ? (
175
- <span id={`dm-chat-history-item-title-${item.id}`} className='dm-chat-history-item-title'>
179
+ <span id={`dm-chat-history-item-title-${item.id}`} className={styles['dm-chat-history-item-title']}>
176
180
  {item.title}
177
181
  </span>
178
182
  ) : (
179
183
  <Input
180
- className='dm-chat-history-item-title'
184
+ className={styles['dm-chat-history-item-title']}
181
185
  defaultValue={item.title}
182
186
  ref={inputRef}
183
187
  onPressEnter={(e: any) => {
@@ -187,7 +191,7 @@ const ChatHistory: FC<IChatHistoryProps> = memo(
187
191
  />
188
192
  )}
189
193
  </div>
190
- <div className='dm-chat-history-item-actions'>
194
+ <div className={styles['dm-chat-history-item-actions']}>
191
195
  {/* <EditOutlined
192
196
  title={localize('aiNative.operate.chatHistory.edit')}
193
197
  style={{ marginRight: 8 }}
@@ -198,7 +202,7 @@ const ChatHistory: FC<IChatHistoryProps> = memo(
198
202
  }}
199
203
  /> */}
200
204
  <EnhanceIcon
201
- className={cls('dm-chat-history-item-actions-delete', getIcon('delete'))}
205
+ className={cls(styles['dm-chat-history-item-actions-delete'], getIcon('delete'))}
202
206
  onClick={(e) => {
203
207
  e.preventDefault();
204
208
  e.stopPropagation();
@@ -237,10 +241,10 @@ const ChatHistory: FC<IChatHistoryProps> = memo(
237
241
  value={searchValue}
238
242
  onChange={handleSearchChange}
239
243
  />
240
- <div className='dm-chat-history-list'>
244
+ <div className={styles['dm-chat-history-list']}>
241
245
  {groupedHistoryList.map((group) => (
242
246
  <div key={group.key} style={{ padding: '4px' }}>
243
- <div className='dm-chat-history-time'>{group.key}</div>
247
+ <div className={styles['dm-chat-history-time']}>{group.key}</div>
244
248
  {group.items.map(renderHistoryItem)}
245
249
  </div>
246
250
  ))}
@@ -253,11 +257,11 @@ const ChatHistory: FC<IChatHistoryProps> = memo(
253
257
  const getPopupContainer = useCallback((triggerNode: HTMLElement) => triggerNode.parentElement!, []);
254
258
 
255
259
  return (
256
- <div className={cls('dm-chat-history-header', className)}>
257
- <div className='dm-chat-history-header-title'>
260
+ <div className={cls(styles['dm-chat-history-header'], className)}>
261
+ <div className={styles['dm-chat-history-header-title']}>
258
262
  <span>{title}</span>
259
263
  </div>
260
- <div className='dm-chat-history-header-actions'>
264
+ <div className={styles['dm-chat-history-header-actions']}>
261
265
  <Popover
262
266
  id='dm-chat-history-header-actions-history'
263
267
  content={renderHistory()}
@@ -267,10 +271,12 @@ const ChatHistory: FC<IChatHistoryProps> = memo(
267
271
  getPopupContainer={getPopupContainer}
268
272
  >
269
273
  <div
270
- className='dm-chat-history-header-actions-history'
274
+ className={styles['dm-chat-history-header-actions-history']}
271
275
  title={localize('aiNative.operate.chatHistory.title')}
272
276
  >
273
- <EnhanceIcon className={cls('dm-chat-history-header-actions-history', 'codicon codicon-history')} />
277
+ <EnhanceIcon
278
+ className={cls(styles['dm-chat-history-header-actions-history'], 'codicon codicon-history')}
279
+ />
274
280
  </div>
275
281
  </Popover>
276
282
  <Popover
@@ -279,7 +285,7 @@ const ChatHistory: FC<IChatHistoryProps> = memo(
279
285
  title={localize('aiNative.operate.newChat.title')}
280
286
  >
281
287
  <EnhanceIcon
282
- className={cls('dm-chat-history-header-actions-new', getIcon('plus'))}
288
+ className={cls(styles['dm-chat-history-header-actions-new'], getIcon('plus'))}
283
289
  onClick={handleNewChat}
284
290
  />
285
291
  </Popover>
@@ -1,21 +1,31 @@
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 { ChatAgentViewServiceToken, ChatFeatureRegistryToken, localize, runWhenIdle } from '@opensumi/ide-core-common';
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
- import { ChatContext } from './ChatContext';
19
29
  import styles from './components.module.less';
20
30
 
21
31
  const INSTRUCTION_BOTTOM = 8;
@@ -195,12 +205,29 @@ export const ChatInput = React.forwardRef((props: IChatInputProps, ref) => {
195
205
  const [isExpand, setIsExpand] = useState(false);
196
206
  const [placeholder, setPlaceHolder] = useState(localize('aiNative.chat.input.placeholder.default'));
197
207
 
208
+ const dialogService = useInjectable<IDialogService>(IDialogService);
209
+ const aiNativeConfigService = useInjectable<AINativeConfigService>(AINativeConfigService);
210
+ const mcpServerProxyService = useInjectable<MCPServerProxyService>(TokenMCPServerProxyService);
198
211
  const monacoCommandRegistry = useInjectable<MonacoCommandRegistry>(MonacoCommandRegistry);
199
212
  const chatAgentService = useInjectable<IChatAgentService>(IChatAgentService);
200
213
  const chatFeatureRegistry = useInjectable<ChatFeatureRegistry>(ChatFeatureRegistryToken);
214
+ const commandService = useInjectable<CommandService>(CommandService);
201
215
 
202
216
  const currentAgentIdRef = useLatest(agentId);
203
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: ['关闭'],
228
+ });
229
+ }, [mcpServerProxyService, dialogService]);
230
+
204
231
  useImperativeHandle(ref, () => ({
205
232
  setInputValue: (v: string) => {
206
233
  setValue(v);
@@ -462,6 +489,42 @@ export const ChatInput = React.forwardRef((props: IChatInputProps, ref) => {
462
489
  height={inputHeight}
463
490
  popoverPosition={PopoverPosition.left}
464
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>
465
528
  </div>
466
529
  );
467
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
- <span className={cls(styles['expand-icon'], { [styles.expanded]: isExpanded })}>▶</span>
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>
@@ -3,7 +3,7 @@
3
3
  align-items: center;
4
4
  justify-content: space-between;
5
5
  font-size: 13px;
6
- padding: 0 4px 0 12px;
6
+ padding: 0 0 0 12px;
7
7
  color: var(--editor-foreground);
8
8
  text-overflow: ellipsis;
9
9
  white-space: nowrap;
@@ -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
+ }