Ulugbek Abdullaev
90d · built 2026-07-24
90-day totals
- Commits
- 67
- Grow
- 12.1
- Maintenance
- 8.8
- Fixes
- 7.9
- Total ETV
- 28.8
Where this dev ranks
Percentile against the global top-100 leaderboard (all-time totals).
- By commits
- Top 58 %
- By Growth share
- Top 30 %
30-day trajectory
Last 30 days vs. the 30 days before. Up arrows on Growth and ETV mean improvement; up arrow on Fixes share means more time on fixes (worse).
↑+87.0 %
vs 23 prior
↑+3.3 pp
recent vs prior
↑+19.1 pp
recent vs prior
Daily performance
Daily ETV, stacked by Growth, Maintenance and Fixes.
Work-mix over time
Share of Growth / Maintenance / Fixes over a rolling 7-day window. Reads as 'where is effort flowing right now'.
Repository spread
Where this developer's commits land. Concentrated work (top1 > 80%) vs polymath spread (top1 < 30%).
Most impactful commits
Top 20 by ETV in the 90-day window.
- 3.0ETVAgents: Fix automation branch picker (#325777) * Sessions: Make repository setters asynchronous Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: f5aa3878-217b-45dc-9b52-0b5091ddf707 * Agents: Fix automation branch picker Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: f5aa3878-217b-45dc-9b52-0b5091ddf707github.com-microsoft-vscode · c7f9ddca · 2026-07-15
- 2.3ETVAgents: Support workspace-less automations (#326315) Add workspace-less Automation targets, unify workspace selection, reuse headless quick-chat creation, and model persisted targets as discriminated unions. Copilot-Session: 7600152c-d485-4547-bd86-dd21ad05debd Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · e8bf36ec · 2026-07-18
- 1.9ETVnes-datagen: add cursor-jump (NCLP) sample task (#320113) * nes-datagen: add cursor-jump (NCLP) task Extend nes-datagen with a next-cursor-line prediction task alongside the existing xtab path. Detects the user's next intentional cursor move after the request bookmark and emits a training sample with the production cursor-prediction prompt + the observed jump as the expected response. Three sub-modes via --sample-task: - cursor-same-file: a jump farther than N lines from cursor at request time - cursor-cross-file: focus/selection on a different file - cursor-both: either of the above Reuses the production cursor-prediction prompt by capturing it via the telemetry builder and a no-op fetcher; the cross-file target line is resolved from a request-time content snapshot + post-request replay so previously-opened targets get a correct line number instead of being silently labelled :0. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes-datagen: replace SAMPLE_TASK_VALUES tuple with a string enum Convert the string-union + as-const tuple to a proper NesDatagenSampleTask string enum. CLI surface is string-enum members keep theunchanged kebab-case wire values ('xtab', 'cursor-same-file', ...). All consumers (dispatch, fixtures, response metadata typing) updated to reference enum members instead of string literals. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes-datagen: lower default --same-file-jump-min-above to 2 Upward cursor jumps (back to a definition, an import, etc.) are typically tighter than downward jumps after the user has been writing. Lower the default threshold to match. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes-datagen: rename NCLP to cursor-jump throughout Drop the NCLP abbreviation in favor of the more descriptive 'cursor-jump' name already used in the production xtab provider. cursorJumpPromptStep, cursorJumpResponseStep), the capture request ids, and all surrounding doc comments / test descriptions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes-datagen: build documentIndexMapping from whole recording path map from only the pre-request slice and then re-walked the post-request slice to backfill any documentEncountered entries that arrived later. Pass the whole recording into documentIndexMapping instead so the helper sees every document the user touched in a single pass; the backfill loop is gone. splitRecordingAtRequestTime now also returns the full entries array so both callers can reuse it without re-deriving it from altAction. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes-datagen: use shared Result type in cursor-jump detectors Drop the bespoke { ok, value | reason } discriminated union in detectJump.ts and reuse the existing Result<T, E> from src/util/common/result. JumpDetectionResult<T> is now just an alias for Result<T, string>. .isOk(), .err) and the spec file accordingly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes-datagen: strip raw cursor-jump prompt from emitted telemetry cursorJumpRawMessages and cursorJumpKeptRange were added to IStatelessNextEditTelemetry so in-process debug / datagen tooling could read them back via getStatelessNextEditTelemetry(). However LlmNESTelemetryBuilder.build() spreads ...this._statelessNextEditTelemetry into the emitted payload, so those two fields would leak to telemetry cursorJumpRawMessages can contain full prompt content (sourcesinks code), which must never leave the process. Destructure them out before spreading into the build() payload. They remain readable via getStatelessNextEditTelemetry() for tooling. Documented the privacy contract on the IStatelessNextEditTelemetry field declarations so future edits don't forget. Addresses copilot-pull-request-reviewer feedback on PR #320113. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes-datagen: fail cross-file detection when no selection lands on target detectCrossFileJump previously returned Result.ok with toLine undefined when only a focused event was seen for the target doc (no selectionChanged). That left generateCrossFileResponse to drop the sample later while the detector still reported a successful jump. Treat focused-without-selectionChanged as a failed detection ('crossFileTargetNoSelection') so callers can skip early, and tighten ICrossFileJump.toLine to non-undefined now that ok results always have a usable line number. Removes the dead error path in generateCrossFileResponse. Adds a regression test that focused-only triggers the new error. Addresses copilot-pull-request-reviewer feedback on PR #320113. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes-datagen: capture cursor-jump prompt via logContext, not telemetry The datagen pipeline previously stashed the raw cursor-jump prompt and keptRange on IStatelessNextEditTelemetry so cursorJumpPromptStep.ts could read them back via LlmNESTelemetryBuilder.getStatelessNextEditTelemetry(). That leaked raw prompts into the telemetry payload (worked around by a destructure-strip hack in LlmNESTelemetryBuilder.build()) and was asymmetric with the xtab path, which captures via InlineEditRequestLogContext.rawMessages. Move the cursor-jump capture vehicle onto InlineEditRequestLogContext to match xtab: - Add cursorJumpRawMessages / cursorJumpKeptRange fields and setCursorJumpPrompt(messages, keptRange) to InlineEditRequestLogContext. - XtabNextCursorPredictor.predictNextCursorPosition now takes a logContext parameter and writes to it directly. The xtabProvider callsite passes the same logContext it already had in scope. - cursorJumpPromptStep reads from logContext instead of the telemetry builder. - Remove cursorJumpRawMessages / cursorJumpKeptRange from IStatelessNextEditTelemetry, plus the corresponding setter/getter on StatelessNextEditTelemetryBuilder and the getter on LlmNESTelemetryBuilder. - Revert the destructure-strip hack in LlmNESTelemetryBuilder.build(). The pre-existing cursorJumpPrompt telemetry field (JSON-stringified, fed by setCursorJumpPrompt(messages)) is intentional and unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes-datagen: cursor-jump ground truth is first user EDIT, not cursor landing Selection-based detection treated peek, navigation, IDE auto-scroll, and recursive cursor settling as if they were the user's next intended edit location. The model's job is to predict where the user will EDIT next, so key off the first 'changed' event after the request bookmark instead. Same-file detector: - Walks for the first 'changed' on the active doc; uses the first edit's start offset to compute toLine; applies the linesAbove/linesBelow threshold. Bails with editsAnotherFileFirst when a non-active doc is edited first (lets the cross-file detector claim the sample in cursor-both mode). 'selectionChanged' is no longer consulted, so the settle-after-edit filter is gone it was a workaround for thetoo selection-based approach. Cross-file detector: - Walks for the first 'changed' on a non-active doc; uses the first edit's start offset, resolved against the target doc's snapshot just-before applying the event. Drops focused / selectionChanged heuristics and the crossFileTargetNoSelection error path (a focused event without an edit no longer counts; background peek can't pollute the dataset). buildLineResolver: tightened i <= entryIndex to i < entryIndex so the resolver returns the pre-edit line when entryIndex is itself a 'changed' event. The bound is equivalent for the old selectionChanged caller. Spec: switched ground-truth events from selChanged to changed; added coverage for first-edit-of-multi-edit, editsAnotherFileFirst, and active-doc-then-other-doc ordering. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * xtab: predictNextCursorPosition takes RequestTracingContext Every other helper in xtabProvider takes RequestTracingContext (the { tracer, logContext, telemetry } bundle). The cursor predictor was the odd one out, taking the three pieces as separate positional params with the latter two that asymmetry made the new logContext-captureoptional plumbing look more invasive than it is and forced an awkward ?.setCursorJumpPrompt chain at the use site. Switch the predictor to take RequestTracingContext directly: - Export RequestTracingContext from xtabProvider so the predictor can type-import it (TS-erased to avoid the runtime circular import). - predictNextCursorPosition signature collapses from 5 params to 3. - Drop the optional chains; tracing.telemetry / tracing.logContext are always present in production and the spec constructs a real bundle. - Spec adds a createTestTracingContext helper using the cheap InlineEditRequestLogContext / StatelessNextEditTelemetryBuilder constructors already used by other inlineEdits specs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes-datagen: rename splitRecording 'entries' field to 'wholeRecording' Review feedback: the field on the splitRecordingAtRequestTime return shape was named 'entries' but in context it carries the whole unsplit recording (i.e. before slicing into prior/after parts). 'wholeRecording' matches the comment at the consumer (documentIndexMapping callsite). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes-datagen: inline JumpDetectionResult<T> as Result<T, string> Review feedback: the one-line alias was used in exactly two places in the same file and gave nothing over the underlying Result type. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes-datagen: discriminated union for sample task + jump metadata Review feedback: ISampleMetadata had 'task' + an optional 'jump' field with toFilePath also optional. That let xtab samples accidentally carry a jump and let cursor-cross-file samples omit toFilePath. Replace with a discriminated union on task: - xtab: no jump - cursorSameFile: jump with fromLine/toLine/distance - cursorCrossFile: jump with required toFilePath assembleSample now takes a single SampleClassification arg, removing the parallel task/jump parameters that callers had to keep in sync. cursorJumpResponseStep is split into ISameFileGeneratedResponse and ICrossFileGeneratedResponse so the generator return types map cleanly to the union variants without a non-null assertion at the assembly site. DetectedJump no longer needs an assistantTask hint: the pipeline constructs the classification directly from the response shape. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix dup import * nes-datagen: address round-4 review feedback on pipeline.ts Five review threads on pipeline. all addressed in-place.ts - modelResponse: cursor samples were emitting an empty string for the expected response. Populate it with the assistant content (which IS the expected output) so downstream tooling has the gold label. - Promise.all unbounded throws: wrap the limiter callback body in try/catch so an unexpected exception from generateCursorPromptFromRecording becomes a recorded per-row error instead of aborting the whole batch via Promise.all's first-rejection semantics. - Inline import for OffsetRange: replace the inline import('...').OffsetRange type expression with a regular top-of-file import. - Duplicated config-override block: both pipelines applied the same applyConfigFile + four setConfig debounce/cache disables. Extract into applyBatchModeConfig(configService, configs) and call from both. - runInputPipeline parallelism + memory: add a doc comment clarifying that this is the single-process entry point, that cursor-jump tasks also benefit from runInputPipelineParallel (--sample-task is propagated to workers), and that loadAndParseInput is in-memory by design (sized per worker; use --parallelism > 1 for large inputs). Full architectural unification of the parallel and non-parallel paths is intentionally left as a follow- the surface area isup large and out of scope for this PR. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes-datagen: add e2e tests for cursor-jump pipeline Mirrors the existing xtab pipeline.e2e.spec.ts: drives two fixture rows (a same-file jump and a cross-file jump) through the full `runInputPipeline` for each `sampleTask` mode (cursor-same-file, cursor-cross-file, cursor-both) and asserts on the JSONL output. Coverage: - only the matching row is emitted per mode; both rows are emitted in cursor-both - emitted samples carry strategy=next-cursor-line-prediction and the correct discriminated `task` field (cursor-same-file / cursor-cross-file) - assistant message targets the jumped-to line / file - metadata.modelResponse mirrors the assistant content (the round-4 fix) - --row-offset is reflected in metadata.rowIndex Test fixtures are constructed in `fixtures/cursorJumpFixtureData.ts` with synthesized recordings: an explicit no-op edit + selectionChanged before the bookmark so the cursor-prediction path's recent-edit gating is satisfied, then a single post-request `changed` event the detector picks up. The cursor pipeline needs a prompting strategy whose response handler tolerates an empty stream — use `xtabUnifiedModel` in a dedicated `cursorJumpConfig.json` (the existing patchBased02 config crashes on empty output, which is acceptable in production but breaks the prompt-only capture path). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Strengthen cursor-jump e2e assertions Replace fuzzy matchers (toMatch(/25/), arrayContaining for tasks) with exact assertions on assistant content, metadata.task, and metadata.jump. In cursor-both, locate samples by filePath so a row→classification swap would now be caught instead of passing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Make cursor-jump e2e helper accept partial nesDatagen overrides Helper previously took Partial<RunPipelineOptions>; if a caller passed `nesDatagen`, the spread fully replaced the default block and the configured path. Now the helper accepts a partial nesDatagen overlay and merges field-by-field, so the row-offset test only specifies the two fields it actually changes and there are no non-null assertions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add within-threshold cursor-jump negative fixture Scenario C: cursor on line 10, post-request edit on line 12 (only 2 lines below). Default threshold is ±5 lines, so neither the same-file nor the cross-file generator should emit a sample for this row. Asserted in cursor-both via a dedicated 'does not emit a sample for the within-threshold row' test, and implicitly in cursor-same-file / cursor-cross-file (their existing count==1 assertions would fail if the threshold guard regressed). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Ulugbek Abdullaev <ulugbekna@github.com>github.com-microsoft-vscode · a3e359ab · 2026-06-12
- 1.7ETVnes-datagen: generate training data from continuous recordings (#323855) * utils: document binarySearch * nes-datagen: generate training data from continuous recordings Continuous enhanced telemetry now ships sliding-window recordings that, unlike per-request alternative-action recordings, carry no requestTime. The datagen pipeline needs a point to split each recording into edit history before/after, so this adds a pluggable pivot strategy (starting with Random, selectable via --pivot-strategy) and a new continuous/ pipeline module that replays a recording at the chosen pivot to produce a processed row. Along the way this consolidates the pipeline's error and index handling: a shared WithRowIndex<T> replaces the ad-hoc { originalRowIndex, ... } pairs, per-record processing returns Result<IProcessedRow, Error> instead of field-presence unions, and failures surface as original Error objects (no string round-tripping). The telemetry sender's continuous payload is now the documented IContinuousRecording type. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * nes-datagen: label alt-action replay errors by originalRowIndex Address PR review: the alternative-action path mislabeled diagnostics when earlier records failed to parse. - processAllRows: push replay errors with the row's true `originalRowIndex` instead of its position in the filtered `rows` array (parse failures make `rows` sparse, so the two diverge). - loadAndProduceProcessedRows: resolve `languageForRow` via an `originalRowIndex`-keyed Map rather than positional `rows[i]`, matching how callers pass `e.originalRowIndex`. - Clarify the `recordCount` doc: it counts successfully-parsed records (parse failures are counted separately in `parseErrors`). - Add a regression spec asserting replay errors carry the row index, not the array position. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · 6bd7400f · 2026-07-01
- 1.2ETVSupport system-wide (OS global) keybindings (#323871) * Add support for system-wide (OS global) keybindings Allow user keybindings in keybindings.json to be marked with "systemWide": true so they register as operating-system global shortcuts that fire even when the window is not focused. - Thread the systemWide flag through IUserFriendlyKeybinding, ResolvedKeybindingItem and KeybindingIO (read + serialize) - New GlobalKeybindingsMainService owns Electron's globalShortcut, reconciles per-window registrations, resolves conflicts deterministically and routes triggers through the existing vscode:runAction path - New renderer contribution syncs opted-in bindings to the main process, gated behind the experimental, off-by-default setting keyboard.enableSystemWideKeybindings with a one-time confirmation dialog - Enable the GlobalShortcutsPortal feature on Linux/Wayland Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Avoid focusing the routing window on system-wide keybinding trigger Force-focusing the routing (main) window before dispatching the command pulled it to the foreground even when the command opens/reveals a different window (e.g. openAgentsWindow reveals the agents window), producing a visible flicker. Remove the force-focus and let the invoked command control what is surfaced/focused, matching every other vscode:runAction sender. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Add workbench.action.focusWindow to raise the current window Adds a generic command that brings the current window to the foreground and focuses it using FocusMode.Force (which works even when the application is not the active app). This lets users compose system-wide keybindings via runCommands to reveal the window before running a command that surfaces UI in it, e.g. [workbench.action.focusWindow, workbench.action.quickOpen]. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Address Copilot review: schema default, mnemonic comment, test grammar - keybindingService.ts: correct 'systemWide' schema default to false to match KeybindingIO parsing (defaults to false when absent/invalid) - systemWideKeybindings.contribution.ts: add '&& denotes a mnemonic' translator comment to the Enable button label - keybindingEditing.test.ts: fix test title grammar (a user) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Always enable system-wide keybindings; drop the enablement setting Removes the experimental `keyboard.enableSystemWideKeybindings` setting so the feature is always active: any user keybinding with "systemWide": true is a candidate. The one-time confirmation dialog is retained and now serves as the opt-out - its Enable/Disable choice is persisted as a tri-state consent (unset -> ask, granted -> register, denied -> stay off and never re-ask). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Make the first-run dialog an informational notice, not a permission prompt The system-wide keybindings feature is always on, so the first-run dialog no longer needs to grant/deny permission. Replace the Enable/Disable confirm dialog with a single-button informational notice ("I Understand") shown once before the first registration. Collapses the tri-state consent to a boolean acknowledged flag; the feature has no decline path, so there is no stuck off-state. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · dd611853 · 2026-07-01
- 1.1ETVFix persisted Agent Host MCP authentication (#327154) Restore persisted dynamic OAuth providers silently after extension host restarts while preserving consent and noninteractive client behavior. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 111cc987-c300-40e6-83f7-f5f524b35fedgithub.com-microsoft-vscode · 0fcfb104 · 2026-07-23
- 1.1ETVautomations: fix: automation startup readiness race (#326868) * Fix automation startup readiness race Defer automation runs until their session target and requested model are ready, then retry from deterministic readiness signals. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2db12056-f41c-49ba-88e2-0c82044adf64 * Honor folder-specific session type readiness Recheck folder-scoped types while waiting for model readiness and use URI identity semantics in target availability tests. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2db12056-f41c-49ba-88e2-0c82044adf64 --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · 68dfdd12 · 2026-07-22
- 0.9ETVnes: send periodic enhanced telemetry with overlapping recording windows (#319595) * nes: send periodic enhanced telemetry with overlapping recording windows Adds ContinuousEnhancedTelemetrySender which periodically ships a fixed-length slice (5 min) of DebugRecorder activity as an enhanced GH telemetry event, reusing the existing 'copilot-nes/provideInlineEdit' channel and tagging events with 'continuous: true' so the backend can route them. Adjacent slices are guaranteed to overlap by >= 30 s. With tick cadence INTERVAL = WINDOW - OVERLAP - HARD_CAP and a (idle, hard_cap) wait that mirrors the suggestion-anchored TelemetrySender, the slice always ends at a 'stable' moment so we don't capture mid-keystroke state. Slices with no actual edits are skipped. - DebugRecorder gains getLogInRange(from, to), with framing fast-forwarded so the emitted setContent reflects the document state at the slice start. - New experiment-gated setting chat.advanced.nes.continuousEnhancedTelemetry.enabled (default off). - Wired into InlineEditProviderFeature alongside TelemetrySender. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes: address PR review feedback - Fix config key mismatch: TS used 'chat.advanced.nes...' but package.json exposed 'chat.nes...', so user/experiment config was never read. Align the TS key with the package.json key. - Use DebugRecorder.getTimestamp() instead of Date.now() for the window end so edits whose recorded instant was bumped past Date.now() for total ordering aren't dropped at the boundary. - Drop unused 'at' parameter from the insertEdit test helper and clean up the call sites that were still passing a redundant timestamp. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes: drop config gate for continuous enhanced telemetry Per PR feedback: the existing GH enhanced-telemetry user controls are sufficient gating; no need for a dedicated setting. Removes: - chat.nes.continuousEnhancedTelemetry.enabled setting (package.json, package.nls.json, ConfigKey). - IConfigurationService + IExperimentationService dependencies from the sender; the loop now runs unconditionally for the sender's lifetime. - Two tests that exercised the config toggle. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes: clarify continuous telemetry semantics + drop misnamed field Subagent review findings: - Drop `activeDocumentRepository` for continuous events: a 5-min slice spans many docs over time, so there's no meaningful 'active' document. The full workspace repo set is reported via `repositories` already. - Rename `MAX_ENTRIES_BYTES` -> `MAX_ENTRIES_CHARS` (truth in advertising: it's `string.length` / UTF-16 code units, matching the existing suggestion- anchored recording cap). - Class-level doc: clarify that the overlap guarantee assumes timely scheduler execution; extension-host stalls / machine sleep / skipped empty slices can produce gaps. Treat `windowStart`/`windowEnd` as authoritative; don't infer contiguity from `sequenceNumber + 1`. - Doc that `sessionId` is per-sender-lifetime, and that the sender can be recreated within one extension session when `InlineEditProviderFeature`'s autorun reruns. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes: don't bump docVersion on selectionChanged in DebugRecorder Per PR review: `selectionChanged` entries have no `v` field in the schema (workspaceLog.ts:64), and production `WorkspaceRecorder` only bumps version on real document content changes via VS Code's model version. The replayer consumes `changed.v` directly when applying edits. Previously, `DebugRecorder` synthesized `v` and bumped it on every recorded event including selections, which produced phantom gaps in the `changed` version sequence (e.g. 2, 4, 5 instead of 2, 3, 4) that don't match what a real recording would contain. Fixed in both `getDocumentLog` and `getDocumentLogInRange`. Snapshot test updated; added a focused regression test asserting consecutive `changed` entries get consecutive `v` values regardless of interleaved selection changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes: drop caller reference from DebugRecorder.getLogInRange jsdoc Per PR review: low-level method docs shouldn't reference specific callers — they easily go stale. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes: clamp slice framing times + dedup upstream-remote helper Two PR review threads: 1. Slice framing times made misleading. `getDocumentLogInRange` was emitting `documentEncountered.time = creationTime` and `setContent.time = baseValueTime`, both of which can pre-date the requested `[fromTimeMs, toTimeMs]` window (a doc may have been open for hours). Now framing times are clamped up to `fromTimeMs` so the slice's per-event `time` contract holds. Documented the invariant and added a coverage test asserting every emitted time falls in range; updated the fast-forward test's expectation accordingly. 2. Upstream-remote extraction was copy-pasted in three places (twice in `nextEditProviderTelemetry.ts`, once in the new sender). Extracted to `getUpstreamRemote(repository)` in `platform/git/common/utils.ts` and reused everywhere. Behaviour preserved. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes: extract NES_GH_TELEMETRY_EVENT_NAME constant Per PR review: the literal 'copilot-nes/provideInlineEdit' was hardcoded in three call sites in nextEditProviderTelemetry.ts plus the new continuous sender. Extract into a named export from nextEditProviderTelemetry.ts (the file that already owns the event) and import it from the continuous sender so the relationship is explicit. Behaviour unchanged. Tests intentionally still use the literal string since they assert on the wire-level event name. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes: revert clamp of framing times in getDocumentLogInRange The clamp I added in b1d795c was wrong on three counts: 1. **Sort ambiguity**: clamping multiple docs' framing to `fromTimeMs` creates ties in the sortTime used by the cross-doc merge sort in `getLogInRange`. Ordering then depends on insertion order (i.e. map iteration order) instead of real time. Stable sort still preserves the per-doc framing-before-edits invariant, but the result becomes load-bearing on insertion order in a way the old code wasn't. 2. **Inconsistency with production**: `WorkspaceRecorder` (workspaceRecorder.ts:254) emits `documentEncountered`/`setContent`/ `opened` with their actual timestamps, never clamped to a window. The DebugRecorder slice should match that semantic. 3. **Worse for stitching**: with clamping, the same logical `documentEncountered` event gets a different time in each overlapping slice (fromTimeMs of that slice) — harder to dedup than the stable true creationTime. Revert the clamp; document that framing carries true creation/base-value times even when they pre-date `fromTimeMs`, and that consumers should treat any entry with `time < fromTimeMs` as framing. Drop the out-of-range test, restore the original setContent.time expectation in the fast-forward test. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes: harden continuous telemetry loop against subagent-found issues Subagent review (rounds: code-review HIGH + rubber-duck #2,#3,#8) found: 1. **Unhandled throw in _sendNow kills the loop forever.** RunOnceScheduler's runner has no try/catch, so an exception from JSON.stringify or the telemetry service would propagate out and never let reschedule() run. Fix: try/finally around _sendNow() so reschedule() always fires. Added regression test. 2. **cleanUpHistory() in getDocumentLogInRange races with fromTimeMs.** Cleanup uses getNow() - 5min as its cutoff. Between the caller computing windowEnd and the per-doc cleanup running, getNow() can advance enough that earliestTime > fromTimeMs, causing an edit at the leading edge of the requested range to be rotated into baseValue and dropped from the emitted slice. Fix: don't call cleanUpHistory() in this getter at all — the fast-forward loop already handles any base state, and the per-edit cleanup in handleEdit keeps memory bounded. 3. **Disposed idleStores accumulate in loopStore.** Calling idleStore.dispose() doesn't remove it from the parent's tracking Set, so dead inner stores leak one per ~4 min for the sender's lifetime. Fix: loopStore.delete(idleStore) instead. 4. **_sendNow() duration not in overlap math.** Added a doc caveat — the JSON.stringify cost is added to inter-send spacing but is well under 1 % of the 30 s overlap budget in practice. No code change. 5. **No test for doc opened after toTimeMs.** Added one. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · 67ac0eef · 2026-06-12
- 0.8ETVFix inline edit cache telemetry attribution Preserve model attribution on cached inline edit results without copying request-specific telemetry. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 79a2259b-1b96-461c-969d-95ddb965f75dgithub.com-microsoft-vscode · 34f6e514 · 2026-07-13
- 0.8ETVcopilot status bar hover: fix: status dashboard checkbox flicker (#325769) * Fix status dashboard checkbox flicker Keep the language completion tri-state synchronized with configured settings while preserving immediate feedback and serialized writes. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 089ad95e-853f-4c52-8a82-3b463b724cb8 * Fix status dashboard browser test Keep the regression test focused on the checkbox state, configured value, and override hint that this change owns. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 089ad95e-853f-4c52-8a82-3b463b724cb8 * Handle inherited completion overrides Remove language entries from every configured scope, resync the override hint after failed writes, and keep the browser regression test focused on owned state. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 089ad95e-853f-4c52-8a82-3b463b724cb8github.com-microsoft-vscode · 4980d698 · 2026-07-14
- 0.8ETVAdd Adhoc Request Sender Mode with Tag Highlighting (#323100) * Agent Host changes for agents/adhoc-request-sender-mode-extension-55e2bb6f * Remove unconfigured react-hooks/exhaustive-deps eslint directive The eslint-disable directive referenced a rule that isn't registered in this repo's ESLint config, which caused ESLint to error with "Definition for rule 'react-hooks/exhaustive-deps' was not found" and failed the Compile & Hygiene and Copilot - Test CI checks. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Coalesce adhoc tag-decoration rescans with requestAnimationFrame Rescanning the whole editor text on every content change is wasteful for bursty updates (e.g. a streamed response). Debounce the decoration update to at most once per animation frame and cancel any pending frame during cleanup so the callback can't run after the editor is disposed. The initial scan stays synchronous so tags are highlighted immediately on mount. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR feedback: dispose token source; validate adhoc request JSON - adhocRequestSender: always dispose the per-send CancellationTokenSource in the finally block (separate from the current-send guard) so its cancellation listeners don't leak across repeated Send/Stop cycles. - simulationMain: validate and normalize the adhoc request JSON before use so malformed input (missing/null/wrong-typed model/user/system) yields a focused error message instead of a thrown stack trace. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · a9757315 · 2026-06-26
- 0.8ETVNES: experiment-driven global token budget for the inline-edits prompt (#323948) * nes: fold currentFile budgeting into the global budget cascade Under the opt-in global budget experiment, the current file now draws its clip budget from the shared pool (its `shares.currentFile` slice of `totalTokens`) and donates whatever it does not use to the cascade as the initial surplus. When the global budget is disabled (prod default) behavior is byte-identical, and the new defaults (totalTokens 8000, shares in eighths) reproduce today's per-part `maxTokens` caps exactly. - xtabPromptOptions: add `GlobalBudgetSharePart`, `currentFileBudget()` and `validate()`; grow `shares` to include `currentFile`; bump `DEFAULT_TOTAL_TOKENS` to 8000 and rebalance `DEFAULT_SHARES`. - promptCrafting: seed the cascade's initial surplus from the current file's leftover budget; delegate validation to the namespace helper. - xtabProvider: size and clip the current file from the pool and compute the surplus, gated on `globalBudget` being defined. - Tests: volume-neutral invariant, `currentFileBudget`/`validate` units, and provider-level regression + new-behavior coverage. - Docs: rewrite globalBudgetCascade.md for the seeded-surplus design. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes: collapse global-budget settings into a single exp-driven JSON string Replace the two experiment-driven global-budget settings (globalBudget.enabled boolean + globalBudget.totalTokens number) with a single JSON-encoded string setting, modelled after modelConfigurationString, that defines totalTokens, order, and shares together. - configurationService: remove InlineEditsXtabGlobalBudgetEnabled and InlineEditsXtabGlobalBudgetTotalTokens; add InlineEditsXtabGlobalBudget (string | undefined, ExperimentBased, default undefined). - xtabPromptOptions: add GlobalBudgetOptions.VALIDATOR (all top-level fields optional; shares must be complete when present) and a pure GlobalBudgetOptions.fromConfigString(): Result<GlobalBudgetOptions, string> that JSON-parses, structurally validates, merges over the defaults, then runs the semantic validate(). Never throws. - xtabProvider: inject ITelemetryService; resolve the budget via getGlobalBudget(), returning undefined (disabled, identical to prod) when the string is unset/empty/invalid and emitting incorrectNesGlobalBudgetConfig telemetry on parse/validation failure. - Tests: migrate the provider global-budget tests to the JSON string and add fromConfigString unit tests. - Docs: rewrite the globalBudgetCascade.md Wiring section and migration note. No regression: an unset string keeps the byte-identical legacy path. '{}' enables the budget with the volume-neutral defaults; {"totalTokens":N} only overrides the pool size. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes: clip the current file last under a global budget to reuse cascade leftover Under a global budget the current file is now clipped LAST, sized to its base share plus whatever the budget cascade left unused (`currentFileBudget + finalSurplus`), so it trims less and reuses leftover budget. The cascade runs first (seeded with 0, the current file never donates) and is threaded into `getUserPrompt` via `precomputedCascade` so it renders exactly once. This replaces the earlier two-mode design: the opt-in `reuseLeftoverForCurrentFile` flag and the seeded-surplus "donate-forward" path are dropped, along with all `currentFileBudgetSurplus`/`initialSurplus` threading. Clip-last is now the single behavior under a global budget. The validator hardening (rejecting non-finite or negative `totalTokens`/shares) is kept. No production regression: when `globalBudget` is undefined the current file is still clipped to its own `currentFile.maxTokens` with the legacy await ordering, byte-identical to before. The global budget remains experiment-gated and off in prod. Tests and globalBudgetCascade.md updated for the clip-last-only behavior. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * nes: address review — restore nLinesOfCurrentFileInPrompt telemetry timing - xtabProvider: record setNLinesOfCurrentFileInPrompt inside both budget branches. In the legacy/prod branch the clip happens before the context-gathering awaits, so the telemetry call is moved back there to match prod timing exactly (it is still emitted when a request is cancelled mid-gathering). The clip-last branch records it after the cascade, as the clip is inherently last there. - xtabPromptOptions: fix two stale JSDoc blocks that still described the removed donate-forward behavior; describe clip-last instead. - globalBudgetCascade.md: correct the conservation bound to T·(Σ shares) and document the share-sum tolerance (over-allocation ≤ ~1e-3·T). - promptCrafting.spec: add a cascade test asserting finalSurplus shrinks as the cascade consumes budget (current file reuses less leftover). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * nes: fix stale DEFAULT_ORDER doc comment to say clip-last Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * nes: rename clipCurrentFileToBudget param to overriddenMaxTokens Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * nes: extract current-file clip + context gathering into a method Pulls the ~55-line global-budget/legacy if-else out of doGetNextEditWithSelection into a private gatherContextAndClipCurrentFile method returning Result<{ clippedTaggedCurrentDoc, areaAroundCodeToEdit, precomputedCascade, langCtx, neighborSnippets }, NoNextEditReason>. Behavior, clip-first/clip-last ordering, and nLinesOfCurrentFileInPrompt telemetry timing are unchanged. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * nes: recalibrate global-budget defaults to merged currentFile cap (1500) main (#322382) lowered currentFile.maxTokens 2000->1500, which broke the global-budget 'volume-neutral defaults' invariant (floor(total*share) must equal each part's legacy cap). Recalibrate DEFAULT_SHARES to cap/7500 and set DEFAULT_TOTAL_TOKENS to 7500 (the sum of the merged per-part caps: 1500 + 2000 + 2000 + 1000 + 1000), so shares still sum to exactly 1 and every part's base allocation reproduces its cap. finalSurplus stays 6000 (7500 - 1500). Update dependent specs (literal 8000 -> DEFAULT_TOTAL_TOKENS, stale 2000 cap comments -> 1500) and the design doc (defaults table, worked examples, effective caps, ordering caveat, migration note) for T=7500 and currentFile base 1500. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · 3073c2bb · 2026-07-02
- 0.6ETVPreserve Agent Host turn identity after cancellation (#326889) * agentHost: preserve turn identity after cancellation Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 682bdbda-f6ce-40c0-961e-52823f577143 * agentHost: harden stale turn filtering Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 682bdbda-f6ce-40c0-961e-52823f577143github.com-microsoft-vscode · 7e2c92ba · 2026-07-22
- 0.6ETVnes-datagen: stream multi-GB inputs/outputs and switch output to JSON Lines (#320089) * nes-datagen: stream large JSON array inputs to avoid 2 GiB readFile limit Reading the whole input via fs.readFile fails for files larger than 2 GiB (and exceeds V8's max string length). Add a streaming JSON-array parser and use it in both the sequential and parallel pipeline paths so multi-GB recordings can be processed with bounded memory. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes-datagen: also accept JSON Lines (NDJSON) input Auto-detect the input format from the first non-whitespace character: a leading '[' is parsed as a single JSON array, otherwise the file is parsed as JSON Lines (one JSON object per line). Both formats are streamed so multi-GB inputs work regardless of shape. Rename streamJsonArray -> streamJsonRecords to reflect the broader purpose. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes-datagen: infer JSON vs JSON Lines input format from file extension Use the file extension (.jsonl/.ndjson -> JSON Lines, otherwise JSON array) to select the streaming parser instead of sniffing the content. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes-datagen: validate streamed JSON arrays for truncation and malformed input The new streaming parser previously accepted any prefix of a JSON array silently: a truncated file (no closing ']'), a missing element between commas, a trailing comma or trailing data after the array all produced zero or fewer records rather than an error. That is especially dangerous for the multi-GB inputs this parser was introduced for, because the underlying file is much more likely to be incomplete. Tighten the state machine to surface these as errors, matching what the old whole-file JSON.parse would have done, and add tests for each case. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes-datagen: stream worker-result merging and final output write For multi-GB inputs the parent process was still hitting V8's ~512 MiB max-string-length limit in two places after the input-side fix: 1. Merging worker result files used fs.promises.readFile + JSON.parse on each result, but with a 5+ GB input split N ways each per-worker file is hundreds of MB of similar-shaped data and easily exceeds the string limit. 2. writeSamples serialized the entire validSamples array via a single JSON.stringify(arr, null, 2) before writing, which has the same problem on output. Switch both to stream over individual records: - A new shared openWriteStream(filePath) helper wraps fs.createWriteStream, attaches an 'error' listener immediately (so async write failures don't surface as uncaughtException and skip cleanup), awaits backpressure via the per-write callback, and exposes an idempotent close(). - writeChunkFiles uses the helper inside a try/finally so any mid-stream ENOSPC/EIO bubbles up cleanly and the tmp dir is still removed. - The merge step now uses streamJsonRecords<ISample>(resultPath), so the parent never materializes a single worker's output as one string. - writeSamples emits the output JSON array incrementally: per-sample JSON.stringify(..., null, 2) (indented two spaces to match the previous layout) joined with ',\n'. Byte size is accumulated for the existing IWriteResult.fileSize. Also documents that single-process loadAndParseInput still buffers the full row set in memory and that --parallelism is required for very large inputs (workers each only load their slice). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes-datagen: switch output to JSON Lines Both the final user-facing output and the per-worker intermediate result files now use JSON Lines (one record per line) instead of a pretty-printed JSON array. JSONL is dramatically simpler to write and read incrementally: no surrounding brackets/commas to track, no multi-line per-element indentation, just JSON.stringify + '\n' per record on the write side and split-on-newline + JSON.parse per non-empty line on the read side (this is what streamJsonRecords already does when it detects the .jsonl extension). Changes: - writeSamples emits one JSON.stringify(sample) + '\n' per validated sample via no array wrapper, no pretty-printing.openWriteStream - resolveOutputPath defaults the implicit output to <input>_output.jsonl (was <input>_output.json). - Per-worker result files in runInputPipelineParallel are now result_${w}.jsonl, so the merge step's streamJsonRecords auto-picks the JSONL parser from the extension. - E2e tests updated to read JSONL (split on newline, JSON.parse per line) and to use .jsonl output paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * nes-datagen: surface worker-result parse errors and update --out help text Two review follow-ups: 1. The merge step that streams each worker's result file used to wrap the iteration in a try/catch that downgraded any parse error to a console.error warning. With the new streaming reader that is unsafe: streamJsonRecords yields N valid records first and then throws on a malformed/truncated tail, leaving those N partial records already in allSamples. The pipeline would then quietly emit a truncated training-data output. Drop the swallowing try/catch so a corrupt worker result aborts the run non-zero. 2. The --out help text in simulationOptions.ts still advertised the old JSON-array default (<input>_output.json). Update it to reflect the JSONL output, and also note in --input that the format is inferred from the .jsonl/.ndjson extension. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · 02629fd4 · 2026-06-05
- 0.6ETVNES: split open-tab vs related-file neighbor context (#326626) Two behavior-preserving improvements to the xtab (NES) neighboring-files context, both keyed on distinguishing open-tab neighbors from language-service "related" files: 1. Related-file snippets omit line numbers in the prompt (matching NES's own language-context path); open-tab snippets keep them. 2. New neighborFiles.includeRelatedFiles option (default true) can disable the related-files context; when off, the related-files/LSP work is skipped entirely. Provenance is tagged once at the source: getNeighborFilesAndTraits stamps isFromRelatedFile on each related doc via isRelatedNeighboringFileType(type), getSimilarSnippets propagates it (and the source uri) onto every snippet and guarantees both on its return type, and SimilarFilesContextService reads the flag directly. Defaults are unchanged, so this is a no-op until the new exp key is flipped. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1bb7414b-49be-41eb-b86b-bc8d7a319268github.com-microsoft-vscode · 395f76c0 · 2026-07-20
- 0.6ETVnes: support neighbor files to be included in NES prompt Co-authored-by: Copilot <copilot@github.com>github.com-microsoft-vscode · 40cc75ec · 2026-04-26
- 0.5ETVnes: track originating model patch for streamed edits (#322573) PR #322438 allowed splitting one model-sent diff-patch into multiple LineReplacements, breaking the invariant that the Nth shown edit corresponded to the Nth model patch (progressive ghost-text reveal already broke it too). As a result, telemetry could no longer attribute a served edit back to the model patch it came from. Stamp a 0-based `patchIndex` on each Patch in extractEdits, thread it through the streamed-edit -> cache -> telemetry pipeline, and emit a new `sourcePatchIndex` telemetry measurement. All fragments produced from the same patch (diff splitting or ghost-text early + continuation) share the index. The field is optional since the edit-window and INSERT response formats have no patch structure. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · 0035fb2e · 2026-06-23
- 0.5ETVNES: yield additive cursor-line edit first for multi-line patches (#324904) * NES: add exp config to yield additive cursor-line edit first for multi-line patches For diff-patch responses, the progressive ghost-text reveal emits the cursor-line edit ASAP when it additively changes the cursor line, but previously only for patches removing a single line. Extend it to fire for multi-removed-line first patches behind a new experiment config `chat.advanced.inlineEdits.xtabProvider.patchFastYieldLineWithCursorMultiLine` (default off): the additive cursor-line change (removed[0] -> added[0]) is yielded immediately and the remaining removed/added lines stream as a continuation. The early edit is a 1-for-1 additive replacement, so it causes no line shift and the continuation (anchored at cursorLine+1 over the original document) stays correctly anchored — the union is byte-identical to the original patch. Multi-line reveal is restricted to duplicate-additions modes that preserve a patch's removed range (Off / TrimDuplicate); DropPatch/DropAllRemaining could skip the continuation after the early edit was already emitted. The early reveal edit is additionally excluded from the duplicate-additions policy: it carries no re-emitted context to trim, and running the policy on it could spuriously trim its added line to empty and emit a cursor-line deletion when that line coincides with the line below the cursor (cascade edits). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Refactor NES multi-line reveal handler for readability Behavior-preserving cleanup of the diff-patch progressive-reveal logic in xtabPatchResponseHandler.ts. No functional change (75/75 spec tests pass unchanged). - Extract named policy helpers: duplicateModePreservesRemovedRange, allowsMultiLineProgressiveReveal, and shouldApplyDuplicatePolicy (a type guard that preserves the Exclude<..., Off> narrowing for applyDuplicatePolicy). - Add Patch.progressiveRevealParts() factory that owns the early/continuation split invariants; remove the misleading Patch.insertion helper (it built non-insertions for the multi-line case). - Split isGhostTextPatch into early returns plus a named isEmptyCursorLineShiftUp predicate for the empty-cursor-line shift-up guard. - Relocate long rationale comments into helper JSDoc so the streaming loop reads top-to-bottom. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · 953f1f48 · 2026-07-08
- 0.5ETVnes: fix: NES cached suggestion not shown after rebasing over user indentation (#326537) * Fix NES cached suggestion not shown after rebasing over user indentation When a cached NES suggestion is a line-based insertion that restates the line's indentation (e.g. predicting " return [" on an empty body line) and the user tabs to indent that line, tryRebaseCacheEntry served the raw, non-minimized edit whose range spans the indentation the user already typed. That edit is not a clean at-cursor insertion, so the core inline-completions renderer drops it and the cached suggestion is silently not shown. Minimize the served rebased edit via removeCommonSuffixAndPrefix so the indentation the user already typed is stripped, yielding a clean at-cursor insertion that renders as ghost text. This is semantically neutral (same apply() result on the current document) and idempotent for the downstream isRejectedNextEdit check. Minimizing is done at the cache serving layer rather than in editRebase, which intentionally keeps the full line edit for response/telemetry fidelity. Adds a regression test covering the empty-line + tab scenario. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 02c9dab3-1534-4b24-86c1-410c66e9d550 * Salvage NES suggestion on rebaseFailed for indentation mismatch The previous commit minimized the served edit in the rebase *success* branch, but that path already renders as ghost text, so the change was a semantic no-op and its test modeled an artificial success path. The real bug is in the rebase *failure* path: strict rebase matches indentation literally, so when the user re-types a line's leading whitespace differently than the model predicted (e.g. pressing Tab to insert a tab character, or a different number of spaces, on an empty body line), the whole suggestion is silently dropped and nothing is shown. Salvage that case in the cache layer: on `rebaseFailed`, re-anchor the model's still-valid content as a clean at-cursor insertion that respects the indentation the user actually typed. This mirrors the reconciliation the engine already performs when the indentation matches, is a faithful representation of the model's intent (so it upholds the display layer's soundness invariant), and only fires when the suggestion would otherwise be dropped. Revert the no-op minimization and replace the misleading regression test with a faithful one covering the tab-character drop scenario (which fails without this salvage). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 02c9dab3-1534-4b24-86c1-410c66e9d550 * Gate NES indentation-mismatch salvage behind a setting Put the rebaseFailed re-anchoring behavior behind a new team-internal, experiment-based setting `chat.advanced.inlineEdits.reanchorContentOnIndentationMismatch` (default off) so it can be rolled out or disabled independently. Thread the flag through `NesRebaseConfigs` (built in `_getNesRebaseConfigs`) and gate the `tryReanchorContentAfterIndentation` salvage call on it. Add a regression test asserting the suggestion is dropped when the setting is disabled, alongside the existing salvage test with it enabled. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 02c9dab3-1534-4b24-86c1-410c66e9d550 --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · ae0e51e8 · 2026-07-20
- 0.4ETVNES: cache cross-file suggestions under the active document (#323150) * NES: cache cross-file suggestions under the active document When the model returns a Next Edit Suggestion for a document other than the one being edited (cross-file NES), it was only cached under the target document, so it could not be re-served until the user navigated there. Also cache an `activeDoc (content + edit window) -> edit-in-target` association so the suggestion can be re-served from cache while the cursor is still in the active document. A cross-file entry is served only while its target document is open and byte-identical to the snapshot the edit's offsets index into; otherwise the read path treats it as a cache miss and refetches, rather than serving a misplaced edit or getting stuck re-serving a dead entry until the active document changes. At stream end the active document is no longer cached as "no edit" when a cross-file entry was just stored under the same key, which would otherwise clobber it. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Dispose provider and documents in runCrossFileScenario Tear down the NextEditProvider (which registers autoruns/watchers on openDocuments) and both documents at the end of each cross-file scenario run so the tests are self-contained and do not accumulate observers. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · 4fc2b334 · 2026-06-27