feat(web,desktop): a coding agent's worker row says where the worker's own session stands, not its call (one runtime 5a/n)

Merged
DA
6d ago
+467-12

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. codingAgentMessagesAnswerSchema gains an optional subagents field: per worker, its call, status, model, effort and startedAt. 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 with codingAgentStatusOf, 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-transcript holds 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): delegationsOf lists 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.json and the view's golden were re-recorded with LUKE_UPDATE_FIXTURES=1. The only change is the new optional subagents array.
  • 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


Open workspace in Conductor


Devin Review