diff --git a/extensions/copilot/package.json b/extensions/copilot/package.json index e76c8aa237f..76e5801e04d 100644 --- a/extensions/copilot/package.json +++ b/extensions/copilot/package.json @@ -2426,6 +2426,20 @@ "markdownDescription": "%github.copilot.nextEditSuggestions.enabled%", "scope": "language-overridable" }, + "github.copilot.nextEditSuggestions.nextCursorPrediction.enabled": { + "type": "string", + "enum": [ + "off", + "onlyWithEdit", + "jump" + ], + "default": "off", + "tags": [ + "nextEditSuggestions", + "onExp" + ], + "markdownDescription": "%github.copilot.nextEditSuggestions.nextCursorPrediction.enabled%" + }, "github.copilot.nextEditSuggestions.fixes": { "type": "boolean", "default": true, @@ -5198,4 +5212,4 @@ "string_decoder": "npm:string_decoder@1.2.0", "node-gyp": "npm:node-gyp@10.3.1" } -} \ No newline at end of file +} diff --git a/extensions/copilot/package.nls.json b/extensions/copilot/package.nls.json index 73536fcfa77..163d50a4bf7 100644 --- a/extensions/copilot/package.nls.json +++ b/extensions/copilot/package.nls.json @@ -91,6 +91,7 @@ "github.copilot.config.edits.enabled": "Whether to enable the Copilot Edits feature.", "github.copilot.config.codesearch.enabled": "Whether to enable agentic codesearch when using `#codebase`.", "github.copilot.nextEditSuggestions.enabled": "Whether to enable next edit suggestions (NES).\n\nNES can propose a next edit based on your recent changes. [Learn more](https://aka.ms/vscode-nes) about next edit suggestions.", + "github.copilot.nextEditSuggestions.nextCursorPrediction.enabled": "Controls when next cursor line prediction is enabled for next edit suggestions (NES).\n\n- `off`: Disable next cursor line prediction.\n- `onlyWithEdit` (recommended): Enable next cursor line prediction only when an edit is proposed.\n- `jump`: Always enable next cursor line prediction, even if no edit is proposed.", "github.copilot.nextEditSuggestions.fixes": "Whether to offer fixes for diagnostics via next edit suggestions (NES).", "github.copilot.nextEditSuggestions.allowWhitespaceOnlyChanges": "Whether to allow whitespace-only changes be proposed by next edit suggestions (NES).", "github.copilot.chat.copilotDebugCommand.enabled": "Whether the `copilot-debug` command is enabled in the terminal.", diff --git a/extensions/copilot/src/extension/configuration/vscode-node/configurationMigration.ts b/extensions/copilot/src/extension/configuration/vscode-node/configurationMigration.ts index 05fc663dc0a..13c2ca0c582 100644 --- a/extensions/copilot/src/extension/configuration/vscode-node/configurationMigration.ts +++ b/extensions/copilot/src/extension/configuration/vscode-node/configurationMigration.ts @@ -11,6 +11,7 @@ import { ConfigurationTarget, l10n, Uri, window, workspace, WorkspaceFolder } from 'vscode'; import { ConfigurationKeyValuePairs, ConfigurationMigration, ConfigurationMigrationRegistry, ConfigurationValue } from '../../../platform/configuration/common/configurationService'; +import { NextCursorLinePrediction } from '../../../platform/inlineEdits/common/dataTypes/nextCursorLinePrediction'; import { DisposableStore, IDisposable } from '../../../util/vs/base/common/lifecycle'; import { IExtensionContribution } from '../../common/contributions'; @@ -160,3 +161,18 @@ ConfigurationMigrationRegistry.registerConfigurationMigrations([{ ]; } }]); + +ConfigurationMigrationRegistry.registerConfigurationMigrations([{ + key: 'github.copilot.chat.advanced.inlineEdits.nextCursorPrediction.enabled', + migrateFn: async (value: NextCursorLinePrediction | /* the rest is for backward compat: */ 'labelOnlyWithEdit' | boolean | undefined) => { + if (typeof value === 'boolean') { + value = value ? NextCursorLinePrediction.OnlyWithEdit : NextCursorLinePrediction.Off; + } else if (value === 'labelOnlyWithEdit') { + value = NextCursorLinePrediction.OnlyWithEdit; + } + return [ + ['github.copilot.nextEditSuggestions.nextCursorPrediction.enabled', { value }], + ['github.copilot.chat.advanced.inlineEdits.nextCursorPrediction.enabled', { value: undefined }] + ]; + } +}]); diff --git a/extensions/copilot/src/extension/xtab/node/xtabNextCursorPredictor.ts b/extensions/copilot/src/extension/xtab/node/xtabNextCursorPredictor.ts index 0f1654ac4b5..0049411fd2c 100644 --- a/extensions/copilot/src/extension/xtab/node/xtabNextCursorPredictor.ts +++ b/extensions/copilot/src/extension/xtab/node/xtabNextCursorPredictor.ts @@ -43,23 +43,14 @@ export class XtabNextCursorPredictor { return undefined; } - const originalNextCursorLinePrediction = this.configService.getExperimentBasedConfig(ConfigKey.TeamInternal.InlineEditsNextCursorPredictionEnabled, this.expService); + const originalNextCursorLinePrediction = this.configService.getExperimentBasedConfig(ConfigKey.InlineEditsNextCursorPredictionEnabled, this.expService); switch (originalNextCursorLinePrediction) { case NextCursorLinePrediction.OnlyWithEdit: case NextCursorLinePrediction.Jump: - case undefined: + case NextCursorLinePrediction.Off: return originalNextCursorLinePrediction; - // remove support for LabelOnlyWithEdit - case NextCursorLinePrediction.LabelOnlyWithEdit: - return NextCursorLinePrediction.OnlyWithEdit; - - // for backward compatibility - case true: - return NextCursorLinePrediction.OnlyWithEdit; - case false: - return undefined; default: assertNever(originalNextCursorLinePrediction); } diff --git a/extensions/copilot/src/extension/xtab/node/xtabProvider.ts b/extensions/copilot/src/extension/xtab/node/xtabProvider.ts index ea8f043ee60..a687a7ecce9 100644 --- a/extensions/copilot/src/extension/xtab/node/xtabProvider.ts +++ b/extensions/copilot/src/extension/xtab/node/xtabProvider.ts @@ -827,7 +827,7 @@ export class XtabProvider implements IStatelessNextEditProvider { } const nextCursorLinePrediction = this.nextCursorPredictor.determineEnablement(); - if (nextCursorLinePrediction !== undefined && retryState === RetryState.NotRetrying) { + if (nextCursorLinePrediction !== undefined && retryState === RetryState.NotRetrying && nextCursorLinePrediction !== NextCursorLinePrediction.Off) { const nextCursorLineR = await this.nextCursorPredictor.predictNextCursorPosition(promptPieces, tracer); if (cancellationToken.isCancellationRequested) { pushEdit(Result.error(new NoNextEditReason.NoSuggestions(request.documentBeforeEdits, editWindow))); @@ -861,8 +861,7 @@ export class XtabProvider implements IStatelessNextEditProvider { pushEdit(Result.error(new NoNextEditReason.NoSuggestions(request.documentBeforeEdits, editWindow, nextCursorPosition))); return; } - case NextCursorLinePrediction.OnlyWithEdit: - case NextCursorLinePrediction.LabelOnlyWithEdit: { + case NextCursorLinePrediction.OnlyWithEdit: { this.doGetNextEditWithSelection( request, new Range(nextCursorLineOneBased, nextCursorColumn, nextCursorLineOneBased, nextCursorColumn), diff --git a/extensions/copilot/src/extension/xtab/test/node/xtabNextCursorPredictor.spec.ts b/extensions/copilot/src/extension/xtab/test/node/xtabNextCursorPredictor.spec.ts index 63fbb098432..0949f10846c 100644 --- a/extensions/copilot/src/extension/xtab/test/node/xtabNextCursorPredictor.spec.ts +++ b/extensions/copilot/src/extension/xtab/test/node/xtabNextCursorPredictor.spec.ts @@ -100,7 +100,7 @@ describe('XtabNextCursorPredictor', () => { // Enable the next cursor prediction feature const configService = accessor.get(IConfigurationService); - configService.setConfig(ConfigKey.TeamInternal.InlineEditsNextCursorPredictionEnabled, NextCursorLinePrediction.OnlyWithEdit); + configService.setConfig(ConfigKey.InlineEditsNextCursorPredictionEnabled, NextCursorLinePrediction.OnlyWithEdit); configService.setConfig(ConfigKey.TeamInternal.InlineEditsNextCursorPredictionModelName, 'test-model'); }); diff --git a/extensions/copilot/src/platform/configuration/common/configurationService.ts b/extensions/copilot/src/platform/configuration/common/configurationService.ts index 9503517edad..2938b21a0b3 100644 --- a/extensions/copilot/src/platform/configuration/common/configurationService.ts +++ b/extensions/copilot/src/platform/configuration/common/configurationService.ts @@ -755,7 +755,6 @@ export namespace ConfigKey { export const InlineEditsDebounceOnSelectionChange = defineTeamInternalSetting('chat.advanced.inlineEdits.debounceOnSelectionChange', ConfigType.ExperimentBased, undefined); export const InlineEditsProviderId = defineTeamInternalSetting('chat.advanced.inlineEdits.providerId', ConfigType.ExperimentBased, undefined); export const InlineEditsUnification = defineTeamInternalSetting('chat.advanced.inlineEdits.unification', ConfigType.ExperimentBased, false); - export const InlineEditsNextCursorPredictionEnabled = defineTeamInternalSetting('chat.advanced.inlineEdits.nextCursorPrediction.enabled', ConfigType.ExperimentBased, { defaultValue: undefined, teamDefaultValue: NextCursorLinePrediction.OnlyWithEdit, owner: 'ulugbekna', expirationDate: '2026-01-18' }); export const InlineEditsNextCursorPredictionModelName = defineTeamInternalSetting('chat.advanced.inlineEdits.nextCursorPrediction.modelName', ConfigType.ExperimentBased, 'copilot-suggestions-himalia-001'); export const InlineEditsNextCursorPredictionMaxResponseTokens = defineTeamInternalSetting('chat.advanced.inlineEdits.nextCursorPrediction.maxResponseTokens', ConfigType.ExperimentBased, 4); export const InlineEditsNextCursorPredictionLintOptionsString = defineTeamInternalSetting('chat.advanced.inlineEdits.nextCursorPrediction.lintOptionsString', ConfigType.ExperimentBased, undefined); @@ -873,6 +872,7 @@ export namespace ConfigKey { export const InlineEditsEnabled = defineSetting('nextEditSuggestions.enabled', ConfigType.ExperimentBased, false); export const InlineEditsEnableDiagnosticsProvider = defineSetting('nextEditSuggestions.fixes', ConfigType.ExperimentBased, true); export const InlineEditsAllowWhitespaceOnlyChanges = defineSetting('nextEditSuggestions.allowWhitespaceOnlyChanges', ConfigType.ExperimentBased, true); + export const InlineEditsNextCursorPredictionEnabled = defineSetting('nextEditSuggestions.nextCursorPrediction.enabled', ConfigType.ExperimentBased, NextCursorLinePrediction.Off); export const NewWorkspaceCreationAgentEnabled = defineSetting('chat.newWorkspaceCreation.enabled', ConfigType.Simple, true); export const NewWorkspaceUseContext7 = defineSetting('chat.newWorkspace.useContext7', ConfigType.Simple, false); export const SummarizeAgentConversationHistory = defineSetting('chat.summarizeAgentConversationHistory.enabled', ConfigType.Simple, true); diff --git a/extensions/copilot/src/platform/inlineEdits/common/dataTypes/nextCursorLinePrediction.ts b/extensions/copilot/src/platform/inlineEdits/common/dataTypes/nextCursorLinePrediction.ts index dbfc5ca9601..f099fb4cac4 100644 --- a/extensions/copilot/src/platform/inlineEdits/common/dataTypes/nextCursorLinePrediction.ts +++ b/extensions/copilot/src/platform/inlineEdits/common/dataTypes/nextCursorLinePrediction.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ export enum NextCursorLinePrediction { + Off = 'off', Jump = 'jump', OnlyWithEdit = 'onlyWithEdit', - LabelOnlyWithEdit = 'labelOnlyWithEdit', }