kupe.realtime.sessions.create, then kupe.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
Node 18+ (ESM). From a folder wherekupe-sdk is installed:
realtime.mjs):
Events you will see
sendText / send_text send conversation.item.create then response.create. Mic path: rt.appendAudio(pcm16) 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 andappendAudio 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 echoSuppression: "half_duplex" to mute the mic while the agent is
still speaking:
appendAudio returns true when the chunk was sent and false when it was
muted; rt.suppressedChunks counts the muted chunks, and rt.agentIsSpeaking
exposes the gate. Pass { force: true } to bypass it for one chunk. Tune the
hold after playback ends with echoTailMs (default 250).
A muted chunk 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.
In the browser you normally want the default
"none": request the mic with
getUserMedia({ audio: { echoCancellation: true } }) and the browser cancels
the echo for you, keeping barge-in working.
