From 275b8adcee07c5bc666f94dbbae00a0cddf6a81b Mon Sep 17 00:00:00 2001 From: Osvaldo Ortega Date: Wed, 25 Feb 2026 11:25:06 -0800 Subject: [PATCH] Add support for allowed session targets in chat components - Introduced `SessionsChatViewPane` to restrict session targets to Local and Cloud. - Updated interfaces and classes to include optional `allowedSessionTargets` for session target and delegation pickers. - Enhanced visibility logic in `DelegationSessionPickerActionItem` and `SessionTypePickerActionItem` to respect allowed targets. --- .../contrib/chat/browser/chat.contribution.ts | 13 ++++++++++++- src/vs/workbench/contrib/chat/browser/chat.ts | 15 +++++++++++++++ .../contrib/chat/browser/widget/chatWidget.ts | 1 + .../chat/browser/widget/input/chatInputPart.ts | 8 ++++++++ .../input/delegationSessionPickerActionItem.ts | 5 +++++ .../widget/input/sessionTargetPickerActionItem.ts | 4 ++++ .../browser/widgetHosts/viewPane/chatViewPane.ts | 11 +++++++++++ 7 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/vs/sessions/contrib/chat/browser/chat.contribution.ts b/src/vs/sessions/contrib/chat/browser/chat.contribution.ts index 8fa8db33b1c..5dfa313d840 100644 --- a/src/vs/sessions/contrib/chat/browser/chat.contribution.ts +++ b/src/vs/sessions/contrib/chat/browser/chat.contribution.ts @@ -37,6 +37,17 @@ import { ViewPaneContainer } from '../../../../workbench/browser/parts/views/vie import { registerIcon } from '../../../../platform/theme/common/iconRegistry.js'; import { ChatViewPane } from '../../../../workbench/contrib/chat/browser/widgetHosts/viewPane/chatViewPane.js'; +/** + * Sessions-window subclass of {@link ChatViewPane} that restricts the session + * target and delegation pickers to only show targets supported by the agent + * sessions window (Local and Cloud). + */ +class SessionsChatViewPane extends ChatViewPane { + protected override getAllowedSessionTargets(): ReadonlySet { + return new Set([AgentSessionProviders.Local, AgentSessionProviders.Cloud]); + } +} + export class OpenSessionWorktreeInVSCodeAction extends Action2 { static readonly ID = 'chat.openSessionWorktreeInVSCode'; @@ -201,7 +212,7 @@ class RegisterChatViewContainerContribution implements IWorkbenchContribution { name: localize2('chat.viewContainer.label', "Chat"), canToggleVisibility: false, canMoveView: false, - ctorDescriptor: new SyncDescriptor(ChatViewPane), + ctorDescriptor: new SyncDescriptor(SessionsChatViewPane), when: IsNewChatSessionContext.negate(), windowVisibility: WindowVisibility.Sessions }, { diff --git a/src/vs/workbench/contrib/chat/browser/chat.ts b/src/vs/workbench/contrib/chat/browser/chat.ts index c29b6a4843b..d5ffe928496 100644 --- a/src/vs/workbench/contrib/chat/browser/chat.ts +++ b/src/vs/workbench/contrib/chat/browser/chat.ts @@ -91,6 +91,13 @@ export interface ISessionTypePickerDelegate { * this stores the target for delegation on the next submit instead of immediately creating a new session. */ setPendingDelegationTarget?(provider: AgentSessionProviders): void; + /** + * Optional getter for the set of allowed session targets. + * When provided, the session target and delegation pickers will only show targets + * in this set. This allows host contexts (e.g. the agent sessions window) to restrict + * visible targets without adding host-specific dependencies to chat core. + */ + getAllowedTargets?(): ReadonlySet | undefined; /** * Optional event that fires when the active session provider changes. * When provided, listeners (like chatInputPart) can react to session type changes @@ -272,6 +279,14 @@ export interface IChatWidgetViewOptions { */ sessionTypePickerDelegate?: ISessionTypePickerDelegate; + /** + * Optional set of allowed session targets for the pickers. + * When provided, only targets in this set will be visible in the session target + * and delegation pickers. This allows host contexts (e.g. the agent sessions window) + * to restrict the available targets. + */ + allowedSessionTargets?: ReadonlySet; + /** * Optional delegate for the workspace picker. * When provided, shows a workspace picker in the chat input allowing users to select diff --git a/src/vs/workbench/contrib/chat/browser/widget/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/widget/chatWidget.ts index 4134d04ad82..acb7271c572 100644 --- a/src/vs/workbench/contrib/chat/browser/widget/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/widget/chatWidget.ts @@ -1832,6 +1832,7 @@ export class ChatWidget extends Disposable implements IChatWidget { widgetViewKindTag: this.getWidgetViewKindTag(), defaultMode: this.viewOptions.defaultMode, sessionTypePickerDelegate: this.viewOptions.sessionTypePickerDelegate, + allowedSessionTargets: this.viewOptions.allowedSessionTargets, workspacePickerDelegate: this.viewOptions.workspacePickerDelegate, }; diff --git a/src/vs/workbench/contrib/chat/browser/widget/input/chatInputPart.ts b/src/vs/workbench/contrib/chat/browser/widget/input/chatInputPart.ts index aa98e73062c..4f60c1d918b 100644 --- a/src/vs/workbench/contrib/chat/browser/widget/input/chatInputPart.ts +++ b/src/vs/workbench/contrib/chat/browser/widget/input/chatInputPart.ts @@ -159,6 +159,12 @@ export interface IChatInputPartOptions { * When provided, allows the input part to maintain independent state for the selected session type. */ sessionTypePickerDelegate?: ISessionTypePickerDelegate; + /** + * Optional set of allowed session targets for the pickers. + * When provided, only targets in this set will be visible in the session target + * and delegation pickers. + */ + allowedSessionTargets?: ReadonlySet; /** * Optional delegate for the workspace picker. * When provided, shows a workspace picker allowing users to select a target workspace @@ -2199,6 +2205,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge const sessionResource = this._widget?.viewModel?.sessionResource; return sessionResource ? getAgentSessionProvider(sessionResource) : undefined; }; + const allowedSessionTargets = this.options.allowedSessionTargets; const delegate: ISessionTypePickerDelegate = this.options.sessionTypePickerDelegate ?? { getActiveSessionProvider: () => { return getActiveSessionType(); @@ -2213,6 +2220,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge this.updateAgentSessionTypeContextKey(); this.refreshChatSessionPickers(); }, + getAllowedTargets: allowedSessionTargets ? () => allowedSessionTargets : undefined, }; const isWelcomeViewMode = !!this.options.sessionTypePickerDelegate?.setActiveSessionProvider; const Picker = (action.id === OpenSessionTargetPickerAction.ID || isWelcomeViewMode) ? SessionTypePickerActionItem : DelegationSessionPickerActionItem; diff --git a/src/vs/workbench/contrib/chat/browser/widget/input/delegationSessionPickerActionItem.ts b/src/vs/workbench/contrib/chat/browser/widget/input/delegationSessionPickerActionItem.ts index 9e5218f2afb..a1a901d986d 100644 --- a/src/vs/workbench/contrib/chat/browser/widget/input/delegationSessionPickerActionItem.ts +++ b/src/vs/workbench/contrib/chat/browser/widget/input/delegationSessionPickerActionItem.ts @@ -50,6 +50,11 @@ export class DelegationSessionPickerActionItem extends SessionTypePickerActionIt } protected override _isVisible(type: AgentSessionProviders): boolean { + const allowedTargets = this.delegate.getAllowedTargets?.(); + if (allowedTargets && !allowedTargets.has(type)) { + return false; + } + if (this.delegate.getActiveSessionProvider() === type) { return true; // Always show active session type } diff --git a/src/vs/workbench/contrib/chat/browser/widget/input/sessionTargetPickerActionItem.ts b/src/vs/workbench/contrib/chat/browser/widget/input/sessionTargetPickerActionItem.ts index 7095abd9ecd..089e0523423 100644 --- a/src/vs/workbench/contrib/chat/browser/widget/input/sessionTargetPickerActionItem.ts +++ b/src/vs/workbench/contrib/chat/browser/widget/input/sessionTargetPickerActionItem.ts @@ -181,6 +181,10 @@ export class SessionTypePickerActionItem extends ChatInputPickerActionViewItem { } protected _isVisible(type: AgentSessionProviders): boolean { + const allowedTargets = this.delegate.getAllowedTargets?.(); + if (allowedTargets && !allowedTargets.has(type)) { + return false; + } return true; } diff --git a/src/vs/workbench/contrib/chat/browser/widgetHosts/viewPane/chatViewPane.ts b/src/vs/workbench/contrib/chat/browser/widgetHosts/viewPane/chatViewPane.ts index 9ff8c082319..f3b5355c39d 100644 --- a/src/vs/workbench/contrib/chat/browser/widgetHosts/viewPane/chatViewPane.ts +++ b/src/vs/workbench/contrib/chat/browser/widgetHosts/viewPane/chatViewPane.ts @@ -49,6 +49,7 @@ import { IChatSessionsService, localChatSessionType } from '../../../common/chat import { LocalChatSessionUri, getChatSessionType } from '../../../common/model/chatUri.js'; import { ChatAgentLocation, ChatConfiguration, ChatModeKind } from '../../../common/constants.js'; import { AgentSessionsControl } from '../../agentSessions/agentSessionsControl.js'; +import { AgentSessionProviders } from '../../agentSessions/agentSessions.js'; import { ACTION_ID_NEW_CHAT } from '../../actions/chatActions.js'; import { ChatWidget } from '../../widget/chatWidget.js'; import { ChatViewWelcomeController, IViewWelcomeDelegate } from '../../viewsWelcome/chatViewWelcomeController.js'; @@ -530,6 +531,7 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate { : 'explicit', supportsChangingModes: true, dndContainer: parent, + allowedSessionTargets: this.getAllowedSessionTargets(), }, { listForeground: SIDE_BAR_FOREGROUND, @@ -547,6 +549,15 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate { return this._widget; } + /** + * Returns the set of allowed session targets for the pickers, or undefined to allow all. + * Subclasses (e.g. in the agent sessions window) can override this to restrict + * the visible targets in the session target and delegation pickers. + */ + protected getAllowedSessionTargets(): ReadonlySet | undefined { + return undefined; + } + private createChatTitleControl(parent: HTMLElement): void { this.titleControl = this._register(this.instantiationService.createInstance(ChatViewTitleControl, parent,