feat(web): record a subagent's wake-up turn as a child completion
Merged
CH
11d ago+137+137+012345678901234567890123456789-8-8-0123456789
Stacked on #1820.
Why
When a subagent finishes, eve opens a new turn on the session that delegated, to hand the result back. eve puts no marker on that turn. It runs under the last request's auth, so it inherits that request's turn kind, and it carries no delivery. Today the relay records it as an unasked spoken turn with no user line. The voice service never follows it, and the record says the developer spoke.
What changes
- The relay's state notes when the session has delegated, from Luke's own call to a subagent tool (
actions.requested). eve'ssubagent.calledevent doesn't reach the hook, as the end-to-end eval showed. - In a session that has delegated, a turn with no delivery is recorded as a child completion. The relay reuses the existing
TURN_ORIGIN.CHILD_COMPLETIONandBRAIN_TURN_TRIGGER.CHILD_COMPLETION. eve's notification, with the child's result, becomes the turn's line, authored by the brain (OBSERVATION_SOURCE.CHILD_COMPLETION, already handled byuserMetadataOf). RELAY_TURN(bounds.ts) adds that kind beside the two the door admits. A request can't name it: the door still admits onlyBRAIN_HOST_TURN.
The rule depends on one fact: every ask after a session's opening one carries its own delivery. The opening ask comes before any delegation, so the rule never misreads it.
Tests
hosted-brain-host-relay.test.ts: after a delegation, a wake-up turn records aschild_completion, with the result as the brain's line. A later turn that carries an ask's delivery staysspoken. Without the change, this test fails../scripts/check.shpasses.
This is a web-only change. The voice side, following these turns and speaking them, is the next PR.
š¤ Generated with Claude Code