feat(acp-chat): sidebar parity, background work menu and subagents for ACP chat

Merged
HA
1mo ago
+3376-1277

Summary

ACP chat agents (acp-chat flag) now behave like terminal agents everywhere outside the pane, and the background work they start is visible and stoppable in one place.

  1. Sidebar and workspace parity: status dots, chime, agent count, ports, workspace auto-naming, last-active ranking and page-comment delivery work for a pane on the chat surface.
  2. Standardised background work: dev servers and subagents are reported through the JetBrains AIR ACP extension that claude-agent-acp and codex-acp both speak, as one backgroundTasks list on the chat session.
  3. Workspace activity menu: the Pages menu moves to the tab bar and groups background processes (with stop), subagents and pages. It replaces the background terminals button.

Also includes: a queued-prompt badge on sidebar rows, the chat session title as the pane title, scroll-to-load for older messages, tool runs that collapse once the turn moves on, and composer buttons sized to match.


Part 1: Sidebar and workspace parity

Why

Switching an agent pane to the chat surface kills its pty, which ends the terminal agent binding. Every sidebar signal is keyed by that binding, so a chat showed no status, count, ports or title, and a workspace opened straight into a chat stayed "New workspace".

How

  • A LiveSessionObserver in chat-runtime lets the host follow sessions. chat-v3/chatAgentBridge.ts reports each chat under the pane's terminal id, which the renderer now passes as an optional terminalId on createSession.
  • Chat bindings live in memory in TerminalAgentStore and merge into listByWorkspace. The lifecycle fan-out (broadcast, activity, naming, linked-task start) is shared with the hook handler via fan-out-agent-lifecycle.ts.
  • The adapter pid is registered with the port scanner, and SUPERSET_TERMINAL_ID is set in the agent env, so detached dev servers are attributed. The reaper leaves chat-owned port sessions alone.
  • Page watches deliver to the chat as a prompt (promptChatSession). That only happens when a chat is attached to the terminal, which only happens behind the flag. Otherwise delivery is unchanged.
  • workspaces.create and createSession take an optional namingAgent, so chat-opened workspaces get an AI title.

Part 2: Background tasks and subagents

Why

Users could not see that an agent had a dev server running or a subagent working, and could not stop either.

How

  • The adapter advertises AIR asyncTasks and nativeSubagentSessions. It folds async_task_*, subagent_spawned/state_update and ACP v2 subagent_update into a shared BackgroundTasks tracker.
  • Child-session output stays out of the parent transcript. A subagent gets one transcript row, and its latest step becomes its detail, coalesced to one update a second.
  • stopBackgroundTask runs protocol → router → live session → adapter (_session/async_task/stop).
DecisionChoiceRationale
Source of truthAIR extension, not _meta.claudeCodeBoth shipped ACP adapters implement it, so any AIR-speaking agent works without UI changes
SurfaceWorkspace-level menu, not a strip on the composerCovers every agent in the workspace and keeps the composer clean
Stop allAgent tasks onlyDetached terminals keep a per-row stop; one click should not kill a user's dev servers

Part 3: Desktop

  • WorkspaceActivityMenu (renamed from WorkspacePagesMenu): groups with a header action, and a running-count dot on the trigger.
  • BackgroundTerminalsButton is removed. Its helpers moved to $workspaceId/utils/backgroundTerminals.
  • DashboardSidebarWorkspaceQueuedBadge: queued prompt count per workspace.
  • useLoadOlderOnReach replaces the "Load earlier messages" button.
  • transcriptRows: a tool run collapses once later entries exist and none of its tools are running.

Manual QA

Checked in the dev app over CDP with the acp-chat and chat-v3 flag overrides:

  • Chat-opened workspace gets an AI title in the sidebar ("Add port conflict troubleshooting to README")
  • Activity menu lists a chat's background dev server with stop and stop-all; Pages group has "+", no "View all"
  • Sidebar row shows the working state and the port chip for a chat agent
  • Header button height matches Changes/Commit (28px); composer Send matches the pickers (26px)
  • Live probe against claude-agent-acp 0.85: a background shell task and a native subagent appear, show their step, and clear when done; subagent tool calls stay out of the parent transcript

Not verified end to end:

  • Page comment delivered into a chat
  • Queued badge with a busy chat
  • Stopping a task from the menu
  • codex-acp

Testing

  • bun test in packages/chat (42), packages/chat-runtime (193), host-service chat-v3, terminal-agents, page-watch, notifications and terminal-agents router (264), and the desktop v2-workspace and DashboardSidebar suites (631). All pass.
  • tsc --noEmit is clean for every touched file. The remaining errors in this worktree are ungenerated route types and auth typings on main.
  • bun run check:i18n passes, with all new strings translated in 16 locales.
  • The full host-service suite has 41 failures in git-watcher, tunnel dial and git-helpers tests that this branch does not touch (jest.advanceTimersByTime is missing under the local Bun 1.3.2).

What changes for users without the flag

The activity menu ships to everyone, because it replaces the Pages menu and the background terminals button:

  • The trigger is always in the tab bar. It shows a running dot and count for agent background tasks and subagents (terminal agents' subagents included); idle detached terminals are listed but not counted.
  • Detached terminals keep a per-row stop and reopen on click. The attach debounce and a loading state carry over from the old button, and terminals shown in the right pane area (#8194) count as attached.
  • Pages moved here from the right sidebar and right pane area headers.
  • Terminal-agent subagents now appear in the Subagents group; clicking one opens its transcript.

Compatibility

All tRPC changes are additive and optional (terminalId, namingAgent, stopBackgroundTask, binding fields chatSessionId, backgroundTasks, queuedPrompts). Older hosts strip the unknown inputs and never emit the new fields, so the new UI stays empty.

Known Limitations

  • Only AIR-speaking ACP adapters report background work. The native (non-ACP) Claude and Codex harnesses don't feed the tracker yet.
  • Chat subagents are not in the sidebar agents chip, because its rows open a transcript file that only terminal agents have.
  • A page watch registered while the pane was a terminal is dropped when the pane switches to chat. Publishing again from the chat re-registers it.
  • Chat bindings are in memory; after a host restart they return when the pane re-creates its session.

Follow-ups

  • agents run --continue on a chat pane should prompt the chat instead of launching a terminal agent.

Rollout / Rollback

Behind the existing acp-chat flag. With the flag off, no chat sessions exist and every terminal path is unchanged. The exception is the activity menu replacing the background terminals button, which ships to everyone. Rollback is a revert of the three commits.


Summary by cubic

ACP chat agents behind the acp-chat flag now behave like terminal agents everywhere outside the pane, and the background work they start — dev servers and subagents — is visible and stoppable from a new workspace activity menu.

Background work

  • Chat sessions report under the pane's terminal id, so sidebar status, ports, agent count, workspace naming, and page-comment delivery work as with terminal agents.
  • Dev servers and subagents come from the JetBrains AIR extension that claude-agent-acp and codex-acp both speak, folded into one backgroundTasks list; subagent output stays out of the parent transcript, and stale or duplicate updates don't revive a finished subagent. Once the parent session is known, updates from any other session — including those arriving while a resume replays history — are treated as child activity, so a stray titled tool call never reaches the parent transcript.
  • Step changes travel as live-only background deltas, so they don't journal or bump the session's updatedAt; the task list itself stays durable.
  • stopBackgroundTask stops a chat's background task from the menu — only tasks the adapter knows and can stop — and detached terminals keep their per-row stop. A disconnected subagent shows as failed, and clearing a dead chat's statuses leaves it failed so it isn't treated as alive.
  • Chat bindings live in memory and reappear when the pane re-creates its session after a host restart; closing a fork only falls back to the original chat when the replacement never started, and a pane that adopts a branched copy closes the chat it branched from.

UI

  • Pages and background work move into the tab bar's workspace activity menu, which replaces the background terminals button and ships to everyone; the menu debounces pane attachment, shows a loading state for terminal sessions, its running dot counts agent tasks and subagents rather than idle detached terminals, its clock follows every listed row, and arrow keys move between items.
  • Sidebar rows show a queued-prompt badge (announced to screen readers); chat panes take the session title; resumed chats open at their end only after the session starts; older messages load on scroll once the user has scrolled up, with a retry on failure; tool runs collapse once the turn moves past them; composer buttons match the pickers.

Summary by CodeRabbit

  • New Features

    • Added a workspace activity menu that brings background processes, subagents, workspace pages, and pinned pages together. Open or stop eligible background work, stop all stoppable agent tasks, and create pages from the menu.
    • Workspace items display queued-message counts.
    • Chat transcripts load older messages as you scroll, with progress and retry feedback.
    • Supported background tasks can be stopped, and chat sessions can display updated titles.
    • Workspace naming can use the selected agent when creating a chat workspace.
  • Bug Fixes

    • Improved tool-call collapsing while keeping active work and pending approvals visible.
    • Chat transcripts show a loading state while a session is starting, even when messages are already present.