Skip to main content
Mint with client.realtime.sessions.create, then client.realtime.connect(session). Audio is PCM16 mono 24 kHz. Model kupe-realtime. Web-only — no telephony minutes. Identify the agent with name or agent_id. A new name creates the agent with prompt, greeting, voice, and tools/mcp. Pass voice (sanitized name) or voice_id — either one (copy the id from the voice library).

Terminal

Save the same code as realtime_turn.py and run python realtime_turn.py. Existing agent from the console:

Events you will see

send_text sends conversation.item.create then response.create. Mic path: rt.append_audio(pcm16_bytes) at 24 kHz.

Echo: speakers vs headset

If you play the agent’s audio through open speakers next to the mic, the mic records the agent and append_audio sends its own voice back as user speech. The agent then answers itself, and its greeting shows up in the transcript as a user turn. Pass echo_suppression="half_duplex" to mute the mic while the agent is still speaking:
append_audio returns True when the frame was sent and False when it was muted; rt.suppressed_frames counts the muted frames, and rt.agent_is_speaking exposes the gate. Pass force=True to bypass it for one frame. Tune the hold after playback ends with echo_tail_ms (default 250). A muted frame is still sent, as silence. The server runs streaming VAD and STT over a continuous audio stream, so sending nothing at all would stall turn detection and the agent would stop hearing you even after it stopped talking.
The gate advances only while something is iterating the connection, since it is driven by response.output_audio.delta sizes. Keep your reader loop running — a common mistake is reading events only after the mic loop ends.
Full event tables: Realtime WebSocket.