feat(desktop,host): a shown transcript tab hears its pages pushed, with no read loop

Draft
CH
5d ago
+452-660

Second of three small PRs that remove Luke's last transcript and voice loops, stacked on #3909. The window now uses the transcript push from #3909, and the host's held transcript read is retired.

What changed

  • use-agent-transcript.ts:
    • The hook takes a transcript key and a TranscriptFollower instead of a reader. While the tab is shown, it subscribes to app:transcript, follows the transcript, and joins each pushed page by message id. It unfollows when the tab is hidden or unmounts.
    • The read loop, the cursor ref, and the read-through bookkeeping are gone.
    • A failure page sets failed, and the messages already held stay. Try again follows the transcript again, and the next good page clears failed.
    • reading is true while nothing is held and the last page says the agent may still write.
  • Agent tab, worker tab, and planning worker tab: they follow by key. A task's planning worker tab passes { kind: "taskWorker", taskId, callId }; it used to swap in a readTranscript that called tasks.messages. CodingAgentsControl now carries transcripts, built from the window's acts and bridge.
  • Copy transcript keeps reading: codingAgents.messages and tasks.messages with a callId are still used by readWholeTranscript, so they aren't retired. They now answer at once through the service's wait=none read, with holds removed in the host.
  • Host: transcriptPast, readUntilSaid, TranscriptReads, and the 20 s HOLD are removed from transcript-follow.ts. followsAgent is removed, since only the loop used it.
  • The service's held /messages routes are untouched, for desktops already released.

Tests

  • New use-agent-transcript.test.ts:
    • A shown tab follows, joins only its own pages, and lets go once hidden.
    • A failure offers Try again, which follows again while the messages held stay.
  • The tab tests that stubbed readTranscript now push their pages through pushedTranscripts (#testing/tasks-control). The agent page test answers the follow act and pushes through its fake bridge.
  • Host tests deleted, because they test the held read this PR retires: in compose-coding-agents.test.ts, "a running agent's transcript is held open…", "a worker's transcript is followed under its own seal…", "a transcript the account does not reach is not found…" and "a read the service says only the clock may end…"; in compose-tasks.test.ts, "a planning worker's transcript … the service seals nothing for…". #3909's follow tests cover the same live behaviour.
  • Host test replaced: "a planning worker's transcript is held here…" became an at-once read test. The method-table test now expects codingAgents.messages to read at once without sealing.

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 and desktop
  • vitest for host (261 tests) and the whole desktop renderer project (2097 tests)

What to check by hand (Electron)

  1. Running agent: open a task with a running agent and show its tab. Lines should land as the agent writes them, with no lag of about a second.
  2. Ended agent: show it. The whole transcript appears, and the spinner doesn't stay.
  3. Hide and show: switch to another tab and back. The transcript is still complete, with no duplicated lines.
  4. Agent's worker: open a worker's tab from its row. Its transcript fills in and keeps up while the worker runs.
  5. Planning worker: during a call, open a planning worker's tab from the plan's work. Its transcript fills in.
  6. Two windows: show the same agent in two windows. Both keep up.
  7. Copy transcript: in the tab's ⋯ menu, copying an agent's or a worker's transcript still gives the full text.
  8. Message links: a Luke link to a message in a long transcript still scrolls to that message once its page lands.

Made with Luke