feat(voice): Luke speaks a subagent's result at a pause

Merged
CH
11d ago
+436-10

Stacked on #1823.

CI couldn't verify the voice behavior. This PR changes what the developer hears, and no CI job runs a live call. It needs a ./scripts/verify.sh pass and a live call on a Mac: ask Luke to research something, keep talking, then check that he answers right away and brings the findings back after his current answer.

What changes

  • Brain (apps/web/server/voice/live-brain.ts). Each socket watches its conversation (store.turns.wokenIn, polled every second) for child_completion turns from that socket's start onward. It tells each one once as a new LIVE_BRAIN_RUN_EVENT.WOKEN, then follows it under the turn's own id. It reuses projectTurnEvents, runEventOf, and the follow's cadence and bound.
  • Service (live-session-service.ts). A woken run gets an exchange with no delegation, so it speaks session-wide (delegation_id: null).
    • Its reply waits while any asked run of the session is under way, and is said once that run has ended. The developer's answer is never cut off.
    • The developer's next ask silences it, like any older revision, following the GPT Live guide's advice to drop stale results.
    • A woken run that fails says nothing, because nobody asked for it.
  • Eval (brain-host.eval.ts). The scripted model learns Research: … and hands it to the worker. The eval checks that the planning session is woken in a settled child_completion turn, whose first line is the brain's.

Known limits

  • A re-attached connection doesn't take a woken turn up again. No ask row holds how far it was told.
  • The watch reads from the socket's start, so a result that lands while no voice socket is attached is recorded but not spoken.

Tests

  • live-session-service.test.ts: a woken reply waits for the asked run and is said after it, with delegation_id null. The developer's next ask silences a waiting woken reply, and a failed woken run says nothing. The first test fails without the change.
  • voice-live-brain.test.ts: a child-completion turn played through the real relay is told as woken, then its sentences and end, all under the turn's id. It fails without the change.
  • brain-host.eval.ts: needs Postgres, so it wasn't run locally. CI runs it.
  • ./scripts/check.sh passes.

šŸ¤– Generated with Claude Code


Open workspace in Conductor