Skip to content

H-6763: Migrate voice interviews to GPT-Realtime-2 - #9399

Merged
kostandinang merged 14 commits into
mainfrom
kostandin/h-6763-gpt-realtime-2
Sep 2, 2026
Merged

H-6763: Migrate voice interviews to GPT-Realtime-2#9399
kostandinang merged 14 commits into
mainfrom
kostandin/h-6763-gpt-realtime-2

Conversation

@kostandinang

@kostandinang kostandinang commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

🌟 What is the purpose of this PR?

Migrate the H-6763 voice interview from a transcription-plus-TTS chain to gpt-realtime-2 as an ephemeral duplex media shell, while keeping Brunch the sole durable authority for interview state and business logic. Present canonical Brunch output through a warm, professionally neutral expert-interviewer voice.

🔗 Related links

🚫 Blocked by

🔍 What does this change?

  • Configures a server-owned gpt-realtime-2 WebRTC session with audio input/output, low-effort reasoning, low-eagerness semantic VAD, automatic interruption, and one required continue_interview function.
  • Adds a focused Realtime–Brunch bridge that validates and serializes tool calls, derives stable submission identity, preserves pending brunch_ask correlation, and rejects duplicate, overlapping, or stale work.
  • Lets the first complete spoken description start Brunch when no question is pending, while later turns remain correlated with the active question.
  • Emits brunch_ask as a dynamic AI SDK tool so Petrinaut recognizes and renders each returned question.
  • Keeps the microphone active during Brunch processing and assistant playback, receives remote audio over WebRTC, and exposes orthogonal connection/input/output state to the existing minimal voice UI.
  • Clears provisional transcript text after failed turns and surfaces specific correlation, response, and submission diagnostics.
  • Gives the Realtime session and canonical response requests a consistent expert-interviewer delivery policy without allowing OpenAI to invent, alter, or answer interview questions.
  • Returns canonical Brunch segments through the function result and requests tool-free audio without treating generated speech as the visible source of truth.
  • Removes the separate Speech API route, MP3 playback controller, speech queue, and manual done/interrupt controls.
  • Updates the voice ADR, Petrinaut website setup, and Petrinaut user guide. Transient implementation plans and design artifacts are excluded from the final diff.

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

This PR:

  • does not modify any publishable blocks or libraries, or modifications do not need publishing

📜 Does this require a change to the docs?

The changes in this PR:

  • require changes to docs which are made as part of this PR

🕸️ Does this require a change to the Turbo Graph?

The changes in this PR:

  • do not affect the execution graph

⚠️ Known issues

  • Voice remains a non-production preview and is still disabled by server policy in production.
  • The live OpenAI preflight used synthetic browser media in the orb; a physical microphone and real acoustic environment still need preview-deployment validation.

🐾 Next steps

  • Exercise microphone quality, thinking pauses, expert-interviewer delivery, and barge-in with a physical device in the preview deployment.

🛡 What tests cover this?

  • Focused website tests cover Realtime session policy, initial interview startup, pending-question correlation, canonical response delivery, transcript cleanup, diagnostics, reconnect, and cleanup.
  • Brunch transport tests cover dynamic brunch_ask tool streaming and return-path handling.
  • Integration coverage exercises remote media, semantic turn events, automatic interruption, malformed events, failures, and continuous capture.
  • TypeScript checks, ESLint, formatting, architecture docs validation, and the production build pass.
  • A live gpt-realtime-2 WebRTC preflight confirmed remote RTP audio, function calling, semantic VAD, and automatic interruption with the configured key.

❓ How to test this?

  1. Configure a preview or local environment with PETRINAUT_OPENAI_VOICE_ENABLED=true, OPENAI_VOICE_API_KEY, and a working Brunch endpoint.
  2. Start an empty interview, speak a process description, and confirm Brunch starts and returns the first recognized question without an unknown-tool error.
  3. Answer the pending question and confirm the answer reaches that brunch_ask call exactly once.
  4. Confirm the canonical Brunch response remains visible while Realtime speaks it with the expert-interviewer delivery style.
  5. Speak during interviewer audio and confirm playback stops automatically while the microphone remains active.
  6. Exercise failed submission, pause, reconnect, end, and text fallback; confirm provisional text clears after failure and old media/events do not survive reconnect or end.

📹 Demo

No screenshot replacement is required; the affected documentation contains no screenshots of this surface.

@vercel

vercel Bot commented Aug 28, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated
petrinaut Ready Ready Preview Sep 2, 2026 9:39am UTC
petrinaut-docs Ready Ready Preview Sep 2, 2026 9:39am UTC
2 Skipped Deployments
Project Deployment Actions Updated
hash Ignored Ignored Preview Sep 2, 2026 9:39am UTC
hashdotdesign-tokens Ignored Ignored Preview Sep 2, 2026 9:39am UTC

Request Review

@CLAassistant

CLAassistant commented Aug 28, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@cursor

cursor Bot commented Aug 31, 2026

Copy link
Copy Markdown

PR Summary

High Risk
Large real-time voice and interview-turn correlation change (WebRTC, tool bridging, Brunch authority); mitigated by preview-only production disable but still high complexity and regression surface.

Overview
Replaces the transcription-only Realtime + Speech API (MP3) pipeline with a duplex gpt-realtime-2 WebRTC session: remote interviewer audio plays in-browser, the mic stays open through Brunch work and playback, and barge-in is automatic (no manual “Done speaking” or “Interrupt”).

OpenAIRealtimeSession now queues canonical Brunch text as tool-free Realtime audio responses, parses continue_interview tool streams, authorizes only those responses, and fails closed on stray provider audio or malformed tool output.

Adds RealtimeBrunchBridge to validate tool arguments, submit answers through the existing composer with stable IDs and brunch_ask correlation, then return canonical segments via completeFunctionCall before speaking.

Removes /api/voice/speech, SpeechPlaybackController, and related tests; updates the voice UI snapshot to connection / input / output axes and refreshes README voice-preview documentation.

Reviewed by Cursor Bugbot for commit b930ef9. Bugbot is set up for automated code reviews on this repo. Configure here.

lunelson
lunelson previously approved these changes Sep 1, 2026
lunelson
lunelson previously approved these changes Sep 2, 2026
kostandinang and others added 13 commits September 2, 2026 11:02
Co-authored-by: Cursor <cursoragent@cursor.com>
Ensure initial spoken descriptions reach Brunch, dynamic questions render correctly, and canonical responses use the expert-interviewer voice.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep implementation-only planning artifacts out of the product pull request.

Co-authored-by: Cursor <cursoragent@cursor.com>
Serialize canonical speech, isolate cancelled tool streams, and tolerate only correlated provider no-op errors.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Retry canonical speech when its provider error arrives after the blocking response ends, and bind answer revisions to the question active when submission began.

Co-authored-by: Cursor <cursoragent@cursor.com>
Retain completed cancel event IDs until a late no-op response arrives so expected provider races cannot tear down an active voice session.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 66f7a87. Configure here.

Keep the in-flight input phase through pause and resume so the UI cannot accept an overlapping voice turn before Brunch responds.

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/apps area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > frontend Owned by the @frontend team

Development

Successfully merging this pull request may close these issues.

3 participants