@opensumi/ide-ai-native 3.8.2-next-1741622293.0 → 3.8.2

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 (123) 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/tools/components/EditFile.js +3 -24
  51. package/lib/browser/mcp/tools/components/EditFile.js.map +1 -1
  52. package/lib/browser/mcp/tools/components/ExpandableFileList.js +3 -2
  53. package/lib/browser/mcp/tools/components/ExpandableFileList.js.map +1 -1
  54. package/lib/browser/model/msg-history-manager.d.ts +0 -2
  55. package/lib/browser/model/msg-history-manager.d.ts.map +1 -1
  56. package/lib/browser/model/msg-history-manager.js +1 -6
  57. package/lib/browser/model/msg-history-manager.js.map +1 -1
  58. package/lib/browser/preferences/schema.d.ts.map +1 -1
  59. package/lib/browser/preferences/schema.js +8 -0
  60. package/lib/browser/preferences/schema.js.map +1 -1
  61. package/lib/browser/widget/inline-diff/inline-diff-manager.d.ts.map +1 -1
  62. package/lib/browser/widget/inline-diff/inline-diff-manager.js +2 -2
  63. package/lib/browser/widget/inline-diff/inline-diff-manager.js.map +1 -1
  64. package/lib/browser/widget/inline-diff/inline-diff.controller.d.ts +1 -1
  65. package/lib/browser/widget/inline-diff/inline-diff.controller.d.ts.map +1 -1
  66. package/lib/browser/widget/inline-diff/inline-diff.controller.js.map +1 -1
  67. package/lib/browser/widget/inline-diff/inline-diff.service.d.ts +3 -2
  68. package/lib/browser/widget/inline-diff/inline-diff.service.d.ts.map +1 -1
  69. package/lib/browser/widget/inline-diff/inline-diff.service.js.map +1 -1
  70. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts +1 -1
  71. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts.map +1 -1
  72. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js.map +1 -1
  73. package/lib/browser/widget/inline-stream-diff/live-preview.component.d.ts +0 -33
  74. package/lib/browser/widget/inline-stream-diff/live-preview.component.d.ts.map +1 -1
  75. package/lib/browser/widget/inline-stream-diff/live-preview.component.js +1 -6
  76. package/lib/browser/widget/inline-stream-diff/live-preview.component.js.map +1 -1
  77. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.d.ts.map +1 -1
  78. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.js +15 -14
  79. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.js.map +1 -1
  80. package/lib/common/index.d.ts +7 -2
  81. package/lib/common/index.d.ts.map +1 -1
  82. package/lib/common/index.js +3 -2
  83. package/lib/common/index.js.map +1 -1
  84. package/lib/common/prompts/context-prompt-provider.d.ts.map +1 -1
  85. package/lib/common/prompts/context-prompt-provider.js +2 -4
  86. package/lib/common/prompts/context-prompt-provider.js.map +1 -1
  87. package/lib/common/types.d.ts +33 -0
  88. package/lib/common/types.d.ts.map +1 -1
  89. package/lib/common/types.js +6 -1
  90. package/lib/common/types.js.map +1 -1
  91. package/package.json +23 -23
  92. package/src/browser/ai-core.contribution.ts +28 -0
  93. package/src/browser/chat/chat-manager.service.ts +53 -31
  94. package/src/browser/chat/chat-model.ts +22 -8
  95. package/src/browser/chat/chat-proxy.service.ts +2 -0
  96. package/src/browser/chat/chat.view.tsx +80 -9
  97. package/src/browser/components/ApplyStatus.tsx +44 -0
  98. package/src/browser/components/ChangeList.tsx +131 -0
  99. package/src/browser/components/ChatToolRender.module.less +27 -15
  100. package/src/browser/components/ChatToolRender.tsx +14 -12
  101. package/src/browser/components/change-list.module.less +126 -0
  102. package/src/browser/components/chat-history.module.less +1 -1
  103. package/src/browser/components/components.module.less +14 -0
  104. package/src/browser/contrib/inline-completions/prompt/matcher.ts +2 -2
  105. package/src/browser/contrib/inline-completions/prompt/similarSnippets.ts +2 -2
  106. package/src/browser/contrib/intelligent-completions/view/default.ts +1 -0
  107. package/src/browser/index.ts +5 -4
  108. package/src/browser/mcp/base-apply.service.ts +84 -62
  109. package/src/browser/mcp/config/components/mcp-config.view.tsx +4 -0
  110. package/src/browser/mcp/config/mcp-config.contribution.ts +1 -1
  111. package/src/browser/mcp/tools/components/EditFile.tsx +3 -37
  112. package/src/browser/mcp/tools/components/ExpandableFileList.tsx +3 -1
  113. package/src/browser/model/msg-history-manager.ts +1 -8
  114. package/src/browser/preferences/schema.ts +8 -0
  115. package/src/browser/widget/inline-diff/inline-diff-manager.tsx +3 -2
  116. package/src/browser/widget/inline-diff/inline-diff.controller.ts +2 -1
  117. package/src/browser/widget/inline-diff/inline-diff.service.ts +3 -2
  118. package/src/browser/widget/inline-stream-diff/inline-stream-diff.handler.tsx +4 -4
  119. package/src/browser/widget/inline-stream-diff/live-preview.component.tsx +0 -34
  120. package/src/browser/widget/inline-stream-diff/live-preview.decoration.tsx +8 -9
  121. package/src/common/index.ts +9 -2
  122. package/src/common/prompts/context-prompt-provider.ts +2 -6
  123. package/src/common/types.ts +35 -0
@@ -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,
@@ -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
- };
@@ -71,7 +71,9 @@ const ExpandableFileList: React.FC<ExpandableFileListProps> = ({
71
71
 
72
72
  useEffect(() => {
73
73
  const toDispose = chatService.sessionModel.history.onMessageAdditionalChange((additional) => {
74
- setFileList(additional[toolCallId]?.files || []);
74
+ if (additional[toolCallId]) {
75
+ setFileList(additional[toolCallId].files || []);
76
+ }
75
77
  });
76
78
  return () => {
77
79
  toDispose.dispose();
@@ -29,7 +29,6 @@ export class MsgHistoryManager extends Disposable {
29
29
  public clearMessages() {
30
30
  this.messageMap.clear();
31
31
  this.messageAdditionalMap.clear();
32
- this.startIndex = 0;
33
32
  }
34
33
 
35
34
  private doAddMessage(message: IExcludeMessage): string {
@@ -53,19 +52,13 @@ export class MsgHistoryManager extends Disposable {
53
52
  return Array.from(this.messageMap.values()).sort((a, b) => a.order - b.order);
54
53
  }
55
54
 
56
- private startIndex = 0;
57
-
58
- public get slicedMessageCount(): number {
59
- return this.startIndex;
60
- }
61
-
62
55
  public get lastMessageId(): string | undefined {
63
56
  const list = this.messageList;
64
57
  return list[list.length - 1]?.id;
65
58
  }
66
59
 
67
60
  public getMessages(): IHistoryChatMessage[] {
68
- return this.messageList.slice(this.startIndex);
61
+ return this.messageList;
69
62
  }
70
63
 
71
64
  public addUserMessage(
@@ -97,6 +97,14 @@ export const aiNativePreferenceSchema: PreferenceSchema = {
97
97
  default: '',
98
98
  description: localize('preference.ai.native.openai.baseURL.description'),
99
99
  },
100
+ [AINativeSettingSectionsId.ContextWindow]: {
101
+ type: 'number',
102
+ description: localize('preference.ai.native.contextWindow.description'),
103
+ },
104
+ [AINativeSettingSectionsId.MaxTokens]: {
105
+ type: 'number',
106
+ description: localize('preference.ai.native.maxTokens.description'),
107
+ },
100
108
  [AINativeSettingSectionsId.MCPServers]: {
101
109
  type: 'array',
102
110
  default: [],
@@ -3,6 +3,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
3
3
  import { Icon, Popover } from '@opensumi/ide-components';
4
4
  import { AppConfig, IDisposable, URI, localize, path, useInjectable } from '@opensumi/ide-core-browser';
5
5
  import { IResource, WorkbenchEditorService } from '@opensumi/ide-editor';
6
+ import { Path } from '@opensumi/ide-utils/lib/path';
6
7
 
7
8
  import { BaseApplyService } from '../../mcp/base-apply.service';
8
9
 
@@ -113,13 +114,13 @@ export const InlineDiffManager: React.FC<{ resource: IResource }> = (props) => {
113
114
  <div className={styles.mid}>
114
115
  <IconWithPopover
115
116
  icon='codicon codicon-check'
116
- onClick={() => applyService.processAll(props.resource.uri, 'accept')}
117
+ onClick={() => applyService.processAll('accept', props.resource.uri)}
117
118
  content={localize('aiNative.inlineDiff.acceptAll')}
118
119
  id='inline-diff-manager-accept-all'
119
120
  />
120
121
  <IconWithPopover
121
122
  icon='codicon codicon-close'
122
- onClick={() => applyService.processAll(props.resource.uri, 'reject')}
123
+ onClick={() => applyService.processAll('reject', props.resource.uri)}
123
124
  content={localize('aiNative.inlineDiff.rejectAll')}
124
125
  id='inline-diff-manager-reject-all'
125
126
  />
@@ -23,7 +23,6 @@ import {
23
23
  import { BaseAIMonacoEditorController } from '../../contrib/base';
24
24
  import { EInlineDiffPreviewMode } from '../../preferences/schema';
25
25
  import { InlineChatController } from '../inline-chat/inline-chat-controller';
26
- import { EResultKind } from '../inline-chat/inline-chat.service';
27
26
  import { BaseInlineStreamDiffHandler } from '../inline-stream-diff/inline-stream-diff.handler';
28
27
 
29
28
  import {
@@ -34,6 +33,8 @@ import {
34
33
  } from './inline-diff-previewer';
35
34
  import { InlineDiffWidget } from './inline-diff-widget';
36
35
 
36
+ import type { EResultKind } from '../inline-chat/inline-chat.service';
37
+
37
38
  type IInlineDiffPreviewer = BaseInlineDiffPreviewer<InlineDiffWidget | BaseInlineStreamDiffHandler>;
38
39
 
39
40
  export class InlineDiffController extends BaseAIMonacoEditorController {
@@ -1,10 +1,11 @@
1
1
  import { Injectable } from '@opensumi/di';
2
2
  import { Emitter } from '@opensumi/ide-utils';
3
3
 
4
- import { IPartialEditEvent } from '../inline-stream-diff/live-preview.component';
4
+ import type { IInlineDiffService } from '../../../common/index';
5
+ import type { IPartialEditEvent } from '../../../common/types';
5
6
 
6
7
  @Injectable()
7
- export class InlineDiffService {
8
+ export class InlineDiffService implements IInlineDiffService {
8
9
  /**
9
10
  * Used in `codeblitz`, do not remove it.
10
11
  */
@@ -11,13 +11,13 @@ import { IModelService } from '@opensumi/monaco-editor-core/esm/vs/editor/common
11
11
  import { LineTokens } from '@opensumi/monaco-editor-core/esm/vs/editor/common/tokens/lineTokens';
12
12
  import { UndoRedoGroup } from '@opensumi/monaco-editor-core/esm/vs/platform/undoRedo/common/undoRedo';
13
13
 
14
- import { IDecorationSerializableState } from '../../model/enhanceDecorationsCollection';
15
- import { IDiffPreviewerOptions, IInlineDiffPreviewerNode } from '../inline-diff/inline-diff-previewer';
16
-
17
14
  import { InlineStreamDiffComputer } from './inline-stream-diff-computer';
18
- import { IRemovedWidgetState } from './live-preview.component';
19
15
  import { LivePreviewDiffDecorationModel } from './live-preview.decoration';
20
16
 
17
+ import type { IRemovedWidgetState } from './live-preview.component';
18
+ import type { IDecorationSerializableState } from '../../model/enhanceDecorationsCollection';
19
+ import type { IDiffPreviewerOptions, IInlineDiffPreviewerNode } from '../inline-diff/inline-diff-previewer';
20
+
21
21
  interface IRangeChangeData {
22
22
  removedTextLines: string[];
23
23
  removedLinesOriginalRange: LineRange;
@@ -46,40 +46,6 @@ export interface IRemovedWidgetState {
46
46
  position: IPosition;
47
47
  }
48
48
 
49
- export enum EPartialEdit {
50
- accept = 'accept',
51
- discard = 'discard',
52
- }
53
-
54
- export interface IPartialEditEvent {
55
- uri: URI;
56
- /**
57
- * 总 diff 数
58
- */
59
- totalPartialEditCount: number;
60
- /**
61
- * 已处理的个数
62
- */
63
- resolvedPartialEditCount: number;
64
- /**
65
- * 已添加行数
66
- */
67
- totalAddedLinesCount: number;
68
- /**
69
- * 已采纳的个数
70
- */
71
- acceptPartialEditCount: number;
72
- /**
73
- * 已删除行数
74
- */
75
- totalDeletedLinesCount: number;
76
- currentPartialEdit: {
77
- type: EPartialEdit;
78
- addedLinesCount: number;
79
- deletedLinesCount: number;
80
- };
81
- }
82
-
83
49
  export interface ITextLinesTokens {
84
50
  text: string;
85
51
  lineTokens: LineTokens;
@@ -19,9 +19,10 @@ import { LineRange } from '@opensumi/monaco-editor-core/esm/vs/editor/common/cor
19
19
  import { ModelDecorationOptions } from '@opensumi/monaco-editor-core/esm/vs/editor/common/model/textModel';
20
20
  import { IUndoRedoService, UndoRedoGroup } from '@opensumi/monaco-editor-core/esm/vs/platform/undoRedo/common/undoRedo';
21
21
 
22
+ import { IInlineDiffService, InlineDiffServiceToken } from '../../../common';
23
+ import { EPartialEdit, IPartialEditEvent } from '../../../common/types';
22
24
  import { AINativeContextKey } from '../../ai-core.contextkeys';
23
25
  import { IDecorationSerializableState, IEnhanceModelDeltaDecoration } from '../../model/enhanceDecorationsCollection';
24
- import { InlineDiffService } from '../inline-diff';
25
26
 
26
27
  import styles from './inline-stream-diff.module.less';
27
28
  import { InlineStreamDiffService } from './inline-stream-diff.service';
@@ -31,8 +32,6 @@ import {
31
32
  ActiveLineDecoration,
32
33
  AddedRangeDecoration,
33
34
  AddedRangeDecorationsCollection,
34
- EPartialEdit,
35
- IPartialEditEvent,
36
35
  IPartialEditWidgetOptions,
37
36
  IRemovedWidgetState,
38
37
  IRemovedZoneWidgetOptions,
@@ -66,8 +65,8 @@ export class LivePreviewDiffDecorationModel extends Disposable {
66
65
  @Autowired(InlineStreamDiffService)
67
66
  private readonly inlineStreamDiffService: InlineStreamDiffService;
68
67
 
69
- @Autowired(InlineDiffService)
70
- private readonly inlineDiffService: InlineDiffService;
68
+ @Autowired(InlineDiffServiceToken)
69
+ private readonly inlineDiffService: IInlineDiffService;
71
70
 
72
71
  @Autowired(IMessageService)
73
72
  private readonly messageService: IMessageService;
@@ -537,15 +536,15 @@ export class LivePreviewDiffDecorationModel extends Disposable {
537
536
  }
538
537
 
539
538
  public acceptUnProcessed(): void {
540
- const showingWidgets = this.partialEditWidgetList.filter((widget) => !widget.isHidden);
541
- showingWidgets.forEach((widget) => {
539
+ const pendingWidgets = this.partialEditWidgetList.filter((widget) => widget.isPending);
540
+ pendingWidgets.forEach((widget) => {
542
541
  this.handlePartialEditAction(EPartialEdit.accept, widget, false);
543
542
  });
544
543
  }
545
544
 
546
545
  public discardUnProcessed(): void {
547
- const showingWidgets = this.partialEditWidgetList.filter((widget) => !widget.isHidden);
548
- showingWidgets.forEach((widget) => {
546
+ const pendingWidgets = this.partialEditWidgetList.filter((widget) => widget.isPending);
547
+ pendingWidgets.forEach((widget) => {
549
548
  this.handlePartialEditAction(EPartialEdit.discard, widget, false);
550
549
  });
551
550
  }
@@ -16,7 +16,7 @@ import { DESIGN_MENUBAR_CONTAINER_VIEW_ID } from '@opensumi/ide-design/lib/commo
16
16
  import { IPosition, ITextModel, InlineCompletionContext } from '@opensumi/ide-monaco/lib/common';
17
17
 
18
18
  import { MCPServerDescription } from './mcp-server-manager';
19
- import { MCPTool } from './types';
19
+ import { IPartialEditEvent, MCPTool } from './types';
20
20
 
21
21
  import type { CoreMessage } from 'ai';
22
22
 
@@ -37,7 +37,7 @@ export const AI_CHAT_LOGO_AVATAR_ID = 'AI-Chat-Logo-Avatar';
37
37
  export const AI_MENU_BAR_DEBUG_TOOLBAR = 'AI_MENU_BAR_DEBUG_TOOLBAR';
38
38
 
39
39
  // 内置 MCP 服务器名称
40
- export const BUILTIN_MCP_SERVER_NAME = 'sumi-builtin';
40
+ export const BUILTIN_MCP_SERVER_NAME = 'builtin';
41
41
 
42
42
  /**
43
43
  * @deprecated Use {@link DESIGN_MENUBAR_CONTAINER_VIEW_ID} instead
@@ -309,3 +309,10 @@ export interface IAIInlineCompletionsProvider {
309
309
  ): Promise<T>;
310
310
  setVisibleCompletion(arg0: boolean): void;
311
311
  }
312
+
313
+ export interface IInlineDiffService {
314
+ onPartialEdit: Event<IPartialEditEvent>;
315
+ firePartialEdit(event: IPartialEditEvent): void;
316
+ }
317
+
318
+ export const InlineDiffServiceToken = Symbol('InlineDiffService');
@@ -42,15 +42,11 @@ ${context.recentlyViewFiles.map((file, idx) => ` ${idx + 1}: ${file}`).join('
42
42
  `,
43
43
  )}
44
44
  </attached_files>
45
- ${
46
- currentModel
47
- ? `<current_opened_file>
45
+ ${currentModel ? `<current_opened_file>
48
46
  \`\`\`${currentModel.languageId} ${currentModel.uri.toString()}
49
47
  ${currentModel.getText()}
50
48
  \`\`\`
51
- </current_opened_file>`
52
- : ''
53
- }
49
+ </current_opened_file>` : ''}
54
50
  </additional_data>
55
51
  <user_query>
56
52
  ${userMessage}