@opensumi/ide-ai-native 3.7.1-next-1737628160.0 → 3.7.1-next-1737703128.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 (165) hide show
  1. package/lib/browser/ai-core.contribution.d.ts +3 -0
  2. package/lib/browser/ai-core.contribution.d.ts.map +1 -1
  3. package/lib/browser/ai-core.contribution.js +31 -4
  4. package/lib/browser/ai-core.contribution.js.map +1 -1
  5. package/lib/browser/chat/chat-model.d.ts +2 -2
  6. package/lib/browser/chat/chat-model.d.ts.map +1 -1
  7. package/lib/browser/chat/chat-model.js +21 -9
  8. package/lib/browser/chat/chat-model.js.map +1 -1
  9. package/lib/browser/chat/chat-proxy.service.d.ts +1 -0
  10. package/lib/browser/chat/chat-proxy.service.d.ts.map +1 -1
  11. package/lib/browser/chat/chat-proxy.service.js +11 -0
  12. package/lib/browser/chat/chat-proxy.service.js.map +1 -1
  13. package/lib/browser/components/ChatEditor.d.ts +8 -0
  14. package/lib/browser/components/ChatEditor.d.ts.map +1 -1
  15. package/lib/browser/components/ChatEditor.js +8 -7
  16. package/lib/browser/components/ChatEditor.js.map +1 -1
  17. package/lib/browser/components/ChatReply.d.ts.map +1 -1
  18. package/lib/browser/components/ChatReply.js +33 -4
  19. package/lib/browser/components/ChatReply.js.map +1 -1
  20. package/lib/browser/components/ChatToolRender.d.ts +6 -0
  21. package/lib/browser/components/ChatToolRender.d.ts.map +1 -0
  22. package/lib/browser/components/ChatToolRender.js +24 -0
  23. package/lib/browser/components/ChatToolRender.js.map +1 -0
  24. package/lib/browser/components/components.module.less +32 -31
  25. package/lib/browser/contrib/intelligent-completions/index.d.ts +1 -5
  26. package/lib/browser/contrib/intelligent-completions/index.d.ts.map +1 -1
  27. package/lib/browser/contrib/intelligent-completions/index.js.map +1 -1
  28. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.d.ts.map +1 -1
  29. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.js +1 -2
  30. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.js.map +1 -1
  31. package/lib/browser/contrib/intelligent-completions/source/base.d.ts +2 -1
  32. package/lib/browser/contrib/intelligent-completions/source/base.d.ts.map +1 -1
  33. package/lib/browser/contrib/intelligent-completions/source/base.js.map +1 -1
  34. package/lib/browser/contrib/intelligent-completions/source/line-change.source.d.ts +3 -2
  35. package/lib/browser/contrib/intelligent-completions/source/line-change.source.d.ts.map +1 -1
  36. package/lib/browser/contrib/intelligent-completions/source/line-change.source.js +21 -51
  37. package/lib/browser/contrib/intelligent-completions/source/line-change.source.js.map +1 -1
  38. package/lib/browser/index.d.ts +11 -3
  39. package/lib/browser/index.d.ts.map +1 -1
  40. package/lib/browser/index.js +39 -3
  41. package/lib/browser/index.js.map +1 -1
  42. package/lib/browser/mcp/mcp-server-proxy.service.d.ts +17 -0
  43. package/lib/browser/mcp/mcp-server-proxy.service.d.ts.map +1 -0
  44. package/lib/browser/mcp/mcp-server-proxy.service.js +36 -0
  45. package/lib/browser/mcp/mcp-server-proxy.service.js.map +1 -0
  46. package/lib/browser/mcp/mcp-server.feature.registry.d.ts +16 -0
  47. package/lib/browser/mcp/mcp-server.feature.registry.d.ts.map +1 -0
  48. package/lib/browser/mcp/mcp-server.feature.registry.js +45 -0
  49. package/lib/browser/mcp/mcp-server.feature.registry.js.map +1 -0
  50. package/lib/browser/mcp/tools/createNewFileWithText.d.ts +9 -0
  51. package/lib/browser/mcp/tools/createNewFileWithText.d.ts.map +1 -0
  52. package/lib/browser/mcp/tools/createNewFileWithText.js +84 -0
  53. package/lib/browser/mcp/tools/createNewFileWithText.js.map +1 -0
  54. package/lib/browser/mcp/tools/findFilesByNameSubstring.d.ts +9 -0
  55. package/lib/browser/mcp/tools/findFilesByNameSubstring.d.ts.map +1 -0
  56. package/lib/browser/mcp/tools/findFilesByNameSubstring.js +92 -0
  57. package/lib/browser/mcp/tools/findFilesByNameSubstring.js.map +1 -0
  58. package/lib/browser/mcp/tools/getCurrentFilePath.d.ts +8 -0
  59. package/lib/browser/mcp/tools/getCurrentFilePath.d.ts.map +1 -0
  60. package/lib/browser/mcp/tools/getCurrentFilePath.js +49 -0
  61. package/lib/browser/mcp/tools/getCurrentFilePath.js.map +1 -0
  62. package/lib/browser/mcp/tools/getDiagnosticsByPath.d.ts +10 -0
  63. package/lib/browser/mcp/tools/getDiagnosticsByPath.d.ts.map +1 -0
  64. package/lib/browser/mcp/tools/getDiagnosticsByPath.js +119 -0
  65. package/lib/browser/mcp/tools/getDiagnosticsByPath.js.map +1 -0
  66. package/lib/browser/mcp/tools/getFileTextByPath.d.ts +9 -0
  67. package/lib/browser/mcp/tools/getFileTextByPath.d.ts.map +1 -0
  68. package/lib/browser/mcp/tools/getFileTextByPath.js +97 -0
  69. package/lib/browser/mcp/tools/getFileTextByPath.js.map +1 -0
  70. package/lib/browser/mcp/tools/getOpenEditorFileDiagnostics.d.ts +11 -0
  71. package/lib/browser/mcp/tools/getOpenEditorFileDiagnostics.d.ts.map +1 -0
  72. package/lib/browser/mcp/tools/getOpenEditorFileDiagnostics.js +119 -0
  73. package/lib/browser/mcp/tools/getOpenEditorFileDiagnostics.js.map +1 -0
  74. package/lib/browser/mcp/tools/getOpenEditorFileText.d.ts +8 -0
  75. package/lib/browser/mcp/tools/getOpenEditorFileText.d.ts.map +1 -0
  76. package/lib/browser/mcp/tools/getOpenEditorFileText.js +50 -0
  77. package/lib/browser/mcp/tools/getOpenEditorFileText.js.map +1 -0
  78. package/lib/browser/mcp/tools/getSelectedText.d.ts +8 -0
  79. package/lib/browser/mcp/tools/getSelectedText.d.ts.map +1 -0
  80. package/lib/browser/mcp/tools/getSelectedText.js +57 -0
  81. package/lib/browser/mcp/tools/getSelectedText.js.map +1 -0
  82. package/lib/browser/preferences/schema.d.ts.map +1 -1
  83. package/lib/browser/preferences/schema.js +0 -4
  84. package/lib/browser/preferences/schema.js.map +1 -1
  85. package/lib/browser/types.d.ts +31 -0
  86. package/lib/browser/types.d.ts.map +1 -1
  87. package/lib/browser/types.js +4 -1
  88. package/lib/browser/types.js.map +1 -1
  89. package/lib/common/index.d.ts +5 -0
  90. package/lib/common/index.d.ts.map +1 -1
  91. package/lib/common/index.js +4 -1
  92. package/lib/common/index.js.map +1 -1
  93. package/lib/common/mcp-server-manager.d.ts +39 -0
  94. package/lib/common/mcp-server-manager.d.ts.map +1 -0
  95. package/lib/common/mcp-server-manager.js +6 -0
  96. package/lib/common/mcp-server-manager.js.map +1 -0
  97. package/lib/common/tool-invocation-registry.d.ts +67 -0
  98. package/lib/common/tool-invocation-registry.d.ts.map +1 -0
  99. package/lib/common/tool-invocation-registry.js +68 -0
  100. package/lib/common/tool-invocation-registry.js.map +1 -0
  101. package/lib/common/types.d.ts +14 -0
  102. package/lib/common/types.d.ts.map +1 -1
  103. package/lib/node/anthropic/anthropic-language-model.d.ts +13 -0
  104. package/lib/node/anthropic/anthropic-language-model.d.ts.map +1 -0
  105. package/lib/node/anthropic/anthropic-language-model.js +79 -0
  106. package/lib/node/anthropic/anthropic-language-model.js.map +1 -0
  107. package/lib/node/index.d.ts.map +1 -1
  108. package/lib/node/index.js +21 -0
  109. package/lib/node/index.js.map +1 -1
  110. package/lib/node/mcp/sumi-mcp-server.d.ts +84 -0
  111. package/lib/node/mcp/sumi-mcp-server.d.ts.map +1 -0
  112. package/lib/node/mcp/sumi-mcp-server.js +134 -0
  113. package/lib/node/mcp/sumi-mcp-server.js.map +1 -0
  114. package/lib/node/mcp-server-manager-impl.d.ts +20 -0
  115. package/lib/node/mcp-server-manager-impl.d.ts.map +1 -0
  116. package/lib/node/mcp-server-manager-impl.js +123 -0
  117. package/lib/node/mcp-server-manager-impl.js.map +1 -0
  118. package/lib/node/mcp-server.d.ts +205 -0
  119. package/lib/node/mcp-server.d.ts.map +1 -0
  120. package/lib/node/mcp-server.js +86 -0
  121. package/lib/node/mcp-server.js.map +1 -0
  122. package/lib/node/openai/openai-language-model.d.ts +12 -0
  123. package/lib/node/openai/openai-language-model.d.ts.map +1 -0
  124. package/lib/node/openai/openai-language-model.js +136 -0
  125. package/lib/node/openai/openai-language-model.js.map +1 -0
  126. package/package.json +26 -21
  127. package/src/browser/ai-core.contribution.ts +47 -4
  128. package/src/browser/chat/chat-model.ts +21 -9
  129. package/src/browser/chat/chat-proxy.service.ts +12 -0
  130. package/src/browser/components/ChatEditor.tsx +6 -4
  131. package/src/browser/components/ChatReply.tsx +40 -4
  132. package/src/browser/components/ChatToolRender.tsx +27 -0
  133. package/src/browser/components/components.module.less +32 -31
  134. package/src/browser/contrib/intelligent-completions/index.ts +2 -3
  135. package/src/browser/contrib/intelligent-completions/intelligent-completions.controller.ts +1 -2
  136. package/src/browser/contrib/intelligent-completions/source/base.ts +2 -0
  137. package/src/browser/contrib/intelligent-completions/source/line-change.source.ts +24 -79
  138. package/src/browser/index.ts +50 -4
  139. package/src/browser/mcp/mcp-server-proxy.service.ts +32 -0
  140. package/src/browser/mcp/mcp-server.feature.registry.ts +47 -0
  141. package/src/browser/mcp/tools/createNewFileWithText.ts +85 -0
  142. package/src/browser/mcp/tools/findFilesByNameSubstring.ts +93 -0
  143. package/src/browser/mcp/tools/getCurrentFilePath.ts +49 -0
  144. package/src/browser/mcp/tools/getDiagnosticsByPath.ts +123 -0
  145. package/src/browser/mcp/tools/getFileTextByPath.ts +97 -0
  146. package/src/browser/mcp/tools/getOpenEditorFileDiagnostics.ts +121 -0
  147. package/src/browser/mcp/tools/getOpenEditorFileText.ts +50 -0
  148. package/src/browser/mcp/tools/getSelectedText.ts +57 -0
  149. package/src/browser/preferences/schema.ts +0 -4
  150. package/src/browser/types.ts +39 -0
  151. package/src/common/index.ts +9 -0
  152. package/src/common/mcp-server-manager.ts +45 -0
  153. package/src/common/tool-invocation-registry.ts +124 -0
  154. package/src/common/types.ts +18 -0
  155. package/src/node/anthropic/anthropic-language-model.ts +96 -0
  156. package/src/node/index.ts +24 -0
  157. package/src/node/mcp/sumi-mcp-server.ts +161 -0
  158. package/src/node/mcp-server-manager-impl.ts +130 -0
  159. package/src/node/mcp-server.ts +118 -0
  160. package/src/node/openai/openai-language-model.ts +152 -0
  161. package/lib/browser/contrib/intelligent-completions/source/typing.source.d.ts +0 -9
  162. package/lib/browser/contrib/intelligent-completions/source/typing.source.d.ts.map +0 -1
  163. package/lib/browser/contrib/intelligent-completions/source/typing.source.js +0 -38
  164. package/lib/browser/contrib/intelligent-completions/source/typing.source.js.map +0 -1
  165. package/src/browser/contrib/intelligent-completions/source/typing.source.ts +0 -36
@@ -70,7 +70,11 @@ import {
70
70
  AI_CHAT_VIEW_ID,
71
71
  AI_MENU_BAR_DEBUG_TOOLBAR,
72
72
  ChatProxyServiceToken,
73
+ ISumiMCPServerBackend,
74
+ SumiMCPServerProxyServicePath,
73
75
  } from '../common';
76
+ import { MCPServerDescription, MCPServerManager, MCPServerManagerPath } from '../common/mcp-server-manager';
77
+ import { ToolInvocationRegistry, ToolInvocationRegistryImpl } from '../common/tool-invocation-registry';
74
78
 
75
79
  import { ChatProxyService } from './chat/chat-proxy.service';
76
80
  import { AIChatView } from './chat/chat.view';
@@ -94,10 +98,13 @@ import {
94
98
  IChatFeatureRegistry,
95
99
  IChatRenderRegistry,
96
100
  IIntelligentCompletionsRegistry,
101
+ IMCPServerRegistry,
97
102
  IProblemFixProviderRegistry,
98
103
  IRenameCandidatesProviderRegistry,
99
104
  IResolveConflictRegistry,
100
105
  ITerminalProviderRegistry,
106
+ MCPServerContribution,
107
+ TokenMCPServerRegistry,
101
108
  } from './types';
102
109
  import { InlineChatEditorController } from './widget/inline-chat/inline-chat-editor.controller';
103
110
  import { InlineChatFeatureRegistry } from './widget/inline-chat/inline-chat.feature.registry';
@@ -142,6 +149,12 @@ export class AINativeBrowserContribution
142
149
  @Autowired(AINativeCoreContribution)
143
150
  private readonly contributions: ContributionProvider<AINativeCoreContribution>;
144
151
 
152
+ @Autowired(MCPServerContribution)
153
+ private readonly mcpServerContributions: ContributionProvider<MCPServerContribution>;
154
+
155
+ @Autowired(TokenMCPServerRegistry)
156
+ private readonly mcpServerRegistry: IMCPServerRegistry;
157
+
145
158
  @Autowired(InlineChatFeatureRegistryToken)
146
159
  private readonly inlineChatFeatureRegistry: InlineChatFeatureRegistry;
147
160
 
@@ -205,6 +218,12 @@ export class AINativeBrowserContribution
205
218
  @Autowired(CodeActionSingleHandler)
206
219
  private readonly codeActionSingleHandler: CodeActionSingleHandler;
207
220
 
221
+ // @Autowired(MCPServerManagerPath)
222
+ // private readonly mcpServerManager: MCPServerManager;
223
+
224
+ @Autowired(SumiMCPServerProxyServicePath)
225
+ private readonly sumiMCPServerBackendProxy: ISumiMCPServerBackend;
226
+
208
227
  constructor() {
209
228
  this.registerFeature();
210
229
  }
@@ -303,6 +322,11 @@ export class AINativeBrowserContribution
303
322
  contribution.registerIntelligentCompletionFeature?.(this.intelligentCompletionsRegistry);
304
323
  contribution.registerProblemFixFeature?.(this.problemFixProviderRegistry);
305
324
  });
325
+
326
+ // 注册 Opensumi 框架提供的 MCP Server Tools 能力 (此时的 Opensumi 作为 MCP Server)
327
+ this.mcpServerContributions.getContributions().forEach((contribution) => {
328
+ contribution.registerMCPServer(this.mcpServerRegistry);
329
+ });
306
330
  }
307
331
 
308
332
  registerSetting(registry: ISettingRegistry) {
@@ -365,10 +389,6 @@ export class AINativeBrowserContribution
365
389
  id: AINativeSettingSectionsId.CodeEditsLineChange,
366
390
  localized: 'preference.ai.native.codeEdits.lineChange',
367
391
  },
368
- {
369
- id: AINativeSettingSectionsId.CodeEditsTyping,
370
- localized: 'preference.ai.native.codeEdits.typing',
371
- },
372
392
  ],
373
393
  });
374
394
  }
@@ -411,6 +431,29 @@ export class AINativeBrowserContribution
411
431
  }
412
432
 
413
433
  registerCommands(commands: CommandRegistry): void {
434
+ commands.registerCommand(
435
+ { id: 'ai.native.mcp.start', label: 'MCP: Start MCP Server' },
436
+ {
437
+ execute: async () => {
438
+ // this.mcpServerManager.initBuiltinServer();
439
+
440
+ this.sumiMCPServerBackendProxy.initBuiltinMCPServer();
441
+
442
+ const description: MCPServerDescription = {
443
+ name: 'filesystem',
444
+ command: 'npx',
445
+ args: ['-y', '@modelcontextprotocol/server-filesystem', '/Users/retrox/AlipayProjects/core'],
446
+ env: {},
447
+ };
448
+
449
+ // this.mcpServerManager.addOrUpdateServer(description);
450
+
451
+ // await this.mcpServerManager.startServer(description.name);
452
+ // await this.mcpServerManager.collectTools(description.name);
453
+ },
454
+ },
455
+ );
456
+
414
457
  commands.registerCommand(AI_INLINE_CHAT_VISIBLE, {
415
458
  execute: (value: boolean) => {
416
459
  this.aiInlineChatService._onInlineChatVisible.fire(value);
@@ -6,6 +6,7 @@ import {
6
6
  IChatComponent,
7
7
  IChatMarkdownContent,
8
8
  IChatProgress,
9
+ IChatToolContent,
9
10
  IChatTreeData,
10
11
  ILogger,
11
12
  memoize,
@@ -26,7 +27,7 @@ import {
26
27
  import { MsgHistoryManager } from '../model/msg-history-manager';
27
28
  import { IChatSlashCommandItem } from '../types';
28
29
 
29
- export type IChatProgressResponseContent = IChatMarkdownContent | IChatAsyncContent | IChatTreeData | IChatComponent;
30
+ export type IChatProgressResponseContent = IChatMarkdownContent | IChatAsyncContent | IChatTreeData | IChatComponent | IChatToolContent;
30
31
 
31
32
  @Injectable({ multiple: true })
32
33
  export class ChatResponseModel extends Disposable {
@@ -81,8 +82,8 @@ export class ChatResponseModel extends Disposable {
81
82
  }
82
83
 
83
84
  updateContent(progress: IChatProgress, quiet?: boolean): void {
85
+ const responsePartLength = this.#responseParts.length - 1;
84
86
  if (progress.kind === 'content' || progress.kind === 'markdownContent') {
85
- const responsePartLength = this.#responseParts.length - 1;
86
87
  const lastResponsePart = this.#responseParts[responsePartLength];
87
88
 
88
89
  if (!lastResponsePart || lastResponsePart.kind !== 'markdownContent') {
@@ -120,11 +121,19 @@ export class ChatResponseModel extends Disposable {
120
121
  }
121
122
  this.#updateResponseText(quiet);
122
123
  });
123
- } else if (progress.kind === 'treeData') {
124
+ } else if (progress.kind === 'treeData' || progress.kind === 'component') {
124
125
  this.#responseParts.push(progress);
125
126
  this.#updateResponseText(quiet);
126
- } else if (progress.kind === 'component') {
127
- this.#responseParts.push(progress);
127
+ } else if (progress.kind === 'toolCall') {
128
+ // @ts-ignore
129
+ const find: IChatToolContent | undefined = this.#responseParts.find((item) => item.kind === 'toolCall' && (item.content.id === progress.content.id || item.content.index === progress.content.index));
130
+ if (find) {
131
+ find.content.function.arguments = find.content.function.arguments + progress.content.function.arguments;
132
+ this.#responseParts[responsePartLength] = find;
133
+ } else {
134
+ this.#responseParts.push(progress);
135
+ }
136
+ console.log("🚀 ~ ChatResponseModel ~ updateContent ~ this.#responseParts:", this.#responseParts)
128
137
  this.#updateResponseText(quiet);
129
138
  }
130
139
  }
@@ -141,6 +150,9 @@ export class ChatResponseModel extends Disposable {
141
150
  if (part.kind === 'component') {
142
151
  return '';
143
152
  }
153
+ if (part.kind === 'toolCall') {
154
+ return part.content.function.name;
155
+ }
144
156
  return part.content.value;
145
157
  })
146
158
  .join('\n\n');
@@ -162,9 +174,9 @@ export class ChatResponseModel extends Disposable {
162
174
  }
163
175
  this.#responseContents = result;
164
176
 
165
- if (!quiet) {
177
+ // if (!quiet) {
166
178
  this.#onDidChange.fire();
167
- }
179
+ // }
168
180
  }
169
181
 
170
182
  complete(): void {
@@ -258,10 +270,10 @@ export class ChatModel extends Disposable implements IChatModel {
258
270
 
259
271
  const { kind } = progress;
260
272
 
261
- const basicKind = ['content', 'markdownContent', 'asyncContent', 'treeData', 'component'];
273
+ const basicKind = ['content', 'markdownContent', 'asyncContent', 'treeData', 'component', 'toolCall'];
262
274
 
263
275
  if (basicKind.includes(kind)) {
264
- request.response.updateContent(progress, quiet);
276
+ request.response.updateContent(progress, false);
265
277
  } else {
266
278
  this.logger.error(`Couldn't handle progress: ${JSON.stringify(progress)}`);
267
279
  }
@@ -25,6 +25,9 @@ import {
25
25
 
26
26
  import { ChatService } from './chat.api.service';
27
27
  import { ChatFeatureRegistry } from './chat.feature.registry';
28
+ import { ChatAgentViewServiceToken } from '@opensumi/ide-core-common';
29
+ import { IChatAgentViewService } from '../types';
30
+ import { ChatToolRender } from '../components/ChatToolRender';
28
31
 
29
32
  /**
30
33
  * @internal
@@ -52,9 +55,18 @@ export class ChatProxyService extends Disposable {
52
55
  @Autowired(IAIReporter)
53
56
  private readonly aiReporter: IAIReporter;
54
57
 
58
+ @Autowired(ChatAgentViewServiceToken)
59
+ private readonly chatAgentViewService: IChatAgentViewService;
60
+
55
61
  private chatDeferred: Deferred<void> = new Deferred<void>();
56
62
 
57
63
  public registerDefaultAgent() {
64
+ this.chatAgentViewService.registerChatComponent({
65
+ id: 'toolCall',
66
+ component: ChatToolRender,
67
+ initialProps: {},
68
+ });
69
+
58
70
  this.addDispose(
59
71
  this.chatAgentService.registerAgent({
60
72
  id: ChatProxyService.AGENT_ID,
@@ -130,11 +130,12 @@ export const CodeEditorWithHighlight = (props: Props) => {
130
130
  );
131
131
  };
132
132
 
133
- const CodeBlock = ({
133
+ export const CodeBlock = ({
134
134
  content = '',
135
135
  relationId,
136
136
  renderText,
137
137
  agentId = '',
138
+ language = '',
138
139
  command = '',
139
140
  }: {
140
141
  content?: string;
@@ -142,14 +143,15 @@ const CodeBlock = ({
142
143
  renderText?: (t: string) => React.ReactNode;
143
144
  agentId?: string;
144
145
  command?: string;
146
+ language?: string;
145
147
  }) => {
146
148
  const rgInlineCode = /`([^`]+)`/g;
147
149
  const rgBlockCode = /```([^]+?)```/g;
148
150
  const rgBlockCodeBefore = /```([^]+)?/g;
149
151
 
150
152
  const renderCodeEditor = (content: string) => {
151
- const language = content.split('\n')[0].trim().toLowerCase();
152
- const heighLightLang = highLightLanguageSupport.find((lang) => lang === language) || 'plaintext';
153
+ const _language = content.split('\n')[0].trim().toLowerCase();
154
+ const heighLightLang = highLightLanguageSupport.find((lang) => lang === _language) || 'plaintext';
153
155
 
154
156
  content = content.replace(/.*?\n/, '');
155
157
  content = content.trim();
@@ -158,7 +160,7 @@ const CodeBlock = ({
158
160
  <div className={styles.code_language}>{capitalize(heighLightLang)}</div>
159
161
  <CodeEditorWithHighlight
160
162
  input={content}
161
- language={language}
163
+ language={_language || language}
162
164
  relationId={relationId}
163
165
  agentId={agentId}
164
166
  command={command}
@@ -38,6 +38,7 @@ import {
38
38
  IChatComponent,
39
39
  IChatContent,
40
40
  IChatResponseProgressFileTreeData,
41
+ IChatToolContent,
41
42
  URI,
42
43
  } from '@opensumi/ide-core-common';
43
44
  import { IIconService } from '@opensumi/ide-theme';
@@ -148,6 +149,34 @@ const TreeRenderer = (props: { treeData: IChatResponseProgressFileTreeData }) =>
148
149
  );
149
150
  };
150
151
 
152
+ const ToolCallRender = (props: { toolCall: IChatToolContent['content'] }) => {
153
+ console.log("🚀 ~ ToolCallRender ~ props:", props)
154
+ const { toolCall } = props;
155
+ const chatAgentViewService = useInjectable<IChatAgentViewService>(ChatAgentViewServiceToken);
156
+ const [node, setNode] = useState<React.JSX.Element | null>(null);
157
+
158
+ useEffect(() => {
159
+ const config = chatAgentViewService.getChatComponent('toolCall');
160
+ if (config) {
161
+ const { component: Component, initialProps } = config;
162
+ setNode(<Component {...initialProps} value={toolCall} />);
163
+ return;
164
+ }
165
+ setNode(
166
+ <div>
167
+ <Loading />
168
+ <span style={{ marginLeft: 4 }}>正在加载组件</span>
169
+ </div>,
170
+ );
171
+ const deferred = chatAgentViewService.getChatComponentDeferred('toolCall')!;
172
+ deferred.promise.then(({ component: Component, initialProps }) => {
173
+ setNode(<Component {...initialProps} value={toolCall} />);
174
+ });
175
+ }, [toolCall]);
176
+
177
+ return node;
178
+ };
179
+
151
180
  const ComponentRender = (props: { component: string; value?: unknown }) => {
152
181
  const chatAgentViewService = useInjectable<IChatAgentViewService>(ChatAgentViewServiceToken);
153
182
  const [node, setNode] = useState<React.JSX.Element | null>(null);
@@ -202,6 +231,7 @@ export const ChatReply = (props: IChatReplyProps) => {
202
231
 
203
232
  disposableCollection.push(
204
233
  request.response.onDidChange(() => {
234
+ console.log("🚀 ~ request.response.onDidChange ~ onDidChange:", 'onDidChange')
205
235
  history.updateAssistantMessage(msgId, { content: request.response.responseText });
206
236
 
207
237
  if (request.response.isComplete) {
@@ -219,10 +249,10 @@ export const ChatReply = (props: IChatReplyProps) => {
219
249
  });
220
250
  }
221
251
 
222
- startTransition(() => {
223
- onDidChange?.();
224
- update();
225
- });
252
+ // startTransition(() => {
253
+ // });
254
+ onDidChange?.();
255
+ update();
226
256
  }),
227
257
  );
228
258
 
@@ -274,6 +304,10 @@ export const ChatReply = (props: IChatReplyProps) => {
274
304
  <ComponentRender component={componentId} value={value} />
275
305
  );
276
306
 
307
+ const renderToolCall = (toolCall: IChatToolContent['content']) => {
308
+ return <ToolCallRender toolCall={toolCall} />;
309
+ };
310
+
277
311
  const contentNode = React.useMemo(
278
312
  () =>
279
313
  request.response.responseContents.map((item, index) => {
@@ -284,6 +318,8 @@ export const ChatReply = (props: IChatReplyProps) => {
284
318
  node = renderTreeData(item.treeData);
285
319
  } else if (item.kind === 'component') {
286
320
  node = renderComponent(item.component, item.value);
321
+ } else if (item.kind === 'toolCall') {
322
+ node = renderToolCall(item.content);
287
323
  } else {
288
324
  node = renderMarkdown(item.content);
289
325
  }
@@ -0,0 +1,27 @@
1
+ import { IChatToolContent, uuid } from "@opensumi/ide-core-common";
2
+ import React from "react";
3
+ import { CodeEditorWithHighlight } from "./ChatEditor";
4
+
5
+ export const ChatToolRender = (props: { value: IChatToolContent['content'] }) => {
6
+ const { value } = props;
7
+ console.log("🚀 ~ ChatToolRender ~ toolCall:", value)
8
+
9
+ if (!value || !value.function || !value.id) {
10
+ return null;
11
+ }
12
+
13
+ return <div>
14
+ <span>当前调用的工具: </span>
15
+ <span>{value?.function?.name}</span>
16
+ <br />
17
+ <span></span>
18
+ {
19
+ value?.function?.arguments &&
20
+ (<CodeEditorWithHighlight
21
+ input={value?.function?.arguments}
22
+ language={'json'}
23
+ relationId={uuid(4)}
24
+ />)
25
+ }
26
+ </div>
27
+ };
@@ -244,44 +244,45 @@
244
244
  }
245
245
  }
246
246
 
247
- .code_block {
247
+ .monaco_wrapper {
248
248
  position: relative;
249
- min-width: 100px;
250
- margin-top: 4px;
251
- .monaco_wrapper {
252
- position: relative;
253
- min-width: 130px;
254
- > pre {
255
- margin-bottom: 10px;
256
- }
257
- .editor {
258
- border-radius: 8px;
259
- font-size: 12px;
260
- padding: 32px 8px 8px 8px;
261
- line-height: 18px;
262
- &::-webkit-scrollbar {
263
- width: auto;
264
- height: 4px;
265
- }
249
+ min-width: 130px;
250
+ > pre {
251
+ margin-bottom: 10px;
252
+ }
253
+ .editor {
254
+ border-radius: 8px;
255
+ font-size: 12px;
256
+ padding: 32px 8px 8px 8px;
257
+ line-height: 18px;
258
+ &::-webkit-scrollbar {
259
+ width: auto;
260
+ height: 4px;
266
261
  }
262
+ }
267
263
 
268
- .action_toolbar {
269
- display: flex;
270
- position: absolute;
271
- right: 8px;
272
- top: 6px;
273
- z-index: 100;
274
- height: 20px;
275
- align-items: center;
276
- overflow: hidden;
264
+ .action_toolbar {
265
+ display: flex;
266
+ position: absolute;
267
+ right: 8px;
268
+ top: 6px;
269
+ z-index: 100;
270
+ height: 20px;
271
+ align-items: center;
272
+ overflow: hidden;
277
273
 
278
- :global {
279
- .kt-popover {
280
- height: inherit;
281
- }
274
+ :global {
275
+ .kt-popover {
276
+ height: inherit;
282
277
  }
283
278
  }
284
279
  }
280
+ }
281
+
282
+ .code_block {
283
+ position: relative;
284
+ min-width: 100px;
285
+ margin-top: 4px;
285
286
 
286
287
  :global {
287
288
  .hljs {
@@ -1,5 +1,5 @@
1
1
  import { Disposable, ECodeEditsSourceTyping } from '@opensumi/ide-core-common';
2
- import { IModelContentChangedEvent, IPosition, IRange, InlineCompletion } from '@opensumi/ide-monaco';
2
+ import { IPosition, IRange, InlineCompletion } from '@opensumi/ide-monaco';
3
3
 
4
4
  import type { ILineChangeData } from './source/line-change.source';
5
5
  import type { ILinterErrorData } from './source/lint-error.source';
@@ -14,8 +14,7 @@ export interface IIntelligentCompletionsResult<T = any> {
14
14
 
15
15
  export type ICodeEditsContextBean =
16
16
  | { typing: ECodeEditsSourceTyping.LinterErrors; position: IPosition; data: ILinterErrorData }
17
- | { typing: ECodeEditsSourceTyping.LineChange; position: IPosition; data: ILineChangeData }
18
- | { typing: ECodeEditsSourceTyping.Typing; position: IPosition; data: IModelContentChangedEvent };
17
+ | { typing: ECodeEditsSourceTyping.LineChange; position: IPosition; data: ILineChangeData };
19
18
 
20
19
  export interface ICodeEdit {
21
20
  /**
@@ -47,7 +47,6 @@ import { IntelligentCompletionsRegistry } from './intelligent-completions.featur
47
47
  import { CodeEditsSourceCollection } from './source/base';
48
48
  import { LineChangeCodeEditsSource } from './source/line-change.source';
49
49
  import { LintErrorCodeEditsSource } from './source/lint-error.source';
50
- import { TypingCodeEditsSource } from './source/typing.source';
51
50
 
52
51
  import { CodeEditsResultValue } from './index';
53
52
 
@@ -96,7 +95,7 @@ export class IntelligentCompletionsController extends BaseAIMonacoEditorControll
96
95
  this.additionsDeletionsDecorationModel = new AdditionsDeletionsDecorationModel(this.monacoEditor);
97
96
  this.aiNativeContextKey = this.injector.get(AINativeContextKey, [this.monacoEditor.contextKeyService]);
98
97
  this.codeEditsSourceCollection = this.injector.get(CodeEditsSourceCollection, [
99
- [LintErrorCodeEditsSource, LineChangeCodeEditsSource, TypingCodeEditsSource],
98
+ [LintErrorCodeEditsSource, LineChangeCodeEditsSource],
100
99
  this.monacoEditor,
101
100
  ]);
102
101
 
@@ -69,6 +69,8 @@ export abstract class BaseCodeEditsSource extends Disposable {
69
69
  private cancellationTokenSource = new CancellationTokenSource();
70
70
  private readonly relationID = observableValue<string | undefined>(this, undefined);
71
71
 
72
+ protected abstract doTrigger(...args: any[]): MaybePromise<void>;
73
+
72
74
  public readonly codeEditsContextBean = disposableObservableValue<CodeEditsContextBean | undefined>(this, undefined);
73
75
  public abstract priority: number;
74
76
  public abstract mount(): IDisposable;
@@ -1,102 +1,47 @@
1
1
  import { Injectable } from '@opensumi/di';
2
2
  import { AINativeSettingSectionsId, ECodeEditsSourceTyping, IDisposable } from '@opensumi/ide-core-common';
3
- import { ICursorPositionChangedEvent, IModelContentChangedEvent } from '@opensumi/ide-monaco';
4
- import {
5
- autorunDelta,
6
- derivedHandleChanges,
7
- observableFromEvent,
8
- recomputeInitiallyAndOnChange,
9
- } from '@opensumi/ide-monaco/lib/common/observable';
3
+ import { ICursorPositionChangedEvent, Position } from '@opensumi/ide-monaco';
10
4
 
11
5
  import { BaseCodeEditsSource } from './base';
12
6
 
13
7
  export interface ILineChangeData {
14
8
  currentLineNumber: number;
15
9
  preLineNumber?: number;
16
- change?: IModelContentChangedEvent;
17
10
  }
18
11
 
19
12
  @Injectable({ multiple: true })
20
13
  export class LineChangeCodeEditsSource extends BaseCodeEditsSource {
21
14
  public priority = 2;
22
15
 
23
- public mount(): IDisposable {
24
- const modelContentChangeObs = observableFromEvent<IModelContentChangedEvent>(
25
- this,
26
- this.monacoEditor.onDidChangeModelContent,
27
- (event: IModelContentChangedEvent) => event,
28
- );
29
- const positionChangeObs = observableFromEvent<ICursorPositionChangedEvent>(
30
- this,
31
- this.monacoEditor.onDidChangeCursorPosition,
32
- (event: ICursorPositionChangedEvent) => event,
33
- );
16
+ private prePosition = this.monacoEditor.getPosition();
34
17
 
35
- const latestModelContentChangeObs = derivedHandleChanges(
36
- {
37
- owner: this,
38
- createEmptyChangeSummary: () => ({ change: undefined }),
39
- handleChange: (ctx, changeSummary: { change: IModelContentChangedEvent | undefined }) => {
40
- // 如果只是改了光标则设置 change 为空,避免获取到缓存的 change
41
- if (ctx.didChange(positionChangeObs)) {
42
- changeSummary.change = undefined;
43
- } else {
44
- changeSummary.change = modelContentChangeObs.get();
45
- }
46
- return true;
47
- },
48
- },
49
- (reader, changeSummary) => {
50
- positionChangeObs.read(reader);
51
- modelContentChangeObs.read(reader);
52
- return changeSummary.change;
53
- },
54
- );
55
-
56
- this.addDispose(recomputeInitiallyAndOnChange(latestModelContentChangeObs));
57
-
58
- let lastModelContent: IModelContentChangedEvent | undefined;
18
+ public mount(): IDisposable {
59
19
  this.addDispose(
60
- /**
61
- * 由于 monaco 的 changeModelContent 事件比 changeCursorPosition 事件先触发,所以这里需要拿上一次的值进行消费
62
- * 否则永远返回 undefined
63
- */
64
- autorunDelta(latestModelContentChangeObs, ({ lastValue }) => {
65
- lastModelContent = lastValue;
20
+ this.monacoEditor.onDidChangeCursorPosition((event: ICursorPositionChangedEvent) => {
21
+ const currentPosition = event.position;
22
+ if (this.prePosition && this.prePosition.lineNumber !== currentPosition.lineNumber) {
23
+ this.doTrigger(currentPosition);
24
+ this.prePosition = currentPosition;
25
+ }
66
26
  }),
67
27
  );
28
+ return this;
29
+ }
68
30
 
69
- this.addDispose(
70
- autorunDelta(positionChangeObs, ({ lastValue, newValue }) => {
71
- const contentChange = lastModelContent;
72
-
73
- const isLineChangeEnabled = this.preferenceService.getValid(
74
- AINativeSettingSectionsId.CodeEditsLineChange,
75
- false,
76
- );
77
- if (!isLineChangeEnabled) {
78
- return false;
79
- }
80
-
81
- const prePosition = lastValue?.position;
82
- const currentPosition = newValue?.position;
83
- if (prePosition && prePosition.lineNumber !== currentPosition?.lineNumber) {
84
- this.setBean({
85
- typing: ECodeEditsSourceTyping.LineChange,
86
- position: currentPosition,
87
- data: {
88
- preLineNumber: prePosition.lineNumber,
89
- currentLineNumber: currentPosition.lineNumber,
90
- change: contentChange,
91
- },
92
- });
93
- }
31
+ protected doTrigger(position: Position) {
32
+ const isLineChangeEnabled = this.preferenceService.getValid(AINativeSettingSectionsId.CodeEditsLineChange, false);
94
33
 
95
- // 消费完之后设置为 undefined,避免下次获取到缓存的值
96
- lastModelContent = undefined;
97
- }),
98
- );
34
+ if (!isLineChangeEnabled || !position) {
35
+ return;
36
+ }
99
37
 
100
- return this;
38
+ this.setBean({
39
+ typing: ECodeEditsSourceTyping.LineChange,
40
+ position,
41
+ data: {
42
+ preLineNumber: this.prePosition?.lineNumber,
43
+ currentLineNumber: position.lineNumber,
44
+ },
45
+ });
101
46
  }
102
47
  }