@opensumi/ide-ai-native 3.8.1-next-1741092802.0 → 3.8.1-next-1741093151.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 (64) hide show
  1. package/lib/browser/chat/chat-manager.service.d.ts.map +1 -1
  2. package/lib/browser/chat/chat-manager.service.js +4 -0
  3. package/lib/browser/chat/chat-manager.service.js.map +1 -1
  4. package/lib/browser/chat/chat.view.d.ts.map +1 -1
  5. package/lib/browser/chat/chat.view.js +7 -1
  6. package/lib/browser/chat/chat.view.js.map +1 -1
  7. package/lib/browser/components/chat-history.module.less +1 -0
  8. package/lib/browser/mcp/base-apply.service.d.ts +18 -7
  9. package/lib/browser/mcp/base-apply.service.d.ts.map +1 -1
  10. package/lib/browser/mcp/base-apply.service.js +185 -65
  11. package/lib/browser/mcp/base-apply.service.js.map +1 -1
  12. package/lib/browser/mcp/tools/components/EditFile.d.ts.map +1 -1
  13. package/lib/browser/mcp/tools/components/EditFile.js +15 -9
  14. package/lib/browser/mcp/tools/components/EditFile.js.map +1 -1
  15. package/lib/browser/mcp/tools/components/index.module.less +3 -0
  16. package/lib/browser/mcp/tools/createNewFileWithText.d.ts +1 -0
  17. package/lib/browser/mcp/tools/createNewFileWithText.d.ts.map +1 -1
  18. package/lib/browser/mcp/tools/createNewFileWithText.js +18 -11
  19. package/lib/browser/mcp/tools/createNewFileWithText.js.map +1 -1
  20. package/lib/browser/mcp/tools/handlers/EditFile.js +1 -1
  21. package/lib/browser/mcp/tools/handlers/EditFile.js.map +1 -1
  22. package/lib/browser/model/msg-history-manager.d.ts +1 -0
  23. package/lib/browser/model/msg-history-manager.d.ts.map +1 -1
  24. package/lib/browser/model/msg-history-manager.js +3 -0
  25. package/lib/browser/model/msg-history-manager.js.map +1 -1
  26. package/lib/browser/widget/inline-diff/inline-diff-manager.d.ts.map +1 -1
  27. package/lib/browser/widget/inline-diff/inline-diff-manager.js +68 -8
  28. package/lib/browser/widget/inline-diff/inline-diff-manager.js.map +1 -1
  29. package/lib/browser/widget/inline-diff/inline-diff-previewer.d.ts +10 -4
  30. package/lib/browser/widget/inline-diff/inline-diff-previewer.d.ts.map +1 -1
  31. package/lib/browser/widget/inline-diff/inline-diff-previewer.js +14 -3
  32. package/lib/browser/widget/inline-diff/inline-diff-previewer.js.map +1 -1
  33. package/lib/browser/widget/inline-diff/inline-diff-widget.module.less +25 -4
  34. package/lib/browser/widget/inline-diff/inline-diff.controller.d.ts +3 -3
  35. package/lib/browser/widget/inline-diff/inline-diff.controller.d.ts.map +1 -1
  36. package/lib/browser/widget/inline-diff/inline-diff.controller.js +10 -5
  37. package/lib/browser/widget/inline-diff/inline-diff.controller.js.map +1 -1
  38. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts +46 -17
  39. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts.map +1 -1
  40. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js +110 -53
  41. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js.map +1 -1
  42. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.d.ts +4 -0
  43. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.d.ts.map +1 -1
  44. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.js +26 -1
  45. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.js.map +1 -1
  46. package/lib/common/types.d.ts +1 -0
  47. package/lib/common/types.d.ts.map +1 -1
  48. package/package.json +23 -23
  49. package/src/browser/chat/chat-manager.service.ts +6 -0
  50. package/src/browser/chat/chat.view.tsx +7 -2
  51. package/src/browser/components/chat-history.module.less +1 -0
  52. package/src/browser/mcp/base-apply.service.ts +222 -67
  53. package/src/browser/mcp/tools/components/EditFile.tsx +16 -9
  54. package/src/browser/mcp/tools/components/index.module.less +3 -0
  55. package/src/browser/mcp/tools/createNewFileWithText.ts +20 -12
  56. package/src/browser/mcp/tools/handlers/EditFile.ts +1 -1
  57. package/src/browser/model/msg-history-manager.ts +4 -0
  58. package/src/browser/widget/inline-diff/inline-diff-manager.tsx +143 -21
  59. package/src/browser/widget/inline-diff/inline-diff-previewer.ts +25 -7
  60. package/src/browser/widget/inline-diff/inline-diff-widget.module.less +25 -4
  61. package/src/browser/widget/inline-diff/inline-diff.controller.ts +16 -8
  62. package/src/browser/widget/inline-stream-diff/inline-stream-diff.handler.tsx +139 -68
  63. package/src/browser/widget/inline-stream-diff/live-preview.decoration.tsx +30 -1
  64. package/src/common/types.ts +1 -0
@@ -44,10 +44,13 @@ export enum EComputerMode {
44
44
 
45
45
  const inlineStreamDiffComputer = new InlineStreamDiffComputer();
46
46
 
47
+ /**
48
+ * Abstract base class for inline streaming diff handlers
49
+ */
47
50
  @Injectable({ multiple: true })
48
- export class InlineStreamDiffHandler extends Disposable implements IInlineDiffPreviewerNode {
51
+ export abstract class BaseInlineStreamDiffHandler extends Disposable implements IInlineDiffPreviewerNode {
49
52
  @Autowired(INJECTOR_TOKEN)
50
- private readonly injector: Injector;
53
+ protected readonly injector: Injector;
51
54
 
52
55
  protected readonly _onDidEditChange = this.registerDispose(new Emitter<void>());
53
56
  public readonly onDidEditChange: Event<void> = this._onDidEditChange.event;
@@ -57,15 +60,14 @@ export class InlineStreamDiffHandler extends Disposable implements IInlineDiffPr
57
60
 
58
61
  public previewerOptions: IDiffPreviewerOptions;
59
62
 
60
- private originalModel: ITextModel;
61
- private virtualModel: ITextModel;
63
+ protected savedModel: ITextModel;
64
+ protected virtualModel: ITextModel;
62
65
 
63
- private rawOriginalTextLines: string[];
64
- private rawOriginalTextLinesTokens: LineTokens[] = [];
65
- private undoRedoGroup: UndoRedoGroup = new UndoRedoGroup();
66
+ protected rawSavedTextLines: string[];
67
+ protected rawOriginTextLinesTokens: LineTokens[] | undefined;
68
+ protected undoRedoGroup: UndoRedoGroup = new UndoRedoGroup();
66
69
 
67
- private readonly diffModel: ISettableObservable<IComputeDiffData | undefined> = observableValue(this, undefined);
68
- private readonly finallyDiffModel: ISettableObservable<IComputeDiffData | undefined> = observableValue(
70
+ protected readonly finallyDiffModel: ISettableObservable<IComputeDiffData | undefined> = observableValue(
69
71
  this,
70
72
  undefined,
71
73
  );
@@ -73,14 +75,15 @@ export class InlineStreamDiffHandler extends Disposable implements IInlineDiffPr
73
75
  public livePreviewDiffDecorationModel: LivePreviewDiffDecorationModel;
74
76
 
75
77
  public get uri() {
76
- return this.originalModel.uri;
78
+ return this.savedModel.uri;
77
79
  }
78
80
 
79
- constructor(private readonly monacoEditor: ICodeEditor) {
81
+ constructor(protected readonly monacoEditor: ICodeEditor) {
80
82
  super();
81
83
 
82
84
  const modelService = StandaloneServices.get(IModelService);
83
- this.virtualModel = modelService.createModel(
85
+ const savedModel = this.monacoEditor.getModel()!;
86
+ const setModel = modelService.createModel(
84
87
  '',
85
88
  null,
86
89
  Uri.from({
@@ -89,7 +92,8 @@ export class InlineStreamDiffHandler extends Disposable implements IInlineDiffPr
89
92
  }),
90
93
  true,
91
94
  );
92
- this.originalModel = this.monacoEditor.getModel()!;
95
+ this.savedModel = savedModel;
96
+ this.virtualModel = setModel;
93
97
 
94
98
  this.livePreviewDiffDecorationModel = this.injector.get(LivePreviewDiffDecorationModel, [this.monacoEditor]);
95
99
  this.addDispose(this.livePreviewDiffDecorationModel);
@@ -113,45 +117,21 @@ export class InlineStreamDiffHandler extends Disposable implements IInlineDiffPr
113
117
  });
114
118
  }
115
119
 
116
- initialize(selection: Selection): void {
117
- const eol = this.originalModel.getEOL();
118
- const startPosition = selection.getStartPosition();
119
- const endPosition = selection.getEndPosition();
120
-
121
- this.rawOriginalTextLines = this.originalModel
122
- .getValueInRange(Range.fromPositions(startPosition, endPosition))
123
- .split(eol);
124
-
125
- this.rawOriginalTextLinesTokens = this.rawOriginalTextLines.map((_, index) => {
126
- const lineNumber = startPosition.lineNumber + index;
127
- this.originalModel.tokenization.forceTokenization(lineNumber);
128
- const lineTokens = this.originalModel.tokenization.getLineTokens(lineNumber);
129
- return lineTokens;
130
- });
131
-
132
- const zone = LineRange.fromRangeInclusive(
133
- Range.fromPositions(
134
- { lineNumber: selection.startLineNumber, column: 1 },
135
- { lineNumber: selection.endLineNumber, column: Number.MAX_SAFE_INTEGER },
136
- ),
137
- );
138
-
139
- this.livePreviewDiffDecorationModel.initialize(zone);
140
- }
120
+ abstract initialize(selection: Selection): void;
141
121
 
142
122
  getVirtualModelValue() {
143
123
  return this.virtualModel.getValue();
144
124
  }
145
125
 
146
126
  getOriginModelValue() {
147
- return this.rawOriginalTextLines.join('\n');
127
+ return this.rawSavedTextLines.join('\n');
148
128
  }
149
129
 
150
130
  get onPartialEditWidgetListChange() {
151
131
  return this.livePreviewDiffDecorationModel.onPartialEditWidgetListChange;
152
132
  }
153
133
 
154
- private computeDiff(
134
+ protected computeDiff(
155
135
  originalTextLines: string[],
156
136
  newTextLines: string[],
157
137
  computerMode: EComputerMode = EComputerMode.default,
@@ -285,7 +265,12 @@ export class InlineStreamDiffHandler extends Disposable implements IInlineDiffPr
285
265
  },
286
266
  textLines: removedTextLines.map((text, index) => ({
287
267
  text,
288
- lineTokens: this.rawOriginalTextLinesTokens[removedLinesOriginalRange.startLineNumber - 1 + index],
268
+ lineTokens:
269
+ this.rawOriginTextLinesTokens?.[removedLinesOriginalRange.startLineNumber - 1 + index] ||
270
+ LineTokens.createEmpty(text, {
271
+ encodeLanguageId: () => 0,
272
+ decodeLanguageId: () => 'plaintext',
273
+ }),
289
274
  })),
290
275
  });
291
276
  }
@@ -298,6 +283,11 @@ export class InlineStreamDiffHandler extends Disposable implements IInlineDiffPr
298
283
  });
299
284
  }
300
285
 
286
+ /**
287
+ * Get the original model for diff operations
288
+ */
289
+ protected abstract getOriginalModel(): ITextModel;
290
+
301
291
  /**
302
292
  * 令当前的 inline diff 在流式渲染过程当中使用 pushEditOperations 进行编辑的操作都放在同一组 undo/redo 堆栈里
303
293
  * 一旦撤销到最顶层则关闭当前的 inline diff
@@ -310,22 +300,24 @@ export class InlineStreamDiffHandler extends Disposable implements IInlineDiffPr
310
300
  });
311
301
  }
312
302
 
313
- private renderDiffEdits(diffModel: IComputeDiffData): void {
303
+ protected renderDiffEdits(diffModel: IComputeDiffData): void {
314
304
  const { activeLine, newFullRangeTextLines, pendingRange } = diffModel;
315
- const eol = this.originalModel.getEOL();
316
305
  const zone = this.getZone();
317
306
 
307
+ const originalModel = this.getOriginalModel();
308
+ const eol = originalModel.getEOL();
309
+
318
310
  const validZone =
319
311
  zone.startLineNumber < zone.endLineNumberExclusive
320
312
  ? new Range(
321
313
  zone.startLineNumber,
322
314
  1,
323
315
  zone.endLineNumberExclusive - 1,
324
- this.originalModel.getLineMaxColumn(zone.endLineNumberExclusive - 1),
316
+ originalModel.getLineMaxColumn(zone.endLineNumberExclusive - 1),
325
317
  )
326
318
  : new Range(zone.startLineNumber, 1, zone.startLineNumber, 1);
327
319
 
328
- const newOriginalTextLines = this.originalModel.getValueInRange(validZone).split(eol);
320
+ const newOriginalTextLines = originalModel.getValueInRange(validZone).split(eol);
329
321
  const diffComputation = linesDiffComputers.getDefault().computeDiff(newOriginalTextLines, newFullRangeTextLines, {
330
322
  computeMoves: false,
331
323
  maxComputationTimeMs: 200,
@@ -370,7 +362,7 @@ export class InlineStreamDiffHandler extends Disposable implements IInlineDiffPr
370
362
  validZone.startLineNumber + change.original.startLineNumber - 1,
371
363
  1,
372
364
  validZone.startLineNumber + change.original.endLineNumberExclusive - 2,
373
- this.originalModel.getLineMaxColumn(validZone.startLineNumber + change.original.endLineNumberExclusive - 2),
365
+ originalModel.getLineMaxColumn(validZone.startLineNumber + change.original.endLineNumberExclusive - 2),
374
366
  );
375
367
  }
376
368
  const edit = {
@@ -381,7 +373,7 @@ export class InlineStreamDiffHandler extends Disposable implements IInlineDiffPr
381
373
  realTimeChanges.push(edit);
382
374
  }
383
375
  }
384
- this.originalModel.pushEditOperations(null, realTimeChanges, () => null, this.undoRedoGroup);
376
+ originalModel.pushEditOperations(null, realTimeChanges, () => null, this.undoRedoGroup);
385
377
 
386
378
  /**
387
379
  * 根据 newFullRangeTextLines 内容长度重新计算 zone,避免超过最大长度,进而影响未选中的代码区域
@@ -421,17 +413,20 @@ export class InlineStreamDiffHandler extends Disposable implements IInlineDiffPr
421
413
  this._onDidEditChange.fire();
422
414
  }
423
415
 
424
- public recompute(computerMode: EComputerMode, newContent?: string): IComputeDiffData {
425
- if (newContent) {
426
- this.virtualModel.setValue(newContent);
416
+ public recompute(computerMode: EComputerMode, content?: string): IComputeDiffData {
417
+ if (content) {
418
+ this.virtualModel.setValue(content);
427
419
  }
428
420
 
429
- const newTextLines = this.virtualModel.getLinesContent();
430
- return this.computeDiff(this.rawOriginalTextLines, newTextLines, computerMode);
421
+ const textLines = this.virtualModel.getLinesContent();
422
+ return this.processDiffComputation(textLines, computerMode);
431
423
  }
432
424
 
433
- private currentEditLine = 0;
434
- private isEditing = false;
425
+ protected currentEditLine = 0;
426
+ protected isEditing = false;
427
+
428
+ protected abstract processDiffComputation(currentText: string[], computerMode?: EComputerMode): IComputeDiffData;
429
+
435
430
  public async rateRenderEditController(): Promise<void> {
436
431
  if (this.isEditing === false) {
437
432
  this.isEditing = true;
@@ -443,19 +438,14 @@ export class InlineStreamDiffHandler extends Disposable implements IInlineDiffPr
443
438
 
444
439
  const virtualTextLines = this.virtualModel.getLinesContent();
445
440
  const currentText = virtualTextLines.slice(0, this.currentEditLine);
446
- const currentDiffModel = this.computeDiff(this.rawOriginalTextLines, currentText);
447
- transaction((tx) => {
448
- this.diffModel.set(currentDiffModel, tx);
449
- });
450
-
451
- this.onDiffFinishedEmitter.fire(currentDiffModel);
441
+ const currentDiffModel = this.processDiffComputation(currentText);
452
442
 
453
- if (this.originalModel.id === this.monacoEditor.getModel()?.id) {
443
+ if (this.savedModel.id === this.monacoEditor.getModel()?.id) {
454
444
  this.renderDiffEdits(currentDiffModel);
455
445
  }
456
446
 
457
447
  this.currentEditLine += 1;
458
-
448
+ // 这个 sleep 会带来潜在的时序问题,如 finallyRender 时模型已经被 dispose
459
449
  await sleep(FRAME_THREE);
460
450
  }
461
451
 
@@ -469,10 +459,7 @@ export class InlineStreamDiffHandler extends Disposable implements IInlineDiffPr
469
459
  }
470
460
 
471
461
  public addLinesToDiff(newText: string, computerMode: EComputerMode = EComputerMode.default): void {
472
- const diffModel = this.recompute(computerMode, newText);
473
- transaction((tx) => {
474
- this.diffModel.set(diffModel, tx);
475
- });
462
+ this.recompute(computerMode, newText);
476
463
  }
477
464
 
478
465
  public pushRateFinallyDiffStack(diffModel: IComputeDiffData): void {
@@ -488,14 +475,17 @@ export class InlineStreamDiffHandler extends Disposable implements IInlineDiffPr
488
475
  public finallyRender(diffModel: IComputeDiffData): void {
489
476
  transaction((tx) => {
490
477
  this.finallyDiffModel.set(diffModel, tx);
491
- this.diffModel.set(diffModel, tx);
492
478
  });
493
479
 
494
- if (this.originalModel.id !== this.monacoEditor.getModel()?.id) {
480
+ if (this.savedModel.id !== this.monacoEditor.getModel()?.id) {
495
481
  return;
496
482
  }
497
483
 
498
484
  this.onDiffFinishedEmitter.fire(diffModel);
485
+
486
+ if (this.livePreviewDiffDecorationModel.disposed) {
487
+ return;
488
+ }
499
489
  this.renderPartialEditWidgets(diffModel);
500
490
  this.renderDiffEdits(diffModel);
501
491
  this.pushStackElement();
@@ -537,3 +527,84 @@ export class InlineStreamDiffHandler extends Disposable implements IInlineDiffPr
537
527
  return this.livePreviewDiffDecorationModel.getTotalCodeInfo();
538
528
  }
539
529
  }
530
+
531
+ /**
532
+ * Regular inline stream diff handler (non-reverse mode)
533
+ */
534
+ @Injectable({ multiple: true })
535
+ export class InlineStreamDiffHandler extends BaseInlineStreamDiffHandler {
536
+ initialize(selection: Selection): void {
537
+ const eol = this.savedModel.getEOL();
538
+ const startPosition = selection.getStartPosition();
539
+ const endPosition = selection.getEndPosition();
540
+
541
+ this.rawSavedTextLines = this.savedModel
542
+ .getValueInRange(Range.fromPositions(startPosition, endPosition))
543
+ .split(eol);
544
+
545
+ const zone = LineRange.fromRangeInclusive(
546
+ Range.fromPositions(
547
+ { lineNumber: selection.startLineNumber, column: 1 },
548
+ { lineNumber: selection.endLineNumber, column: Number.MAX_SAFE_INTEGER },
549
+ ),
550
+ );
551
+
552
+ this.livePreviewDiffDecorationModel.initialize(zone);
553
+ this.rawOriginTextLinesTokens = this.rawSavedTextLines.map((_, index) => {
554
+ const lineNumber = startPosition.lineNumber + index;
555
+ this.savedModel.tokenization.forceTokenization(lineNumber);
556
+ const lineTokens = this.savedModel.tokenization.getLineTokens(lineNumber);
557
+ return lineTokens;
558
+ });
559
+ }
560
+
561
+ protected processDiffComputation(currentText: string[], computerMode?: EComputerMode): IComputeDiffData {
562
+ return this.computeDiff(this.rawSavedTextLines, currentText, computerMode);
563
+ }
564
+
565
+ protected getOriginalModel(): ITextModel {
566
+ return this.savedModel;
567
+ }
568
+ }
569
+
570
+ /**
571
+ * Reverse inline stream diff handler
572
+ * In reverse mode, the roles of savedModel and virtualModel are swapped
573
+ */
574
+ @Injectable({ multiple: true })
575
+ export class ReverseInlineStreamDiffHandler extends BaseInlineStreamDiffHandler {
576
+ recompute(computerMode: EComputerMode, content?: string): IComputeDiffData {
577
+ const result = super.recompute(computerMode, content);
578
+ this.rawOriginTextLinesTokens = this.virtualModel.getLinesContent().map((_, index) => {
579
+ const lineNumber = index + 1;
580
+ this.virtualModel.tokenization.forceTokenization(lineNumber);
581
+ const lineTokens = this.virtualModel.tokenization.getLineTokens(lineNumber);
582
+ return lineTokens;
583
+ });
584
+ return result;
585
+ }
586
+
587
+ initialize(): void {
588
+ const eol = this.savedModel.getEOL();
589
+
590
+ // reverse 模式不支持 range
591
+ this.rawSavedTextLines = this.savedModel.getValue().split(eol);
592
+
593
+ // TODO: reverse 模式暂不支持 range
594
+ const zone = LineRange.fromRangeInclusive(
595
+ Range.fromPositions(
596
+ { lineNumber: 1, column: 1 },
597
+ { lineNumber: this.virtualModel.getLineCount(), column: Number.MAX_SAFE_INTEGER },
598
+ ),
599
+ );
600
+ this.livePreviewDiffDecorationModel.initialize(zone);
601
+ }
602
+
603
+ protected getOriginalModel(): ITextModel {
604
+ return this.virtualModel;
605
+ }
606
+
607
+ protected processDiffComputation(currentText: string[], computerMode?: EComputerMode): IComputeDiffData {
608
+ return this.computeDiff(currentText, this.rawSavedTextLines, computerMode);
609
+ }
610
+ }
@@ -7,11 +7,13 @@ import {
7
7
  Emitter,
8
8
  Event,
9
9
  IAIReporter,
10
+ localize,
10
11
  runWhenIdle,
11
12
  } from '@opensumi/ide-core-common';
12
13
  import { ISingleEditOperation } from '@opensumi/ide-editor';
13
14
  import { ICodeEditor, IEditorDecorationsCollection, ITextModel, Position, Range } from '@opensumi/ide-monaco';
14
15
  import { StandaloneServices } from '@opensumi/ide-monaco/lib/browser/monaco-api/services';
16
+ import { IMessageService } from '@opensumi/ide-overlay';
15
17
  import { EditOperation } from '@opensumi/monaco-editor-core/esm/vs/editor/common/core/editOperation';
16
18
  import { LineRange } from '@opensumi/monaco-editor-core/esm/vs/editor/common/core/lineRange';
17
19
  import { ModelDecorationOptions } from '@opensumi/monaco-editor-core/esm/vs/editor/common/model/textModel';
@@ -67,6 +69,9 @@ export class LivePreviewDiffDecorationModel extends Disposable {
67
69
  @Autowired(InlineDiffService)
68
70
  private readonly inlineDiffService: InlineDiffService;
69
71
 
72
+ @Autowired(IMessageService)
73
+ private readonly messageService: IMessageService;
74
+
70
75
  private activeLineDec: IEditorDecorationsCollection;
71
76
  private pendingRangeDec: IEditorDecorationsCollection;
72
77
  private aiNativeContextKey: AINativeContextKey;
@@ -87,6 +92,10 @@ export class LivePreviewDiffDecorationModel extends Disposable {
87
92
  private removedZoneWidgets: RemovedZoneWidget[] = [];
88
93
  private zone: LineRange;
89
94
 
95
+ public get partialEditWidgetCount() {
96
+ return this.partialEditWidgetList.length;
97
+ }
98
+
90
99
  constructor(private readonly monacoEditor: ICodeEditor) {
91
100
  super();
92
101
  this.model = this.monacoEditor.getModel()!;
@@ -616,7 +625,7 @@ export class LivePreviewDiffDecorationModel extends Disposable {
616
625
  if (this.options.renderRemovedWidgetImmediately) {
617
626
  run();
618
627
  } else {
619
- runWhenIdle(run);
628
+ this.addDispose(runWhenIdle(run));
620
629
  }
621
630
  }
622
631
 
@@ -681,6 +690,26 @@ export class LivePreviewDiffDecorationModel extends Disposable {
681
690
  }
682
691
  }
683
692
 
693
+ currentChangeIndex: number = 0;
694
+
695
+ revealSiblingChange(direction: 'up' | 'down') {
696
+ this.currentChangeIndex = this.currentChangeIndex + (direction === 'up' ? -1 : 1);
697
+ if (this.currentChangeIndex >= 0 && this.currentChangeIndex < this.partialEditWidgetList.length) {
698
+ const siblingChange = this.partialEditWidgetList[this.currentChangeIndex];
699
+ const pos = siblingChange.getPosition();
700
+ if (pos?.position) {
701
+ this.monacoEditor.revealLineInCenter(pos.position!.lineNumber);
702
+ return this.currentChangeIndex;
703
+ }
704
+ } else {
705
+ this.messageService.info(
706
+ direction === 'up'
707
+ ? localize('aiNative.inlineDiff.noMoreChangesUp')
708
+ : localize('aiNative.inlineDiff.noMoreChangesDown'),
709
+ );
710
+ }
711
+ }
712
+
684
713
  setPreviewerOptions(options: IModelOptions) {
685
714
  this.options = options;
686
715
  }
@@ -52,6 +52,7 @@ export interface MCPTool {
52
52
  export interface CodeBlockData {
53
53
  toolCallId: string;
54
54
  codeEdit: string;
55
+ originalCode: string;
55
56
  updatedCode?: string;
56
57
  relativePath: string;
57
58
  status: CodeBlockStatus;