Skip to content

Commit be6925a

Browse files
committed
nes: support /models on proxy and model picker
1 parent aa3d1d3 commit be6925a

File tree

12 files changed

+425
-51
lines changed

12 files changed

+425
-51
lines changed

package.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4004,6 +4004,16 @@
40044004
"onExp"
40054005
]
40064006
},
4007+
"github.copilot.nextEditSuggestions.preferredModel": {
4008+
"type": "string",
4009+
"default": "none",
4010+
"markdownDescription": "%github.copilot.config.nextEditSuggestions.preferredModel%",
4011+
"tags": [
4012+
"advanced",
4013+
"experimental",
4014+
"onExp"
4015+
]
4016+
},
40074017
"github.copilot.chat.suggestRelatedFilesFromGitHistory.useEmbeddings": {
40084018
"type": "boolean",
40094019
"default": false,

package.nls.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,7 @@
409409
"github.copilot.config.inlineEdits.nextCursorPrediction.displayLine": "Display predicted cursor line for next edit suggestions.",
410410
"github.copilot.config.inlineEdits.nextCursorPrediction.currentFileMaxTokens": "Maximum tokens for current file in next cursor prediction.",
411411
"github.copilot.config.inlineEdits.renameSymbolSuggestions": "Enable rename symbol suggestions in inline edits.",
412+
"github.copilot.nextEditSuggestions.preferredModel": "Preferred model for next edit suggestions.",
412413
"github.copilot.command.refreshAgentSessions": "Refresh Agent Sessions",
413414
"github.copilot.command.deleteAgentSession": "Delete Agent Session",
414415
"github.copilot.command.cli.sessions.resumeInTerminal": "Resume Agent Session in Terminal",

src/extension/extension/vscode-node/services.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ import { IIgnoreService, NullIgnoreService } from '../../../platform/ignore/comm
3434
import { VsCodeIgnoreService } from '../../../platform/ignore/vscode-node/ignoreService';
3535
import { IImageService } from '../../../platform/image/common/imageService';
3636
import { ImageServiceImpl } from '../../../platform/image/node/imageServiceImpl';
37+
import { IInlineEditsModelService } from '../../../platform/inlineEdits/common/inlineEditsModelService';
38+
import { InlineEditsModelService } from '../../../platform/inlineEdits/node/inlineEditsModelService';
3739
import { ILanguageContextProviderService } from '../../../platform/languageContextProvider/common/languageContextProviderService';
3840
import { ILanguageContextService } from '../../../platform/languageServer/common/languageContextService';
3941
import { ICompletionsFetchService } from '../../../platform/nesFetch/common/completionsFetchService';
@@ -204,6 +206,7 @@ export function registerServices(builder: IInstantiationServiceBuilder, extensio
204206
builder.define(ITodoListContextProvider, new SyncDescriptor(TodoListContextProvider));
205207
builder.define(IGithubAvailableEmbeddingTypesService, new SyncDescriptor(GithubAvailableEmbeddingTypesService));
206208
builder.define(IRerankerService, new SyncDescriptor(RerankerService));
209+
builder.define(IInlineEditsModelService, new SyncDescriptor(InlineEditsModelService));
207210
}
208211

209212
function setupMSFTExperimentationService(builder: IInstantiationServiceBuilder, extensionContext: ExtensionContext) {

src/extension/inlineEdits/vscode-node/inlineCompletionProvider.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import { CancellationToken, Command, EndOfLine, InlineCompletionContext, InlineCompletionDisplayLocation, InlineCompletionDisplayLocationKind, InlineCompletionEndOfLifeReason, InlineCompletionEndOfLifeReasonKind, InlineCompletionItem, InlineCompletionItemProvider, InlineCompletionList, InlineCompletionsDisposeReason, InlineCompletionsDisposeReasonKind, NotebookCell, NotebookCellKind, Position, Range, TextDocument, TextDocumentShowOptions, Event as vscodeEvent, window, workspace } from 'vscode';
76
import * as l10n from '@vscode/l10n';
7+
import { CancellationToken, Command, EndOfLine, InlineCompletionContext, InlineCompletionDisplayLocation, InlineCompletionDisplayLocationKind, InlineCompletionEndOfLifeReason, InlineCompletionEndOfLifeReasonKind, InlineCompletionItem, InlineCompletionItemProvider, InlineCompletionList, InlineCompletionModelInfo, InlineCompletionsDisposeReason, InlineCompletionsDisposeReasonKind, NotebookCell, NotebookCellKind, Position, Range, TextDocument, TextDocumentShowOptions, Event as vscodeEvent, window, workspace } from 'vscode';
88
import { ConfigKey, IConfigurationService } from '../../../platform/configuration/common/configurationService';
99
import { IDiffService } from '../../../platform/diff/common/diffService';
1010
import { stringEditFromDiff } from '../../../platform/editing/common/edit';
@@ -13,6 +13,7 @@ import { EditSurvivalReporter } from '../../../platform/editSurvivalTracking/com
1313
import { IGitExtensionService } from '../../../platform/git/common/gitExtensionService';
1414
import { DocumentId } from '../../../platform/inlineEdits/common/dataTypes/documentId';
1515
import { InlineEditRequestLogContext } from '../../../platform/inlineEdits/common/inlineEditLogContext';
16+
import { IInlineEditsModelService } from '../../../platform/inlineEdits/common/inlineEditsModelService';
1617
import { ShowNextEditPreference } from '../../../platform/inlineEdits/common/statelessNextEditProvider';
1718
import { shortenOpportunityId } from '../../../platform/inlineEdits/common/utils/utils';
1819
import { ILogService } from '../../../platform/log/common/logService';
@@ -27,7 +28,8 @@ import { findCell, findNotebook, isNotebookCell } from '../../../util/common/not
2728
import { ITracer, createTracer } from '../../../util/common/tracing';
2829
import { raceCancellation, timeout } from '../../../util/vs/base/common/async';
2930
import { CancellationTokenSource } from '../../../util/vs/base/common/cancellation';
30-
import { Event } from '../../../util/vs/base/common/event';
31+
import { Emitter, Event } from '../../../util/vs/base/common/event';
32+
import { Disposable } from '../../../util/vs/base/common/lifecycle';
3133
import { IObservable } from '../../../util/vs/base/common/observable';
3234
import { basename } from '../../../util/vs/base/common/path';
3335
import { StringEdit } from '../../../util/vs/editor/common/core/edits/stringEdit';
@@ -101,7 +103,7 @@ function isLlmCompletionInfo(item: NesCompletionInfo): item is LlmCompletionInfo
101103
const GoToNextEdit = l10n.t('Go To Inline Suggestion');
102104

103105

104-
export class InlineCompletionProviderImpl implements InlineCompletionItemProvider {
106+
export class InlineCompletionProviderImpl extends Disposable implements InlineCompletionItemProvider {
105107
public readonly displayName = 'Inline Suggestion';
106108

107109
private readonly _tracer: ITracer;
@@ -110,6 +112,13 @@ export class InlineCompletionProviderImpl implements InlineCompletionItemProvide
110112
public readonly handleDidPartiallyAcceptCompletionItem = undefined;
111113
public readonly handleDidRejectCompletionItem = undefined;
112114

115+
public modelInfo: InlineCompletionModelInfo | undefined;
116+
117+
private readonly _onDidChangeModelInfo = this._register(new Emitter<void>());
118+
public onDidChangeModelInfo = this._onDidChangeModelInfo.event;
119+
120+
public setCurrentModelId: ((modelId: string) => Thenable<void>) | undefined;
121+
113122
private readonly _displayNextEditorNES: boolean;
114123
private readonly _renameSymbolSuggestions: IObservable<boolean>;
115124

@@ -129,10 +138,19 @@ export class InlineCompletionProviderImpl implements InlineCompletionItemProvide
129138
@INotebookService private readonly _notebookService: INotebookService,
130139
@IWorkspaceService private readonly _workspaceService: IWorkspaceService,
131140
@IRequestLogger private readonly _requestLogger: IRequestLogger,
141+
@IInlineEditsModelService private readonly _modelService: IInlineEditsModelService,
132142
) {
143+
super();
133144
this._tracer = createTracer(['NES', 'Provider'], (s) => this._logService.trace(s));
134145
this._displayNextEditorNES = this._configurationService.getExperimentBasedConfig(ConfigKey.Advanced.UseAlternativeNESNotebookFormat, this._expService);
135146
this._renameSymbolSuggestions = this._configurationService.getExperimentBasedConfigObservable(ConfigKey.Advanced.InlineEditsRenameSymbolSuggestions, this._expService);
147+
148+
this.modelInfo = this._modelService.modelInfo;
149+
this._modelService.onModelListUpdated(() => {
150+
this.modelInfo = this._modelService.modelInfo;
151+
this._onDidChangeModelInfo.fire();
152+
});
153+
this.setCurrentModelId = (modelId: string) => this._modelService.setCurrentModelId(modelId);
136154
}
137155

138156
// copied from `vscodeWorkspace.ts` `DocumentFilter#_enabledLanguages`

src/extension/test/node/services.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import { IGitExtensionService } from '../../../platform/git/common/gitExtensionS
1919
import { IGitService } from '../../../platform/git/common/gitService';
2020
import { NullGitDiffService } from '../../../platform/git/common/nullGitDiffService';
2121
import { NullGitExtensionService } from '../../../platform/git/common/nullGitExtensionService';
22+
import { IInlineEditsModelService } from '../../../platform/inlineEdits/common/inlineEditsModelService';
23+
import { InlineEditsModelService } from '../../../platform/inlineEdits/node/inlineEditsModelService';
2224
import { ILogService } from '../../../platform/log/common/logService';
2325
import { EditLogService, IEditLogService } from '../../../platform/multiFileEdit/common/editLogService';
2426
import { IMultiFileEditInternalTelemetryService, MultiFileEditInternalTelemetryService } from '../../../platform/multiFileEdit/common/multiFileEditQualityTelemetry';
@@ -94,6 +96,7 @@ export function createExtensionUnitTestingServices(disposables: Pick<DisposableS
9496
testingServiceCollection.define(IToolsService, new SyncDescriptor(TestToolsService, [new Set()]));
9597
testingServiceCollection.define(IClaudeCodeSdkService, new SyncDescriptor(MockClaudeCodeSdkService));
9698
testingServiceCollection.define(IEditLogService, new SyncDescriptor(EditLogService));
99+
testingServiceCollection.define(IInlineEditsModelService, new SyncDescriptor(InlineEditsModelService));
97100
testingServiceCollection.define(IMultiFileEditInternalTelemetryService, new SyncDescriptor(MultiFileEditInternalTelemetryService));
98101
testingServiceCollection.define(ICodeMapperService, new SyncDescriptor(CodeMapperService));
99102
testingServiceCollection.define(IAlternativeNotebookContentService, new SyncDescriptor(SimulationAlternativeNotebookContentService));

src/extension/test/vscode-node/services.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ import { IOctoKitService } from '../../../platform/github/common/githubService';
4343
import { OctoKitService } from '../../../platform/github/common/octoKitServiceImpl';
4444
import { IIgnoreService, NullIgnoreService } from '../../../platform/ignore/common/ignoreService';
4545
import { IImageService, nullImageService } from '../../../platform/image/common/imageService';
46+
import { IInlineEditsModelService } from '../../../platform/inlineEdits/common/inlineEditsModelService';
47+
import { InlineEditsModelService } from '../../../platform/inlineEdits/node/inlineEditsModelService';
4648
import { ILanguageDiagnosticsService } from '../../../platform/languages/common/languageDiagnosticsService';
4749
import { ILanguageFeaturesService, NoopLanguageFeaturesService } from '../../../platform/languages/common/languageFeaturesService';
4850
import { LanguageDiagnosticsServiceImpl } from '../../../platform/languages/vscode/languageDiagnosticsServiceImpl';
@@ -187,6 +189,7 @@ export function createExtensionTestingServices(): TestingServiceCollection {
187189
testingServiceCollection.define(IToolGroupingService, new SyncDescriptor(ToolGroupingService));
188190
testingServiceCollection.define(ITodoListContextProvider, new SyncDescriptor(TodoListContextProvider));
189191
testingServiceCollection.define(IGithubAvailableEmbeddingTypesService, new SyncDescriptor(GithubAvailableEmbeddingTypesService));
192+
testingServiceCollection.define(IInlineEditsModelService, new SyncDescriptor(InlineEditsModelService));
190193

191194
return testingServiceCollection;
192195
}

src/extension/xtab/node/xtabProvider.ts

Lines changed: 5 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import { Raw } from '@vscode/prompt-tsx';
77
import { FetchStreamSource } from '../../../platform/chat/common/chatMLFetcher';
88
import { ChatFetchError, ChatFetchResponseType, ChatLocation } from '../../../platform/chat/common/commonTypes';
9-
import { ConfigKey, ExperimentBasedConfig, IConfigurationService, XTabProviderId } from '../../../platform/configuration/common/configurationService';
9+
import { ConfigKey, IConfigurationService, XTabProviderId } from '../../../platform/configuration/common/configurationService';
1010
import { IDiffService } from '../../../platform/diff/common/diffService';
1111
import { ChatEndpoint } from '../../../platform/endpoint/node/chatEndpoint';
1212
import { createProxyXtabEndpoint } from '../../../platform/endpoint/node/proxyXtabEndpoint';
@@ -18,6 +18,7 @@ import { NextCursorLinePrediction } from '../../../platform/inlineEdits/common/d
1818
import * as xtabPromptOptions from '../../../platform/inlineEdits/common/dataTypes/xtabPromptOptions';
1919
import { LanguageContextLanguages, LanguageContextOptions } from '../../../platform/inlineEdits/common/dataTypes/xtabPromptOptions';
2020
import { InlineEditRequestLogContext } from '../../../platform/inlineEdits/common/inlineEditLogContext';
21+
import { IInlineEditsModelService } from '../../../platform/inlineEdits/common/inlineEditsModelService';
2122
import { ResponseProcessor } from '../../../platform/inlineEdits/common/responseProcessor';
2223
import { IStatelessNextEditProvider, NoNextEditReason, PushEdit, ShowNextEditPreference, StatelessNextEditDocument, StatelessNextEditRequest, StatelessNextEditResult, StatelessNextEditTelemetryBuilder } from '../../../platform/inlineEdits/common/statelessNextEditProvider';
2324
import { editWouldDeleteWhatWasJustInserted, editWouldDeleteWhatWasJustInserted2, IgnoreEmptyLineAndLeadingTrailingWhitespaceChanges, IgnoreWhitespaceOnlyChanges } from '../../../platform/inlineEdits/common/statelessNextEditProviders';
@@ -28,7 +29,6 @@ import { OptionalChatRequestParams, Prediction } from '../../../platform/network
2829
import { IChatEndpoint } from '../../../platform/networking/common/networking';
2930
import { ISimulationTestContext } from '../../../platform/simulationTestContext/common/simulationTestContext';
3031
import { IExperimentationService } from '../../../platform/telemetry/common/nullExperimentationService';
31-
import { ITelemetryService } from '../../../platform/telemetry/common/telemetry';
3232
import { IWorkspaceService } from '../../../platform/workspace/common/workspaceService';
3333
import { raceFilter } from '../../../util/common/async';
3434
import * as errors from '../../../util/common/errors';
@@ -83,6 +83,7 @@ export class XtabProvider implements IStatelessNextEditProvider {
8383
private nextCursorPredictor: XtabNextCursorPredictor;
8484

8585
constructor(
86+
@IInlineEditsModelService private readonly modelService: IInlineEditsModelService,
8687
@ISimulationTestContext private readonly simulationCtx: ISimulationTestContext,
8788
@IInstantiationService private readonly instaService: IInstantiationService,
8889
@IWorkspaceService private readonly workspaceService: IWorkspaceService,
@@ -92,7 +93,6 @@ export class XtabProvider implements IStatelessNextEditProvider {
9293
@ILanguageContextProviderService private readonly langCtxService: ILanguageContextProviderService,
9394
@ILanguageDiagnosticsService private readonly langDiagService: ILanguageDiagnosticsService,
9495
@IIgnoreService private readonly ignoreService: IIgnoreService,
95-
@ITelemetryService private readonly telemetryService: ITelemetryService
9696
) {
9797
this.delayer = new Delayer(this.configService, this.expService);
9898
this.nextCursorPredictor = this.instaService.createInstance(XtabNextCursorPredictor, XtabProvider.computeTokens);
@@ -1009,51 +1009,8 @@ export class XtabProvider implements IStatelessNextEditProvider {
10091009
includePostScript: true,
10101010
};
10111011

1012-
const localOverridingModelConfig = this.configService.getConfig(ConfigKey.TeamInternal.InlineEditsXtabProviderModelConfiguration);
1013-
if (localOverridingModelConfig) {
1014-
return XtabProvider.overrideModelConfig(sourcedModelConfig, localOverridingModelConfig);
1015-
}
1016-
1017-
const expBasedModelConfig = this.overrideByStringModelConfig(sourcedModelConfig, ConfigKey.TeamInternal.InlineEditsXtabProviderModelConfigurationString);
1018-
if (expBasedModelConfig) {
1019-
return expBasedModelConfig;
1020-
}
1021-
1022-
const defaultModelConfig = this.overrideByStringModelConfig(sourcedModelConfig, ConfigKey.TeamInternal.InlineEditsXtabProviderDefaultModelConfigurationString);
1023-
if (defaultModelConfig) {
1024-
return defaultModelConfig;
1025-
}
1026-
1027-
return sourcedModelConfig;
1028-
}
1029-
1030-
private overrideByStringModelConfig(originalModelConfig: ModelConfig, configKey: ExperimentBasedConfig<string | undefined>): ModelConfig | undefined {
1031-
const configString = this.configService.getExperimentBasedConfig(configKey, this.expService);
1032-
if (configString === undefined) {
1033-
return undefined;
1034-
}
1035-
1036-
let parsedConfig: xtabPromptOptions.ModelConfiguration | undefined;
1037-
try {
1038-
parsedConfig = JSON.parse(configString);
1039-
} catch (e: unknown) {
1040-
/* __GDPR__
1041-
"incorrectNesModelConfig" : {
1042-
"owner": "ulugbekna",
1043-
"comment": "Capture if model configuration string is invalid JSON.",
1044-
"configName": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "Name of the configuration that failed to parse." },
1045-
"errorMessage": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "Error message from JSON.parse." },
1046-
"configValue": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "The invalid JSON string." }
1047-
}
1048-
*/
1049-
this.telemetryService.sendMSFTTelemetryEvent('incorrectNesModelConfig', { configName: configKey.id, errorMessage: errors.toString(errors.fromUnknown(e)), configValue: configString });
1050-
}
1051-
1052-
if (parsedConfig) {
1053-
return XtabProvider.overrideModelConfig(originalModelConfig, parsedConfig);
1054-
}
1055-
1056-
return undefined;
1012+
const modelConfig = this.modelService.selectedModelConfiguration();
1013+
return XtabProvider.overrideModelConfig(sourcedModelConfig, modelConfig);
10571014
}
10581015

10591016
private static overrideModelConfig(modelConfig: ModelConfig, overridingConfig: xtabPromptOptions.ModelConfiguration): ModelConfig {

src/platform/configuration/common/configurationService.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,7 @@ export namespace ConfigKey {
678678
export const InlineEditsNextCursorPredictionDisplayLine = defineAndMigrateExpSetting<boolean>('chat.advanced.inlineEdits.nextCursorPrediction.displayLine', 'chat.inlineEdits.nextCursorPrediction.displayLine', true);
679679
export const InlineEditsNextCursorPredictionCurrentFileMaxTokens = defineAndMigrateExpSetting<number>('chat.advanced.inlineEdits.nextCursorPrediction.currentFileMaxTokens', 'chat.inlineEdits.nextCursorPrediction.currentFileMaxTokens', xtabPromptOptions.DEFAULT_OPTIONS.currentFile.maxTokens);
680680
export const InlineEditsRenameSymbolSuggestions = defineSetting<boolean>('chat.inlineEdits.renameSymbolSuggestions', ConfigType.ExperimentBased, { defaultValue: false, teamDefaultValue: true });
681+
export const InlineEditsPreferredModel = defineSetting<string | "none">('nextEditSuggestions.preferredModel', ConfigType.ExperimentBased, "none");
681682
export const DiagnosticsContextProvider = defineAndMigrateExpSetting<boolean>('chat.advanced.inlineEdits.diagnosticsContextProvider.enabled', 'chat.inlineEdits.diagnosticsContextProvider.enabled', false);
682683
export const Gemini3ReplaceStringOnly = defineSetting<boolean>('chat.edits.gemini3ReplaceStringOnly', ConfigType.ExperimentBased, false);
683684
export const Gemini3MultiReplaceString = defineSetting<boolean>('chat.edits.gemini3MultiReplaceString', ConfigType.ExperimentBased, false);
@@ -699,6 +700,7 @@ export namespace ConfigKey {
699700
*/
700701
export const DebugReportFeedback = defineTeamInternalSetting<boolean>('chat.advanced.debug.reportFeedback', ConfigType.Simple, { defaultValue: false, teamDefaultValue: true });
701702
export const InlineEditsIgnoreCompletionsDisablement = defineTeamInternalSetting<boolean>('chat.advanced.inlineEdits.ignoreCompletionsDisablement', ConfigType.Simple, false, vBoolean());
703+
export const InlineEditsModelPickerEnabled = defineTeamInternalSetting<boolean>('chat.advanced.inlineEdits.modelPicker.enabled', ConfigType.ExperimentBased, false, vBoolean());
702704
export const InlineEditsLogContextRecorderEnabled = defineTeamInternalSetting<boolean>('chat.advanced.inlineEdits.logContextRecorder.enabled', ConfigType.Simple, false);
703705
export const InlineEditsHideInternalInterface = defineTeamInternalSetting<boolean>('chat.advanced.inlineEdits.hideInternalInterface', ConfigType.Simple, false, vBoolean());
704706
export const InlineEditsLogCancelledRequests = defineTeamInternalSetting<boolean>('chat.advanced.inlineEdits.logCancelledRequests', ConfigType.Simple, false, vBoolean());

0 commit comments

Comments
 (0)