feat(web,desktop): a coding agent's worker row says where the worker's own session stands, not its call (one runtime 5a/n)
One-agent-runtime migration, PR 5a: the first half of one delegation mechanism with foreground and background subagents (docs/proposals/one-agent-runtime.md §8, Decision 3; Dean picked option A).
Why this comes first
Option A makes delegate an eve task in both roots. A task call settles the moment its worker is under way: the model gets a receipt, and the answer arrives later as a <task_result>. A coding agent's subagent row reads "running" and "done" from that call's own state, so after the switch every worker would read done at once.
This PR makes the row read where the worker's own session stands instead. It works with today's blocking delegate too, since a worker's session and its call agree there. So it's safe on its own, and 5b (the switch to a task) changes no row.
What
-
Store.
delegationsOf(parent)(coding-agent-store.ts, new) lists every worker a conversation delegated to by a kept call, oldest first, each with its child conversation and the pair its delegation recorded. Another account's conversation reads none. -
Wire.
codingAgentMessagesAnswerSchemagains an optionalsubagentsfield: per worker, its call, status, model, effort andstartedAt. It's absent on a worker's page, while nothing was delegated, and from older services. -
Server. The agent's transcript page (
coder-host/transcript.ts) computes each worker's standing by reading the newest turn of its child conversation withcodingAgentStatusOf, the same reading an agent's own status gets:- starting within the grace while its session has opened no turn, failed past it;
- running, completed, failed or cancelled once it has a turn.
The route passes it through.
-
Desktop.
use-agent-transcriptholds the standings, and the agent tab hands them to its delegation rows (DelegationDoors.standings).- A row draws the standing's state (
workerToolState: starting or running is running; completed or stopped is at rest; failed is failed) and the recorded pair, over the call's own state and input. - A running worker counts from the standing's start.
- Opening a worker's tab passes the standing's status.
- Without standings (an older service) the row reads the call, as before.
Tests
packages/database/src/models/__tests__/coding-agent-store.test.ts(new sibling):delegationsOflists a conversation's delegations oldest first on their recorded pairs, and another account reads none.tests/coder-host.test.ts, new: with two workers delegated, the agent's page says the one whose session settled a turn is completed and the one whose session opened none is starting, each on its recorded pair.agent-tab.test.ts, new: each row says its own session's standing over the call's state:- running though its call settled with a receipt;
- at rest once completed though its call still waits;
- failed where it failed;
- each on the recorded pair.
- Goldens.
coding-agent-wire-codingAgentMessagesAnswerSchema.jsonand the view's golden were re-recorded withLUKE_UPDATE_FIXTURES=1. The only change is the new optionalsubagentsarray. - Suites. The web suite (155 files), the desktop renderer (127 files, 1,476 tests),
packages/hosted,packages/database, lint and repository checks pass.
CI could not verify the Mac UI: CI builds nothing for the Mac, and ./scripts/verify.sh was not run (LUKE-159 is the manual Mac pass). With today's blocking delegate the rows look the same as before. The difference shows once 5b lands.
🤖 Generated with Claude Code