From 936dee9d943a558ec0742ebae25d027b54ca6f10 Mon Sep 17 00:00:00 2001 From: digitarald Date: Tue, 10 Feb 2026 09:42:24 -0800 Subject: [PATCH] Moved planAgent model config to core for picker UI --- .../contrib/chat/browser/chat.contribution.ts | 9 ++ .../chat/browser/planAgentDefaultModel.ts | 107 ++++++++++++++++++ .../contrib/chat/common/constants.ts | 1 + 3 files changed, 117 insertions(+) create mode 100644 src/vs/workbench/contrib/chat/browser/planAgentDefaultModel.ts diff --git a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts index 1c71ce192a5..91706e2e422 100644 --- a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts +++ b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts @@ -143,6 +143,7 @@ import { ChatRepoInfoContribution } from './chatRepoInfo.js'; import { VALID_PROMPT_FOLDER_PATTERN } from '../common/promptSyntax/utils/promptFilesLocator.js'; import { ChatTipService, IChatTipService } from './chatTipService.js'; import { ChatQueuePickerRendering } from './widget/input/chatQueuePickerActionItem.js'; +import { PlanAgentDefaultModel } from './planAgentDefaultModel.js'; const toolReferenceNameEnumValues: string[] = []; const toolReferenceNameEnumDescriptions: string[] = []; @@ -614,6 +615,14 @@ configurationRegistry.registerConfiguration({ } } }, + [ChatConfiguration.PlanAgentDefaultModel]: { + type: 'string', + description: nls.localize('chat.planAgent.defaultModel.description', "Select the default language model to use for the Plan agent from the available providers."), + default: '', + enum: PlanAgentDefaultModel.modelIds, + enumItemLabels: PlanAgentDefaultModel.modelLabels, + markdownEnumDescriptions: PlanAgentDefaultModel.modelDescriptions + }, [ChatConfiguration.RequestQueueingEnabled]: { type: 'boolean', description: nls.localize('chat.requestQueuing.enabled.description', "When enabled, allows queuing additional messages while a request is in progress and steering the current request with a new message."), diff --git a/src/vs/workbench/contrib/chat/browser/planAgentDefaultModel.ts b/src/vs/workbench/contrib/chat/browser/planAgentDefaultModel.ts new file mode 100644 index 00000000000..37c49f0774f --- /dev/null +++ b/src/vs/workbench/contrib/chat/browser/planAgentDefaultModel.ts @@ -0,0 +1,107 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Disposable } from '../../../../base/common/lifecycle.js'; +import { localize } from '../../../../nls.js'; +import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from '../../../../platform/configuration/common/configurationRegistry.js'; +import { ILogService } from '../../../../platform/log/common/log.js'; +import { Registry } from '../../../../platform/registry/common/platform.js'; +import { registerWorkbenchContribution2, WorkbenchPhase } from '../../../common/contributions.js'; +import { ChatConfiguration } from '../common/constants.js'; +import { ILanguageModelChatMetadata, ILanguageModelsService } from '../common/languageModels.js'; +import { DEFAULT_MODEL_PICKER_CATEGORY } from '../common/widget/input/modelPickerWidget.js'; + +const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); + +export class PlanAgentDefaultModel extends Disposable { + static readonly ID = 'workbench.contrib.planAgentDefaultModel'; + static readonly configName = ChatConfiguration.PlanAgentDefaultModel; + + static modelIds: string[] = ['']; + static modelLabels: string[] = [localize('defaultModel', 'Auto (Vendor Default)')]; + static modelDescriptions: string[] = [localize('defaultModelDescription', "Use the vendor's default model")]; + + constructor( + @ILanguageModelsService private readonly languageModelsService: ILanguageModelsService, + @ILogService private readonly logService: ILogService, + ) { + super(); + this._register(languageModelsService.onDidChangeLanguageModels(() => this._updateModelValues())); + this._updateModelValues(); + } + + private _updateModelValues(): void { + try { + // Clear arrays + PlanAgentDefaultModel.modelIds.length = 0; + PlanAgentDefaultModel.modelLabels.length = 0; + PlanAgentDefaultModel.modelDescriptions.length = 0; + + // Add default/empty option + PlanAgentDefaultModel.modelIds.push(''); + PlanAgentDefaultModel.modelLabels.push(localize('defaultModel', 'Auto (Vendor Default)')); + PlanAgentDefaultModel.modelDescriptions.push(localize('defaultModelDescription', "Use the vendor's default model")); + + const models: { identifier: string; metadata: ILanguageModelChatMetadata }[] = []; + const modelIds = this.languageModelsService.getLanguageModelIds(); + + for (const modelId of modelIds) { + try { + const metadata = this.languageModelsService.lookupLanguageModel(modelId); + if (metadata) { + models.push({ identifier: modelId, metadata }); + } else { + this.logService.warn(`[PlanAgentDefaultModel] No metadata found for model ID: ${modelId}`); + } + } catch (e) { + this.logService.error(`[PlanAgentDefaultModel] Error looking up model ${modelId}:`, e); + } + } + + const supportedModels = models.filter(model => { + if (!model.metadata?.isUserSelectable) { + return false; + } + if (!model.metadata.capabilities?.toolCalling) { + return false; + } + return true; + }); + + supportedModels.sort((a, b) => { + const aCategory = a.metadata.modelPickerCategory ?? DEFAULT_MODEL_PICKER_CATEGORY; + const bCategory = b.metadata.modelPickerCategory ?? DEFAULT_MODEL_PICKER_CATEGORY; + + if (aCategory.order !== bCategory.order) { + return aCategory.order - bCategory.order; + } + + return a.metadata.name.localeCompare(b.metadata.name); + }); + + for (const model of supportedModels) { + try { + const qualifiedName = `${model.metadata.name} (${model.metadata.vendor})`; + PlanAgentDefaultModel.modelIds.push(qualifiedName); + PlanAgentDefaultModel.modelLabels.push(model.metadata.name); + PlanAgentDefaultModel.modelDescriptions.push(model.metadata.tooltip ?? model.metadata.detail ?? ''); + } catch (e) { + this.logService.error(`[PlanAgentDefaultModel] Error adding model ${model.metadata.name}:`, e); + } + } + + configurationRegistry.notifyConfigurationSchemaUpdated({ + id: 'chatSidebar', + properties: { + [ChatConfiguration.PlanAgentDefaultModel]: {} + } + }); + } catch (e) { + this.logService.error('[PlanAgentDefaultModel] Error updating model values:', e); + } + } +} + +registerWorkbenchContribution2(PlanAgentDefaultModel.ID, PlanAgentDefaultModel, WorkbenchPhase.BlockRestore); diff --git a/src/vs/workbench/contrib/chat/common/constants.ts b/src/vs/workbench/contrib/chat/common/constants.ts index 8270d7cf9e4..a5eec8a6ad8 100644 --- a/src/vs/workbench/contrib/chat/common/constants.ts +++ b/src/vs/workbench/contrib/chat/common/constants.ts @@ -11,6 +11,7 @@ import { RawContextKey } from '../../../../platform/contextkey/common/contextkey export enum ChatConfiguration { AIDisabled = 'chat.disableAIFeatures', AgentEnabled = 'chat.agent.enabled', + PlanAgentDefaultModel = 'chat.planAgent.defaultModel', RequestQueueingEnabled = 'chat.requestQueuing.enabled', RequestQueueingDefaultAction = 'chat.requestQueuing.defaultAction', AgentStatusEnabled = 'chat.agentsControl.enabled',