From d13d7c7add720c958308ba619e02cd37caffad76 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Mon, 30 Mar 2026 19:47:26 -0700 Subject: [PATCH] Remote agent host: fix model picker on new session page (#306553) * Revert bad merge from #306130 Co-authored-by: Copilot * Always resolve language models on provider registration Previously, registerLanguageModelProvider only eagerly resolved models when _hasStoredModelForVendor returned true. Otherwise it waited for onDidChange. This created a hidden temporal coupling: if a provider populated models before registration (like AgentHostLanguageModelProvider), the onDidChange event fired with no listener attached, and the models never appeared. Fix: always call _resolveAllLanguageModels on registration. This is safe (the provider guard handles unregistration races, and the per-vendor sequencer prevents duplicate work). Also use ActiveSessionProviderIdContext.key instead of a hardcoded string in the remote agent host context key expression. (Written by Copilot) * fix Co-authored-by: Copilot * fix Co-authored-by: Copilot --------- Co-authored-by: Copilot --- .../browser/copilotChatSessionsActions.ts | 18 ++++++++++-------- .../browser/remoteAgentHost.contribution.ts | 6 +++--- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/vs/sessions/contrib/copilotChatSessions/browser/copilotChatSessionsActions.ts b/src/vs/sessions/contrib/copilotChatSessions/browser/copilotChatSessionsActions.ts index 2ab3811132f..8585506a81c 100644 --- a/src/vs/sessions/contrib/copilotChatSessions/browser/copilotChatSessionsActions.ts +++ b/src/vs/sessions/contrib/copilotChatSessions/browser/copilotChatSessionsActions.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { coalesce } from '../../../../base/common/arrays.js'; import { Disposable } from '../../../../base/common/lifecycle.js'; import { IReader, autorun, observableValue } from '../../../../base/common/observable.js'; import { localize2 } from '../../../../nls.js'; @@ -40,7 +41,7 @@ const IsActiveSessionCopilotCloud = ContextKeyExpr.equals(ActiveSessionTypeConte const IsActiveCopilotChatSessionProvider = ContextKeyExpr.equals(ActiveSessionProviderIdContext.key, COPILOT_PROVIDER_ID); const IsActiveSessionCopilotChatCLI = ContextKeyExpr.and(IsActiveSessionCopilotCLI, IsActiveCopilotChatSessionProvider); const IsActiveSessionCopilotChatCloud = ContextKeyExpr.and(IsActiveSessionCopilotCloud, IsActiveCopilotChatSessionProvider); -const IsActiveSessionRemoteAgentHost = ContextKeyExpr.regex('activeSessionProviderId', /^agenthost-/); +const IsActiveSessionRemoteAgentHost = ContextKeyExpr.regex(ActiveSessionProviderIdContext.key, /^agenthost-/); // -- Actions -- @@ -246,7 +247,7 @@ class CopilotPickerActionViewItemContribution extends Disposable implements IWor modelPicker.setEnabled(models.length > 0); if (!currentModel.get() && models.length > 0) { const remembered = rememberedModelId ? models.find(m => m.identifier === rememberedModelId) : undefined; - currentModel.set(remembered ?? models[0], undefined); + delegate.setModel(remembered ?? models[0]); } }; initModel(); @@ -362,17 +363,18 @@ class CopilotSessionContextMenuBridge extends Disposable implements IWorkbenchCo this._bridgedIds.add(commandId); const wrapperId = `sessionsViewPane.bridge.${commandId}`; - this._register(CommandsRegistry.registerCommand(wrapperId, (accessor, sessionData?: ISession) => { - if (!sessionData) { + this._register(CommandsRegistry.registerCommand(wrapperId, (accessor, context?: ISession | ISession[]) => { + if (!context) { return; } - const agentSession = this.agentSessionsService.getSession(sessionData.resource); - if (!agentSession) { + const sessions = Array.isArray(context) ? context : [context]; + const agentSessions = coalesce(sessions.map(s => this.agentSessionsService.getSession(s.resource))); + if (agentSessions.length === 0) { return; } return this.commandService.executeCommand(commandId, { - session: agentSession, - sessions: [agentSession], + session: agentSessions[0], + sessions: agentSessions, $mid: MarshalledId.AgentSessionContext, }); })); diff --git a/src/vs/sessions/contrib/remoteAgentHost/browser/remoteAgentHost.contribution.ts b/src/vs/sessions/contrib/remoteAgentHost/browser/remoteAgentHost.contribution.ts index 36ada54fccf..fa9c3658474 100644 --- a/src/vs/sessions/contrib/remoteAgentHost/browser/remoteAgentHost.contribution.ts +++ b/src/vs/sessions/contrib/remoteAgentHost/browser/remoteAgentHost.contribution.ts @@ -258,8 +258,8 @@ export class RemoteAgentHostContribution extends Disposable implements IWorkbenc loggedConnection.logError('subscribe(root)', err); }); - // Authenticate with this new connection - this._authenticateWithConnection(loggedConnection); + // Authenticate with this new connection and refresh models afterward + this._authenticateWithConnection(loggedConnection).then(() => loggedConnection.refreshModels()).catch(() => { /* best-effort */ }); // Wire connection to existing sessions provider this._providerInstances.get(address)?.setConnection(loggedConnection, connectionInfo.defaultDirectory); @@ -380,7 +380,7 @@ export class RemoteAgentHostContribution extends Disposable implements IWorkbenc private _authenticateAllConnections(): void { for (const [, connState] of this._connections) { - this._authenticateWithConnection(connState.loggedConnection); + this._authenticateWithConnection(connState.loggedConnection).then(() => connState.loggedConnection.refreshModels()).catch(() => { /* best-effort */ }); } }