Skip to content

nes: implement cursor or whole edit window early cancellation of async request due to divergence#309871

Merged
ulugbekna merged 2 commits intomainfrom
ulugbekna/like-giraffe
Apr 14, 2026
Merged

nes: implement cursor or whole edit window early cancellation of async request due to divergence#309871
ulugbekna merged 2 commits intomainfrom
ulugbekna/like-giraffe

Conversation

@ulugbekna
Copy link
Copy Markdown
Contributor

No description provided.

Copilot AI review requested due to automatic review settings April 14, 2026 14:51
@ulugbekna ulugbekna enabled auto-merge (squash) April 14, 2026 14:51
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Implements configurable early cancellation of async xtab inline-edit requests when the user’s intermediate edits diverge from the model’s streamed output, expanding the check from cursor-line-only to optionally cover the whole edit window.

Changes:

  • Introduces EarlyDivergenceCancellationMode (Off / Cursor / EditWindow) and wires it into the team-internal config.
  • Updates XtabProvider streaming pipeline to cancel the fetch early on detected divergence, with backward compatibility for legacy boolean config values.
  • Adds extensive integration and unit tests covering cursor vs edit-window behavior and compatibility edge cases.
Show a summary per file
File Description
extensions/copilot/src/platform/inlineEdits/common/dataTypes/xtabPromptOptions.ts Adds an enum to represent divergence-cancellation scope modes.
extensions/copilot/src/platform/configuration/common/configurationService.ts Changes config type from boolean to the new enum and updates defaults.
extensions/copilot/src/extension/xtab/node/xtabProvider.ts Implements mode-driven divergence checking and backward-compatible config parsing.
extensions/copilot/src/extension/xtab/node/cursorLineDivergence.ts Generalizes cursor-line helpers to line-agnostic helpers.
extensions/copilot/src/extension/xtab/test/node/*.spec.ts Updates existing tests and adds new coverage for modes + backward compat.

Copilot's findings

Comments suppressed due to low confidence (2)

extensions/copilot/src/extension/xtab/test/node/cursorLineDivergence.spec.ts:16

  • The test suite descriptions still reference the old function names (isModelCursorLineCompatible, getCurrentCursorLine) even though the code now tests isModelLineCompatible / getCurrentLine. Updating these describe(...) strings will make failures and test reports easier to understand.
describe('isModelCursorLineCompatible', () => {

extensions/copilot/src/extension/xtab/test/node/cursorLineDivergence.spec.ts:765

  • The test suite descriptions still reference the old function names (isModelCursorLineCompatible, getCurrentCursorLine) even though the code now tests isModelLineCompatible / getCurrentLine. Updating these describe(...) strings will make failures and test reports easier to understand.
describe('getCurrentCursorLine', () => {
  • Files reviewed: 6/6 changed files
  • Comments generated: 6

Comment on lines +1702 to +1709
if (shouldCheckLine(lineIdx)) {
const docLineIdx = editWindowLineRange.start + lineIdx;
const currentLine = getCurrentLine(transformer, docLineIdx, intermediateEdit);
if (currentLine !== undefined) {
const originalLine = editWindowLines[lineIdx];
if (currentLine !== originalLine // user changed this line
&& !isModelLineCompatible(originalLine, currentLine, line) // model's line isn't compatible with user's typing
) {
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

editWindowLines[lineIdx]can beundefinedwhen the model streams more lines thaneditWindowLines.length(which is plausible for insertions / longer completions). That will flow intoisModelLineCompatible(originalLine, ...)and can throw (sinceoriginalLineis expected to be a string). Fix by bounding the divergence check to the edit window (e.g.,if (lineIdx >= editWindowLines.length) { /* skip check */ }or incorporate the bound intoshouldCheckLineforEditWindow` mode).

Copilot uses AI. Check for mistakes.
Comment on lines 55 to 57
const mappedOffset = lineStartOffset + delta;
const currentDoc = intermediateEdit.apply(originalDoc.text);
const currentTransformer = new PositionOffsetTransformer(currentDoc);
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getCurrentLine()applies the fullintermediateEditto the entire document and constructs a newPositionOffsetTransformeron every call. InEditWindowmode this can happen once per streamed line, which is potentially expensive (O(lines * docSize)). Consider precomputingcurrentDoc+currentTransformeronce inlinesWithIntermediateEditDivergenceCheckand passing them into a helper, or refactoringgetCurrentLine` to accept a pre-applied doc/transformer.

Copilot uses AI. Check for mistakes.
export const InlineEditsXtabNNonSignificantLinesToConverge = defineTeamInternalSetting<number>('chat.advanced.inlineEdits.xtabProvider.nNonSignificantLinesToConverge', ConfigType.ExperimentBased, ResponseProcessor.DEFAULT_DIFF_PARAMS.nLinesToConverge);
export const InlineEditsXtabNSignificantLinesToConverge = defineTeamInternalSetting<number>('chat.advanced.inlineEdits.xtabProvider.nSignificantLinesToConverge', ConfigType.ExperimentBased, ResponseProcessor.DEFAULT_DIFF_PARAMS.nSignificantLinesToConverge);
export const InlineEditsXtabEarlyCursorLineDivergenceCancellation = defineTeamInternalSetting<boolean>('chat.advanced.inlineEdits.xtabProvider.earlyCursorLineDivergenceCancellation', ConfigType.ExperimentBased, false);
export const InlineEditsXtabEarlyCursorLineDivergenceCancellation = defineTeamInternalSetting<EarlyDivergenceCancellationMode>('chat.advanced.inlineEdits.xtabProvider.earlyCursorLineDivergenceCancellation', ConfigType.ExperimentBased, EarlyDivergenceCancellationMode.Off);
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This setting changed from boolean to an enum-like string, but there is no validator ensuring only Off | Cursor | EditWindow are accepted. Adding a vEnum(...) validator (similar to other settings in this file) would prevent invalid string values from silently disabling checks or selecting unintended behavior at runtime.

Copilot uses AI. Check for mistakes.
Comment on lines +997 to +1000
// const earlyDivergenceCancellationRaw =
const earlyDivergenceMode = backwardCompatSetting<boolean | undefined, EarlyDivergenceCancellationMode>(
this.configService.getExperimentBasedConfig(ConfigKey.TeamInternal.InlineEditsXtabEarlyCursorLineDivergenceCancellation, this.expService),
(value) => (value === false || value === undefined) ? EarlyDivergenceCancellationMode.Off : (value === true ? EarlyDivergenceCancellationMode.Cursor : value)
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There’s a stray commented-out line (// const earlyDivergenceCancellationRaw =) that should be removed. Also, the backward-compat mapping returns value in the last branch; if the intent is to pass through modern enum values, consider typing the incoming value as a union (e.g., boolean | EarlyDivergenceCancellationMode | undefined) and explicitly handling unexpected strings to avoid silently accepting invalid modes.

Suggested change
// const earlyDivergenceCancellationRaw =
const earlyDivergenceMode = backwardCompatSetting<boolean | undefined, EarlyDivergenceCancellationMode>(
this.configService.getExperimentBasedConfig(ConfigKey.TeamInternal.InlineEditsXtabEarlyCursorLineDivergenceCancellation, this.expService),
(value) => (value === false || value === undefined) ? EarlyDivergenceCancellationMode.Off : (value === true ? EarlyDivergenceCancellationMode.Cursor : value)
const earlyDivergenceMode = backwardCompatSetting<boolean | EarlyDivergenceCancellationMode | undefined, EarlyDivergenceCancellationMode>(
this.configService.getExperimentBasedConfig(ConfigKey.TeamInternal.InlineEditsXtabEarlyCursorLineDivergenceCancellation, this.expService),
(value) => {
switch (value) {
case false:
case undefined:
return EarlyDivergenceCancellationMode.Off;
case true:
return EarlyDivergenceCancellationMode.Cursor;
case EarlyDivergenceCancellationMode.Off:
case EarlyDivergenceCancellationMode.Cursor:
case EarlyDivergenceCancellationMode.EditWindow:
return value;
default:
return EarlyDivergenceCancellationMode.Off;
}
}

Copilot uses AI. Check for mistakes.
&& !isModelLineCompatible(originalLine, currentLine, line) // model's line isn't compatible with user's typing
) {
setLineDiverged(true);
tracer.trace(`Line ${lineIdx} DIVERGED (mode=${mode}): model="${line}" current="${currentLine}"`);
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This trace message logs the full model line and the user’s current line content. With EditWindow mode it can log non-cursor lines as well, increasing the amount of potentially sensitive user code captured in traces. Consider truncating/ellipsizing the logged line content, logging only metadata (line index, lengths), or gating the full-text log behind a stricter debug flag.

Suggested change
tracer.trace(`Line ${lineIdx} DIVERGED (mode=${mode}): model="${line}" current="${currentLine}"`);
tracer.trace(
`Line ${lineIdx} DIVERGED (mode=${mode}, docLine=${docLineIdx}, modelLength=${line.length}, currentLength=${currentLine.length}, originalLength=${originalLine.length})`
);

Copilot uses AI. Check for mistakes.
Comment on lines +122 to +132
/**
* Controls the scope of the early divergence cancellation check.
*
* - `Cursor`: only check the cursor line for divergence (original behavior).
* - `EditWindow`: check every line in the edit window for divergence.
*/
export enum EarlyDivergenceCancellationMode {
Cursor = 'cursor',
EditWindow = 'editWindow',
Off = 'off',
}
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The JSDoc omits the Off mode even though it’s part of the enum and is now the default in config. Please document Off explicitly (e.g., “disable early divergence cancellation checks”) to keep the API self-explanatory.

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 14, 2026

Screenshot Changes

Base: beaa5dbf Current: 10fd6062

Changed (2)

chat/aiCustomizations/aiCustomizationManagementEditor/McpBrowseMode/Light
Before After
before after
editor/inlineCompletions/other/JumpToHint/Dark
Before After
before after

…num validator, use switch for backward compat
@ulugbekna ulugbekna merged commit e157dac into main Apr 14, 2026
40 of 41 checks passed
@ulugbekna ulugbekna deleted the ulugbekna/like-giraffe branch April 14, 2026 17:19
@vs-code-engineering vs-code-engineering Bot added this to the 1.117.0 milestone Apr 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants