diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx
index 8b510d457fd..26a5c41ded5 100644
--- a/apps/web/src/components/ChatView.tsx
+++ b/apps/web/src/components/ChatView.tsx
@@ -5913,6 +5913,11 @@ function ChatViewContent(props: ChatViewProps) {
rightPanelAvailable={activeProject !== null}
rightPanelOpen={rightPanelOpen}
rightPanelShortcutLabel={shortcutLabelForCommand(keybindings, "rightPanel.toggle")}
+ // Suppressed while the Agents surface is visible: the roster itself is
+ // on screen, so the toggle badge would be pointing at nothing.
+ liveAgentCount={
+ rightPanelOpen && activeRightPanelSurface?.kind === "agents" ? 0 : agentPanelModel.liveCount
+ }
onToggleTerminal={toggleTerminalVisibility}
onToggleRightPanel={toggleRightPanel}
/>
@@ -6419,6 +6424,7 @@ function ChatViewContent(props: ChatViewProps) {
browserAvailable={isPreviewSupportedInRuntime()}
diffAvailable={isServerThread && isGitRepo}
filesAvailable={activeProject !== null}
+ liveAgentCount={agentPanelModel.liveCount}
>
{rightPanelContent}
@@ -6447,6 +6453,7 @@ function ChatViewContent(props: ChatViewProps) {
browserAvailable={isPreviewSupportedInRuntime()}
diffAvailable={isServerThread && isGitRepo}
filesAvailable={activeProject !== null}
+ liveAgentCount={agentPanelModel.liveCount}
>
{rightPanelContent}
diff --git a/apps/web/src/components/RightPanelTabs.tsx b/apps/web/src/components/RightPanelTabs.tsx
index b9345ab8c3c..0b1700e7349 100644
--- a/apps/web/src/components/RightPanelTabs.tsx
+++ b/apps/web/src/components/RightPanelTabs.tsx
@@ -48,6 +48,8 @@ interface RightPanelTabsProps {
browserAvailable: boolean;
diffAvailable: boolean;
filesAvailable: boolean;
+ /** Running + waiting subagents; badges the Agents card in the empty state. */
+ liveAgentCount: number;
children: ReactNode;
}
@@ -96,6 +98,7 @@ function RightPanelEmptyState(props: {
browserAvailable: boolean;
diffAvailable: boolean;
filesAvailable: boolean;
+ liveAgentCount: number;
}) {
const actions = [
{
@@ -105,6 +108,7 @@ function RightPanelEmptyState(props: {
available: props.browserAvailable,
disabledReason: SURFACE_DISABLED_REASONS.browser,
onClick: props.onAddBrowser,
+ badgeCount: 0,
},
{
label: "Terminal",
@@ -113,6 +117,7 @@ function RightPanelEmptyState(props: {
available: true,
disabledReason: null,
onClick: props.onAddTerminal,
+ badgeCount: 0,
},
{
label: "Files",
@@ -121,6 +126,7 @@ function RightPanelEmptyState(props: {
available: props.filesAvailable,
disabledReason: SURFACE_DISABLED_REASONS.files,
onClick: props.onAddFiles,
+ badgeCount: 0,
},
{
label: "Diff",
@@ -129,6 +135,7 @@ function RightPanelEmptyState(props: {
available: props.diffAvailable,
disabledReason: SURFACE_DISABLED_REASONS.diff,
onClick: props.onAddDiff,
+ badgeCount: 0,
},
{
label: "Agents",
@@ -137,6 +144,7 @@ function RightPanelEmptyState(props: {
available: true,
disabledReason: null,
onClick: props.onAddAgents,
+ badgeCount: props.liveAgentCount,
},
] as const;
@@ -154,7 +162,17 @@ function RightPanelEmptyState(props: {
const Icon = action.icon;
const content = (
<>
-
+
+
+ {action.badgeCount > 0 ? (
+
+ {action.badgeCount}
+
+ ) : null}
+
{action.label}
{action.description}
@@ -498,6 +516,7 @@ export function RightPanelTabs(props: RightPanelTabsProps) {
browserAvailable={props.browserAvailable}
diffAvailable={props.diffAvailable}
filesAvailable={props.filesAvailable}
+ liveAgentCount={props.liveAgentCount}
/>
) : (
props.children
diff --git a/apps/web/src/components/chat/PanelLayoutControls.tsx b/apps/web/src/components/chat/PanelLayoutControls.tsx
index deb7b3ee9af..c61826f677d 100644
--- a/apps/web/src/components/chat/PanelLayoutControls.tsx
+++ b/apps/web/src/components/chat/PanelLayoutControls.tsx
@@ -11,6 +11,8 @@ interface PanelLayoutControlsProps {
rightPanelAvailable: boolean;
rightPanelOpen: boolean;
rightPanelShortcutLabel: string | null;
+ /** Running + waiting subagents in this thread; badges the right panel toggle. */
+ liveAgentCount: number;
onToggleTerminal: () => void;
onToggleRightPanel: () => void;
}
@@ -22,6 +24,7 @@ export const PanelLayoutControls = memo(function PanelLayoutControls({
rightPanelAvailable,
rightPanelOpen,
rightPanelShortcutLabel,
+ liveAgentCount,
onToggleTerminal,
onToggleRightPanel,
}: PanelLayoutControlsProps) {
@@ -59,18 +62,34 @@ export const PanelLayoutControls = memo(function PanelLayoutControls({
className="shrink-0 [-webkit-app-region:no-drag]"
pressed={rightPanelOpen}
onPressedChange={onToggleRightPanel}
- aria-label="Toggle right panel"
+ aria-label={
+ liveAgentCount > 0
+ ? `Toggle right panel, ${liveAgentCount} ${liveAgentCount === 1 ? "agent" : "agents"} working`
+ : "Toggle right panel"
+ }
variant="ghost"
size="sm"
disabled={!rightPanelAvailable}
>
+ {liveAgentCount > 0 ? (
+
+ {liveAgentCount}
+
+ ) : null}
}
/>
{rightPanelAvailable
- ? `Toggle right panel${rightPanelShortcutLabel ? ` (${rightPanelShortcutLabel})` : ""}`
+ ? `Toggle right panel${rightPanelShortcutLabel ? ` (${rightPanelShortcutLabel})` : ""}${
+ liveAgentCount > 0
+ ? ` ยท ${liveAgentCount} ${liveAgentCount === 1 ? "agent" : "agents"} working`
+ : ""
+ }`
: "Right panel is unavailable"}