@opensumi/ide-ai-native 3.8.1-next-1740556231.0 → 3.8.1-next-1740571693.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 (182) hide show
  1. package/lib/browser/ai-core.contextkeys.d.ts +1 -1
  2. package/lib/browser/ai-core.contextkeys.d.ts.map +1 -1
  3. package/lib/browser/ai-core.contextkeys.js +1 -1
  4. package/lib/browser/ai-core.contextkeys.js.map +1 -1
  5. package/lib/browser/ai-core.contribution.d.ts +1 -4
  6. package/lib/browser/ai-core.contribution.d.ts.map +1 -1
  7. package/lib/browser/ai-core.contribution.js +11 -23
  8. package/lib/browser/ai-core.contribution.js.map +1 -1
  9. package/lib/browser/chat/chat-manager.service.d.ts +0 -1
  10. package/lib/browser/chat/chat-manager.service.d.ts.map +1 -1
  11. package/lib/browser/chat/chat-manager.service.js +0 -13
  12. package/lib/browser/chat/chat-manager.service.js.map +1 -1
  13. package/lib/browser/chat/chat.internal.service.d.ts +0 -1
  14. package/lib/browser/chat/chat.internal.service.d.ts.map +1 -1
  15. package/lib/browser/chat/chat.internal.service.js +0 -3
  16. package/lib/browser/chat/chat.internal.service.js.map +1 -1
  17. package/lib/browser/chat/chat.view.d.ts.map +1 -1
  18. package/lib/browser/chat/chat.view.js +30 -1
  19. package/lib/browser/chat/chat.view.js.map +1 -1
  20. package/lib/browser/components/ChatHistory.d.ts +1 -0
  21. package/lib/browser/components/ChatHistory.d.ts.map +1 -1
  22. package/lib/browser/components/ChatHistory.js +14 -14
  23. package/lib/browser/components/ChatHistory.js.map +1 -1
  24. package/lib/browser/contrib/inline-completions/inline-completions.controller.js +1 -1
  25. package/lib/browser/contrib/inline-completions/inline-completions.controller.js.map +1 -1
  26. package/lib/browser/contrib/intelligent-completions/index.d.ts +2 -1
  27. package/lib/browser/contrib/intelligent-completions/index.d.ts.map +1 -1
  28. package/lib/browser/contrib/intelligent-completions/index.js +4 -1
  29. package/lib/browser/contrib/intelligent-completions/index.js.map +1 -1
  30. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.js +2 -2
  31. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.js.map +1 -1
  32. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.d.ts.map +1 -1
  33. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.js +5 -4
  34. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.js.map +1 -1
  35. package/lib/browser/contrib/intelligent-completions/view/code-edits-previewer.d.ts.map +1 -1
  36. package/lib/browser/contrib/intelligent-completions/view/code-edits-previewer.js +4 -2
  37. package/lib/browser/contrib/intelligent-completions/view/code-edits-previewer.js.map +1 -1
  38. package/lib/browser/contrib/intelligent-completions/view/default.d.ts.map +1 -1
  39. package/lib/browser/contrib/intelligent-completions/view/default.js +17 -11
  40. package/lib/browser/contrib/intelligent-completions/view/default.js.map +1 -1
  41. package/lib/browser/index.d.ts.map +1 -1
  42. package/lib/browser/index.js +4 -0
  43. package/lib/browser/index.js.map +1 -1
  44. package/lib/browser/mcp/base-apply.service.d.ts +40 -31
  45. package/lib/browser/mcp/base-apply.service.d.ts.map +1 -1
  46. package/lib/browser/mcp/base-apply.service.js +167 -233
  47. package/lib/browser/mcp/base-apply.service.js.map +1 -1
  48. package/lib/browser/mcp/config/components/mcp-config.module.less +178 -0
  49. package/lib/browser/mcp/config/components/mcp-config.view.d.ts +3 -0
  50. package/lib/browser/mcp/config/components/mcp-config.view.d.ts.map +1 -0
  51. package/lib/browser/mcp/config/components/mcp-config.view.js +150 -0
  52. package/lib/browser/mcp/config/components/mcp-config.view.js.map +1 -0
  53. package/lib/browser/mcp/config/components/mcp-server-form.d.ts +16 -0
  54. package/lib/browser/mcp/config/components/mcp-server-form.d.ts.map +1 -0
  55. package/lib/browser/mcp/config/components/mcp-server-form.js +84 -0
  56. package/lib/browser/mcp/config/components/mcp-server-form.js.map +1 -0
  57. package/lib/browser/mcp/config/components/mcp-server-form.module.less +78 -0
  58. package/lib/browser/mcp/config/mcp-config.commands.d.ts +10 -0
  59. package/lib/browser/mcp/config/mcp-config.commands.d.ts.map +1 -0
  60. package/lib/browser/mcp/config/mcp-config.commands.js +35 -0
  61. package/lib/browser/mcp/config/mcp-config.commands.js.map +1 -0
  62. package/lib/browser/mcp/config/mcp-config.contribution.d.ts +16 -0
  63. package/lib/browser/mcp/config/mcp-config.contribution.d.ts.map +1 -0
  64. package/lib/browser/mcp/config/mcp-config.contribution.js +62 -0
  65. package/lib/browser/mcp/config/mcp-config.contribution.js.map +1 -0
  66. package/lib/browser/mcp/mcp-server-proxy.service.d.ts +6 -0
  67. package/lib/browser/mcp/mcp-server-proxy.service.d.ts.map +1 -1
  68. package/lib/browser/mcp/mcp-server-proxy.service.js +10 -1
  69. package/lib/browser/mcp/mcp-server-proxy.service.js.map +1 -1
  70. package/lib/browser/mcp/mcp-server.feature.registry.d.ts.map +1 -1
  71. package/lib/browser/mcp/mcp-server.feature.registry.js +3 -2
  72. package/lib/browser/mcp/mcp-server.feature.registry.js.map +1 -1
  73. package/lib/browser/mcp/tools/components/EditFile.d.ts.map +1 -1
  74. package/lib/browser/mcp/tools/components/EditFile.js +41 -55
  75. package/lib/browser/mcp/tools/components/EditFile.js.map +1 -1
  76. package/lib/browser/mcp/tools/components/index.module.less +3 -22
  77. package/lib/browser/mcp/tools/editFile.js +1 -1
  78. package/lib/browser/mcp/tools/editFile.js.map +1 -1
  79. package/lib/browser/mcp/tools/handlers/EditFile.d.ts +1 -5
  80. package/lib/browser/mcp/tools/handlers/EditFile.d.ts.map +1 -1
  81. package/lib/browser/mcp/tools/handlers/EditFile.js +4 -4
  82. package/lib/browser/mcp/tools/handlers/EditFile.js.map +1 -1
  83. package/lib/browser/model/msg-history-manager.d.ts +0 -1
  84. package/lib/browser/model/msg-history-manager.d.ts.map +1 -1
  85. package/lib/browser/model/msg-history-manager.js +2 -12
  86. package/lib/browser/model/msg-history-manager.js.map +1 -1
  87. package/lib/browser/preferences/schema.d.ts.map +1 -1
  88. package/lib/browser/preferences/schema.js +16 -0
  89. package/lib/browser/preferences/schema.js.map +1 -1
  90. package/lib/browser/types.d.ts +1 -1
  91. package/lib/browser/types.d.ts.map +1 -1
  92. package/lib/browser/widget/inline-diff/inline-diff-widget.module.less +0 -12
  93. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts +0 -2
  94. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts.map +1 -1
  95. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js +4 -11
  96. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js.map +1 -1
  97. package/lib/common/index.d.ts +8 -1
  98. package/lib/common/index.d.ts.map +1 -1
  99. package/lib/common/index.js +3 -1
  100. package/lib/common/index.js.map +1 -1
  101. package/lib/common/mcp-server-manager.d.ts +17 -1
  102. package/lib/common/mcp-server-manager.d.ts.map +1 -1
  103. package/lib/common/mcp-server-manager.js.map +1 -1
  104. package/lib/common/tool-invocation-registry.d.ts +2 -2
  105. package/lib/common/tool-invocation-registry.d.ts.map +1 -1
  106. package/lib/common/tool-invocation-registry.js +1 -1
  107. package/lib/common/tool-invocation-registry.js.map +1 -1
  108. package/lib/common/types.d.ts +6 -17
  109. package/lib/common/types.d.ts.map +1 -1
  110. package/lib/common/types.js.map +1 -1
  111. package/lib/common/utils.d.ts.map +1 -1
  112. package/lib/common/utils.js +2 -1
  113. package/lib/common/utils.js.map +1 -1
  114. package/lib/node/base-language-model.d.ts +1 -1
  115. package/lib/node/base-language-model.d.ts.map +1 -1
  116. package/lib/node/base-language-model.js +8 -58
  117. package/lib/node/base-language-model.js.map +1 -1
  118. package/lib/node/mcp/sumi-mcp-server.d.ts +17 -3
  119. package/lib/node/mcp/sumi-mcp-server.d.ts.map +1 -1
  120. package/lib/node/mcp/sumi-mcp-server.js +59 -6
  121. package/lib/node/mcp/sumi-mcp-server.js.map +1 -1
  122. package/lib/node/mcp-server-manager-impl.d.ts +4 -3
  123. package/lib/node/mcp-server-manager-impl.d.ts.map +1 -1
  124. package/lib/node/mcp-server-manager-impl.js +26 -6
  125. package/lib/node/mcp-server-manager-impl.js.map +1 -1
  126. package/lib/node/mcp-server.d.ts +5 -16
  127. package/lib/node/mcp-server.d.ts.map +1 -1
  128. package/lib/node/mcp-server.js +12 -6
  129. package/lib/node/mcp-server.js.map +1 -1
  130. package/lib/node/openai/openai-language-model.d.ts +4 -3
  131. package/lib/node/openai/openai-language-model.d.ts.map +1 -1
  132. package/lib/node/openai/openai-language-model.js +3 -2
  133. package/lib/node/openai/openai-language-model.js.map +1 -1
  134. package/package.json +27 -27
  135. package/src/browser/ai-core.contextkeys.ts +3 -3
  136. package/src/browser/ai-core.contribution.ts +14 -29
  137. package/src/browser/chat/chat-manager.service.ts +0 -12
  138. package/src/browser/chat/chat.internal.service.ts +0 -4
  139. package/src/browser/chat/chat.view.tsx +47 -0
  140. package/src/browser/components/ChatHistory.tsx +15 -21
  141. package/src/browser/contrib/inline-completions/inline-completions.controller.ts +1 -1
  142. package/src/browser/contrib/intelligent-completions/index.ts +5 -1
  143. package/src/browser/contrib/intelligent-completions/intelligent-completions.contribution.ts +3 -3
  144. package/src/browser/contrib/intelligent-completions/intelligent-completions.controller.ts +6 -5
  145. package/src/browser/contrib/intelligent-completions/view/code-edits-previewer.ts +4 -2
  146. package/src/browser/contrib/intelligent-completions/view/default.ts +27 -19
  147. package/src/browser/index.ts +4 -0
  148. package/src/browser/mcp/base-apply.service.ts +213 -266
  149. package/src/browser/mcp/config/components/mcp-config.module.less +178 -0
  150. package/src/browser/mcp/config/components/mcp-config.view.tsx +215 -0
  151. package/src/browser/mcp/config/components/mcp-server-form.module.less +78 -0
  152. package/src/browser/mcp/config/components/mcp-server-form.tsx +144 -0
  153. package/src/browser/mcp/config/mcp-config.commands.ts +29 -0
  154. package/src/browser/mcp/config/mcp-config.contribution.ts +65 -0
  155. package/src/browser/mcp/mcp-server-proxy.service.ts +14 -2
  156. package/src/browser/mcp/mcp-server.feature.registry.ts +3 -2
  157. package/src/browser/mcp/tools/components/EditFile.tsx +60 -82
  158. package/src/browser/mcp/tools/components/index.module.less +3 -22
  159. package/src/browser/mcp/tools/editFile.ts +2 -2
  160. package/src/browser/mcp/tools/handlers/EditFile.ts +4 -4
  161. package/src/browser/model/msg-history-manager.ts +2 -12
  162. package/src/browser/preferences/schema.ts +16 -0
  163. package/src/browser/types.ts +1 -1
  164. package/src/browser/widget/inline-diff/inline-diff-widget.module.less +0 -12
  165. package/src/browser/widget/inline-stream-diff/inline-stream-diff.handler.tsx +4 -13
  166. package/src/common/index.ts +7 -1
  167. package/src/common/mcp-server-manager.ts +17 -1
  168. package/src/common/tool-invocation-registry.ts +2 -2
  169. package/src/common/types.ts +6 -20
  170. package/src/common/utils.ts +3 -1
  171. package/src/node/base-language-model.ts +8 -67
  172. package/src/node/mcp/sumi-mcp-server.ts +67 -9
  173. package/src/node/mcp-server-manager-impl.ts +30 -9
  174. package/src/node/mcp-server.ts +11 -14
  175. package/src/node/openai/openai-language-model.ts +7 -4
  176. package/lib/browser/widget/inline-diff/inline-diff-manager.d.ts +0 -6
  177. package/lib/browser/widget/inline-diff/inline-diff-manager.d.ts.map +0 -1
  178. package/lib/browser/widget/inline-diff/inline-diff-manager.js +0 -27
  179. package/lib/browser/widget/inline-diff/inline-diff-manager.js.map +0 -1
  180. package/src/browser/widget/inline-diff/inline-diff-manager.tsx +0 -38
  181. /package/lib/browser/components/{chat-history.module.less → chat-history.css} +0 -0
  182. /package/src/browser/components/{chat-history.module.less → chat-history.css} +0 -0
@@ -1,13 +1,13 @@
1
1
  import { Autowired, Injectable, Optional } from '@opensumi/di';
2
2
  import { IContextKey, IContextKeyService, IScopedContextKeyService } from '@opensumi/ide-core-browser';
3
3
  import {
4
+ CodeEditsIsVisible,
4
5
  InlineChatIsVisible,
5
6
  InlineCompletionIsTrigger,
6
7
  InlineDiffPartialEditsIsVisible,
7
8
  InlineHintWidgetIsVisible,
8
9
  InlineInputWidgetIsStreaming,
9
10
  InlineInputWidgetIsVisible,
10
- MultiLineEditsIsVisible,
11
11
  } from '@opensumi/ide-core-browser/lib/contextkey/ai-native';
12
12
  import { ContextKeyService } from '@opensumi/monaco-editor-core/esm/vs/platform/contextkey/browser/contextKeyService';
13
13
  import { IContextKeyServiceTarget } from '@opensumi/monaco-editor-core/esm/vs/platform/contextkey/common/contextkey';
@@ -25,7 +25,7 @@ export class AINativeContextKey {
25
25
  public readonly inlineInputWidgetIsVisible: IContextKey<boolean>;
26
26
  public readonly inlineInputWidgetIsStreaming: IContextKey<boolean>;
27
27
  public readonly inlineDiffPartialEditsIsVisible: IContextKey<boolean>;
28
- public readonly multiLineEditsIsVisible: IContextKey<boolean>;
28
+ public readonly codeEditsIsVisible: IContextKey<boolean>;
29
29
  public get contextKeyService() {
30
30
  return this._contextKeyService;
31
31
  }
@@ -38,6 +38,6 @@ export class AINativeContextKey {
38
38
  this.inlineInputWidgetIsVisible = InlineInputWidgetIsVisible.bind(this._contextKeyService);
39
39
  this.inlineInputWidgetIsStreaming = InlineInputWidgetIsStreaming.bind(this._contextKeyService);
40
40
  this.inlineDiffPartialEditsIsVisible = InlineDiffPartialEditsIsVisible.bind(this._contextKeyService);
41
- this.multiLineEditsIsVisible = MultiLineEditsIsVisible.bind(this._contextKeyService);
41
+ this.codeEditsIsVisible = CodeEditsIsVisible.bind(this._contextKeyService);
42
42
  }
43
43
  }
@@ -59,11 +59,7 @@ import {
59
59
  } from '@opensumi/ide-core-common';
60
60
  import { DESIGN_MENU_BAR_RIGHT } from '@opensumi/ide-design';
61
61
  import { IEditor, WorkbenchEditorService } from '@opensumi/ide-editor';
62
- import {
63
- BrowserEditorContribution,
64
- EditorComponentRegistry,
65
- IEditorFeatureRegistry,
66
- } from '@opensumi/ide-editor/lib/browser';
62
+ import { BrowserEditorContribution, IEditorFeatureRegistry } from '@opensumi/ide-editor/lib/browser';
67
63
  import { WorkbenchEditorServiceImpl } from '@opensumi/ide-editor/lib/browser/workbench-editor.service';
68
64
  import { IMainLayoutService } from '@opensumi/ide-main-layout';
69
65
  import { ISettingRegistry, SettingContribution } from '@opensumi/ide-preferences';
@@ -76,6 +72,7 @@ import {
76
72
  AI_CHAT_LOGO_AVATAR_ID,
77
73
  AI_CHAT_VIEW_ID,
78
74
  AI_MENU_BAR_DEBUG_TOOLBAR,
75
+ BUILTIN_MCP_SERVER_NAME,
79
76
  ChatProxyServiceToken,
80
77
  IChatInternalService,
81
78
  IChatManagerService,
@@ -103,7 +100,6 @@ import {
103
100
  AIRightTabRenderer,
104
101
  } from './layout/tabbar.view';
105
102
  import { AIChatLogoAvatar } from './layout/view/avatar/avatar.view';
106
- import { BaseApplyService } from './mcp/base-apply.service';
107
103
  import {
108
104
  AINativeCoreContribution,
109
105
  IChatFeatureRegistry,
@@ -120,7 +116,6 @@ import {
120
116
  import { InlineChatEditorController } from './widget/inline-chat/inline-chat-editor.controller';
121
117
  import { InlineChatFeatureRegistry } from './widget/inline-chat/inline-chat.feature.registry';
122
118
  import { InlineChatService } from './widget/inline-chat/inline-chat.service';
123
- import { InlineDiffManager } from './widget/inline-diff/inline-diff-manager';
124
119
  import { InlineDiffController } from './widget/inline-diff/inline-diff.controller';
125
120
  import { InlineHintController } from './widget/inline-hint/inline-hint.controller';
126
121
  import { InlineInputController } from './widget/inline-input/inline-input.controller';
@@ -128,8 +123,6 @@ import { InlineInputService } from './widget/inline-input/inline-input.service';
128
123
  import { InlineStreamDiffService } from './widget/inline-stream-diff/inline-stream-diff.service';
129
124
  import { SumiLightBulbWidget } from './widget/light-bulb';
130
125
 
131
- export const INLINE_DIFF_MANAGER_WIDGET_ID = 'inline-diff-manager-widget';
132
-
133
126
  @Domain(
134
127
  ClientAppContribution,
135
128
  BrowserEditorContribution,
@@ -244,9 +237,6 @@ export class AINativeBrowserContribution
244
237
  @Autowired(IChatInternalService)
245
238
  private readonly chatInternalService: ChatInternalService;
246
239
 
247
- @Autowired(BaseApplyService)
248
- private readonly applyService: BaseApplyService;
249
-
250
240
  constructor() {
251
241
  this.registerFeature();
252
242
  }
@@ -338,15 +328,23 @@ export class AINativeBrowserContribution
338
328
  }
339
329
 
340
330
  if (supportsMCP) {
341
- // 初始化内置 MCP Server
342
- this.sumiMCPServerBackendProxy.initBuiltinMCPServer();
343
-
344
331
  // 从 preferences 获取并初始化外部 MCP Servers
345
332
  const mcpServers = this.preferenceService.getValid<MCPServerDescription[]>(
346
333
  AINativeSettingSectionsId.MCPServers,
347
334
  );
335
+
336
+ // 查找内置 MCP Server 的配置
337
+ const builtinServer = mcpServers?.find((server) => server.name === BUILTIN_MCP_SERVER_NAME);
338
+
339
+ // 总是初始化内置服务器,根据配置决定是否启用
340
+ this.sumiMCPServerBackendProxy.initBuiltinMCPServer(builtinServer?.enabled ?? true);
341
+
342
+ // 初始化其他外部 MCP Servers
348
343
  if (mcpServers && mcpServers.length > 0) {
349
- this.sumiMCPServerBackendProxy.initExternalMCPServers(mcpServers);
344
+ const externalServers = mcpServers.filter((server) => server.name !== BUILTIN_MCP_SERVER_NAME);
345
+ if (externalServers.length > 0) {
346
+ this.sumiMCPServerBackendProxy.initExternalMCPServers(externalServers);
347
+ }
350
348
  }
351
349
  }
352
350
  });
@@ -526,19 +524,6 @@ export class AINativeBrowserContribution
526
524
  });
527
525
  }
528
526
 
529
- registerEditorComponent(registry: EditorComponentRegistry): void {
530
- registry.registerEditorSideWidget({
531
- id: INLINE_DIFF_MANAGER_WIDGET_ID,
532
- component: InlineDiffManager,
533
- displaysOnResource: (resource) => {
534
- if (this.applyService.getUriPendingCodeBlock(resource.uri)) {
535
- return true;
536
- }
537
- return false;
538
- },
539
- });
540
- }
541
-
542
527
  registerCommands(commands: CommandRegistry): void {
543
528
  commands.registerCommand(AI_INLINE_CHAT_VISIBLE, {
544
529
  execute: (value: boolean) => {
@@ -9,7 +9,6 @@ import {
9
9
  IStorage,
10
10
  STORAGE_NAMESPACE,
11
11
  StorageProvider,
12
- debounce,
13
12
  } from '@opensumi/ide-core-common';
14
13
  import { ChatMessageRole, IChatMessage, IHistoryChatMessage } from '@opensumi/ide-core-common/lib/types/ai-native';
15
14
 
@@ -90,7 +89,6 @@ export class ChatManagerService extends Disposable {
90
89
  const savedSessions = this.fromJSON(sessionsModelData);
91
90
  savedSessions.forEach((session) => {
92
91
  this.#sessionModels.set(session.sessionId, session);
93
- this.listenSession(session);
94
92
  });
95
93
  await this.storageInitEmitter.fireAndAwait();
96
94
  }
@@ -102,7 +100,6 @@ export class ChatManagerService extends Disposable {
102
100
  startSession() {
103
101
  const model = new ChatModel();
104
102
  this.#sessionModels.set(model.sessionId, model);
105
- this.listenSession(model);
106
103
  return model;
107
104
  }
108
105
 
@@ -199,15 +196,6 @@ export class ChatManagerService extends Disposable {
199
196
  }
200
197
  }
201
198
 
202
- protected listenSession(session: ChatModel) {
203
- this.addDispose(
204
- session.history.onMessageAdditionalChange(() => {
205
- this.saveSessions();
206
- }),
207
- );
208
- }
209
-
210
- @debounce(1000)
211
199
  protected saveSessions() {
212
200
  this._chatStorage.set('sessionModels', this.getSessions());
213
201
  }
@@ -94,10 +94,6 @@ 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
-
101
97
  activateSession(sessionId: string) {
102
98
  const targetSession = this.chatManagerService.getSession(sessionId);
103
99
  if (!targetSession) {
@@ -3,6 +3,7 @@ import { MessageList } from 'react-chat-elements';
3
3
 
4
4
  import {
5
5
  AINativeConfigService,
6
+ CommandService,
6
7
  getIcon,
7
8
  useEventEffect,
8
9
  useInjectable,
@@ -52,6 +53,7 @@ import { ChatNotify, ChatReply } from '../components/ChatReply';
52
53
  import { SlashCustomRender } from '../components/SlashCustomRender';
53
54
  import { MessageData, createMessageByAI, createMessageByUser } from '../components/utils';
54
55
  import { WelcomeMessage } from '../components/WelcomeMsg';
56
+ import { OPEN_MCP_CONFIG_COMMAND } from '../mcp/config/mcp-config.commands';
55
57
  import { MCPServerProxyService } from '../mcp/mcp-server-proxy.service';
56
58
  import { MCPToolsDialog } from '../mcp/mcp-tools-dialog.view';
57
59
  import { ChatViewHeaderRender, TSlashCommandCustomRender } from '../types';
@@ -63,6 +65,7 @@ import { ChatFeatureRegistry } from './chat.feature.registry';
63
65
  import { ChatInternalService } from './chat.internal.service';
64
66
  import styles from './chat.module.less';
65
67
  import { ChatRenderRegistry } from './chat.render.registry';
68
+
66
69
  const SCROLL_CLASSNAME = 'chat_scroll';
67
70
 
68
71
  interface TDispatchAction {
@@ -81,11 +84,15 @@ export const AIChatView = () => {
81
84
  const chatRenderRegistry = useInjectable<ChatRenderRegistry>(ChatRenderRegistryToken);
82
85
  const contextService = useInjectable<LLMContextService>(LLMContextServiceToken);
83
86
  const promptProvider = useInjectable<ChatAgentPromptProvider>(ChatAgentPromptProvider);
87
+ const mcpServerProxyService = useInjectable<MCPServerProxyService>(TokenMCPServerProxyService);
84
88
 
85
89
  const layoutService = useInjectable<IMainLayoutService>(IMainLayoutService);
86
90
  const msgHistoryManager = aiChatService.sessionModel.history;
87
91
  const containerRef = React.useRef<HTMLDivElement>(null);
88
92
  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);
89
96
 
90
97
  const [shortcutCommands, setShortcutCommands] = React.useState<ChatSlashCommandItemModel[]>([]);
91
98
 
@@ -107,6 +114,8 @@ export const AIChatView = () => {
107
114
  const [defaultAgentId, setDefaultAgentId] = React.useState<string>('');
108
115
  const [command, setCommand] = React.useState('');
109
116
  const [theme, setTheme] = React.useState<string | null>(null);
117
+ const [mcpToolsCount, setMcpToolsCount] = React.useState<number>(0);
118
+ const [mcpServersCount, setMcpServersCount] = React.useState<number>(0);
110
119
 
111
120
  React.useEffect(() => {
112
121
  const featureSlashCommands = chatFeatureRegistry.getAllShortcutSlashCommand();
@@ -658,6 +667,32 @@ export const AIChatView = () => {
658
667
  };
659
668
  }, [aiChatService.sessionModel]);
660
669
 
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
+
661
696
  return (
662
697
  <div id={styles.ai_chat_view}>
663
698
  <div className={styles.header_container}>
@@ -697,6 +732,18 @@ export const AIChatView = () => {
697
732
  </Popover>
698
733
  ))}
699
734
  </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>
700
747
  </div>
701
748
  <ChatInputWrapperRender
702
749
  onSend={(value, agentId, command) =>
@@ -2,11 +2,10 @@ 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';
5
6
  import { localize } from '@opensumi/ide-core-browser';
6
7
  import { EnhanceIcon } from '@opensumi/ide-core-browser/lib/components/ai-native';
7
8
 
8
- import styles from './chat-history.module.less';
9
-
10
9
  export interface IChatHistoryItem {
11
10
  id: string;
12
11
  title: string;
@@ -163,25 +162,22 @@ const ChatHistory: FC<IChatHistoryProps> = memo(
163
162
  (item: IChatHistoryItem) => (
164
163
  <div
165
164
  key={item.id}
166
- className={cls(
167
- styles['dm-chat-history-item'],
168
- item.id === currentId ? styles['dm-chat-history-item-selected'] : '',
169
- )}
165
+ className={cls('dm-chat-history-item', item.id === currentId ? 'dm-chat-history-item-selected' : '')}
170
166
  onClick={() => handleHistoryItemSelect(item)}
171
167
  >
172
- <div className={styles['dm-chat-history-item-content']}>
168
+ <div className='dm-chat-history-item-content'>
173
169
  {item.loading ? (
174
170
  <Loading />
175
171
  ) : (
176
172
  <Icon icon='message' style={{ width: '16px', height: '16px', marginRight: 4 }} />
177
173
  )}
178
174
  {!historyTitleEditable?.[item.id] ? (
179
- <span id={`dm-chat-history-item-title-${item.id}`} className={styles['dm-chat-history-item-title']}>
175
+ <span id={`dm-chat-history-item-title-${item.id}`} className='dm-chat-history-item-title'>
180
176
  {item.title}
181
177
  </span>
182
178
  ) : (
183
179
  <Input
184
- className={styles['dm-chat-history-item-title']}
180
+ className='dm-chat-history-item-title'
185
181
  defaultValue={item.title}
186
182
  ref={inputRef}
187
183
  onPressEnter={(e: any) => {
@@ -191,7 +187,7 @@ const ChatHistory: FC<IChatHistoryProps> = memo(
191
187
  />
192
188
  )}
193
189
  </div>
194
- <div className={styles['dm-chat-history-item-actions']}>
190
+ <div className='dm-chat-history-item-actions'>
195
191
  {/* <EditOutlined
196
192
  title={localize('aiNative.operate.chatHistory.edit')}
197
193
  style={{ marginRight: 8 }}
@@ -202,7 +198,7 @@ const ChatHistory: FC<IChatHistoryProps> = memo(
202
198
  }}
203
199
  /> */}
204
200
  <EnhanceIcon
205
- className={cls(styles['dm-chat-history-item-actions-delete'], getIcon('delete'))}
201
+ className={cls('dm-chat-history-item-actions-delete', getIcon('delete'))}
206
202
  onClick={(e) => {
207
203
  e.preventDefault();
208
204
  e.stopPropagation();
@@ -241,10 +237,10 @@ const ChatHistory: FC<IChatHistoryProps> = memo(
241
237
  value={searchValue}
242
238
  onChange={handleSearchChange}
243
239
  />
244
- <div className={styles['dm-chat-history-list']}>
240
+ <div className='dm-chat-history-list'>
245
241
  {groupedHistoryList.map((group) => (
246
242
  <div key={group.key} style={{ padding: '4px' }}>
247
- <div className={styles['dm-chat-history-time']}>{group.key}</div>
243
+ <div className='dm-chat-history-time'>{group.key}</div>
248
244
  {group.items.map(renderHistoryItem)}
249
245
  </div>
250
246
  ))}
@@ -257,11 +253,11 @@ const ChatHistory: FC<IChatHistoryProps> = memo(
257
253
  const getPopupContainer = useCallback((triggerNode: HTMLElement) => triggerNode.parentElement!, []);
258
254
 
259
255
  return (
260
- <div className={cls(styles['dm-chat-history-header'], className)}>
261
- <div className={styles['dm-chat-history-header-title']}>
256
+ <div className={cls('dm-chat-history-header', className)}>
257
+ <div className='dm-chat-history-header-title'>
262
258
  <span>{title}</span>
263
259
  </div>
264
- <div className={styles['dm-chat-history-header-actions']}>
260
+ <div className='dm-chat-history-header-actions'>
265
261
  <Popover
266
262
  id='dm-chat-history-header-actions-history'
267
263
  content={renderHistory()}
@@ -271,12 +267,10 @@ const ChatHistory: FC<IChatHistoryProps> = memo(
271
267
  getPopupContainer={getPopupContainer}
272
268
  >
273
269
  <div
274
- className={styles['dm-chat-history-header-actions-history']}
270
+ className='dm-chat-history-header-actions-history'
275
271
  title={localize('aiNative.operate.chatHistory.title')}
276
272
  >
277
- <EnhanceIcon
278
- className={cls(styles['dm-chat-history-header-actions-history'], 'codicon codicon-history')}
279
- />
273
+ <EnhanceIcon className={cls('dm-chat-history-header-actions-history', 'codicon codicon-history')} />
280
274
  </div>
281
275
  </Popover>
282
276
  <Popover
@@ -285,7 +279,7 @@ const ChatHistory: FC<IChatHistoryProps> = memo(
285
279
  title={localize('aiNative.operate.newChat.title')}
286
280
  >
287
281
  <EnhanceIcon
288
- className={cls(styles['dm-chat-history-header-actions-new'], getIcon('plus'))}
282
+ className={cls('dm-chat-history-header-actions-new', getIcon('plus'))}
289
283
  onClick={handleNewChat}
290
284
  />
291
285
  </Popover>
@@ -170,7 +170,7 @@ export class InlineCompletionsController extends BaseAIMonacoEditorController {
170
170
  }
171
171
 
172
172
  // 如果上一次补全结果还在,则不重复请求
173
- const isVisible = this.aiNativeContextKey.multiLineEditsIsVisible.get();
173
+ const isVisible = this.aiNativeContextKey.codeEditsIsVisible.get();
174
174
  if (isVisible) {
175
175
  return;
176
176
  }
@@ -69,7 +69,11 @@ export class CodeEditsResultValue<T extends ICodeEdit = ICodeEdit> extends Dispo
69
69
  }));
70
70
  }
71
71
 
72
- public get range(): IRange {
72
+ public get firstRange(): IRange {
73
73
  return this.raw.items[0].range;
74
74
  }
75
+
76
+ public get firstText(): string {
77
+ return this.raw.items[0].insertText;
78
+ }
75
79
  }
@@ -8,7 +8,7 @@ import {
8
8
  KeybindingScope,
9
9
  } from '@opensumi/ide-core-browser';
10
10
  import { AI_CODE_EDITS_COMMANDS } from '@opensumi/ide-core-browser/lib/ai-native/command';
11
- import { MultiLineEditsIsVisible } from '@opensumi/ide-core-browser/lib/contextkey/ai-native';
11
+ import { CodeEditsIsVisible } from '@opensumi/ide-core-browser/lib/contextkey/ai-native';
12
12
  import { CommandContribution, CommandRegistry, Domain } from '@opensumi/ide-core-common';
13
13
  import { WorkbenchEditorService } from '@opensumi/ide-editor';
14
14
  import { WorkbenchEditorServiceImpl } from '@opensumi/ide-editor/lib/browser/workbench-editor.service';
@@ -61,7 +61,7 @@ export class IntelligentCompletionsContribution implements KeybindingContributio
61
61
  keybindings.registerKeybinding({
62
62
  command: AI_CODE_EDITS_COMMANDS.DISCARD.id,
63
63
  keybinding: Key.ESCAPE.code,
64
- when: MultiLineEditsIsVisible.raw,
64
+ when: CodeEditsIsVisible.raw,
65
65
  priority: 100,
66
66
  });
67
67
 
@@ -69,7 +69,7 @@ export class IntelligentCompletionsContribution implements KeybindingContributio
69
69
  {
70
70
  command: AI_CODE_EDITS_COMMANDS.ACCEPT.id,
71
71
  keybinding: Key.TAB.code,
72
- when: MultiLineEditsIsVisible.raw,
72
+ when: CodeEditsIsVisible.raw,
73
73
  },
74
74
  KeybindingScope.USER,
75
75
  );
@@ -5,7 +5,7 @@ import {
5
5
  KeybindingScope,
6
6
  PreferenceService,
7
7
  } from '@opensumi/ide-core-browser';
8
- import { MultiLineEditsIsVisible } from '@opensumi/ide-core-browser/lib/contextkey/ai-native';
8
+ import { CodeEditsIsVisible } from '@opensumi/ide-core-browser/lib/contextkey/ai-native';
9
9
  import {
10
10
  AINativeSettingSectionsId,
11
11
  CodeEditsRT,
@@ -98,13 +98,13 @@ export class IntelligentCompletionsController extends BaseAIMonacoEditorControll
98
98
  this.monacoEditor,
99
99
  ]);
100
100
 
101
- const multiLineEditsIsVisibleKey = new Set([MultiLineEditsIsVisible.raw]);
101
+ const multiLineEditsIsVisibleKey = new Set([CodeEditsIsVisible.raw]);
102
102
  this.multiLineEditsIsVisibleObs = observableFromEvent(
103
103
  this,
104
104
  Event.filter(this.aiNativeContextKey.contextKeyService!.onDidChangeContext, (e: ContextKeyChangeEvent) =>
105
105
  e.payload.affectsSome(multiLineEditsIsVisibleKey),
106
106
  ),
107
- () => !!this.aiNativeContextKey.multiLineEditsIsVisible.get(),
107
+ () => !!this.aiNativeContextKey.codeEditsIsVisible.get(),
108
108
  );
109
109
 
110
110
  this.registerFeature(this.monacoEditor);
@@ -205,7 +205,7 @@ export class IntelligentCompletionsController extends BaseAIMonacoEditorControll
205
205
 
206
206
  public hide() {
207
207
  this.cancelToken();
208
- this.aiNativeContextKey.multiLineEditsIsVisible.reset();
208
+ this.aiNativeContextKey.codeEditsIsVisible.reset();
209
209
  this.codeEditsPreviewer.hide();
210
210
  }
211
211
 
@@ -273,6 +273,7 @@ export class IntelligentCompletionsController extends BaseAIMonacoEditorControll
273
273
  public trigger(tx: ITransaction): void {
274
274
  const triggerSource = this.codeEditsSourceCollection.getSource(TriggerCodeEditsSource) as TriggerCodeEditsSource;
275
275
  if (triggerSource) {
276
+ this.hide();
276
277
  triggerSource.triggerSignal.trigger(tx);
277
278
  }
278
279
  }
@@ -314,7 +315,7 @@ export class IntelligentCompletionsController extends BaseAIMonacoEditorControll
314
315
  handleChange: (context) => {
315
316
  if (context.didChange(this.codeEditsSourceCollection.codeEditsContextBean)) {
316
317
  // 如果上一次补全结果还在,则不重复请求
317
- const isVisible = this.aiNativeContextKey.multiLineEditsIsVisible.get();
318
+ const isVisible = this.aiNativeContextKey.codeEditsIsVisible.get();
318
319
  return !isVisible;
319
320
  }
320
321
  return false;
@@ -51,19 +51,21 @@ export class CodeEditsPreviewer extends Disposable {
51
51
 
52
52
  public render(completionModel: CodeEditsResultValue) {
53
53
  this.view?.render(completionModel);
54
- this.aiNativeContextKey.multiLineEditsIsVisible.set(true);
54
+ this.aiNativeContextKey.codeEditsIsVisible.set(true);
55
55
  }
56
56
 
57
57
  public hide() {
58
58
  this.view?.hide();
59
- this.aiNativeContextKey.multiLineEditsIsVisible.set(false);
59
+ this.aiNativeContextKey.codeEditsIsVisible.set(false);
60
60
  }
61
61
 
62
62
  public accept() {
63
63
  this.view?.accept();
64
+ this.aiNativeContextKey.codeEditsIsVisible.set(false);
64
65
  }
65
66
 
66
67
  public discard() {
67
68
  this.view?.discard();
69
+ this.aiNativeContextKey.codeEditsIsVisible.set(false);
68
70
  }
69
71
  }
@@ -80,17 +80,23 @@ export class DefaultCodeEditsView extends BaseCodeEditsView {
80
80
  return;
81
81
  }
82
82
 
83
- asyncTransaction(async (tx) => {
84
- const position = this.editorObs.positions.get()?.[0];
85
- if (!position) {
86
- return;
87
- }
83
+ const position = this.editorObs.positions.get()?.[0];
84
+ if (!position) {
85
+ return;
86
+ }
88
87
 
89
- const model = this.editorObs.model.get();
90
- if (!model) {
91
- return;
92
- }
88
+ const model = this.editorObs.model.get();
89
+ if (!model) {
90
+ return;
91
+ }
93
92
 
93
+ const originalContent = model.getValueInRange(completionModel.firstRange);
94
+ // edits 的内容与原内容一样就不展示
95
+ if (originalContent === completionModel.firstText) {
96
+ return;
97
+ }
98
+
99
+ asyncTransaction(async (tx) => {
94
100
  const versionId = this.editorObs.versionId.get();
95
101
  const context: InlineCompletionContext = {
96
102
  triggerKind: InlineCompletionTriggerKind.Automatic,
@@ -103,16 +109,16 @@ export class DefaultCodeEditsView extends BaseCodeEditsView {
103
109
  const inlineEdits: InlineCompletionProviderResult = await provideInlineCompletions(
104
110
  {
105
111
  all: () => [
106
- {
107
- provideInlineCompletions: () => {},
108
- provideInlineEditsForRange(model, range, context, token) {
109
- return completionModel;
110
- },
111
- freeInlineCompletions: () => [],
112
- } as InlineCompletionsProvider<ICodeEditsResult<ICodeEdit>>,
113
- ],
112
+ {
113
+ provideInlineCompletions: () => {},
114
+ provideInlineEditsForRange(model, range, context, token) {
115
+ return completionModel;
116
+ },
117
+ freeInlineCompletions: () => [],
118
+ } as InlineCompletionsProvider<ICodeEditsResult<ICodeEdit>>,
119
+ ],
114
120
  } as unknown as LanguageFeatureRegistry<InlineCompletionsProvider>,
115
- Range.lift(completionModel.range),
121
+ Range.lift(completionModel.firstRange),
116
122
  model,
117
123
  context,
118
124
  );
@@ -122,9 +128,11 @@ export class DefaultCodeEditsView extends BaseCodeEditsView {
122
128
  request,
123
129
  model,
124
130
  this.editorObs.versionId,
125
- constObservable(1000),
131
+ constObservable(4000),
126
132
  );
133
+
127
134
  source.inlineCompletions.set(completions, tx);
135
+ source.loading.set(false, tx);
128
136
  });
129
137
  }
130
138
 
@@ -55,6 +55,8 @@ import { RenameCandidatesProviderRegistry } from './contrib/rename/rename.featur
55
55
  import { TerminalAIContribution } from './contrib/terminal/terminal-ai.contributon';
56
56
  import { TerminalFeatureRegistry } from './contrib/terminal/terminal.feature.registry';
57
57
  import { LanguageParserService } from './languages/service';
58
+ import { MCPConfigCommandContribution } from './mcp/config/mcp-config.commands';
59
+ import { MCPConfigContribution } from './mcp/config/mcp-config.contribution';
58
60
  import { MCPServerProxyService } from './mcp/mcp-server-proxy.service';
59
61
  import { MCPServerRegistry } from './mcp/mcp-server.feature.registry';
60
62
  import { CreateNewFileWithTextTool } from './mcp/tools/createNewFileWithText';
@@ -91,6 +93,8 @@ export class AINativeModule extends BrowserModule {
91
93
  AICodeActionContribution,
92
94
  AINativePreferencesContribution,
93
95
  IntelligentCompletionsContribution,
96
+ MCPConfigContribution,
97
+ MCPConfigCommandContribution,
94
98
 
95
99
  // MCP Server Contributions START
96
100
  ListDirTool,