From 48662ad101daeb69b9a95fdccc4c4f45522ffb3d Mon Sep 17 00:00:00 2001 From: Josh Spicer <23246594+joshspicer@users.noreply.github.com> Date: Wed, 21 Jan 2026 19:27:44 -0800 Subject: [PATCH] further splitting of agent status bar features (#289554) --- .../agentSessionProjectionActions.ts | 3 +- .../agentSessionsExperiments.contribution.ts | 33 +++++++----- .../experiments/agentTitleBarStatusWidget.ts | 51 +++++++++++-------- .../media/agenttitlebarstatuswidget.css | 12 +++-- 4 files changed, 59 insertions(+), 40 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/agentSessions/experiments/agentSessionProjectionActions.ts b/src/vs/workbench/contrib/chat/browser/agentSessions/experiments/agentSessionProjectionActions.ts index 15182db4d4c..a4526e5aa5f 100644 --- a/src/vs/workbench/contrib/chat/browser/agentSessions/experiments/agentSessionProjectionActions.ts +++ b/src/vs/workbench/contrib/chat/browser/agentSessions/experiments/agentSessionProjectionActions.ts @@ -120,8 +120,7 @@ export class ToggleUnifiedAgentsBarAction extends ToggleTitleBarConfigAction { ContextKeyExpr.and( ChatContextKeys.enabled, IsCompactTitleBarContext.negate(), - ChatContextKeys.supported, - ContextKeyExpr.has(`config.${ChatConfiguration.AgentStatusEnabled}`) + ChatContextKeys.supported ) ); } diff --git a/src/vs/workbench/contrib/chat/browser/agentSessions/experiments/agentSessionsExperiments.contribution.ts b/src/vs/workbench/contrib/chat/browser/agentSessions/experiments/agentSessionsExperiments.contribution.ts index 784003860b8..25815e4802e 100644 --- a/src/vs/workbench/contrib/chat/browser/agentSessions/experiments/agentSessionsExperiments.contribution.ts +++ b/src/vs/workbench/contrib/chat/browser/agentSessions/experiments/agentSessionsExperiments.contribution.ts @@ -34,6 +34,7 @@ class AgentSessionReadyContribution extends Disposable implements IWorkbenchCont private readonly _widgetDisposables = this._register(new DisposableStore()); private _entriesWatcher: IDisposable | undefined; private _watchedSessionResource: URI | undefined; + private _suppressSessionReady = false; // Suppress re-showing session-ready after user explicitly exits projection constructor( @IChatWidgetService private readonly chatWidgetService: IChatWidgetService, @@ -59,15 +60,13 @@ class AgentSessionReadyContribution extends Disposable implements IWorkbenchCont } })); - // When projection mode changes, re-check session state - this._register(this.agentTitleBarStatusService.onDidChangeMode(() => { - // If we entered projection mode, the title bar service already handles it - // If we exited projection mode, check if we should show session-ready state - if (!this.agentSessionProjectionService.isActive) { - const currentWidget = this.chatWidgetService.getAllWidgets().find(w => w.location === ChatAgentLocation.Chat); - if (currentWidget) { - this._checkSession(currentWidget.viewModel?.sessionResource); - } + // When projection mode exits, suppress session-ready for the same session + this._register(this.agentSessionProjectionService.onDidChangeProjectionMode(isActive => { + if (!isActive) { + // User explicitly exited projection - suppress re-showing session-ready for this session + this._suppressSessionReady = true; + this._clearEntriesWatcher(); + this.agentTitleBarStatusService.exitSessionReadyMode(); } })); @@ -97,6 +96,10 @@ class AgentSessionReadyContribution extends Disposable implements IWorkbenchCont } private _checkSession(sessionResource: URI | undefined): void { + // Clear the suppress flag when switching to a different session + if (sessionResource?.toString() !== this._watchedSessionResource?.toString()) { + this._suppressSessionReady = false; + } // Update state based on current session this._updateSessionReadyState(sessionResource); } @@ -162,7 +165,7 @@ class AgentSessionReadyContribution extends Disposable implements IWorkbenchCont const entries = editingSession.entries.get(); const hasUndecidedChanges = entries.some(entry => entry.state.get() === ModifiedFileEntryState.Modified); - if (hasUndecidedChanges) { + if (hasUndecidedChanges && !this._suppressSessionReady) { // Enter session-ready mode this.agentTitleBarStatusService.enterSessionReadyMode(session.resource, session.label); @@ -205,7 +208,10 @@ MenuRegistry.appendMenuItem(MenuId.CommandCenter, { submenu: MenuId.AgentsTitleBarControlMenu, title: localize('agentsControl', "Agents"), icon: Codicon.chatSparkle, - when: ContextKeyExpr.has(`config.${ChatConfiguration.AgentStatusEnabled}`), + when: ContextKeyExpr.or( + ContextKeyExpr.has(`config.${ChatConfiguration.AgentStatusEnabled}`), + ContextKeyExpr.has(`config.${ChatConfiguration.UnifiedAgentsBar}`) + ), order: 10002 // to the right of the chat button }); @@ -215,7 +221,10 @@ MenuRegistry.appendMenuItem(MenuId.AgentsTitleBarControlMenu, { id: 'workbench.action.chat.toggle', title: localize('openChat', "Open Chat"), }, - when: ContextKeyExpr.has(`config.${ChatConfiguration.AgentStatusEnabled}`), + when: ContextKeyExpr.or( + ContextKeyExpr.has(`config.${ChatConfiguration.AgentStatusEnabled}`), + ContextKeyExpr.has(`config.${ChatConfiguration.UnifiedAgentsBar}`) + ), group: 'a_open', order: 1 }); diff --git a/src/vs/workbench/contrib/chat/browser/agentSessions/experiments/agentTitleBarStatusWidget.ts b/src/vs/workbench/contrib/chat/browser/agentSessions/experiments/agentTitleBarStatusWidget.ts index bf416cdb159..c6be939588c 100644 --- a/src/vs/workbench/contrib/chat/browser/agentSessions/experiments/agentTitleBarStatusWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/agentSessions/experiments/agentTitleBarStatusWidget.ts @@ -149,9 +149,9 @@ export class AgentTitleBarStatusWidget extends BaseActionViewItem { this._render(); })); - // Re-render when enhanced setting changes + // Re-render when settings change this._register(this.configurationService.onDidChangeConfiguration(e => { - if (e.affectsConfiguration(ChatConfiguration.UnifiedAgentsBar)) { + if (e.affectsConfiguration(ChatConfiguration.UnifiedAgentsBar) || e.affectsConfiguration(ChatConfiguration.AgentStatusEnabled)) { this._lastRenderState = undefined; // Force re-render this._render(); } @@ -203,8 +203,9 @@ export class AgentTitleBarStatusWidget extends BaseActionViewItem { // Get current filter state for state key const { isFilteredToUnread, isFilteredToInProgress } = this._getCurrentFilterState(); - // Check if enhanced mode is enabled - const isEnhanced = this.configurationService.getValue(ChatConfiguration.UnifiedAgentsBar) === true; + // Check which settings are enabled (these are independent settings) + const unifiedAgentsBarEnabled = this.configurationService.getValue(ChatConfiguration.UnifiedAgentsBar) === true; + const agentStatusEnabled = this.configurationService.getValue(ChatConfiguration.AgentStatusEnabled) === true; // Build state key for comparison const stateKey = JSON.stringify({ @@ -217,7 +218,8 @@ export class AgentTitleBarStatusWidget extends BaseActionViewItem { label, isFilteredToUnread, isFilteredToInProgress, - isEnhanced, + unifiedAgentsBarEnabled, + agentStatusEnabled, }); // Skip re-render if state hasn't changed @@ -238,13 +240,14 @@ export class AgentTitleBarStatusWidget extends BaseActionViewItem { } else if (this.agentTitleBarStatusService.mode === AgentStatusMode.SessionReady) { // Session ready mode - show session title + enter projection button this._renderSessionReadyMode(this._dynamicDisposables); - } else if (isEnhanced) { - // Enhanced mode - show full pill with label + status badge + } else if (unifiedAgentsBarEnabled) { + // Unified Agents Bar - show full pill with label + status badge this._renderChatInputMode(this._dynamicDisposables); - } else { - // Basic mode - show only the status badge (sparkle + unread/active counts) + } else if (agentStatusEnabled) { + // Agent Status - show only the status badge (sparkle + unread/active counts) this._renderBadgeOnlyMode(this._dynamicDisposables); } + // If neither setting is enabled, nothing is rendered (container is already cleared) } finally { this._isRendering = false; } @@ -398,8 +401,10 @@ export class AgentTitleBarStatusWidget extends BaseActionViewItem { } })); - // Status badge (separate rectangle on right) - always rendered for smooth transitions - this._renderStatusBadge(disposables, activeSessions, unreadSessions); + // Status badge (separate rectangle on right) - only when Agent Status is enabled + if (this.configurationService.getValue(ChatConfiguration.AgentStatusEnabled) === true) { + this._renderStatusBadge(disposables, activeSessions, unreadSessions); + } } private _renderSessionMode(disposables: DisposableStore): void { @@ -443,8 +448,10 @@ export class AgentTitleBarStatusWidget extends BaseActionViewItem { disposables.add(addDisposableListener(pill, EventType.CLICK, exitHandler)); disposables.add(addDisposableListener(pill, EventType.MOUSE_DOWN, exitHandler)); - // Status badge (separate rectangle on right) - always rendered for smooth transitions - this._renderStatusBadge(disposables, activeSessions, unreadSessions); + // Status badge (separate rectangle on right) - only when Agent Status is enabled + if (this.configurationService.getValue(ChatConfiguration.AgentStatusEnabled) === true) { + this._renderStatusBadge(disposables, activeSessions, unreadSessions); + } } /** @@ -492,8 +499,10 @@ export class AgentTitleBarStatusWidget extends BaseActionViewItem { disposables.add(addDisposableListener(pill, EventType.CLICK, enterHandler)); disposables.add(addDisposableListener(pill, EventType.MOUSE_DOWN, enterHandler)); - // Status badge (separate rectangle on right) - always rendered for smooth transitions - this._renderStatusBadge(disposables, activeSessions, unreadSessions); + // Status badge (separate rectangle on right) - only when Agent Status is enabled + if (this.configurationService.getValue(ChatConfiguration.AgentStatusEnabled) === true) { + this._renderStatusBadge(disposables, activeSessions, unreadSessions); + } } /** @@ -1112,21 +1121,21 @@ export class AgentTitleBarStatusRendering extends Disposable implements IWorkben }, undefined)); // Add/remove CSS classes on workbench based on settings - // Force enable command center and disable chat controls when agent status is enabled + // Force enable command center and disable chat controls when agent status or unified agents bar is enabled const updateClass = () => { const enabled = configurationService.getValue(ChatConfiguration.AgentStatusEnabled) === true; const enhanced = configurationService.getValue(ChatConfiguration.UnifiedAgentsBar) === true; mainWindow.document.body.classList.toggle('agent-status-enabled', enabled); - mainWindow.document.body.classList.toggle('unified-agents-bar', enabled && enhanced); + mainWindow.document.body.classList.toggle('unified-agents-bar', enhanced); - // Force enable command center when agent status is enabled - if (enabled && configurationService.getValue(LayoutSettings.COMMAND_CENTER) !== true) { + // Force enable command center when agent status or unified agents bar is enabled + if ((enabled || enhanced) && configurationService.getValue(LayoutSettings.COMMAND_CENTER) !== true) { configurationService.updateValue(LayoutSettings.COMMAND_CENTER, true); } - // Turn off chat controls when agent status is enabled (they would be duplicates) - if (enabled && configurationService.getValue('chat.commandCenter.enabled') === true) { + // Turn off chat controls when agent status or unified agents bar is enabled (they would be duplicates) + if ((enabled || enhanced) && configurationService.getValue('chat.commandCenter.enabled') === true) { configurationService.updateValue('chat.commandCenter.enabled', false); } }; diff --git a/src/vs/workbench/contrib/chat/browser/agentSessions/experiments/media/agenttitlebarstatuswidget.css b/src/vs/workbench/contrib/chat/browser/agentSessions/experiments/media/agenttitlebarstatuswidget.css index 12afaeb7076..6ad214c5c04 100644 --- a/src/vs/workbench/contrib/chat/browser/agentSessions/experiments/media/agenttitlebarstatuswidget.css +++ b/src/vs/workbench/contrib/chat/browser/agentSessions/experiments/media/agenttitlebarstatuswidget.css @@ -11,7 +11,8 @@ display: none !important; } -.agent-status-enabled .command-center { +.agent-status-enabled .command-center, +.unified-agents-bar .command-center { overflow: visible !important; } @@ -130,9 +131,9 @@ opacity: 1; } -/* Session mode (viewing a session) */ +/* Session mode (viewing a session) - use hover color as default to show we're "inside" projection */ .agent-status-pill.session-mode { - background-color: var(--vscode-quickInput-background); + background-color: var(--vscode-chat-requestBubbleBackground); border: 1px solid var(--vscode-commandCenter-border, transparent); padding: 0 12px; cursor: pointer; @@ -140,6 +141,7 @@ .agent-status-pill.session-mode:hover { background-color: var(--vscode-chat-requestBubbleBackground); + filter: brightness(1.1); border-color: var(--vscode-commandCenter-border, transparent); } @@ -411,7 +413,7 @@ display: flex; align-items: center; justify-content: center; - padding: 0 6px; + padding: 0 4px; height: 100%; border-top-left-radius: 5px; border-bottom-left-radius: 5px; @@ -442,7 +444,7 @@ display: flex; align-items: center; justify-content: center; - width: 22px; + width: 18px; height: 100%; padding: 0; }