feat(desktop): the Call tab and a planning worker's tab read the plan's conversation on the agent tab's held read (one runtime §3.7 C)

Merged
DA
6d ago
+513-350

One-agent-runtime §3.7, PR C of the one-held-read plan: the renderer switch. It builds on A (#2436) and B (#2437), both merged, and keeps #2433's Call tab behaviour and tests.

Compatibility (expand/contract)

  • The service: still sends plan.work and still serves /api/plans/{id}/work for v0.12.0 desktops.
  • The host: still holds planning.work; this renderer stops reading it.
  • Removal: dropping both, along with planWorkOf and PlanWorkTurn, is the contract PR (D), once the release carrying this PR is the floor.
  • Service version: this PR needs a service with A's routes, which production has since #2436 merged.

What

  • work-model.ts: workRowsOf builds the Call tab's rows from planning.conversation, the plan's planning conversation as the agent tab reads a coding agent's.
    • Turns: each turn is its journal message. It moves while the call stands and the journal is open, and reads as ended without answering where its record names an ending, so a stopped turn still says "Stopped".
    • Workers: a worker is a delegation part of the journal, standing where the page's standings (its own session) say. Its call part answers the pair its session ran on, as before.
    • Stop naming and starts: workerJobs reads eve's receipts off the journals, so a stop names its worker's job. startedAgentCallIds reads the journals too.
  • plan-call.tsx: takes conversation in place of turns/earlier. Turns are placed under their asking lines by the message's own asked/askedAt. "Show earlier work" reads the conversation's earlier page (PLANNING_CONVERSATION_EARLIER).
  • A planning worker's tab is now the agent tab's own AgentSubagentTab:
    • It reads its session through /api/plans/{id}/subagents/{call}/messages (PLANNING_MESSAGES), with the plan in the agent's place, as an agent's worker tab does.
    • Its hover card and copy read what the tab held, or the whole session, as a delegated worker's do.
    • plan-work.tsx's SubagentTab and transcript-copy's workerTranscript are deleted.
  • Other consumers (use-plans-tab.ts, side-panel.tsx, command-palette.tsx, plan-summary.tsx): worker tab holding, the agent-list re-read on Luke's starts, the Call tab's "holds something", the palette, the plan's summary and the side panel's workers all read the conversation.
  • Two review fixes: a worker whose session failed carries a failed ending, so its tab and cards say "Failed", not "Stopped". The transcript message gains an optional earlierOmitted, which the planner page sets and the row reads, so a cut turn keeps its "Earlier steps are not shown." notice. Goldens are re-recorded with LUKE_UPDATE_FIXTURES=1; the only change is the new optional key. It's additive, and the service may send it before or after this desktop.
  • agent-tab.tsx: WORKER_LEAD and AgentTranscriptView are internal again; nothing outside uses them now.

Tests

  • apps/desktop/src/testing/plan-work.ts: a new conversationOf(turns) builds the conversation a planner page carries from the existing turn builders, so every Call tab and work-model test reads the new path.
  • Fixtures moved, assertions unchanged:
    • plan-call.test.ts (including #2433's: a brain turn under its ask, a steered first ask, brain words and Worked-for inside the fold) passes conversation: conversationOf([...]) where it passed turns;
    • work-model.test.ts builds rows with workRowsOf(conversationOf(...)).
  • Changed, because a worker's session is no longer on the Call tab's wire (its own tab reads it, through the agent tab's tested useAgentTranscript):
    • work-model.test.ts's "a worker's session is read into parts the way a turn is… and its tab finds it among the turns" keeps its tab-finding half (workerOf) and drops the session-parts half;
    • the background-worker test drops its session-journal assertion.
  • New in use-plans-tab.test.ts: a planning worker's tab reads its session through PLANNING_MESSAGES with the plan in the agent's place and the call that started it. The test mount now hands an answered act its payload.
  • ./scripts/check.sh exits 0.

Mac UI

CI could not verify the Mac UI, and ./scripts/verify.sh was not run (no Mac here; LUKE-159 is the manual pass). The screenshots are the real components (PlanCall over conversationOf, and AgentSubagentTab over a fake planner worker reader) rendered in jsdom over the built styles.css and captured in headless Chrome. They are not the Electron window.

LightDark
Call tab
Planning worker tab

The running turn shows its words above Luke's spoken line. That is #2433's behaviour; the same turn renders the same way on main through the old path.

🤖 Generated with Claude Code