Skip to content

feat(voice): port the pure realtime core - #2387

Merged
2witstudios merged 1 commit into
pu/gpt-realtimefrom
pu/rt-core
Aug 10, 2026
Merged

feat(voice): port the pure realtime core#2387
2witstudios merged 1 commit into
pu/gpt-realtimefrom
pu/rt-core

Conversation

@2witstudios

Copy link
Copy Markdown
Owner

First leaf of the audio-native voice epic. Adds the pure, I/O-free realtime core under apps/web/src/lib/ai/realtime/, ported from the working pagespace-voice prototype.

  • events.tsextractFunctionCalls, extractTranscript (handles both response.output_audio_transcript.done and the legacy response.audio_transcript.done), buildFunctionOutput, parseEvent
  • session.ts — session config builder, resolveRealtimeModel(env), and the RealtimeTool wire type
  • session-state.ts — the UI reducer; a failed connection preserves the transcript

DEFAULT_REALTIME_MODEL = 'gpt-realtime', not 2.1 — the W0 spike proved gpt-realtime-2.1 is not on this account (mint returns 200, then /v1/realtime/calls 403s model_not_found), and the prototype's own .env pins gpt-realtime. OPENAI_REALTIME_MODEL remains the upgrade path.

Verification: 68 tests pass; tsc --noEmit clean; mutation-checked the dual transcript-event-name coverage (deleting the legacy name turns exactly one test red).

Pure only — no I/O, no clock, no randomness. 888 insertions, no lockfile noise.

Ports the proven core from the pagespace-voice prototype into
apps/web/src/lib/ai/realtime/ as three pure modules — no I/O, no clock,
no randomness, no module-level mutable state, no React:

- events.ts: function calls out of `response.done`, transcripts under BOTH
  `response.output_audio_transcript.done` and the older
  `response.audio_transcript.done` (renamed across releases, deployments
  straddle it), the `function_call_output` client event, and a `parseEvent`
  that returns undefined on a malformed frame rather than throwing.
- session.ts: the `client_secrets` body shape, the two endpoint URLs, the
  `oai-events` channel name, and defensive `value` narrowing on the mint
  response. Default model is `gpt-realtime` — access is per-account,
  `client_secrets` accepts any string, and `/v1/realtime/calls` 403s
  `model_not_found` at connect time — with OPENAI_REALTIME_MODEL as the
  upgrade path, resolved purely from a passed-in env bag.
- session-state.ts: the session reducer. A failure keeps the transcript;
  a drop mid-conversation must not erase the record.

Tool definitions are deliberately not ported: PageSpace has its own tool
registry, so only the transport-shaped `RealtimeTool` type lives here.

68 tests, 100% statements/branches/functions/lines on all three files,
mutation-checked (34 mutations, each verified to turn the suite red).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuzQWypmJU8b8pKvqt3BgW
@2witstudios
2witstudios merged commit 27cbadf into pu/gpt-realtime Aug 10, 2026
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 98dd8c5c-b427-4fb9-a84e-feaaeb84f812

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

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