From 7b2081533c63181f0ae9cd26d528e2492431acde Mon Sep 17 00:00:00 2001 From: eleanorjboyd <26030610+eleanorjboyd@users.noreply.github.com> Date: Wed, 28 Jan 2026 10:09:48 -0800 Subject: [PATCH] updates --- .../chatContentParts/chatSuggestNextWidget.ts | 28 ++++++++++++++++--- .../contrib/chat/browser/widget/chatWidget.ts | 2 +- .../languageProviders/promptValidator.ts | 7 ++++- .../common/promptSyntax/promptFileParser.ts | 10 +++++-- 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatSuggestNextWidget.ts b/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatSuggestNextWidget.ts index c24470548f7..c9e3d0c4a96 100644 --- a/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatSuggestNextWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatSuggestNextWidget.ts @@ -104,6 +104,14 @@ export class ChatSuggestNextWidget extends Disposable { private createPromptButton(handoff: IHandOff): HTMLElement { const disposables = new DisposableStore(); + // Capture the label to look up the current handoff at click time + // This ensures we get the latest handoff data (e.g., updated model from settings) + const handoffLabel = handoff.label; + const getCurrentHandoff = (): IHandOff | undefined => { + const currentHandoffs = this._currentMode?.handOffs?.get(); + return currentHandoffs?.find(h => h.label === handoffLabel) ?? handoff; + }; + const button = dom.$('.chat-welcome-view-suggested-prompt'); button.setAttribute('tabindex', '0'); button.setAttribute('role', 'button'); @@ -155,7 +163,10 @@ export class ChatSuggestNextWidget extends Disposable { ThemeIcon.isThemeIcon(icon) ? ThemeIcon.asClassName(icon) : undefined, true, () => { - this._onDidSelectPrompt.fire({ handoff, agentId: contrib.name }); + const currentHandoff = getCurrentHandoff(); + if (currentHandoff) { + this._onDidSelectPrompt.fire({ handoff: currentHandoff, agentId: contrib.name }); + } } ); }); @@ -180,18 +191,27 @@ export class ChatSuggestNextWidget extends Disposable { if (dom.isHTMLElement(e.target) && e.target.closest('.chat-suggest-next-dropdown')) { return; } - this._onDidSelectPrompt.fire({ handoff }); + const currentHandoff = getCurrentHandoff(); + if (currentHandoff) { + this._onDidSelectPrompt.fire({ handoff: currentHandoff }); + } })); } else { disposables.add(dom.addDisposableListener(button, 'click', () => { - this._onDidSelectPrompt.fire({ handoff }); + const currentHandoff = getCurrentHandoff(); + if (currentHandoff) { + this._onDidSelectPrompt.fire({ handoff: currentHandoff }); + } })); } disposables.add(dom.addDisposableListener(button, 'keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); - this._onDidSelectPrompt.fire({ handoff }); + const currentHandoff = getCurrentHandoff(); + if (currentHandoff) { + this._onDidSelectPrompt.fire({ handoff: currentHandoff }); + } } })); diff --git a/src/vs/workbench/contrib/chat/browser/widget/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/widget/chatWidget.ts index 430d6cf6d6c..11e38cc7612 100644 --- a/src/vs/workbench/contrib/chat/browser/widget/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/widget/chatWidget.ts @@ -1210,7 +1210,7 @@ export class ChatWidget extends Disposable implements IChatWidget { this._switchToAgentByName(handoff.agent); // Switch to the specified model if provided if (handoff.model) { - this.input.switchModelByQualifiedName(handoff.model); + this.input.switchModelByQualifiedName([handoff.model]); } // Insert the handoff prompt into the input this.input.setValue(promptToUse, false); diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptValidator.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptValidator.ts index 2314291840c..2140a1a488a 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptValidator.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptValidator.ts @@ -514,8 +514,13 @@ export class PromptValidator { report(toMarker(localize('promptValidator.handoffShowContinueOnMustBeBoolean', "The 'showContinueOn' property in a handoff must be a boolean."), prop.value.range, MarkerSeverity.Error)); } break; + case 'model': + if (prop.value.type !== 'string') { + report(toMarker(localize('promptValidator.handoffModelMustBeString', "The 'model' property in a handoff must be a string."), prop.value.range, MarkerSeverity.Error)); + } + break; default: - report(toMarker(localize('promptValidator.unknownHandoffProperty', "Unknown property '{0}' in handoff object. Supported properties are 'label', 'agent', 'prompt' and optional 'send', 'showContinueOn'.", prop.key.value), prop.value.range, MarkerSeverity.Warning)); + report(toMarker(localize('promptValidator.unknownHandoffProperty', "Unknown property '{0}' in handoff object. Supported properties are 'label', 'agent', 'prompt' and optional 'send', 'showContinueOn', 'model'.", prop.key.value), prop.value.range, MarkerSeverity.Warning)); } required.delete(prop.key.value); } diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/promptFileParser.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/promptFileParser.ts index c69a453afe2..cdd864e7e75 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/promptFileParser.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/promptFileParser.ts @@ -238,7 +238,7 @@ export class PromptHeader { return undefined; } if (handoffsAttribute.value.type === 'array') { - // Array format: list of objects: { agent, label, prompt, send?, showContinueOn? } + // Array format: list of objects: { agent, label, prompt, send?, showContinueOn?, model? } const handoffs: IHandOff[] = []; for (const item of handoffsAttribute.value.items) { if (item.type === 'object') { @@ -247,6 +247,7 @@ export class PromptHeader { let prompt: string | undefined; let send: boolean | undefined; let showContinueOn: boolean | undefined; + let model: string | undefined; for (const prop of item.properties) { if (prop.key.value === 'agent' && prop.value.type === 'string') { agent = prop.value.value; @@ -258,6 +259,8 @@ export class PromptHeader { send = prop.value.value; } else if (prop.key.value === 'showContinueOn' && prop.value.type === 'boolean') { showContinueOn = prop.value.value; + } else if (prop.key.value === 'model' && prop.value.type === 'string') { + model = prop.value.value; } } if (agent && label && prompt !== undefined) { @@ -266,7 +269,8 @@ export class PromptHeader { label, prompt, ...(send !== undefined ? { send } : {}), - ...(showContinueOn !== undefined ? { showContinueOn } : {}) + ...(showContinueOn !== undefined ? { showContinueOn } : {}), + ...(model !== undefined ? { model } : {}) }; handoffs.push(handoff); } @@ -325,7 +329,7 @@ export interface IHandOff { readonly prompt: string; readonly send?: boolean; readonly showContinueOn?: boolean; // treated exactly like send (optional boolean) - readonly model?: readonly string[]; // qualified model name(s) to switch to (e.g., "GPT-4o (copilot)") + readonly model?: string; // qualified model name to switch to (e.g., "GPT-4o (copilot)") } export interface IHeaderAttribute {