feat(web,desktop): the Call tab reads the planner's own journal and each worker where its own session stands (one runtime 9b/n)
One-agent-runtime migration, PR 9b (docs/proposals/one-agent-runtime.md §8). Stacked on 5b (#2402, merged). 9c follows and deletes the projection this PR stops reading.
What
A planning turn's work now carries the planner's own data next to the projected parts.
Wire (packages/hosted/src/planning-view.ts), both fields optional so an older service still parses:
journal: the turn's journal as the AI SDK stored it (words, reasoning, each tool call under its own name). It keeps the newestPARTSand cuts every string toTEXT_CHARS, keeping its shape.workers: each worker the turn delegated to, by the call that started it:- its job and eve's task id;
- where it stands, read from its own session;
- its session as a bounded journal;
- its span, title and record.
Server (apps/web/server/voice/plan-work.ts): planWorkOf emits both.
- A worker's state comes from its session: running while its newest task is still being written, failed where its call failed or that task failed or ran past its bound, done otherwise.
- A worker with no session yet still reads off the turn's steps, as before.
- The turn's asks (
asked/askedAt) are unchanged and still come only fromspokenAskRows. - Like the projection, the journal leaves out a
show_pagecall's HTML (only the frame that draws the page reads it) and a board look's image.
Desktop (apps/desktop/src/renderer/planning/work-model.ts): workRowsOf reads a turn that carries journal and workers the way the agent tab reads a coding agent's journal.
- A worker's delegate call stands where the worker does, and answers the pair its session ran on. Before, a background
delegatecall settled at eve's receipt, so its row stopped running at once. - A worker keeps running past the turn that started it while the call stands.
- An unanswered call in a turn that stopped moving reads as having run, never as failed.
- An older service's turn still reads through the projected parts.
#2404's rules are untouched: work sits under the asking line by askedAt, before Luke's spoken reply; a spoken turn's written reply isn't drawn; a reply a newer ask silenced keeps its words. They run on the message's text parts, which the raw journal carries the same way. None of #2404's tests changed.
Tests
apps/web/tests/plan-work.test.ts, 2 new:- A background
delegate's turn carries its own journal and a worker beside it. The worker is running while its session runs (though the turn and its call are done), done once it answers, and failed where its task's record failed. - A turn's journal keeps its newest parts, says older ones were left out, and cuts strings while keeping the call's shape.
- A background
- Extended: "a page shown … carries no HTML to the Mac" and "every tool … a board look shows no image" now also check the journal.
apps/desktop/src/renderer/planning/work-model.test.ts, 3 new:- A background worker reads as running past its receipt and past its turn while the call stands.
- Its row names its session's pair, and reads as failed where its session failed.
- An unanswered call reads as running while the turn moves, and as having run once the call ended.
- Goldens: re-recorded with
LUKE_UPDATE_FIXTURES=1.live-contract-planWorkFrameSchema.jsongains the optionaljournalandworkers.coding-agent-wire-storedObjectSchema.jsonis new becausestoredObjectSchemais now exported for the wire to reuse.- No existing key changed.
./scripts/check.shexits 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 below are the real renderer components (PlanCall, SubagentTab) rendered to static markup in jsdom over the built styles.css and captured in headless Chrome. They are not the Electron window.
| Light | Dark | |
|---|---|---|
| Call tab | ![]() | ![]() |
| Worker tab | ![]() | ![]() |
The Call tab shows the background worker of the running turn still running with its timer, though its delegate call answered at the receipt.
Not in this PR: the finished spoken turn above is laid out flat rather than folded, and a running turn moving below newer speech. Those are the two Call tab bugs a separate worker is fixing on the current path; 9b will rebase over that fix.
🤖 Generated with Claude Code



