Skip to content

feat(service): the voice brain follows a spoken ask's turn on Neon Realtime instead of polling - #3937

Closed
charleslpan wants to merge 3 commits into
luke/neon-realtime-planning-holdfrom
luke/voice-brain-realtime
Closed

charleslpan wants to merge 3 commits into
luke/neon-realtime-planning-holdfrom
luke/voice-brain-realtime

Conversation

@charleslpan

@charleslpan charleslpan commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Third of three small PRs that remove Luke's last transcript and voice loops. The goal is realtime with no fallbacks. On the coordinator's call, this is stacked on #3295 (luke/neon-realtime-planning-hold), beside #3757, and not on #3931: it touches only the service. It needs #3266's lookedUntil/LiveWake and #3267's taskConversationLiveStatements, and #3295 carries both.

What changed

  • voice/live-brain.ts: a spoken ask's follow no longer reads the record every 250 ms (POLL), and no longer wakes on eve's session stream with a 60 ms SETTLE.
    • It now calls lookedUntil on the task conversation's mark. The record is read at once, then again each time the mark moves over Neon Realtime. The mark moves when a message lands, when the journal revision goes up, when the newest turn or its status changes, and when a worker starts or ends.
    • The hold is PARKED_FOLLOW, the widest bound. The look itself still says when a turn is past the plain bound or the parked one, as before.
    • LiveWake is taken where the brain is built, on the socket runtime that runWeb provides with liveWakeFromEnvironment, and passed to each follow's fiber.
    • Retired: POLL, SETTLE, STREAM_RETRY, EVE_DELTA_EVENTS, and the per-session stream listener.
  • voice/live-exchange.ts and exchange-attachment.ts: the exchange gets the session's taskId and passes the brain taskConversationLiveStatements(conversation.userId, taskId).
  • eve-sessions.ts: EveStreamEvent is no longer exported, so knip passes. EveSessions.stream has no caller left. Removing that seam means editing eight test fakes, so I left it for a follow-up.

Worth knowing

lookedUntil on this base still looks every LIVE_SAFETY_POLL (5 s) beside the watch. That's #3266's primitive, and I didn't change it. A worker's own journal moving between its start and its end doesn't move the mark. So a worker step shown on the Work tab can arrive up to 5 s late, until the turn's own journal or a worker's start or end moves the mark. I didn't chase that edge case.

Tests

  • live-brain.test.ts:
    • Its real-clock suite runs on tickingLiveWake, a new helper in testing/live-wake.ts whose watch hears a change every 5 ms, standing in for Realtime hearing each write.
    • The test that a turn is heard the moment eve's stream says something is replaced by one where the turn is heard the moment Realtime says the mark moved. It checks that the follow watches the mark it was handed. It asserts nothing about the time before the mark moves, because on CI's shared Postgres the 5 s safety beat can look first. That race failed the first CI run.
  • live-exchange.test.ts and voice-service-exchange.test.ts provide the ticking wake to the exchange they build.

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 service and web
  • vitest for src/voice, src/agents/brain-host, and src/live (114 tests)

What to check by hand

  1. In a call on a task, ask Luke something that takes a few steps. His activity line and spoken reply should come at least as quickly as before, without the steady 250 ms reads.
  2. Ask him to hand work to a worker. Its findings should still be spoken when they land.

Made with Luke

View guided diff Turn on auto-fix

@vercel

vercel Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
luke-web Ready Ready Preview Oct 20, 2026 2:53am UTC

Request Review

charleslpan and others added 3 commits October 20, 2026 02:44
…altime instead of polling

`live-brain.ts` used to read the record again every 250 ms (`POLL`), and
woke on eve's session stream with a 60 ms settle after it. Now it reads the
record again whenever the task conversation's mark moves. The exchange
passes in the mark (`taskConversationLiveStatements` for the session's
task), and the brain waits on it with `lookedUntil`, with the widest follow
bound as the hold. The look still decides when the turn is overdue. The
stream wake, `POLL`, `SETTLE`, and `STREAM_RETRY` are retired.

Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
…a slow store

Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
…rkers part too

Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
@luke-agent

luke-agent Bot commented Oct 20, 2026

Copy link
Copy Markdown
Contributor

Closing for now: the developer moved every area onto the central live layer with Neon Realtime off (LUKE_REALTIME, #4267; held polls, #4272), and this change only does something with Realtime on. The branch is kept, so the PR can be reopened and rebased when LUKE_REALTIME goes back on.

@luke-agent luke-agent Bot closed this Oct 20, 2026

This branch was successfully deployed

1 active deployment
Preview — 4452cf91 Deployed Oct 20, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant