Hi LiveKit team,
I found a working solution for push to talk on the openai realtime and wanted to share our findings in case it's helpful
for documentation or API improvements.
The Problem(s)
1. Using server_vad with create_response=False produced multiple interim transcripts during recording, even though we only wanted a single final transcript when the user released the PTT button.
2. turn_detection=None on RealtimeModel - Audio was streamed but never processed. OpenAI didn't know what the user said, responses were generic.
3. turn_detection="manual" on AgentSession alone - Without configuring the RealtimeModel, OpenAI's built-in VAD would auto-respond mid-speech.
4. Just commit_user_turn() without generate_reply() - With turn_detection=None, no response was generated at all. The agent stayed in "listening" state.
The Solution:
We had to bypass the AgentSession's commit_user_turn() and instead directly access the underlying OpenAI Realtime session to send native events:
# Configuration
session = AgentSession(
llm=openai.realtime.RealtimeModel(
turn_detection=None, # Disable OpenAI's VAD entirely
),
turn_detection="manual",
)
# On button release
rt_session = session._activity.realtime_llm_session
rt_session.commit_audio() # input_audio_buffer.commit
rt_session.send_event({"type": "response.create"})
This mirrors how we handle PTT in our direct iOS/WebRTC OpenAI implementation and produces a single clean transcript.
Feedback:
2. PTT helper method - Something like session.commit_and_respond() that wraps commit_audio() + response.create would simplify this common pattern.
3. Documentation - The PTT examples focus on STT/LLM/TTS pipelines. A Realtime API-specific example showing this direct commit approach would be valuable.
4. Clarify turn_detection=None behavior - It wasn't obvious that this disables transcription processing entirely, not just auto-response.
I'd love to talk if you think there's a better solution or if you want to understand my use case better
Thanks for the help!