feat(host): a window follows an agent's transcript as a stream of pushed pages

Merged
CH
5d ago
+1271-11

The host half of making the agent transcript live on main. It's stacked on #3298 (luke/live-transcript-clock-edges) and replaces #3909, which was built on the old stack. The window moves over in the next PR.

What changed

  • Act port: a new event-iterator procedure, codingAgents.transcript, takes a transcript key and yields its pages for as long as the window keeps the stream open.
    • The key is an agent's own transcript, one of its workers' (callId), or a task's planning worker's.
    • Opening a stream asks the host to follow from the start, so a window that arrives late gets the whole transcript.
    • Closing the last stream of a transcript lets the host's follow go.
    • Each page of an agent's own transcript notes its title and status, as the read did.
    • web-host serves the same procedures, so a web tab follows transcripts exactly as a window does, with no extra wiring.
  • Gateway:
    • codingAgents.transcriptFollow/Unfollow: followTranscript reads on the transcript's existing Realtime subscription (transcriptFollows) and tells each page as transcript.changed. It reads the first page from the start, the next one right away after a page with messages, and otherwise again only when the statements move or the service's wakeIn edge passes.
    • tasks.workerTranscriptFollow/Unfollow: a planning worker is followed on the service's held tasks.messages read until #3311 gives it live statements of its own. The follow stops once the worker has ended and its page is empty.
  • Wire: codingAgentTranscriptKeySchema and codingAgentTranscriptChangedSchema, recorded in hosted-wire-schemas.test.ts with goldens generated under LUKE_UPDATE_FIXTURES=1.
  • The sealed statements stay in the host.

Tests

  • compose-coding-agents.test.ts: a followed agent transcript is told page by page; a transcript the account can't reach is told not found once; behind a closed gate it's told unanswered; sign-out lets it go.
  • compose-tasks.test.ts: a planning worker is told page by page on the held read, and the follow ends with the worker.
  • agents-procedures.test.ts: two streams of one transcript each hear its pages and nothing of another's; the host lets it go only when the last stream closes.

Checks run locally

pnpm check:affected gets OOM-killed in the sandbox, so I ran its pieces one at a time:

  • repository-checks.sh, biome check ., oxlint, knip
  • discarded-effect (with a larger heap)
  • tsc for host, desktop, web and panel
  • vitest for the whole host suite (451 tests)

What to check by hand

Nothing visible changes yet: no window opens the stream until the next PR.

Made with Luke