feat(desktop,host): the open plan's conversation is read on the agent tab's held read, beside its work, for the Call tab to switch to (one runtime §3.7 B)
Merged
DA
6d ago+860+860+012345678901234567890123456789-63-63-01234567890123456789
One-agent-runtime §3.7, PR B of the one-held-read plan. Stacked on A (#2436); merge after it. This is the desktop host side, additive and inert: nothing in the renderer reads the new field yet, so nothing user-visible changes. PR C switches the Call tab to it.
Compatibility
- The renderer still reads
planning.work,planning.workEarlierand theplan.workframe exactly as today. showWork,readWork,readEarlierWork,withPageand everyplan.workpath are untouched.- No drawing file changed.
What
planning.conversation(optional onplanningViewSchema): the open plan's planning conversation in the agent tab's own page shape (codingAgentMessagesAnswerSchema).compose-planning.ts: one held read for the open plan, aFiberHandlefiber with no raw timers.- Start: it reads the newest page when the plan opens, starts or refreshes. A new start replaces the standing read.
- Follow: it follows
after=cursorwhile the last page's status, or a worker the page names, is STARTING or RUNNING. - Park and wake: it parks on an idle page, because the server answers an idle conversation at once. An activity frame or call end for the open plan wakes it from the cursor it holds. A wake that lands while a read is out keeps that read from parking.
- Merging: pages merge by message id. Workers and their titles merge by call id, newest kept, because a page names only some of them.
- Retries: a failed read retries on a capped exponential backoff (1 s doubling to 30 s). A NOT_FOUND, such as an older service, parks it.
- Stop: switching plans, leaving the plan, deleting it or signing out stops it.
- Earlier pages: the earlier act prepends the page before
earlierwithout moving the forward cursor. planning.messages: serves a plan's page or a planning worker's page to the caller, for the worker tab C will draw.- Gateway and acts:
planning.conversationEarlierandplanning.messagesin the protocol.PLANNING_CONVERSATION_EARLIERandPLANNING_MESSAGESare new acts with router rows; they are panel-only and refused from the voice window.host-operator.tswires them. applyMessagesPagemoved unchanged from the renderer'scoding-agent-model.tsto@sidecar/hosted/coding-agent-wire, so the host and the agent tab share one page merge. Its test moved with it. The only renderer edits are the imports.compose-host.ts: oneHostedCodingAgentClientis now shared by planning and coding agents.
Tests
packages/host/src/compose-planning.test.ts, using a fake planner client and TestClock:- opening a plan publishes its newest page, and an idle conversation isn't asked again;
- a held read rewrites an amended journal in place and appends new rows;
- the earlier page prepends without moving the forward cursor;
- opening another plan stops the old read;
- a failed read retries after the backoff and not before;
- an activity frame wakes a parked read;
- workers and titles join by call id.
apps/desktop/src/main/ipc/planning-acts.test.ts: a worker's page is read from a panel and refused from the voice window.- The moved merge test is in
packages/hosted/src/coding-agent-wire.test.ts. ./scripts/check.shexits 0.
Notes
- Bigger planning frame:
conversationrides everyplanning.changedframe besideworkuntil the contract PR dropswork. This is the main-to-renderer frame on the Mac, not network traffic. - The code read isn't wired yet:
readCodestays unused until C swaps the Code tab's source. - Mac UI: CI cannot verify the Mac, and
./scripts/verify.shwas not run (LUKE-159). Nothing visible changes in this PR.
🤖 Generated with Claude Code