From 05642dca5bf4da23e6f12ef4906e163d6ca75210 Mon Sep 17 00:00:00 2001 From: Kevin Kent Date: Fri, 3 Apr 2026 17:39:49 -0400 Subject: [PATCH 1/8] Add model picker vendor ordering experiment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add github.copilot.chat.modelPickerVendorOrdering experiment setting (tagged experimental + onExp) that enables vendor-prioritized ordering in the model picker: OpenAI → Anthropic → Gemini → others. When the experiment is enabled, sets vendorPriority on each model based on the endpoint's modelProvider field. Auto model is excluded from vendor ordering (always appears first via separate logic in vscode). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- package.json | 9 +++++++++ .../vscode-node/languageModelAccess.ts | 18 +++++++++++++++++- .../vscode.proposed.chatProvider.d.ts | 7 +++++++ .../common/configurationService.ts | 3 +++ 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 98bfd5429f..4d542fc830 100644 --- a/package.json +++ b/package.json @@ -3034,6 +3034,15 @@ "onExp" ] }, + "github.copilot.chat.modelPickerVendorOrdering": { + "type": "boolean", + "default": false, + "markdownDescription": "Enable vendor-prioritized ordering in the model picker (OpenAI → Anthropic → Gemini → others).", + "tags": [ + "experimental", + "onExp" + ] + }, "github.copilot.chat.customInstructionsInSystemMessage": { "type": "boolean", "default": true, diff --git a/src/extension/conversation/vscode-node/languageModelAccess.ts b/src/extension/conversation/vscode-node/languageModelAccess.ts index c341dd609f..d16a04cbd4 100644 --- a/src/extension/conversation/vscode-node/languageModelAccess.ts +++ b/src/extension/conversation/vscode-node/languageModelAccess.ts @@ -11,7 +11,7 @@ import { CopilotToken } from '../../../platform/authentication/common/copilotTok import { IBlockedExtensionService } from '../../../platform/chat/common/blockedExtensionService'; import { ChatFetchResponseType, ChatLocation, getErrorDetailsFromChatFetchError } from '../../../platform/chat/common/commonTypes'; import { getTextPart } from '../../../platform/chat/common/globalStringUtils'; -import { IConfigurationService } from '../../../platform/configuration/common/configurationService'; +import { ConfigKey, IConfigurationService } from '../../../platform/configuration/common/configurationService'; import { EmbeddingType, getWellKnownEmbeddingTypeInfo, IEmbeddingsComputer } from '../../../platform/embeddings/common/embeddingsComputer'; import { IEndpointProvider } from '../../../platform/endpoint/common/endpointProvider'; import { CustomDataPartMimeTypes } from '../../../platform/endpoint/common/endpointTypes'; @@ -159,6 +159,19 @@ function getModelCapabilitiesDescription(endpoint: IChatEndpoint): string | unde return undefined; } +/** + * Maps a model vendor string to a numeric priority for ordering in the model picker. + * Lower values appear higher in the list. + */ +function getVendorPriority(modelProvider: string): number { + switch (modelProvider.toLowerCase()) { + case 'openai': return 0; + case 'anthropic': return 1; + case 'google': return 2; + default: return 3; + } +} + export class LanguageModelAccess extends Disposable implements IExtensionContribution { readonly id = 'languageModelAccess'; @@ -180,6 +193,7 @@ export class LanguageModelAccess extends Disposable implements IExtensionContrib @IVSCodeExtensionContext private readonly _vsCodeExtensionContext: IVSCodeExtensionContext, @IAutomodeService private readonly _automodeService: IAutomodeService, @IExperimentationService private readonly _expService: IExperimentationService, + @IConfigurationService private readonly _configurationService: IConfigurationService, ) { super(); @@ -236,6 +250,7 @@ export class LanguageModelAccess extends Disposable implements IExtensionContrib } const models: vscode.LanguageModelChatInformation[] = []; + const vendorOrderingEnabled = this._configurationService.getConfig(ConfigKey.ModelPickerVendorOrdering); const allEndpoints = await this._endpointProvider.getAllChatEndpoints(); const chatEndpoints = allEndpoints.filter(e => e.showInModelPicker || e.model === 'gpt-4o-mini'); const autoEndpoint = await this._automodeService.resolveAutoModeEndpoint(undefined, allEndpoints); @@ -338,6 +353,7 @@ export class LanguageModelAccess extends Disposable implements IExtensionContrib [ApiChatLocation.Editor]: endpoint instanceof AutoChatEndpoint, // inline chat gets 'Auto' by default }, isUserSelectable: endpoint.showInModelPicker, + vendorPriority: vendorOrderingEnabled && !(endpoint instanceof AutoChatEndpoint) ? getVendorPriority(endpoint.modelProvider) : undefined, capabilities: { imageInput: endpoint instanceof AutoChatEndpoint ? true : endpoint.supportsVision, toolCalling: endpoint.supportsToolCalls, diff --git a/src/extension/vscode.proposed.chatProvider.d.ts b/src/extension/vscode.proposed.chatProvider.d.ts index c20711a330..6babe47b2e 100644 --- a/src/extension/vscode.proposed.chatProvider.d.ts +++ b/src/extension/vscode.proposed.chatProvider.d.ts @@ -92,6 +92,13 @@ declare module 'vscode' { * The value must match a `type` declared in a `chatSessions` extension contribution. */ readonly targetChatSessionType?: string; + + /** + * Optional vendor priority for ordering models in the model picker. + * Lower values appear higher in the list. When set, models are sorted + * by this priority before falling back to alphabetical vendor/name ordering. + */ + readonly vendorPriority?: number; } export interface LanguageModelChatCapabilities { diff --git a/src/platform/configuration/common/configurationService.ts b/src/platform/configuration/common/configurationService.ts index 1d4cfdaf7f..05bbe6e7a7 100644 --- a/src/platform/configuration/common/configurationService.ts +++ b/src/platform/configuration/common/configurationService.ts @@ -876,6 +876,9 @@ export namespace ConfigKey { export const RateLimitAutoSwitchToAuto = defineSetting('chat.rateLimitAutoSwitchToAuto', ConfigType.Simple, false, vBoolean()); + /** Enable vendor-prioritized ordering in the model picker */ + export const ModelPickerVendorOrdering = defineSetting('chat.modelPickerVendorOrdering', ConfigType.ExperimentBased, false, vBoolean()); + /** Use the Messages API instead of Chat Completions when supported */ export const UseAnthropicMessagesApi = defineSetting('chat.anthropic.useMessagesApi', ConfigType.ExperimentBased, true); /** Context editing mode for Anthropic Messages API. 'off' disables context editing. */ From 42d47f6c753632b9232de039063980683df33743 Mon Sep 17 00:00:00 2001 From: Kevin Kent Date: Fri, 3 Apr 2026 18:06:57 -0400 Subject: [PATCH 2/8] Use fine-grained vendor priority with featured model boosting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Featured models (GPT-5.4, GPT-5.4 mini, Claude Opus 4.6, Claude Sonnet 4.6) get lowest priority values to appear first after Auto. Remaining models use vendor-based grouping: OpenAI (100) → Anthropic (200) → Gemini (300) → others (400). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../vscode-node/languageModelAccess.ts | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/extension/conversation/vscode-node/languageModelAccess.ts b/src/extension/conversation/vscode-node/languageModelAccess.ts index d16a04cbd4..3aaaa319cb 100644 --- a/src/extension/conversation/vscode-node/languageModelAccess.ts +++ b/src/extension/conversation/vscode-node/languageModelAccess.ts @@ -159,17 +159,34 @@ function getModelCapabilitiesDescription(endpoint: IChatEndpoint): string | unde return undefined; } +// Vendor base offsets for model picker ordering +const VENDOR_PRIORITY_BASE: Record = { + 'openai': 100, + 'anthropic': 200, + 'google': 300, +}; +const VENDOR_PRIORITY_OTHER = 400; + +// Featured models that should appear at the very top (after Auto) +const FEATURED_MODEL_PRIORITY: Record = { + 'gpt-5.4': 0, + 'gpt-5.4-mini': 1, + 'claude-opus-4.6': 2, + 'claude-sonnet-4.6': 3, +}; + /** - * Maps a model vendor string to a numeric priority for ordering in the model picker. - * Lower values appear higher in the list. + * Returns a numeric priority for ordering in the model picker. + * Featured models get the lowest values (appear first), then + * remaining models are grouped by vendor: OpenAI → Anthropic → Gemini → others. */ -function getVendorPriority(modelProvider: string): number { - switch (modelProvider.toLowerCase()) { - case 'openai': return 0; - case 'anthropic': return 1; - case 'google': return 2; - default: return 3; +function getVendorPriority(modelId: string, modelProvider: string): number { + const featured = FEATURED_MODEL_PRIORITY[modelId]; + if (featured !== undefined) { + return featured; } + const vendor = modelProvider.toLowerCase(); + return VENDOR_PRIORITY_BASE[vendor] ?? VENDOR_PRIORITY_OTHER; } export class LanguageModelAccess extends Disposable implements IExtensionContribution { @@ -353,7 +370,7 @@ export class LanguageModelAccess extends Disposable implements IExtensionContrib [ApiChatLocation.Editor]: endpoint instanceof AutoChatEndpoint, // inline chat gets 'Auto' by default }, isUserSelectable: endpoint.showInModelPicker, - vendorPriority: vendorOrderingEnabled && !(endpoint instanceof AutoChatEndpoint) ? getVendorPriority(endpoint.modelProvider) : undefined, + vendorPriority: vendorOrderingEnabled && !(endpoint instanceof AutoChatEndpoint) ? getVendorPriority(endpoint.model, endpoint.modelProvider) : undefined, capabilities: { imageInput: endpoint instanceof AutoChatEndpoint ? true : endpoint.supportsVision, toolCalling: endpoint.supportsToolCalls, From 0589edb77904d885721986adbec6395c115bdc4c Mon Sep 17 00:00:00 2001 From: Kevin Kent Date: Fri, 3 Apr 2026 18:08:18 -0400 Subject: [PATCH 3/8] Fix: use getExperimentBasedConfig for ExperimentBased setting ExperimentBased config keys must be read with getExperimentBasedConfig() not getConfig(). This was causing the vendorOrdering setting to never be read as true. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/extension/conversation/vscode-node/languageModelAccess.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/extension/conversation/vscode-node/languageModelAccess.ts b/src/extension/conversation/vscode-node/languageModelAccess.ts index 3aaaa319cb..2c2c8cb7ba 100644 --- a/src/extension/conversation/vscode-node/languageModelAccess.ts +++ b/src/extension/conversation/vscode-node/languageModelAccess.ts @@ -267,7 +267,7 @@ export class LanguageModelAccess extends Disposable implements IExtensionContrib } const models: vscode.LanguageModelChatInformation[] = []; - const vendorOrderingEnabled = this._configurationService.getConfig(ConfigKey.ModelPickerVendorOrdering); + const vendorOrderingEnabled = this._configurationService.getExperimentBasedConfig(ConfigKey.ModelPickerVendorOrdering, this._expService); const allEndpoints = await this._endpointProvider.getAllChatEndpoints(); const chatEndpoints = allEndpoints.filter(e => e.showInModelPicker || e.model === 'gpt-4o-mini'); const autoEndpoint = await this._automodeService.resolveAutoModeEndpoint(undefined, allEndpoints); From b83d8c794eae06fbaf3fbccac42b086c9145c8b7 Mon Sep 17 00:00:00 2001 From: Kevin Kent Date: Fri, 3 Apr 2026 18:30:41 -0400 Subject: [PATCH 4/8] Use provider ordering without hardcoded featured models Remove the hardcoded featured model list and assign vendorPriority only by provider (OpenAI, Anthropic, Gemini, others). Top-level promotion is left to VS Code's models control manifest. Also switch the setting to a simple config-backed flag so it can be enabled reliably in local dev. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../vscode-node/languageModelAccess.ts | 40 +++++++------------ .../common/configurationService.ts | 2 +- 2 files changed, 15 insertions(+), 27 deletions(-) diff --git a/src/extension/conversation/vscode-node/languageModelAccess.ts b/src/extension/conversation/vscode-node/languageModelAccess.ts index 2c2c8cb7ba..ceb739f7aa 100644 --- a/src/extension/conversation/vscode-node/languageModelAccess.ts +++ b/src/extension/conversation/vscode-node/languageModelAccess.ts @@ -159,34 +159,22 @@ function getModelCapabilitiesDescription(endpoint: IChatEndpoint): string | unde return undefined; } -// Vendor base offsets for model picker ordering -const VENDOR_PRIORITY_BASE: Record = { - 'openai': 100, - 'anthropic': 200, - 'google': 300, -}; -const VENDOR_PRIORITY_OTHER = 400; - -// Featured models that should appear at the very top (after Auto) -const FEATURED_MODEL_PRIORITY: Record = { - 'gpt-5.4': 0, - 'gpt-5.4-mini': 1, - 'claude-opus-4.6': 2, - 'claude-sonnet-4.6': 3, -}; - /** * Returns a numeric priority for ordering in the model picker. - * Featured models get the lowest values (appear first), then - * remaining models are grouped by vendor: OpenAI → Anthropic → Gemini → others. + * Lower values appear first. Top-level featuring remains controlled by + * VS Code's models control manifest; this priority only affects ordering. */ -function getVendorPriority(modelId: string, modelProvider: string): number { - const featured = FEATURED_MODEL_PRIORITY[modelId]; - if (featured !== undefined) { - return featured; +function getVendorPriority(modelProvider: string): number { + switch (modelProvider.toLowerCase()) { + case 'openai': + return 0; + case 'anthropic': + return 1; + case 'google': + return 2; + default: + return 3; } - const vendor = modelProvider.toLowerCase(); - return VENDOR_PRIORITY_BASE[vendor] ?? VENDOR_PRIORITY_OTHER; } export class LanguageModelAccess extends Disposable implements IExtensionContribution { @@ -267,7 +255,7 @@ export class LanguageModelAccess extends Disposable implements IExtensionContrib } const models: vscode.LanguageModelChatInformation[] = []; - const vendorOrderingEnabled = this._configurationService.getExperimentBasedConfig(ConfigKey.ModelPickerVendorOrdering, this._expService); + const vendorOrderingEnabled = this._configurationService.getConfig(ConfigKey.ModelPickerVendorOrdering); const allEndpoints = await this._endpointProvider.getAllChatEndpoints(); const chatEndpoints = allEndpoints.filter(e => e.showInModelPicker || e.model === 'gpt-4o-mini'); const autoEndpoint = await this._automodeService.resolveAutoModeEndpoint(undefined, allEndpoints); @@ -370,7 +358,7 @@ export class LanguageModelAccess extends Disposable implements IExtensionContrib [ApiChatLocation.Editor]: endpoint instanceof AutoChatEndpoint, // inline chat gets 'Auto' by default }, isUserSelectable: endpoint.showInModelPicker, - vendorPriority: vendorOrderingEnabled && !(endpoint instanceof AutoChatEndpoint) ? getVendorPriority(endpoint.model, endpoint.modelProvider) : undefined, + vendorPriority: vendorOrderingEnabled && !(endpoint instanceof AutoChatEndpoint) ? getVendorPriority(endpoint.modelProvider) : undefined, capabilities: { imageInput: endpoint instanceof AutoChatEndpoint ? true : endpoint.supportsVision, toolCalling: endpoint.supportsToolCalls, diff --git a/src/platform/configuration/common/configurationService.ts b/src/platform/configuration/common/configurationService.ts index 05bbe6e7a7..9c9dc392e8 100644 --- a/src/platform/configuration/common/configurationService.ts +++ b/src/platform/configuration/common/configurationService.ts @@ -877,7 +877,7 @@ export namespace ConfigKey { export const RateLimitAutoSwitchToAuto = defineSetting('chat.rateLimitAutoSwitchToAuto', ConfigType.Simple, false, vBoolean()); /** Enable vendor-prioritized ordering in the model picker */ - export const ModelPickerVendorOrdering = defineSetting('chat.modelPickerVendorOrdering', ConfigType.ExperimentBased, false, vBoolean()); + export const ModelPickerVendorOrdering = defineSetting('chat.modelPickerVendorOrdering', ConfigType.Simple, false, vBoolean()); /** Use the Messages API instead of Chat Completions when supported */ export const UseAnthropicMessagesApi = defineSetting('chat.anthropic.useMessagesApi', ConfigType.ExperimentBased, true); From 402380fcfe936e4f8bd55ee0f08bf7f70ff4a3ec Mon Sep 17 00:00:00 2001 From: Kevin Kent Date: Fri, 3 Apr 2026 18:34:52 -0400 Subject: [PATCH 5/8] Update proposed API definitions Run vscode-dts:update so the local proposed API definitions and vscodeCommit match the current upstream VS Code commit expected by CI. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- package.json | 2 +- src/extension/vscode.proposed.chatProvider.d.ts | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/package.json b/package.json index 4d542fc830..9d301aa63a 100644 --- a/package.json +++ b/package.json @@ -6409,5 +6409,5 @@ "node-gyp": "npm:node-gyp@10.3.1", "zod": "3.25.76" }, - "vscodeCommit": "20b24833bc088c84b778ee89be4c17f15660441a" + "vscodeCommit": "b564ded0d644b449fc29633a7c571452b18d3350" } diff --git a/src/extension/vscode.proposed.chatProvider.d.ts b/src/extension/vscode.proposed.chatProvider.d.ts index 6babe47b2e..c20711a330 100644 --- a/src/extension/vscode.proposed.chatProvider.d.ts +++ b/src/extension/vscode.proposed.chatProvider.d.ts @@ -92,13 +92,6 @@ declare module 'vscode' { * The value must match a `type` declared in a `chatSessions` extension contribution. */ readonly targetChatSessionType?: string; - - /** - * Optional vendor priority for ordering models in the model picker. - * Lower values appear higher in the list. When set, models are sorted - * by this priority before falling back to alphabetical vendor/name ordering. - */ - readonly vendorPriority?: number; } export interface LanguageModelChatCapabilities { From 22c3ec50e9eeeddda7f66885b454e3b5868ce351 Mon Sep 17 00:00:00 2001 From: Kevin Kent Date: Fri, 3 Apr 2026 18:40:39 -0400 Subject: [PATCH 6/8] Avoid depending on proposed d.ts for vendorPriority Assign vendorPriority after creating the LanguageModelChatInformation object so the runtime property is preserved without requiring the current upstream proposed API typings to include it yet. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/extension/conversation/vscode-node/languageModelAccess.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/extension/conversation/vscode-node/languageModelAccess.ts b/src/extension/conversation/vscode-node/languageModelAccess.ts index ceb739f7aa..25fa95366b 100644 --- a/src/extension/conversation/vscode-node/languageModelAccess.ts +++ b/src/extension/conversation/vscode-node/languageModelAccess.ts @@ -358,13 +358,15 @@ export class LanguageModelAccess extends Disposable implements IExtensionContrib [ApiChatLocation.Editor]: endpoint instanceof AutoChatEndpoint, // inline chat gets 'Auto' by default }, isUserSelectable: endpoint.showInModelPicker, - vendorPriority: vendorOrderingEnabled && !(endpoint instanceof AutoChatEndpoint) ? getVendorPriority(endpoint.modelProvider) : undefined, capabilities: { imageInput: endpoint instanceof AutoChatEndpoint ? true : endpoint.supportsVision, toolCalling: endpoint.supportsToolCalls, }, ...buildConfigurationSchema(endpoint), }; + if (vendorOrderingEnabled && !(endpoint instanceof AutoChatEndpoint)) { + (model as vscode.LanguageModelChatInformation & { vendorPriority?: number }).vendorPriority = getVendorPriority(endpoint.modelProvider); + } models.push(model); From 9fef0f1a78e216c50e7f7ea01ec1bb43769f680c Mon Sep 17 00:00:00 2001 From: Kevin Kent Date: Fri, 3 Apr 2026 19:13:26 -0400 Subject: [PATCH 7/8] Revert vscode dts baseline drift\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9d301aa63a..4d542fc830 100644 --- a/package.json +++ b/package.json @@ -6409,5 +6409,5 @@ "node-gyp": "npm:node-gyp@10.3.1", "zod": "3.25.76" }, - "vscodeCommit": "b564ded0d644b449fc29633a7c571452b18d3350" + "vscodeCommit": "20b24833bc088c84b778ee89be4c17f15660441a" } From 67e1e99c8835769e8da6675a34b1965c6051e50e Mon Sep 17 00:00:00 2001 From: Kevin Kent Date: Fri, 3 Apr 2026 19:50:26 -0400 Subject: [PATCH 8/8] Move model picker setting to experimental section\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- package.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 4d542fc830..9e2f1d423c 100644 --- a/package.json +++ b/package.json @@ -3034,15 +3034,6 @@ "onExp" ] }, - "github.copilot.chat.modelPickerVendorOrdering": { - "type": "boolean", - "default": false, - "markdownDescription": "Enable vendor-prioritized ordering in the model picker (OpenAI → Anthropic → Gemini → others).", - "tags": [ - "experimental", - "onExp" - ] - }, "github.copilot.chat.customInstructionsInSystemMessage": { "type": "boolean", "default": true, @@ -3364,6 +3355,15 @@ ], "markdownDescription": "%github.copilot.config.imageUpload.enabled%" }, + "github.copilot.chat.modelPickerVendorOrdering": { + "type": "boolean", + "default": false, + "markdownDescription": "Enable vendor-prioritized ordering in the model picker (OpenAI → Anthropic → Gemini → others).", + "tags": [ + "experimental", + "onExp" + ] + }, "github.copilot.chat.codeGeneration.instructions": { "markdownDeprecationMessage": "%github.copilot.config.codeGeneration.instructions.deprecated%", "type": "array",