@opensumi/ide-ai-native 3.8.3-next-1741949132.0 → 3.8.3-next-1742183446.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 (84) hide show
  1. package/lib/browser/chat/chat-manager.service.d.ts +1 -1
  2. package/lib/browser/chat/chat-manager.service.d.ts.map +1 -1
  3. package/lib/browser/chat/chat-manager.service.js +2 -3
  4. package/lib/browser/chat/chat-manager.service.js.map +1 -1
  5. package/lib/browser/chat/chat-model.d.ts.map +1 -1
  6. package/lib/browser/chat/chat-model.js +2 -11
  7. package/lib/browser/chat/chat-model.js.map +1 -1
  8. package/lib/browser/chat/chat-proxy.service.d.ts.map +1 -1
  9. package/lib/browser/chat/chat-proxy.service.js +0 -1
  10. package/lib/browser/chat/chat-proxy.service.js.map +1 -1
  11. package/lib/browser/chat/chat.feature.registry.d.ts +1 -4
  12. package/lib/browser/chat/chat.feature.registry.d.ts.map +1 -1
  13. package/lib/browser/chat/chat.feature.registry.js +0 -6
  14. package/lib/browser/chat/chat.feature.registry.js.map +1 -1
  15. package/lib/browser/chat/chat.internal.service.d.ts +1 -1
  16. package/lib/browser/chat/chat.internal.service.d.ts.map +1 -1
  17. package/lib/browser/chat/chat.internal.service.js +2 -2
  18. package/lib/browser/chat/chat.internal.service.js.map +1 -1
  19. package/lib/browser/chat/chat.view.d.ts.map +1 -1
  20. package/lib/browser/chat/chat.view.js +7 -10
  21. package/lib/browser/chat/chat.view.js.map +1 -1
  22. package/lib/browser/components/ChatEditor.d.ts +1 -2
  23. package/lib/browser/components/ChatEditor.d.ts.map +1 -1
  24. package/lib/browser/components/ChatEditor.js +2 -5
  25. package/lib/browser/components/ChatEditor.js.map +1 -1
  26. package/lib/browser/components/ChatInput.d.ts +1 -1
  27. package/lib/browser/components/ChatInput.d.ts.map +1 -1
  28. package/lib/browser/components/ChatInput.js +1 -1
  29. package/lib/browser/components/ChatInput.js.map +1 -1
  30. package/lib/browser/components/ChatMentionInput.d.ts +1 -3
  31. package/lib/browser/components/ChatMentionInput.d.ts.map +1 -1
  32. package/lib/browser/components/ChatMentionInput.js +3 -51
  33. package/lib/browser/components/ChatMentionInput.js.map +1 -1
  34. package/lib/browser/components/components.module.less +0 -49
  35. package/lib/browser/components/mention-input/mention-input.d.ts.map +1 -1
  36. package/lib/browser/components/mention-input/mention-input.js +112 -74
  37. package/lib/browser/components/mention-input/mention-input.js.map +1 -1
  38. package/lib/browser/components/mention-input/mention-input.module.less +0 -1
  39. package/lib/browser/components/mention-input/types.d.ts +1 -3
  40. package/lib/browser/components/mention-input/types.d.ts.map +1 -1
  41. package/lib/browser/components/mention-input/types.js.map +1 -1
  42. package/lib/browser/context/llm-context.service.d.ts.map +1 -1
  43. package/lib/browser/context/llm-context.service.js.map +1 -1
  44. package/lib/browser/mcp/config/components/mcp-config.view.d.ts.map +1 -1
  45. package/lib/browser/mcp/config/components/mcp-config.view.js +17 -3
  46. package/lib/browser/mcp/config/components/mcp-config.view.js.map +1 -1
  47. package/lib/browser/mcp/mcp-server-proxy.service.d.ts +1 -0
  48. package/lib/browser/mcp/mcp-server-proxy.service.d.ts.map +1 -1
  49. package/lib/browser/model/msg-history-manager.d.ts +1 -1
  50. package/lib/browser/model/msg-history-manager.d.ts.map +1 -1
  51. package/lib/browser/model/msg-history-manager.js.map +1 -1
  52. package/lib/browser/types.d.ts +1 -7
  53. package/lib/browser/types.d.ts.map +1 -1
  54. package/lib/browser/types.js.map +1 -1
  55. package/lib/common/index.d.ts +1 -6
  56. package/lib/common/index.d.ts.map +1 -1
  57. package/lib/common/index.js.map +1 -1
  58. package/lib/common/llm-context.d.ts.map +1 -1
  59. package/lib/common/llm-context.js.map +1 -1
  60. package/lib/node/base-language-model.d.ts +1 -1
  61. package/lib/node/base-language-model.d.ts.map +1 -1
  62. package/lib/node/base-language-model.js +4 -15
  63. package/lib/node/base-language-model.js.map +1 -1
  64. package/package.json +23 -23
  65. package/src/browser/chat/chat-manager.service.ts +2 -3
  66. package/src/browser/chat/chat-model.ts +2 -10
  67. package/src/browser/chat/chat-proxy.service.ts +0 -1
  68. package/src/browser/chat/chat.feature.registry.ts +1 -10
  69. package/src/browser/chat/chat.internal.service.ts +2 -2
  70. package/src/browser/chat/chat.view.tsx +8 -18
  71. package/src/browser/components/ChatEditor.tsx +0 -8
  72. package/src/browser/components/ChatInput.tsx +2 -2
  73. package/src/browser/components/ChatMentionInput.tsx +6 -93
  74. package/src/browser/components/components.module.less +0 -49
  75. package/src/browser/components/mention-input/mention-input.module.less +0 -1
  76. package/src/browser/components/mention-input/mention-input.tsx +129 -81
  77. package/src/browser/components/mention-input/types.ts +1 -3
  78. package/src/browser/context/llm-context.service.ts +0 -2
  79. package/src/browser/mcp/config/components/mcp-config.view.tsx +17 -3
  80. package/src/browser/model/msg-history-manager.ts +1 -1
  81. package/src/browser/types.ts +1 -8
  82. package/src/common/index.ts +8 -7
  83. package/src/common/llm-context.ts +0 -2
  84. package/src/node/base-language-model.ts +3 -25
@@ -1,18 +1,14 @@
1
- import { DataContent } from 'ai';
2
1
  import React, { useCallback, useEffect, useMemo, useState } from 'react';
3
2
 
4
- import { Image } from '@opensumi/ide-components/lib/image';
5
3
  import { LabelService, RecentFilesManager, useInjectable } from '@opensumi/ide-core-browser';
6
- import { Icon, getIcon } from '@opensumi/ide-core-browser/lib/components';
7
- import { ChatFeatureRegistryToken, URI, localize } from '@opensumi/ide-core-common';
4
+ import { getIcon } from '@opensumi/ide-core-browser/lib/components';
5
+ import { URI, localize } from '@opensumi/ide-core-common';
8
6
  import { CommandService } from '@opensumi/ide-core-common/lib/command';
9
7
  import { WorkbenchEditorService } from '@opensumi/ide-editor';
10
8
  import { FileSearchServicePath, IFileSearchService } from '@opensumi/ide-file-search';
11
- import { IMessageService } from '@opensumi/ide-overlay';
12
9
  import { IWorkspaceService } from '@opensumi/ide-workspace';
13
10
 
14
11
  import { IChatInternalService } from '../../common';
15
- import { ChatFeatureRegistry } from '../chat/chat.feature.registry';
16
12
  import { ChatInternalService } from '../chat/chat.internal.service';
17
13
  import { OPEN_MCP_CONFIG_COMMAND } from '../mcp/config/mcp-config.commands';
18
14
 
@@ -21,13 +17,7 @@ import { MentionInput } from './mention-input/mention-input';
21
17
  import { FooterButtonPosition, FooterConfig, MentionItem, MentionType } from './mention-input/types';
22
18
 
23
19
  export interface IChatMentionInputProps {
24
- onSend: (
25
- value: string,
26
- images?: string[],
27
- agentId?: string,
28
- command?: string,
29
- option?: { model: string; [key: string]: any },
30
- ) => void;
20
+ onSend: (value: string, agentId?: string, command?: string, option?: { model: string; [key: string]: any }) => void;
31
21
  onValueChange?: (value: string) => void;
32
22
  onExpand?: (value: boolean) => void;
33
23
  placeholder?: string;
@@ -36,7 +26,6 @@ export interface IChatMentionInputProps {
36
26
  sendBtnClassName?: string;
37
27
  defaultHeight?: number;
38
28
  value?: string;
39
- images?: Array<DataContent | URL>;
40
29
  autoFocus?: boolean;
41
30
  theme?: string | null;
42
31
  setTheme: (theme: string | null) => void;
@@ -52,7 +41,6 @@ export const ChatMentionInput = (props: IChatMentionInputProps) => {
52
41
  const { onSend, disabled = false } = props;
53
42
 
54
43
  const [value, setValue] = useState(props.value || '');
55
- const [images, setImages] = useState(props.images || []);
56
44
  const aiChatService = useInjectable<ChatInternalService>(IChatInternalService);
57
45
  const commandService = useInjectable<CommandService>(CommandService);
58
46
  const searchService = useInjectable<IFileSearchService>(FileSearchServicePath);
@@ -60,8 +48,7 @@ export const ChatMentionInput = (props: IChatMentionInputProps) => {
60
48
  const workspaceService = useInjectable<IWorkspaceService>(IWorkspaceService);
61
49
  const editorService = useInjectable<WorkbenchEditorService>(WorkbenchEditorService);
62
50
  const labelService = useInjectable<LabelService>(LabelService);
63
- const messageService = useInjectable<IMessageService>(IMessageService);
64
- const chatFeatureRegistry = useInjectable<ChatFeatureRegistry>(ChatFeatureRegistryToken);
51
+
65
52
  const handleShowMCPConfig = React.useCallback(() => {
66
53
  commandService.executeCommand(OPEN_MCP_CONFIG_COMMAND.id);
67
54
  }, [commandService]);
@@ -252,24 +239,6 @@ export const ChatMentionInput = (props: IChatMentionInputProps) => {
252
239
  onClick: handleShowMCPConfig,
253
240
  position: FooterButtonPosition.LEFT,
254
241
  },
255
- {
256
- id: 'upload-image',
257
- iconClass: 'codicon codicon-file-media',
258
- title: 'Upload Image',
259
- onClick: () => {
260
- const input = document.createElement('input');
261
- input.type = 'file';
262
- input.accept = 'image/*';
263
- input.onchange = (e) => {
264
- const file = (e.target as HTMLInputElement).files?.[0];
265
- if (file) {
266
- handleImageUpload(file);
267
- }
268
- };
269
- input.click();
270
- },
271
- position: FooterButtonPosition.LEFT,
272
- },
273
242
  ],
274
243
  showModelSelector: true,
275
244
  }),
@@ -285,47 +254,13 @@ export const ChatMentionInput = (props: IChatMentionInputProps) => {
285
254
  if (disabled) {
286
255
  return;
287
256
  }
288
- onSend(
289
- content,
290
- images.map((image) => image.toString()),
291
- undefined,
292
- undefined,
293
- option,
294
- );
295
- setImages(props.images || []);
296
- },
297
- [onSend, images, disabled],
298
- );
299
-
300
- const handleImageUpload = useCallback(
301
- async (file: File) => {
302
- const allowedTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp', 'image/gif'];
303
- if (!allowedTypes.includes(file.type)) {
304
- messageService.error('Only JPG, PNG, WebP and GIF images are supported');
305
- return;
306
- }
307
-
308
- const imageUploadProvider = chatFeatureRegistry.getImageUploadProvider();
309
- if (!imageUploadProvider) {
310
- messageService.error('No image upload provider found');
311
- return;
312
- }
313
- const data = await imageUploadProvider.imageUpload(file);
314
- setImages([...images, data]);
257
+ onSend(content, undefined, undefined, option);
315
258
  },
316
- [images],
317
- );
318
-
319
- const handleDeleteImage = useCallback(
320
- (index: number) => {
321
- setImages(images.filter((_, i) => i !== index));
322
- },
323
- [images],
259
+ [onSend, editorService, disabled],
324
260
  );
325
261
 
326
262
  return (
327
263
  <div className={styles.chat_input_container}>
328
- {images.length > 0 && <ImagePreviewer images={images} onDelete={handleDeleteImage} />}
329
264
  <MentionInput
330
265
  mentionItems={defaultMenuItems}
331
266
  onSend={handleSend}
@@ -335,29 +270,7 @@ export const ChatMentionInput = (props: IChatMentionInputProps) => {
335
270
  workspaceService={workspaceService}
336
271
  placeholder={localize('aiNative.chat.input.placeholder.default')}
337
272
  footerConfig={defaultMentionInputFooterOptions}
338
- onImageUpload={handleImageUpload}
339
273
  />
340
274
  </div>
341
275
  );
342
276
  };
343
-
344
- const ImagePreviewer = ({
345
- images,
346
- onDelete,
347
- }: {
348
- images: Array<DataContent | URL>;
349
- onDelete: (index: number) => void;
350
- }) => (
351
- <div>
352
- <div className={styles.thumbnail_container}>
353
- {images.map((image, index) => (
354
- <div key={index} className={styles.thumbnail}>
355
- <Image src={image.toString()} />
356
- <button onClick={() => onDelete(index)} className={styles.delete_button}>
357
- <Icon iconClass='codicon codicon-close' />
358
- </button>
359
- </div>
360
- ))}
361
- </div>
362
- </div>
363
- );
@@ -601,52 +601,3 @@
601
601
  vertical-align: middle;
602
602
  font-size: 12px;
603
603
  }
604
-
605
- .thumbnail_container {
606
- display: flex;
607
- gap: 4px;
608
- padding: 4px 12px;
609
- .thumbnail {
610
- width: 36px;
611
- height: 36px;
612
- border-radius: 4px;
613
- position: relative;
614
- box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.3);
615
- padding: 2px;
616
- display: inline-flex;
617
- align-items: center;
618
- img {
619
- width: 100%;
620
- height: 100%;
621
- object-fit: cover;
622
- }
623
- }
624
- .delete_button {
625
- position: absolute;
626
- top: -5px;
627
- right: -5px;
628
- font-size: 12px;
629
- padding: 2px;
630
- border: 0;
631
- border-radius: 50%;
632
- transition: transform 0.2s ease-in-out;
633
- width: 16px;
634
- height: 16px;
635
- display: flex;
636
- justify-content: center;
637
- align-items: center;
638
- background-color: var(--badge-background);
639
- &:hover {
640
- cursor: pointer;
641
- transform: scale(1.2);
642
- }
643
- :global(.codicon) {
644
- font-size: 12px;
645
- color: var(--badge-foreground);
646
- }
647
- }
648
- }
649
-
650
- .image_wrapper {
651
- display: inline-block;
652
- }
@@ -50,7 +50,6 @@
50
50
  display: flex;
51
51
  align-items: center;
52
52
  cursor: pointer;
53
- text-wrap: nowrap;
54
53
  white-space: nowrap;
55
54
  box-sizing: border-box;
56
55
 
@@ -18,7 +18,6 @@ export const MentionInput: React.FC<MentionInputProps> = ({
18
18
  loading = false,
19
19
  mentionKeyword = MENTION_KEYWORD,
20
20
  onSelectionChange,
21
- onImageUpload,
22
21
  labelService,
23
22
  workspaceService,
24
23
  placeholder = 'Ask anything, @ to mention',
@@ -276,21 +275,6 @@ export const MentionInput: React.FC<MentionInputProps> = ({
276
275
  }
277
276
  };
278
277
 
279
- // 处理图片粘贴事件
280
- const handlePaste = (e: React.ClipboardEvent<HTMLDivElement>) => {
281
- const items = e.clipboardData.items;
282
- // eslint-disable-next-line @typescript-eslint/prefer-for-of
283
- for (let i = 0; i < items.length; i++) {
284
- if (items[i].kind === 'file' && items[i].type.startsWith('image/')) {
285
- const file = items[i].getAsFile();
286
- if (file && onImageUpload) {
287
- e.preventDefault();
288
- onImageUpload(file);
289
- }
290
- }
291
- }
292
- };
293
-
294
278
  // 处理键盘事件
295
279
  const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {
296
280
  // 如果按下ESC键且提及面板处于活动状态或内联搜索处于活动状态
@@ -334,14 +318,74 @@ export const MentionInput: React.FC<MentionInputProps> = ({
334
318
  inlineSearchStartPos: null,
335
319
  loading: false,
336
320
  });
321
+ }
322
+
323
+ // 处理上下方向键导航历史记录
324
+ if ((e.key === 'ArrowUp' || e.key === 'ArrowDown') && !e.shiftKey && !e.ctrlKey && !e.metaKey && !e.altKey) {
325
+ // 只有在非提及面板激活状态下才处理历史导航
326
+ if (!mentionState.active && !mentionState.inlineSearchActive && editorRef.current && history.length > 0) {
327
+ const currentContent = editorRef.current.innerHTML;
328
+
329
+ // 检查是否应该触发历史导航
330
+ const shouldTriggerHistory =
331
+ // 当前内容为空
332
+ !currentContent ||
333
+ currentContent === '<br>' ||
334
+ // 或者当前内容与历史记录中的某一项匹配(正在浏览历史)
335
+ (isNavigatingHistory && historyIndex >= 0 && history[history.length - 1 - historyIndex] === currentContent);
336
+
337
+ if (shouldTriggerHistory) {
338
+ e.preventDefault();
339
+
340
+ // 如果是第一次按上下键,保存当前输入
341
+ if (!isNavigatingHistory) {
342
+ setCurrentInput(currentContent);
343
+ setIsNavigatingHistory(true);
344
+ }
345
+
346
+ // 计算新的历史索引
347
+ let newIndex = historyIndex;
348
+ if (e.key === 'ArrowUp') {
349
+ // 向上导航到较早的历史记录
350
+ newIndex = Math.min(history.length - 1, historyIndex + 1);
351
+ } else {
352
+ // 向下导航到较新的历史记录
353
+ newIndex = Math.max(-1, historyIndex - 1);
354
+ }
355
+
356
+ setHistoryIndex(newIndex);
337
357
 
338
- // 不要阻止默认行为,让 @ 正常输入到编辑器中
358
+ // 更新编辑器内容
359
+ if (newIndex === -1) {
360
+ // 恢复到当前输入
361
+ editorRef.current.innerHTML = currentInput;
362
+ } else {
363
+ // 显示历史记录
364
+ editorRef.current.innerHTML = history[history.length - 1 - newIndex];
365
+ }
366
+
367
+ // 将光标移到末尾
368
+ const range = document.createRange();
369
+ range.selectNodeContents(editorRef.current);
370
+ range.collapse(false);
371
+ const selection = window.getSelection();
372
+ if (selection) {
373
+ selection.removeAllRanges();
374
+ selection.addRange(range);
375
+ }
376
+
377
+ return;
378
+ }
379
+ }
380
+ } else if (isNavigatingHistory && e.key !== 'ArrowUp' && e.key !== 'ArrowDown') {
381
+ // 如果用户在浏览历史记录后开始输入其他内容,退出历史导航模式
382
+ setIsNavigatingHistory(false);
383
+ setHistoryIndex(-1);
339
384
  }
340
385
 
341
386
  // 添加对 Enter 键的处理,只有在按下 Shift+Enter 时才允许换行
342
387
  if (e.key === 'Enter') {
343
388
  // 检查是否是输入法的回车键
344
- // isComposing 属性表示是否正在进行输入法组合输入
345
389
  if (e.nativeEvent.isComposing) {
346
390
  return; // 如果是输入法组合输入过程中的回车,不做任何处理
347
391
  }
@@ -355,57 +399,6 @@ export const MentionInput: React.FC<MentionInputProps> = ({
355
399
  }
356
400
  }
357
401
 
358
- // 处理上下方向键导航历史记录
359
- if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
360
- // 只有在非提及面板激活状态下才处理历史导航
361
- if (!mentionState.active && !mentionState.inlineSearchActive && editorRef.current) {
362
- e.preventDefault();
363
-
364
- // 如果是第一次按上下键,保存当前输入
365
- if (!isNavigatingHistory) {
366
- setCurrentInput(editorRef.current.innerHTML);
367
- setIsNavigatingHistory(true);
368
- }
369
-
370
- // 计算新的历史索引
371
- let newIndex = historyIndex;
372
- if (e.key === 'ArrowUp') {
373
- // 向上导航到较早的历史记录
374
- newIndex = Math.min(history.length - 1, historyIndex + 1);
375
- } else {
376
- // 向下导航到较新的历史记录
377
- newIndex = Math.max(-1, historyIndex - 1);
378
- }
379
-
380
- setHistoryIndex(newIndex);
381
-
382
- // 更新编辑器内容
383
- if (newIndex === -1) {
384
- // 恢复到当前输入
385
- editorRef.current.innerHTML = currentInput;
386
- } else {
387
- // 显示历史记录
388
- editorRef.current.innerHTML = history[history.length - 1 - newIndex];
389
- }
390
-
391
- // 将光标移到末尾
392
- const range = document.createRange();
393
- range.selectNodeContents(editorRef.current);
394
- range.collapse(false);
395
- const selection = window.getSelection();
396
- if (selection) {
397
- selection.removeAllRanges();
398
- selection.addRange(range);
399
- }
400
-
401
- return;
402
- }
403
- } else if (isNavigatingHistory && e.key !== 'ArrowUp' && e.key !== 'ArrowDown') {
404
- // 如果用户在浏览历史记录后开始输入,退出历史导航模式
405
- setIsNavigatingHistory(false);
406
- setHistoryIndex(-1);
407
- }
408
-
409
402
  // 如果提及面板未激活,不处理其他键盘事件
410
403
  if (!mentionState.active) {
411
404
  return;
@@ -420,8 +413,6 @@ export const MentionInput: React.FC<MentionInputProps> = ({
420
413
  filteredItems = filteredItems.filter((item) => item.text.toLowerCase().includes(searchText));
421
414
  }
422
415
 
423
- // 二级菜单过滤已经在 getCurrentItems 中处理
424
-
425
416
  if (filteredItems.length === 0) {
426
417
  return;
427
418
  }
@@ -447,14 +438,6 @@ export const MentionInput: React.FC<MentionInputProps> = ({
447
438
  e.preventDefault();
448
439
  }
449
440
  }
450
-
451
- // 处理 Backspace 键,检查是否需要清空编辑器
452
- if (e.key === 'Backspace' && editorRef.current) {
453
- const content = editorRef.current.innerHTML;
454
- if (content === '<br>' || content === '<br/>') {
455
- editorRef.current.innerHTML = '';
456
- }
457
- }
458
441
  };
459
442
 
460
443
  // 添加对输入法事件的处理
@@ -463,6 +446,71 @@ export const MentionInput: React.FC<MentionInputProps> = ({
463
446
  // 这里可以添加额外的逻辑,如果需要的话
464
447
  };
465
448
 
449
+ // 添加粘贴事件处理
450
+ const handlePaste = (e: React.ClipboardEvent<HTMLDivElement>) => {
451
+ // 阻止默认粘贴行为
452
+ e.preventDefault();
453
+
454
+ // 获取剪贴板中的纯文本内容
455
+ const text = e.clipboardData.getData('text/plain');
456
+
457
+ // 处理文本,保留换行和缩进
458
+ const processedText = text
459
+ // 将制表符转换为4个空格
460
+ .replace(/\t/g, ' ')
461
+ // 将连续的换行符转换为单个换行
462
+ .replace(/\n\s*\n/g, '\n\n')
463
+ // 移除行尾空格
464
+ .replace(/[ \t]+$/gm, '');
465
+
466
+ const selection = window.getSelection();
467
+ if (!selection || !selection.rangeCount) {
468
+ return;
469
+ }
470
+
471
+ const range = selection.getRangeAt(0);
472
+ range.deleteContents();
473
+
474
+ // 将处理后的文本按行分割
475
+ const lines = processedText.split('\n');
476
+ const fragment = document.createDocumentFragment();
477
+
478
+ lines.forEach((line, index) => {
479
+ // 处理行首空格,将每个空格转换为 &nbsp;
480
+ const processedLine = line.replace(/^[ ]+/g, (match) => {
481
+ const span = document.createElement('span');
482
+ span.innerHTML = '\u00A0'.repeat(match.length);
483
+ return span.innerHTML;
484
+ });
485
+
486
+ // 创建一个临时容器来保持 HTML 内容
487
+ const container = document.createElement('span');
488
+ container.innerHTML = processedLine;
489
+
490
+ // 将容器的内容添加到文档片段
491
+ while (container.firstChild) {
492
+ fragment.appendChild(container.firstChild);
493
+ }
494
+
495
+ // 如果不是最后一行,添加换行符
496
+ if (index < lines.length - 1) {
497
+ fragment.appendChild(document.createElement('br'));
498
+ }
499
+ });
500
+
501
+ // 插入处理后的内容
502
+ range.insertNode(fragment);
503
+
504
+ // 将光标移动到插入内容的末尾
505
+ range.setStartAfter(fragment);
506
+ range.setEndAfter(fragment);
507
+ selection.removeAllRanges();
508
+ selection.addRange(range);
509
+
510
+ // 触发 input 事件以更新状态
511
+ handleInput();
512
+ };
513
+
466
514
  // 初始化编辑器
467
515
  React.useEffect(() => {
468
516
  if (editorRef.current) {
@@ -883,7 +931,7 @@ export const MentionInput: React.FC<MentionInputProps> = ({
883
931
  title={button.title}
884
932
  >
885
933
  <EnhanceIcon
886
- className={cls(button.icon ? getIcon(button.icon) : button.iconClass, styles[`${button.id}_logo`])}
934
+ className={cls(getIcon(button.icon), styles[`${button.id}_logo`])}
887
935
  tabIndex={0}
888
936
  role='button'
889
937
  ariaLabel={button.title}
@@ -917,8 +965,8 @@ export const MentionInput: React.FC<MentionInputProps> = ({
917
965
  contentEditable={true}
918
966
  onInput={handleInput}
919
967
  onKeyDown={handleKeyDown}
920
- onPaste={handlePaste}
921
968
  onCompositionEnd={handleCompositionEnd}
969
+ onPaste={handlePaste}
922
970
  />
923
971
  </div>
924
972
  <div className={styles.footer}>
@@ -55,8 +55,7 @@ export enum MentionType {
55
55
 
56
56
  interface FooterButton {
57
57
  id: string;
58
- icon?: string;
59
- iconClass?: string;
58
+ icon: string;
60
59
  title: string;
61
60
  onClick?: () => void;
62
61
  position: FooterButtonPosition;
@@ -76,7 +75,6 @@ export interface MentionInputProps {
76
75
  placeholder?: string;
77
76
  loading?: boolean;
78
77
  onSelectionChange?: (value: string) => void;
79
- onImageUpload?: (file: File) => void;
80
78
  footerConfig?: FooterConfig; // 新增配置项
81
79
  mentionKeyword?: string;
82
80
  labelService?: LabelService;
@@ -1,5 +1,3 @@
1
- import { DataContent } from 'ai';
2
-
3
1
  import { Autowired, Injectable } from '@opensumi/di';
4
2
  import { AppConfig } from '@opensumi/ide-core-browser/lib/react-providers/config-provider';
5
3
  import { WithEventBus } from '@opensumi/ide-core-common/lib/event-bus/event-decorator';
@@ -26,7 +26,21 @@ export const MCPConfigView: React.FC = () => {
26
26
  const [editingServer, setEditingServer] = React.useState<MCPServerFormData | undefined>();
27
27
  const [loadingServer, setLoadingServer] = React.useState<string | undefined>();
28
28
  const loadServers = useCallback(async () => {
29
- const allServers = await mcpServerProxyService.$getServers();
29
+ const userServers = preferenceService.get<MCPServerDescription[]>(AINativeSettingSectionsId.MCPServers, []);
30
+ const runningServers = await mcpServerProxyService.$getServers();
31
+ const builtinServer = runningServers.find((server) => server.name === BUILTIN_MCP_SERVER_NAME);
32
+ const allServers = userServers.map((server) => {
33
+ const runningServer = runningServers.find((s) => s.name === server.name);
34
+ return {
35
+ ...server,
36
+ name: server.name,
37
+ isStarted: runningServer?.isStarted,
38
+ tools: runningServer?.tools,
39
+ };
40
+ }) as MCPServer[];
41
+ if (builtinServer) {
42
+ allServers.unshift(builtinServer);
43
+ }
30
44
  setServers(allServers);
31
45
  }, [mcpServerProxyService]);
32
46
 
@@ -93,8 +107,8 @@ export const MCPConfigView: React.FC = () => {
93
107
  setLoadingServer(undefined);
94
108
  } catch (error) {
95
109
  const msg = error.message || error;
96
- logger.error(`Failed to ${start ? 'start' : 'stop'} server ${serverName}:`, error);
97
- messageService.error(error.message);
110
+ logger.error(`Failed to ${start ? 'start' : 'stop'} server ${serverName}:`, msg);
111
+ messageService.error(msg);
98
112
  setLoadingServer(undefined);
99
113
  }
100
114
  },
@@ -62,7 +62,7 @@ export class MsgHistoryManager extends Disposable {
62
62
  }
63
63
 
64
64
  public addUserMessage(
65
- message: Required<Pick<IExcludeMessage, 'agentId' | 'agentCommand' | 'content' | 'relationId' | 'images'>>,
65
+ message: Required<Pick<IExcludeMessage, 'agentId' | 'agentCommand' | 'content' | 'relationId'>>,
66
66
  ): string {
67
67
  return this.doAddMessage({
68
68
  ...message,
@@ -1,4 +1,3 @@
1
- import { DataContent } from 'ai';
2
1
  import React from 'react';
3
2
  import { ZodSchema } from 'zod';
4
3
 
@@ -130,7 +129,6 @@ export interface IChatSlashCommandHandler {
130
129
  }
131
130
 
132
131
  export interface IChatFeatureRegistry {
133
- registerImageUploadProvider(provider: IImageUploadProvider): void;
134
132
  registerWelcome(content: IChatWelcomeMessageContent | React.ReactNode, sampleQuestions?: ISampleQuestions[]): void;
135
133
  registerSlashCommand(command: IChatSlashCommandItem, handler: IChatSlashCommandHandler): void;
136
134
  }
@@ -142,14 +140,13 @@ export type ChatWelcomeRender = (props: {
142
140
  export type ChatAIRoleRender = (props: { content: string }) => React.ReactElement | React.JSX.Element;
143
141
  export type ChatUserRoleRender = (props: {
144
142
  content: string;
145
- images?: string[];
146
143
  agentId?: string;
147
144
  command?: string;
148
145
  }) => React.ReactElement | React.JSX.Element;
149
146
  export type ChatThinkingRender = (props: { thinkingText?: string }) => React.ReactElement | React.JSX.Element;
150
147
  export type ChatThinkingResultRender = (props: { thinkingResult?: string }) => React.ReactElement | React.JSX.Element;
151
148
  export type ChatInputRender = (props: {
152
- onSend: (value: string, images?: string[], agentId?: string, command?: string) => void;
149
+ onSend: (value: string, agentId?: string, command?: string) => void;
153
150
  onValueChange?: (value: string) => void;
154
151
  onExpand?: (value: boolean) => void;
155
152
  placeholder?: string;
@@ -292,10 +289,6 @@ export interface IProblemFixProviderRegistry {
292
289
  registerHoverFixProvider(handler: IHoverFixHandler): void;
293
290
  }
294
291
 
295
- export interface IImageUploadProvider {
296
- imageUpload(file: File): Promise<DataContent | URL>;
297
- }
298
-
299
292
  export const AINativeCoreContribution = Symbol('AINativeCoreContribution');
300
293
 
301
294
  export interface AINativeCoreContribution {
@@ -52,10 +52,6 @@ export interface IChatMessageStructure {
52
52
  * 用于 chat 面板展示
53
53
  */
54
54
  message: string;
55
- /**
56
- * 图片
57
- */
58
- images?: string[];
59
55
  /**
60
56
  * 实际调用的 prompt
61
57
  */
@@ -138,7 +134,14 @@ export interface ISumiMCPServerBackend {
138
134
  initBuiltinMCPServer(enabled: boolean): void;
139
135
  initExternalMCPServers(servers: MCPServerDescription[]): void;
140
136
  getAllMCPTools(): Promise<MCPTool[]>;
141
- getServers(): Promise<Array<{ name: string; isStarted: boolean; tools: MCPTool[] }>>;
137
+ getServers(): Promise<
138
+ Array<{
139
+ name: string;
140
+ isStarted: boolean;
141
+ type: string;
142
+ tools: MCPTool[];
143
+ }>
144
+ >;
142
145
  startServer(serverName: string): Promise<void>;
143
146
  stopServer(serverName: string): Promise<void>;
144
147
  addOrUpdateServer(description: MCPServerDescription): void;
@@ -204,7 +207,6 @@ export interface IChatAgentRequest {
204
207
  requestId: string;
205
208
  command?: string;
206
209
  message: string;
207
- images?: string[];
208
210
  regenerate?: boolean;
209
211
  }
210
212
 
@@ -242,7 +244,6 @@ export type IChatFollowup = IChatReplyFollowup | IChatResponseCommandFollowup;
242
244
 
243
245
  export interface IChatRequestMessage {
244
246
  prompt: string;
245
- images?: string[];
246
247
  agentId: string;
247
248
  command?: string;
248
249
  }
@@ -1,5 +1,3 @@
1
- import { DataContent } from 'ai';
2
-
3
1
  import { Event, URI } from '@opensumi/ide-core-common/lib/utils';
4
2
 
5
3
  export interface LLMContextService {