fix(desktop): make Agents indicator match the Spawn-tree panel

The status-bar "Agents" item conflated three unrelated signals — running
subagents (aggregated across all sessions), in-flight session turns, and
failed background *system* actions (gateway restarts, toolset installs,
computer-use grants via $desktopActionTasks/preview restart) — yet
clicking it opens AgentsView, which renders only subagents. A failed
gateway restart therefore showed "Agents (1 Failed)" over an empty
"No live subagents" tree. AgentsView also filtered to the active session,
so a subagent running in a background session showed "Agents N running"
with nothing in the tree (the desync reported in #49808).

Unify the scope both surfaces speak:
- AgentsView aggregates subagents across every session (salvages #49819).
- The indicator's running/failed counts come from subagents only
  (aggregated), never background system actions — those keep their own
  surfaces in settings / command center.

So "Agents (N …)" now always points at a populated Spawn tree.

Supersedes #49819. Fixes #49808.
This commit is contained in:
Brooklyn Nicholson 2026-06-24 18:16:14 -05:00
parent 404b06ac4f
commit a268dfff0a
4 changed files with 51 additions and 40 deletions

View file

@ -22,8 +22,6 @@ import type { RuntimeReadinessResult } from '@/lib/runtime-readiness'
import { contextBarLabel, LiveDuration, usageContextLabel } from '@/lib/statusbar'
import { cn } from '@/lib/utils'
import { setGlobalYolo, setSessionYolo } from '@/lib/yolo-session'
import { $desktopActionTasks } from '@/store/activity'
import { $previewServerRestartStatus } from '@/store/preview'
import {
$activeSessionId,
$busy,
@ -31,11 +29,10 @@ import {
$currentUsage,
$sessionStartedAt,
$turnStartedAt,
$workingSessionIds,
$yoloActive,
setYoloActive
} from '@/store/session'
import { $subagentsBySession, activeSubagentCount } from '@/store/subagents'
import { $subagentsBySession, activeSubagentCount, failedSubagentCount } from '@/store/subagents'
import { $gatewayRestarting } from '@/store/system-actions'
import {
$backendUpdateApply,
@ -90,12 +87,9 @@ export function useStatusbarItems({
const yoloActive = useStore($yoloActive)
const busy = useStore($busy)
const currentUsage = useStore($currentUsage)
const desktopActionTasks = useStore($desktopActionTasks)
const gatewayRestarting = useStore($gatewayRestarting)
const previewServerRestartStatus = useStore($previewServerRestartStatus)
const sessionStartedAt = useStore($sessionStartedAt)
const turnStartedAt = useStore($turnStartedAt)
const workingSessionIds = useStore($workingSessionIds)
const subagentsBySession = useStore($subagentsBySession)
const updateStatus = useStore($updateStatus)
const updateApply = useStore($updateApply)
@ -159,24 +153,17 @@ export function useStatusbarItems({
[gatewayLogLines, gatewayState, inferenceStatus, openCommandCenterSection, statusSnapshot]
)
const { bgFailed, bgRunning, subagentsRunning } = useMemo(() => {
const actions = Object.values(desktopActionTasks)
const running = actions.filter(t => t.status.running).length
const failed = actions.filter(t => !t.status.running && (t.status.exit_code ?? 0) !== 0).length
const previewRunning = previewServerRestartStatus === 'running' ? 1 : 0
const previewFailed = previewServerRestartStatus === 'error' ? 1 : 0
const subagentsRunning = Object.values(subagentsBySession).reduce(
(sum, items) => sum + activeSubagentCount(items),
0
)
// The indicator must speak the same scope as the Spawn-tree panel it opens:
// every session's subagents, never background system actions (gateway
// restarts, toolset installs) which surface in their own panels.
const { subagentsFailed, subagentsRunning } = useMemo(() => {
const lists = Object.values(subagentsBySession)
return {
bgFailed: failed + previewFailed,
bgRunning: workingSessionIds.length + running + previewRunning,
subagentsRunning
subagentsFailed: lists.reduce((sum, items) => sum + failedSubagentCount(items), 0),
subagentsRunning: lists.reduce((sum, items) => sum + activeSubagentCount(items), 0)
}
}, [desktopActionTasks, previewServerRestartStatus, subagentsBySession, workingSessionIds])
}, [subagentsBySession])
const gatewayOpen = gatewayState === 'open'
const gatewayConnecting = gatewayState === 'connecting'
@ -321,20 +308,18 @@ export function useStatusbarItems({
{
className: cn(
agentsOpen && 'bg-accent/55 text-foreground',
bgFailed > 0 && 'text-destructive hover:text-destructive'
subagentsFailed > 0 && 'text-destructive hover:text-destructive'
),
detail:
subagentsRunning > 0
? copy.subagents(subagentsRunning)
: bgFailed > 0
? copy.failed(bgFailed)
: bgRunning > 0
? copy.running(bgRunning)
: undefined,
: subagentsFailed > 0
? copy.failed(subagentsFailed)
: undefined,
icon:
bgFailed > 0 ? (
subagentsFailed > 0 ? (
<AlertCircle className="size-3" />
) : bgRunning > 0 || subagentsRunning > 0 ? (
) : subagentsRunning > 0 ? (
<Loader2 className="size-3 animate-spin" />
) : (
<Sparkles className="size-3" />
@ -356,8 +341,6 @@ export function useStatusbarItems({
],
[
agentsOpen,
bgFailed,
bgRunning,
commandCenterOpen,
copy,
gatewayMenuContent,
@ -367,6 +350,7 @@ export function useStatusbarItems({
inferenceReady,
inferenceStatus?.reason,
openAgents,
subagentsFailed,
subagentsRunning,
toggleCommandCenter
]