further splitting of agent status bar features (#289554)

This commit is contained in:
Josh Spicer
2026-01-21 19:27:44 -08:00
committed by GitHub
parent 0ffdfb45f4
commit 48662ad101
4 changed files with 59 additions and 40 deletions
@@ -120,8 +120,7 @@ export class ToggleUnifiedAgentsBarAction extends ToggleTitleBarConfigAction {
ContextKeyExpr.and(
ChatContextKeys.enabled,
IsCompactTitleBarContext.negate(),
ChatContextKeys.supported,
ContextKeyExpr.has(`config.${ChatConfiguration.AgentStatusEnabled}`)
ChatContextKeys.supported
)
);
}
@@ -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
});
@@ -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<boolean>(ChatConfiguration.UnifiedAgentsBar) === true;
// Check which settings are enabled (these are independent settings)
const unifiedAgentsBarEnabled = this.configurationService.getValue<boolean>(ChatConfiguration.UnifiedAgentsBar) === true;
const agentStatusEnabled = this.configurationService.getValue<boolean>(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<boolean>(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<boolean>(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<boolean>(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<boolean>(ChatConfiguration.AgentStatusEnabled) === true;
const enhanced = configurationService.getValue<boolean>(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<boolean>(LayoutSettings.COMMAND_CENTER) !== true) {
// Force enable command center when agent status or unified agents bar is enabled
if ((enabled || enhanced) && configurationService.getValue<boolean>(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<boolean>('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<boolean>('chat.commandCenter.enabled') === true) {
configurationService.updateValue('chat.commandCenter.enabled', false);
}
};
@@ -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;
}