@opensumi/ide-ai-native 3.8.2-next-1741622293.0 → 3.8.3-next-1741661270.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.map +1 -1
  2. package/lib/browser/ai-core.contribution.js +20 -0
  3. package/lib/browser/ai-core.contribution.js.map +1 -1
  4. package/lib/browser/chat/chat-manager.service.d.ts +2 -1
  5. package/lib/browser/chat/chat-manager.service.d.ts.map +1 -1
  6. package/lib/browser/chat/chat-manager.service.js +26 -7
  7. package/lib/browser/chat/chat-manager.service.js.map +1 -1
  8. package/lib/browser/chat/chat-model.d.ts +3 -3
  9. package/lib/browser/chat/chat-model.d.ts.map +1 -1
  10. package/lib/browser/chat/chat-model.js +22 -9
  11. package/lib/browser/chat/chat-model.js.map +1 -1
  12. package/lib/browser/chat/chat-proxy.service.d.ts +1 -0
  13. package/lib/browser/chat/chat-proxy.service.d.ts.map +1 -1
  14. package/lib/browser/chat/chat-proxy.service.js +2 -0
  15. package/lib/browser/chat/chat-proxy.service.js.map +1 -1
  16. package/lib/browser/chat/chat.view.d.ts.map +1 -1
  17. package/lib/browser/chat/chat.view.js +61 -5
  18. package/lib/browser/chat/chat.view.js.map +1 -1
  19. package/lib/browser/components/ApplyStatus.d.ts +7 -0
  20. package/lib/browser/components/ApplyStatus.d.ts.map +1 -0
  21. package/lib/browser/components/ApplyStatus.js +32 -0
  22. package/lib/browser/components/ApplyStatus.js.map +1 -0
  23. package/lib/browser/components/ChangeList.d.ts +17 -0
  24. package/lib/browser/components/ChangeList.d.ts.map +1 -0
  25. package/lib/browser/components/ChangeList.js +72 -0
  26. package/lib/browser/components/ChangeList.js.map +1 -0
  27. package/lib/browser/components/ChatToolRender.d.ts.map +1 -1
  28. package/lib/browser/components/ChatToolRender.js +18 -12
  29. package/lib/browser/components/ChatToolRender.js.map +1 -1
  30. package/lib/browser/components/ChatToolRender.module.less +27 -15
  31. package/lib/browser/components/change-list.module.less +126 -0
  32. package/lib/browser/components/chat-history.module.less +1 -1
  33. package/lib/browser/components/components.module.less +14 -0
  34. package/lib/browser/contrib/inline-completions/prompt/matcher.js +2 -2
  35. package/lib/browser/contrib/inline-completions/prompt/similarSnippets.d.ts +1 -1
  36. package/lib/browser/contrib/inline-completions/prompt/similarSnippets.js +2 -2
  37. package/lib/browser/contrib/intelligent-completions/view/default.d.ts.map +1 -1
  38. package/lib/browser/contrib/intelligent-completions/view/default.js.map +1 -1
  39. package/lib/browser/index.d.ts.map +1 -1
  40. package/lib/browser/index.js +4 -4
  41. package/lib/browser/index.js.map +1 -1
  42. package/lib/browser/mcp/base-apply.service.d.ts +14 -6
  43. package/lib/browser/mcp/base-apply.service.d.ts.map +1 -1
  44. package/lib/browser/mcp/base-apply.service.js +80 -52
  45. package/lib/browser/mcp/base-apply.service.js.map +1 -1
  46. package/lib/browser/mcp/config/components/mcp-config.view.d.ts.map +1 -1
  47. package/lib/browser/mcp/config/components/mcp-config.view.js +12 -8
  48. package/lib/browser/mcp/config/components/mcp-config.view.js.map +1 -1
  49. package/lib/browser/mcp/config/mcp-config.contribution.js.map +1 -1
  50. package/lib/browser/mcp/mcp-server.feature.registry.js +1 -1
  51. package/lib/browser/mcp/mcp-server.feature.registry.js.map +1 -1
  52. package/lib/browser/mcp/tools/components/EditFile.js +3 -24
  53. package/lib/browser/mcp/tools/components/EditFile.js.map +1 -1
  54. package/lib/browser/mcp/tools/components/ExpandableFileList.js +3 -2
  55. package/lib/browser/mcp/tools/components/ExpandableFileList.js.map +1 -1
  56. package/lib/browser/mcp/tools/createNewFileWithText.d.ts.map +1 -1
  57. package/lib/browser/mcp/tools/createNewFileWithText.js +1 -0
  58. package/lib/browser/mcp/tools/createNewFileWithText.js.map +1 -1
  59. package/lib/browser/mcp/tools/editFile.d.ts.map +1 -1
  60. package/lib/browser/mcp/tools/editFile.js +1 -0
  61. package/lib/browser/mcp/tools/editFile.js.map +1 -1
  62. package/lib/browser/mcp/tools/fileSearch.d.ts.map +1 -1
  63. package/lib/browser/mcp/tools/fileSearch.js +1 -0
  64. package/lib/browser/mcp/tools/fileSearch.js.map +1 -1
  65. package/lib/browser/mcp/tools/getDiagnosticsByPath.d.ts.map +1 -1
  66. package/lib/browser/mcp/tools/getDiagnosticsByPath.js +2 -1
  67. package/lib/browser/mcp/tools/getDiagnosticsByPath.js.map +1 -1
  68. package/lib/browser/mcp/tools/getOpenEditorFileDiagnostics.d.ts.map +1 -1
  69. package/lib/browser/mcp/tools/getOpenEditorFileDiagnostics.js +2 -0
  70. package/lib/browser/mcp/tools/getOpenEditorFileDiagnostics.js.map +1 -1
  71. package/lib/browser/mcp/tools/grepSearch.d.ts.map +1 -1
  72. package/lib/browser/mcp/tools/grepSearch.js +1 -0
  73. package/lib/browser/mcp/tools/grepSearch.js.map +1 -1
  74. package/lib/browser/mcp/tools/listDir.d.ts.map +1 -1
  75. package/lib/browser/mcp/tools/listDir.js +1 -0
  76. package/lib/browser/mcp/tools/listDir.js.map +1 -1
  77. package/lib/browser/mcp/tools/readFile.d.ts.map +1 -1
  78. package/lib/browser/mcp/tools/readFile.js +1 -0
  79. package/lib/browser/mcp/tools/readFile.js.map +1 -1
  80. package/lib/browser/mcp/tools/runTerminalCmd.d.ts.map +1 -1
  81. package/lib/browser/mcp/tools/runTerminalCmd.js +1 -0
  82. package/lib/browser/mcp/tools/runTerminalCmd.js.map +1 -1
  83. package/lib/browser/model/msg-history-manager.d.ts +0 -2
  84. package/lib/browser/model/msg-history-manager.d.ts.map +1 -1
  85. package/lib/browser/model/msg-history-manager.js +1 -6
  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 +8 -0
  89. package/lib/browser/preferences/schema.js.map +1 -1
  90. package/lib/browser/types.d.ts +1 -0
  91. package/lib/browser/types.d.ts.map +1 -1
  92. package/lib/browser/widget/inline-diff/inline-diff-manager.d.ts.map +1 -1
  93. package/lib/browser/widget/inline-diff/inline-diff-manager.js +2 -2
  94. package/lib/browser/widget/inline-diff/inline-diff-manager.js.map +1 -1
  95. package/lib/browser/widget/inline-diff/inline-diff.controller.d.ts +1 -1
  96. package/lib/browser/widget/inline-diff/inline-diff.controller.d.ts.map +1 -1
  97. package/lib/browser/widget/inline-diff/inline-diff.controller.js.map +1 -1
  98. package/lib/browser/widget/inline-diff/inline-diff.service.d.ts +3 -2
  99. package/lib/browser/widget/inline-diff/inline-diff.service.d.ts.map +1 -1
  100. package/lib/browser/widget/inline-diff/inline-diff.service.js.map +1 -1
  101. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts +1 -1
  102. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts.map +1 -1
  103. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js.map +1 -1
  104. package/lib/browser/widget/inline-stream-diff/live-preview.component.d.ts +0 -33
  105. package/lib/browser/widget/inline-stream-diff/live-preview.component.d.ts.map +1 -1
  106. package/lib/browser/widget/inline-stream-diff/live-preview.component.js +1 -6
  107. package/lib/browser/widget/inline-stream-diff/live-preview.component.js.map +1 -1
  108. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.d.ts.map +1 -1
  109. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.js +15 -14
  110. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.js.map +1 -1
  111. package/lib/common/index.d.ts +7 -2
  112. package/lib/common/index.d.ts.map +1 -1
  113. package/lib/common/index.js +3 -2
  114. package/lib/common/index.js.map +1 -1
  115. package/lib/common/prompts/context-prompt-provider.d.ts.map +1 -1
  116. package/lib/common/prompts/context-prompt-provider.js +2 -4
  117. package/lib/common/prompts/context-prompt-provider.js.map +1 -1
  118. package/lib/common/types.d.ts +33 -0
  119. package/lib/common/types.d.ts.map +1 -1
  120. package/lib/common/types.js +6 -1
  121. package/lib/common/types.js.map +1 -1
  122. package/package.json +23 -23
  123. package/src/browser/ai-core.contribution.ts +28 -0
  124. package/src/browser/chat/chat-manager.service.ts +53 -31
  125. package/src/browser/chat/chat-model.ts +22 -8
  126. package/src/browser/chat/chat-proxy.service.ts +2 -0
  127. package/src/browser/chat/chat.view.tsx +80 -9
  128. package/src/browser/components/ApplyStatus.tsx +44 -0
  129. package/src/browser/components/ChangeList.tsx +131 -0
  130. package/src/browser/components/ChatToolRender.module.less +27 -15
  131. package/src/browser/components/ChatToolRender.tsx +14 -12
  132. package/src/browser/components/change-list.module.less +126 -0
  133. package/src/browser/components/chat-history.module.less +1 -1
  134. package/src/browser/components/components.module.less +14 -0
  135. package/src/browser/contrib/inline-completions/prompt/matcher.ts +2 -2
  136. package/src/browser/contrib/inline-completions/prompt/similarSnippets.ts +2 -2
  137. package/src/browser/contrib/intelligent-completions/view/default.ts +1 -0
  138. package/src/browser/index.ts +5 -4
  139. package/src/browser/mcp/base-apply.service.ts +84 -62
  140. package/src/browser/mcp/config/components/mcp-config.view.tsx +4 -0
  141. package/src/browser/mcp/config/mcp-config.contribution.ts +1 -1
  142. package/src/browser/mcp/mcp-server.feature.registry.ts +1 -1
  143. package/src/browser/mcp/tools/components/EditFile.tsx +3 -37
  144. package/src/browser/mcp/tools/components/ExpandableFileList.tsx +3 -1
  145. package/src/browser/mcp/tools/createNewFileWithText.ts +1 -0
  146. package/src/browser/mcp/tools/editFile.ts +1 -0
  147. package/src/browser/mcp/tools/fileSearch.ts +1 -0
  148. package/src/browser/mcp/tools/getDiagnosticsByPath.ts +2 -1
  149. package/src/browser/mcp/tools/getOpenEditorFileDiagnostics.ts +2 -0
  150. package/src/browser/mcp/tools/grepSearch.ts +1 -0
  151. package/src/browser/mcp/tools/listDir.ts +1 -0
  152. package/src/browser/mcp/tools/readFile.ts +1 -0
  153. package/src/browser/mcp/tools/runTerminalCmd.ts +1 -0
  154. package/src/browser/model/msg-history-manager.ts +1 -8
  155. package/src/browser/preferences/schema.ts +8 -0
  156. package/src/browser/types.ts +1 -0
  157. package/src/browser/widget/inline-diff/inline-diff-manager.tsx +3 -2
  158. package/src/browser/widget/inline-diff/inline-diff.controller.ts +2 -1
  159. package/src/browser/widget/inline-diff/inline-diff.service.ts +3 -2
  160. package/src/browser/widget/inline-stream-diff/inline-stream-diff.handler.tsx +4 -4
  161. package/src/browser/widget/inline-stream-diff/live-preview.component.tsx +0 -34
  162. package/src/browser/widget/inline-stream-diff/live-preview.decoration.tsx +8 -9
  163. package/src/common/index.ts +9 -2
  164. package/src/common/prompts/context-prompt-provider.ts +2 -6
  165. package/src/common/types.ts +35 -0
@@ -5,6 +5,7 @@ import { useInjectable } from '@opensumi/ide-core-browser';
5
5
  import { Icon } from '@opensumi/ide-core-browser/lib/components';
6
6
  import { Loading } from '@opensumi/ide-core-browser/lib/components/ai-native';
7
7
  import { IChatToolContent, uuid } from '@opensumi/ide-core-common';
8
+ import { localize } from '@opensumi/ide-core-common/lib/localize';
8
9
 
9
10
  import { IMCPServerRegistry, TokenMCPServerRegistry } from '../types';
10
11
 
@@ -64,28 +65,29 @@ export const ChatToolRender = (props: { value: IChatToolContent['content']; mess
64
65
  toolCallId={value.id}
65
66
  />
66
67
  ) : (
67
- <div className={styles['chat-tool-render']}>
68
- <div className={styles['tool-header']} onClick={toggleExpand}>
69
- <div className={styles['tool-name']}>
70
- <Icon iconClass={`codicon codicon-triangle-${isExpanded ? 'down' : 'right'}`} />
71
- {label}
68
+ <div className={styles.chat_tool_render}>
69
+ <div className={styles.tool_header} onClick={toggleExpand}>
70
+ <div className={styles.tool_name}>
71
+ <Icon iconClass={`codicon codicon-chevron-${isExpanded ? 'down' : 'right'}`} />
72
+ <Icon size='small' iconClass={cls('codicon codicon-tools', styles.tool_icon)} />
73
+ <span className={styles.tool_label}>{label}</span>
72
74
  </div>
73
75
  {value.state && (
74
- <div className={styles['tool-state']}>
75
- <span className={styles['state-icon']}>{stateInfo.icon}</span>
76
+ <div className={styles.tool_state}>
77
+ <span className={styles.state_icon}>{stateInfo.icon}</span>
76
78
  </div>
77
79
  )}
78
80
  </div>
79
- <div className={cls(styles['tool-content'], { [styles.expanded]: isExpanded })}>
81
+ <div className={cls(styles.tool_content, { [styles.expanded]: isExpanded })}>
80
82
  {value?.function?.arguments && (
81
- <div className={styles['tool-arguments']}>
82
- <div className={styles['section-label']}>Arguments</div>
83
+ <div className={styles.tool_arguments}>
84
+ <div className={styles.section_label}>{localize('ai.native.mcp.tool.arguments')}:</div>
83
85
  <CodeEditorWithHighlight input={value?.function?.arguments} language={'json'} relationId={uuid(4)} />
84
86
  </div>
85
87
  )}
86
88
  {value?.result && (
87
- <div className={styles['tool-result']}>
88
- <div className={styles['section-label']}>Result</div>
89
+ <div className={styles.tool_result}>
90
+ <div className={styles.section_label}>{localize('ai.native.mcp.tool.results')}:</div>
89
91
  <CodeEditorWithHighlight input={value.result} language={'json'} relationId={uuid(4)} />
90
92
  </div>
91
93
  )}
@@ -0,0 +1,126 @@
1
+ .container {
2
+ margin: 0 12px;
3
+ background: var(--design-chatInput-background);
4
+ border-radius: 9px 9px 0 0;
5
+ border: 1px solid var(--kt-input-border);
6
+ border-bottom: none;
7
+ overflow: hidden;
8
+ padding-bottom: 6px;
9
+ }
10
+
11
+ .header {
12
+ display: flex;
13
+ align-items: center;
14
+ justify-content: space-between;
15
+ padding: 8px 12px 2px 12px;
16
+ background-color: transparent;
17
+ cursor: pointer;
18
+ user-select: none;
19
+ font-size: 12px;
20
+ color: var(--descriptionForeground);
21
+ }
22
+
23
+ .title:hover {
24
+ color: var(--design-text-highlightForeground);
25
+ .toggleButton :global(.kt-icon) {
26
+ color: var(--design-text-highlightForeground);
27
+ transition: color 0.2s ease-in-out;
28
+ }
29
+ }
30
+
31
+ .toggleButton {
32
+ background: none;
33
+ border: none;
34
+ cursor: pointer;
35
+ padding: 0;
36
+ width: 16px;
37
+ height: 16px;
38
+ display: flex;
39
+ align-items: center;
40
+ justify-content: center;
41
+ font-size: 12px;
42
+ }
43
+
44
+ .title {
45
+ gap: 6px;
46
+ transition: color 0.2s ease-in-out;
47
+ display: flex;
48
+ }
49
+
50
+ .fileList {
51
+ list-style: none;
52
+ margin: 0;
53
+ padding: 0 12px;
54
+ }
55
+
56
+ .fileItem {
57
+ display: flex;
58
+ align-items: center;
59
+ padding: 4px 0;
60
+ cursor: pointer;
61
+ border: none;
62
+ font-size: 13px;
63
+ color: var(--descriptionForeground);
64
+ }
65
+
66
+ .fileItem:hover {
67
+ background-color: var(--design-block-hoverBackground);
68
+ }
69
+
70
+ .fileIcon {
71
+ margin-right: 6px;
72
+ width: 16px;
73
+ height: 16px;
74
+ display: flex;
75
+ align-items: center;
76
+ justify-content: center;
77
+ }
78
+
79
+ .fileInfo {
80
+ flex: 1;
81
+ display: flex;
82
+ justify-content: space-between;
83
+ align-items: center;
84
+ overflow: hidden;
85
+ :global(.kt-popover-trigger) {
86
+ margin-left: 8px;
87
+ }
88
+ :global(.codicon) {
89
+ font-size: 12px !important;
90
+ position: relative;
91
+ top: 1px;
92
+ }
93
+ }
94
+
95
+ .filePath {
96
+ font-size: 12px;
97
+ margin: 0;
98
+ white-space: nowrap;
99
+ overflow: hidden;
100
+ text-overflow: ellipsis;
101
+ }
102
+
103
+ .fileStats {
104
+ font-size: 12px;
105
+ display: flex;
106
+ align-items: center;
107
+ gap: 4px;
108
+ }
109
+
110
+ .additions {
111
+ color: #52c41a;
112
+ }
113
+
114
+ .deletions {
115
+ color: var(--debugConsole-errorForeground);
116
+ }
117
+
118
+ .noChange {
119
+ color: #6a737d;
120
+ font-style: italic;
121
+ white-space: nowrap;
122
+ }
123
+
124
+ .collapsed {
125
+ display: none;
126
+ }
@@ -78,7 +78,7 @@
78
78
  .dm-chat-history-list {
79
79
  overflow: auto;
80
80
  max-height: 400px;
81
- max-width: 400px;
81
+ width: 300px;
82
82
  margin-top: 4px;
83
83
  font-size: 13px;
84
84
  }
@@ -527,3 +527,17 @@
527
527
  align-items: center;
528
528
  }
529
529
  }
530
+
531
+ .status {
532
+ :global {
533
+ .codicon-pass {
534
+ color: #52c41a;
535
+ }
536
+ .codicon-error {
537
+ color: var(--debugConsole-errorForeground);
538
+ }
539
+ .codicon-circle-slash {
540
+ color: var(--input-placeholderForeground);
541
+ }
542
+ }
543
+ }
@@ -244,8 +244,8 @@ export abstract class WindowedMatcher {
244
244
  tokens.slice(startLine, endLine).forEach((token) => token.forEach((word) => size.add(word)));
245
245
  cache.push(size);
246
246
  }
247
- const target = cache[index];
248
- const score = this.similarityScore(target, this.referenceTokens);
247
+ const traget = cache[index];
248
+ const score = this.similarityScore(traget, this.referenceTokens);
249
249
  snippets.push({
250
250
  score,
251
251
  startLine,
@@ -15,9 +15,9 @@ import {
15
15
  import { MAX_NEIGHBOR_AGGREGATE_LENGTH } from './const';
16
16
  import { FixedWindowSizeJaccardMatcher } from './jaccardMatcher';
17
17
 
18
- export const getOpenedTabFileList = (documents: IEditorDocumentModel[]) => {
18
+ export const getOpenedTabFileList = (docuemnts: IEditorDocumentModel[]) => {
19
19
  // 过滤超大文档
20
- const recentFiles = documents.filter((document) => isDocumentValid(document));
20
+ const recentFiles = docuemnts.filter((document) => isDocumentValid(document));
21
21
  return recentFiles;
22
22
  };
23
23
 
@@ -29,6 +29,7 @@ import {
29
29
 
30
30
  import { CodeEditsResultValue, ICodeEdit, ICodeEditsResult } from '../index';
31
31
 
32
+
32
33
  import { BaseCodeEditsView } from './base';
33
34
 
34
35
  /**
@@ -25,6 +25,7 @@ import {
25
25
  IChatAgentService,
26
26
  IChatInternalService,
27
27
  IChatManagerService,
28
+ InlineDiffServiceToken,
28
29
  SumiMCPServerProxyServicePath,
29
30
  TokenMCPServerProxyService,
30
31
  } from '../common';
@@ -193,14 +194,14 @@ export class AINativeModule extends BrowserModule {
193
194
  token: IAIInlineCompletionsProvider,
194
195
  useClass: AIInlineCompletionsProvider,
195
196
  },
196
- {
197
- token: InlineDiffService,
198
- useClass: InlineDiffService,
199
- },
200
197
  {
201
198
  token: ChatAgentPromptProvider,
202
199
  useClass: DefaultChatAgentPromptProvider,
203
200
  },
201
+ {
202
+ token: InlineDiffServiceToken,
203
+ useClass: InlineDiffService,
204
+ },
204
205
  {
205
206
  token: BaseApplyService,
206
207
  useClass: ApplyService,
@@ -26,17 +26,13 @@ import { Deferred, DisposableMap, Emitter, IDisposable, URI, path } from '@opens
26
26
  import { SumiReadableStream } from '@opensumi/ide-utils/lib/stream';
27
27
  import { EditOperation } from '@opensumi/monaco-editor-core/esm/vs/editor/common/core/editOperation';
28
28
 
29
- import { IChatInternalService } from '../../common';
29
+ import { IChatInternalService, IInlineDiffService, InlineDiffServiceToken } from '../../common';
30
30
  import { CodeBlockData, CodeBlockStatus } from '../../common/types';
31
31
  import { ChatInternalService } from '../chat/chat.internal.service';
32
32
  import { InlineChatController } from '../widget/inline-chat/inline-chat-controller';
33
- import {
34
- BaseInlineDiffPreviewer,
35
- InlineDiffController,
36
- InlineDiffService,
37
- LiveInlineDiffPreviewer,
38
- } from '../widget/inline-diff';
39
- import { BaseInlineStreamDiffHandler } from '../widget/inline-stream-diff/inline-stream-diff.handler';
33
+ import { BaseInlineDiffPreviewer, InlineDiffController, LiveInlineDiffPreviewer } from '../widget/inline-diff';
34
+
35
+ import type { BaseInlineStreamDiffHandler } from '../widget/inline-stream-diff/inline-stream-diff.handler';
40
36
 
41
37
  export abstract class BaseApplyService extends WithEventBus {
42
38
  @Autowired(IChatInternalService)
@@ -48,8 +44,8 @@ export abstract class BaseApplyService extends WithEventBus {
48
44
  @Autowired(WorkbenchEditorService)
49
45
  protected readonly editorService: WorkbenchEditorService;
50
46
 
51
- @Autowired(InlineDiffService)
52
- private readonly inlineDiffService: InlineDiffService;
47
+ @Autowired(InlineDiffServiceToken)
48
+ private readonly inlineDiffService: IInlineDiffService;
53
49
 
54
50
  @Autowired(IMarkerService)
55
51
  private readonly markerService: IMarkerService;
@@ -155,7 +151,7 @@ export abstract class BaseApplyService extends WithEventBus {
155
151
  // 使用最后一个版本内容渲染 apply 内容
156
152
  if (filePendingApplies.length > 0 && filePendingApplies[0].updatedCode) {
157
153
  const editor = event.payload.group.codeEditor.monacoEditor;
158
- this.renderApplyResult(editor, filePendingApplies[0], filePendingApplies[0].updatedCode);
154
+ await this.renderApplyResult(editor, filePendingApplies[0], filePendingApplies[0].updatedCode);
159
155
  }
160
156
  }
161
157
 
@@ -183,9 +179,10 @@ export abstract class BaseApplyService extends WithEventBus {
183
179
  return sessionCodeBlocks.filter((block) => block.status === 'pending').map((block) => block.relativePath);
184
180
  }
185
181
 
186
- protected getSessionCodeBlocks(sessionId?: string) {
187
- sessionId = sessionId || this.chatInternalService.sessionModel.sessionId;
188
- const sessionModel = this.chatInternalService.getSession(sessionId);
182
+ getSessionCodeBlocks(sessionId?: string) {
183
+ const sessionModel = sessionId
184
+ ? this.chatInternalService.getSession(sessionId)
185
+ : this.chatInternalService.sessionModel;
189
186
  if (!sessionModel) {
190
187
  throw new Error(`Session ${sessionId} not found`);
191
188
  }
@@ -301,22 +298,17 @@ export abstract class BaseApplyService extends WithEventBus {
301
298
  if (!result) {
302
299
  throw new Error('Failed to open file');
303
300
  }
304
- if (typeof fastApplyFileResult.result === 'string') {
305
- codeBlock.updatedCode = fastApplyFileResult.result;
306
- codeBlock.status = 'pending';
307
- this.updateCodeBlock(codeBlock);
308
- }
309
- const applyResult = await this.renderApplyResult(
301
+ const res = await this.renderApplyResult(
310
302
  result.group.codeEditor.monacoEditor,
311
303
  codeBlock,
312
304
  (fastApplyFileResult.result || fastApplyFileResult.stream)!,
313
305
  fastApplyFileResult.range,
314
306
  );
315
- if (applyResult) {
316
- // 用户实际接受的 apply 结果
317
- codeBlock.applyResult = applyResult;
318
- this.updateCodeBlock(codeBlock);
319
- }
307
+ codeBlock.updatedCode = res.updatedCode;
308
+ codeBlock.status = 'pending';
309
+ // 用户实际接受的 apply 结果
310
+ codeBlock.applyResult = res.result;
311
+ this.updateCodeBlock(codeBlock);
320
312
 
321
313
  return codeBlock;
322
314
  } catch (err) {
@@ -328,31 +320,33 @@ export abstract class BaseApplyService extends WithEventBus {
328
320
  }
329
321
  }
330
322
 
323
+ /**
324
+ * 渲染apply结果(支持流式和直接输出结果)
325
+ * 副作用:渲染时会添加accept、reject操作监听器,监听到结果时会自动更新codeBlock的result
326
+ */
331
327
  async renderApplyResult(
332
328
  editor: ICodeEditor,
333
329
  codeBlock: CodeBlockData,
334
330
  updatedContentOrStream: string | SumiReadableStream<IChatProgress>,
335
331
  range?: Range,
336
- ): Promise<{ diff: string; diagnosticInfos: IMarker[] } | undefined> {
337
- const deferred = new Deferred<{ diff: string; diagnosticInfos: IMarker[] }>();
332
+ ): Promise<{ result?: { diff: string; diagnosticInfos: IMarker[] }; updatedCode: string }> {
333
+ const deferred = new Deferred<{ result?: { diff: string; diagnosticInfos: IMarker[] }; updatedCode: string }>();
338
334
  const inlineDiffController = InlineDiffController.get(editor)!;
339
335
  range = range || editor.getModel()!.getFullModelRange();
340
336
 
341
337
  if (typeof updatedContentOrStream === 'string') {
338
+ const updatedContent = updatedContentOrStream;
342
339
  const editorCurrentContent = editor.getModel()!.getValue();
343
340
  const uri = URI.file(path.join(this.appConfig.workspaceDir, codeBlock.relativePath));
344
341
  const document = this.editorDocumentModelService.getModelReference(uri);
345
- if (editorCurrentContent !== updatedContentOrStream || document?.instance.dirty) {
346
- editor.getModel()?.pushEditOperations([], [EditOperation.replace(range, updatedContentOrStream)], () => null);
342
+ if (editorCurrentContent !== updatedContent || document?.instance.dirty) {
343
+ editor.getModel()?.pushEditOperations([], [EditOperation.replace(range, updatedContent)], () => null);
347
344
  await this.editorService.save(uri);
348
345
  }
349
346
  const uriPendingCodeBlocks = this.getUriCodeBlocks(uri)?.filter((block) => block.status === 'pending');
350
347
  const earlistPendingCodeBlock = uriPendingCodeBlocks?.[uriPendingCodeBlocks.length - 1];
351
- if ((earlistPendingCodeBlock?.originalCode || codeBlock.originalCode) === updatedContentOrStream) {
352
- codeBlock.status = 'cancelled';
353
- this.updateCodeBlock(codeBlock);
354
- deferred.resolve();
355
- return;
348
+ if ((earlistPendingCodeBlock || codeBlock)?.originalCode === updatedContent) {
349
+ throw new Error('No changes applied');
356
350
  }
357
351
  // Create diff previewer
358
352
  const previewer = inlineDiffController.createDiffPreviewer(
@@ -380,13 +374,16 @@ export abstract class BaseApplyService extends WithEventBus {
380
374
 
381
375
  const { diff, rangesFromDiffHunk } = this.getDiffResult(
382
376
  codeBlock.originalCode,
383
- codeBlock.updatedCode || updatedContentOrStream,
377
+ updatedContent,
384
378
  codeBlock.relativePath,
385
379
  );
386
380
  const diagnosticInfos = this.getDiagnosticInfos(editor.getModel()!.uri.toString(), rangesFromDiffHunk);
387
381
  deferred.resolve({
388
- diff,
389
- diagnosticInfos,
382
+ result: {
383
+ diff,
384
+ diagnosticInfos,
385
+ },
386
+ updatedCode: updatedContent,
390
387
  });
391
388
  } else {
392
389
  const controller = new InlineChatController();
@@ -414,21 +411,21 @@ export abstract class BaseApplyService extends WithEventBus {
414
411
  this.addDispose(
415
412
  // 流式输出结束后,转为直接输出逻辑
416
413
  previewer.getNode()!.onDiffFinished(async (diffModel) => {
417
- codeBlock.updatedCode = diffModel.newFullRangeTextLines.join('\n');
418
414
  // TODO: 添加 reapply
415
+ const updatedCode = diffModel.newFullRangeTextLines.join('\n');
419
416
  // 实际应用结果为空,则取消
420
- if (codeBlock.updatedCode === codeBlock.originalCode) {
421
- codeBlock.status = 'failed';
422
- this.updateCodeBlock(codeBlock);
417
+ if (codeBlock.originalCode === updatedCode) {
423
418
  previewer.dispose();
424
419
  deferred.reject(new Error('no changes applied'));
425
420
  return;
426
421
  }
427
- codeBlock.status = 'pending';
428
- this.updateCodeBlock(codeBlock);
429
422
  previewer.dispose();
430
- const result = await this.renderApplyResult(editor, codeBlock, codeBlock.updatedCode);
431
- deferred.resolve(result);
423
+ try {
424
+ const res = await this.renderApplyResult(editor, codeBlock, updatedCode);
425
+ deferred.resolve(res);
426
+ } catch (err) {
427
+ deferred.reject(err);
428
+ }
432
429
  }),
433
430
  );
434
431
  this.activePreviewerMap.set(codeBlock.relativePath, previewer);
@@ -483,14 +480,36 @@ export abstract class BaseApplyService extends WithEventBus {
483
480
  }
484
481
  }
485
482
 
486
- processAll(uri: URI, type: 'accept' | 'reject'): void {
487
- const codeBlocks = this.getUriCodeBlocks(uri)?.filter((block) => block.status === 'pending');
483
+ processAll(type: 'accept' | 'reject', uri?: URI): void {
484
+ const codeBlocks = uri
485
+ ? this.getUriCodeBlocks(uri)?.filter((block) => block.status === 'pending')
486
+ : this.getSessionCodeBlocks().filter((block) => block.status === 'pending');
488
487
  if (!codeBlocks?.length) {
489
488
  throw new Error('No pending code block found');
490
489
  }
491
- const decorationModel = this.activePreviewerMap
492
- .get(codeBlocks[0].relativePath)
493
- ?.getNode()?.livePreviewDiffDecorationModel;
490
+ const relativePaths = uri
491
+ ? [codeBlocks[0].relativePath]
492
+ : codeBlocks
493
+ .map((block) => block.relativePath)
494
+ .reduce((acc, cur) => {
495
+ if (acc.includes(cur)) {
496
+ return acc;
497
+ }
498
+ acc.push(cur);
499
+ return acc;
500
+ }, [] as string[]);
501
+ relativePaths.forEach((relativePath) => {
502
+ this.doProcess(type, relativePath);
503
+ });
504
+ codeBlocks.forEach((codeBlock) => {
505
+ codeBlock.status = type === 'accept' ? 'success' : 'cancelled';
506
+ // TODO: 批量更新
507
+ this.updateCodeBlock(codeBlock);
508
+ });
509
+ }
510
+
511
+ protected doProcess(type: 'accept' | 'reject', relativePath: string) {
512
+ const decorationModel = this.activePreviewerMap.get(relativePath)?.getNode()?.livePreviewDiffDecorationModel;
494
513
  if (!decorationModel) {
495
514
  throw new Error('No active previewer found');
496
515
  }
@@ -499,19 +518,13 @@ export abstract class BaseApplyService extends WithEventBus {
499
518
  } else {
500
519
  decorationModel.discardUnProcessed();
501
520
  }
502
- this.editorService.save(uri);
503
- codeBlocks.forEach((codeBlock) => {
504
- codeBlock.status = type === 'accept' ? 'success' : 'cancelled';
505
- // TODO: 批量更新
506
- this.updateCodeBlock(codeBlock);
507
- });
521
+ this.editorService.save(URI.file(path.join(this.appConfig.workspaceDir, relativePath)));
508
522
  }
509
523
 
510
524
  protected listenPartialEdit(model: ITextModel, codeBlock: CodeBlockData) {
511
525
  const deferred = new Deferred<{ diff: string; diagnosticInfos: IMarker[] }>();
512
526
  const uriString = model.uri.toString();
513
527
  const toDispose = this.inlineDiffService.onPartialEdit((event) => {
514
- // TODO 支持自动保存
515
528
  if (
516
529
  event.totalPartialEditCount === event.resolvedPartialEditCount &&
517
530
  event.uri.path === model.uri.path.toString()
@@ -532,11 +545,19 @@ export abstract class BaseApplyService extends WithEventBus {
532
545
  actionSource: ActionSourceEnum.Chat,
533
546
  sessionId: this.chatInternalService.sessionModel.sessionId,
534
547
  isReceive: true,
535
- isDrop: false,
536
- code: codeBlock.codeEdit,
548
+ // 是否有丢弃部分代码
549
+ isDrop: event.acceptPartialEditCount !== event.totalPartialEditCount,
550
+ code: appliedResult,
551
+ originCode: codeBlock.originalCode,
537
552
  message: JSON.stringify({
538
553
  diff,
539
554
  diagnosticInfos,
555
+ instructions: codeBlock.instructions,
556
+ codeEdit: codeBlock.codeEdit,
557
+ partialEditCount: event.totalPartialEditCount,
558
+ acceptPartialEditCount: event.acceptPartialEditCount,
559
+ addedLinesCount: event.totalAddedLinesCount,
560
+ deletedLinesCount: event.totalDeletedLinesCount,
540
561
  }),
541
562
  });
542
563
  deferred.resolve({
@@ -554,8 +575,11 @@ export abstract class BaseApplyService extends WithEventBus {
554
575
  sessionId: this.chatInternalService.sessionModel.sessionId,
555
576
  isReceive: false,
556
577
  isDrop: true,
557
- code: codeBlock.codeEdit,
558
578
  originCode: codeBlock.originalCode,
579
+ message: JSON.stringify({
580
+ instructions: codeBlock.instructions,
581
+ codeEdit: codeBlock.codeEdit,
582
+ }),
559
583
  });
560
584
  }
561
585
  this.editorListenerMap.disposeKey(uriString);
@@ -593,8 +617,6 @@ export abstract class BaseApplyService extends WithEventBus {
593
617
  result?: string;
594
618
  }>;
595
619
 
596
- // FIXME: 貌似筛选逻辑不太对,需要重构
597
- // TODO: 支持使用内存中的document获取诊断信息,实现并行apply accept
598
620
  protected getDiagnosticInfos(uri: string, ranges: Range[]) {
599
621
  const markers = this.markerService.getManager().getMarkers({ resource: uri });
600
622
  return markers.filter(
@@ -5,6 +5,7 @@ import { Badge } from '@opensumi/ide-components';
5
5
  import { AINativeSettingSectionsId, ILogger, useInjectable } from '@opensumi/ide-core-browser';
6
6
  import { PreferenceService } from '@opensumi/ide-core-browser/lib/preferences';
7
7
  import { localize } from '@opensumi/ide-core-common';
8
+ import { IMessageService } from '@opensumi/ide-overlay/lib/common';
8
9
 
9
10
  import { BUILTIN_MCP_SERVER_NAME, ISumiMCPServerBackend, SumiMCPServerProxyServicePath } from '../../../../common';
10
11
  import { MCPServerDescription } from '../../../../common/mcp-server-manager';
@@ -19,6 +20,7 @@ export const MCPConfigView: React.FC = () => {
19
20
  const preferenceService = useInjectable<PreferenceService>(PreferenceService);
20
21
  const sumiMCPServerBackendProxy = useInjectable<ISumiMCPServerBackend>(SumiMCPServerProxyServicePath);
21
22
  const logger = useInjectable<ILogger>(ILogger);
23
+ const messageService = useInjectable<IMessageService>(IMessageService);
22
24
  const [servers, setServers] = React.useState<MCPServer[]>([]);
23
25
  const [formVisible, setFormVisible] = React.useState(false);
24
26
  const [editingServer, setEditingServer] = React.useState<MCPServerFormData | undefined>();
@@ -88,7 +90,9 @@ export const MCPConfigView: React.FC = () => {
88
90
  await preferenceService.set(AINativeSettingSectionsId.MCPServers, updatedServers);
89
91
  await loadServers();
90
92
  } catch (error) {
93
+ const msg = error.message || error;
91
94
  logger.error(`Failed to ${start ? 'start' : 'stop'} server ${serverName}:`, error);
95
+ messageService.error(`Failed to ${start ? 'start' : 'stop'} server ${serverName}:` + msg);
92
96
  }
93
97
  },
94
98
  [mcpServerProxyService, preferenceService, sumiMCPServerBackendProxy, loadServers],
@@ -1,6 +1,6 @@
1
1
  import { Autowired } from '@opensumi/di';
2
2
  import { LabelService } from '@opensumi/ide-core-browser/lib/services';
3
- import { Domain, Schemes, URI } from '@opensumi/ide-core-common';
3
+ import { Domain, URI } from '@opensumi/ide-core-common';
4
4
  import {
5
5
  BrowserEditorContribution,
6
6
  EditorComponentRegistry,
@@ -60,7 +60,7 @@ export class MCPServerRegistry implements IMCPServerRegistry {
60
60
  }
61
61
 
62
62
  getMCPTools(): MCPToolDefinition[] {
63
- return this.tools;
63
+ return this.tools.sort((a, b) => (a.order ?? Infinity) - (b.order ?? Infinity));
64
64
  }
65
65
 
66
66
  async callMCPTool(
@@ -12,13 +12,13 @@ import {
12
12
  path,
13
13
  useInjectable,
14
14
  } from '@opensumi/ide-core-browser';
15
- import { Loading } from '@opensumi/ide-core-browser/lib/components/ai-native';
16
15
  import { WorkbenchEditorService } from '@opensumi/ide-editor';
17
16
  import { ILanguageService } from '@opensumi/monaco-editor-core/esm/vs/editor/common/languages/language';
18
17
  import { IModelService } from '@opensumi/monaco-editor-core/esm/vs/editor/common/services/model';
19
18
  import { StandaloneServices } from '@opensumi/monaco-editor-core/esm/vs/editor/standalone/browser/standaloneServices';
20
19
 
21
20
  import { CodeBlockData } from '../../../../common/types';
21
+ import { ApplyStatus } from '../../../components/ApplyStatus';
22
22
  import { ChatMarkdown } from '../../../components/ChatMarkdown';
23
23
  import { IMCPServerToolComponentProps } from '../../../types';
24
24
  import { BaseApplyService } from '../../base-apply.service';
@@ -76,7 +76,7 @@ export const EditFileToolComponent = (props: IMCPServerToolComponentProps) => {
76
76
  }
77
77
 
78
78
  return [
79
- instructions && <p>{instructions}</p>,
79
+ instructions && <p key={'edit-file-tool-instructions'}>{instructions}</p>,
80
80
  <div className={styles['edit-file-tool']} key={'edit-file-tool'}>
81
81
  <div
82
82
  className={cls(styles['edit-file-tool-header'], {
@@ -96,7 +96,7 @@ export const EditFileToolComponent = (props: IMCPServerToolComponentProps) => {
96
96
  {codeBlockData.iterationCount > 1 && (
97
97
  <span className={styles['edit-file-tool-iteration-count']}>{codeBlockData.iterationCount}/3</span>
98
98
  )}
99
- {renderStatus(codeBlockData, props.result)}
99
+ <ApplyStatus status={codeBlockData.status} error={props.result} />
100
100
  </div>
101
101
  <div className={styles.right}>
102
102
  <Popover title={'Show Code'} id={'edit-file-tool-show-code'}>
@@ -137,37 +137,3 @@ export const EditFileToolComponent = (props: IMCPServerToolComponentProps) => {
137
137
  ),
138
138
  ];
139
139
  };
140
-
141
- const renderStatus = (codeBlockData: CodeBlockData, error?: string) => {
142
- const status = codeBlockData.status;
143
- switch (status) {
144
- case 'generating':
145
- return <Loading />;
146
- case 'pending':
147
- return (
148
- <Popover title='Pending' id={'edit-file-tool-status-pending'}>
149
- <Icon iconClass='codicon codicon-circle-large' />
150
- </Popover>
151
- );
152
- case 'success':
153
- return (
154
- <Popover title='Success' id={'edit-file-tool-status-success'}>
155
- <Icon iconClass='codicon codicon-check-all' />
156
- </Popover>
157
- );
158
- case 'failed':
159
- return (
160
- <Popover title={`Failed (${error})`} id={'edit-file-tool-status-failed'}>
161
- <Icon iconClass='codicon codicon-error' style={{ color: 'var(--debugConsole-errorForeground)' }} />
162
- </Popover>
163
- );
164
- case 'cancelled':
165
- return (
166
- <Popover title='Cancelled' id={'edit-file-tool-status-cancelled'}>
167
- <Icon iconClass='codicon codicon-close' style={{ color: 'var(--input-placeholderForeground)' }} />
168
- </Popover>
169
- );
170
- default:
171
- return null;
172
- }
173
- };