From a8d6c0fd451f2f94200681aed1f2040e2996aed8 Mon Sep 17 00:00:00 2001 From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Date: Fri, 14 Aug 2026 16:15:40 -0700 Subject: [PATCH] fix(agent-status): settle background activity rows --- .../activity/ActivityPrototypePage.test.ts | 16 ++++++++++++++ .../activity/ActivityPrototypePage.tsx | 21 +++++++++++++------ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/renderer/src/components/activity/ActivityPrototypePage.test.ts b/src/renderer/src/components/activity/ActivityPrototypePage.test.ts index e20c9455261..6ca73292a35 100644 --- a/src/renderer/src/components/activity/ActivityPrototypePage.test.ts +++ b/src/renderer/src/components/activity/ActivityPrototypePage.test.ts @@ -21,6 +21,7 @@ import { buildActivityThreadGroups, buildActivityEvents, buildAgentPaneThreads, + getActivityThreadDotState, getActivityThreadGroup, groupActivityThreadsByStatus, isActivitySearchQueryTooLarge @@ -587,6 +588,21 @@ describe('buildActivityEvents', () => { [PANE_KEY_3] ]) }) + + it('settles a background-only row without changing its working group', () => { + const result = makeActivityResult({ + entries: { + [PANE_KEY]: { ...makeWorkingEntryWithoutHistory(), backgroundOnly: true } + } + }) + const thread = makeThreads(result)[0] + + expect(getActivityThreadDotState(thread)).toBe('background') + expect(getActivityThreadGroup(thread, 'status')).toEqual({ + key: 'working', + label: 'Working' + }) + }) }) describe('activity thread grouping', () => { diff --git a/src/renderer/src/components/activity/ActivityPrototypePage.tsx b/src/renderer/src/components/activity/ActivityPrototypePage.tsx index 6157c796d71..14d31e9c889 100644 --- a/src/renderer/src/components/activity/ActivityPrototypePage.tsx +++ b/src/renderer/src/components/activity/ActivityPrototypePage.tsx @@ -11,7 +11,7 @@ import { TerminalSquare } from 'lucide-react' -import { AgentStateDot, agentStateLabel } from '@/components/AgentStateDot' +import { AgentStateDot, agentStateLabel, type AgentDotState } from '@/components/AgentStateDot' import { AgentIcon } from '@/lib/agent-catalog' import { agentTypeToIconAgent, @@ -84,6 +84,7 @@ import { resolveActivityThreadStatusPreview } from '@/lib/activity-thread-display' import { getAgentRowPrimaryText } from '@/lib/agent-row-primary-text' +import { isBackgroundOnlyAgentActivity } from '../../../../shared/agent-background-only-activity' type ThreadReadFilter = 'all' | 'unread' type ActivityGroupBy = 'status' | 'project' | 'worktree' | 'agent' @@ -964,12 +965,19 @@ function threadAgentState(thread: AgentPaneThread): AgentStatusState { return thread.currentAgentState ?? thread.latestEvent?.state ?? 'done' } -function threadAgentStateLabel(thread: AgentPaneThread): string { +export function getActivityThreadDotState(thread: AgentPaneThread): AgentDotState { const state = threadAgentState(thread) if (!thread.currentAgentState && state === 'done' && thread.latestEvent?.entry.interrupted) { - return 'Interrupted' + return 'interrupted' } - return agentStateLabel(state) + if (state === 'working' && isBackgroundOnlyAgentActivity(thread.currentAgentEntry ?? undefined)) { + return 'background' + } + return state +} + +function threadAgentStateLabel(thread: AgentPaneThread): string { + return agentStateLabel(getActivityThreadDotState(thread)) } export function getActivityThreadGroup( @@ -981,7 +989,8 @@ export function getActivityThreadGroup( if (!thread.currentAgentState && state === 'done' && thread.latestEvent?.entry.interrupted) { return { key: 'done:interrupted', label: threadAgentStateLabel(thread) } } - return { key: state, label: threadAgentStateLabel(thread) } + // Background-only rows keep the working group; only their own foreground presentation settles. + return { key: state, label: agentStateLabel(state) } } if (groupBy === 'project') { return thread.repo @@ -1164,7 +1173,7 @@ export function handleActivityFilterFocusShortcut({ } function ThreadAgentStateIndicator({ thread }: { thread: AgentPaneThread }): React.JSX.Element { - const state = threadAgentState(thread) + const state = getActivityThreadDotState(thread) const label = threadAgentStateLabel(thread) return (