- Your app running on Dialog-RSN-1, on the same SDK or WebSocket code, speaking its replies and calling the same tools.
- A test that streams a caller’s spoken question into the app, saves the spoken answer, and shows the server kept every setting the app sends.
- A short line the caller hears while a slow tool runs, instead of silence.
- Your coding agent, set up as in the quickstart’s Set up your agent: the skill installed,
POLY_API_KEYsaved, and the connection check passing. - Your OpenAI Realtime app, in a folder the agent can run. It can use the
openaiSDK or a raw WebSocket, in Python or JavaScript. Commit it to git first, so you can review the port as a diff. - A local text-to-speech command for the test clip in Step 2:
sayon macOS, orespeakon Linux.
Step 1: port the app
Prompt
- The connection. On the
openaiSDK, only the client changes:websocket_base_url="wss://api.studio.poly.ai/v1"(orbase_url="https://api.studio.poly.ai/v1") and the key fromPOLY_API_KEY. The SDK adds/realtimeand sends the key asAuthorization: Bearer, which Dialog-RSN-1 accepts. On a raw WebSocket, the URL becomeswss://api.studio.poly.ai/v1/realtime, and the key goes in anX-API-KEYorAuthorization: Bearerheader. In Node, the skill also has the agent set aUser-Agentheader. Either way the model name does nothing: the server runsdialog-rsn-1whatever you pass. - The session.
output_modalitiesstays["audio"], so replies still arrive asresponse.output_audio.delta(24 kHz PCM16) with the words inresponse.output_audio_transcript.delta. The OpenAI voice name becomes a Cartesia voice id, since names likealloyandmarinare ignored.turn_detectionends up as{"type": "server_vad", "create_response": true}. - Settings it removes. The ones Dialog-RSN-1 accepts and ignores:
model, the turn-detection timing (threshold,prefix_padding_ms,silence_duration_ms,eagerness,semantic_vad),interrupt_response: true, the transcription model,noise_reduction,speedandtracing. The ones it refuses, if your app sends any: see OpenAI features with no match. - Errors. A refused
session.updateapplies nothing, so one leftover field also drops your instructions and tools. Expect your coding agent to make the app wait forsession.updated, and to stop and printerror.codeanderror.paramon anerror. - What stays. The tool loop: a
function_callitem, yourfunction_call_output, thenresponse.create. Some agents move those two sends to afterresponse.done. Sending them as soon as the call arrives also works. Caller transcripts still arrive asconversation.item.input_audio_transcription.completed, with no transcription model to set.
git diff against its list of changes. For the front desk agent in the guide’s repo, it looks like this:
output
reply.wav, as the skill asks.
If your app makes out-of-band requests, such as a call summary with conversation: "none", check their output too. Agents tend to move them into the call session, where they can come back as another in-character reply instead of the summary.
If it goes wrong:
Step 2: test it like a call
Prompt
say or espeak and converted to 24 kHz mono PCM16. The app streams it in real time with input_audio_buffer.append, about 20 ms per frame, then keeps streaming silence until the final reply is done. The server decides when the caller has finished, so the app sends no commit. The reply audio goes to a WAV file.
For the settings, your coding agent compares the session your app sends with the one session.updated returns. A refused field comes back as an error. An ignored field is missing from session.updated or has a different value, except audio.input.transcription and parallel_tool_calls: those come back unchanged and still do nothing.
Check it. Your coding agent shows what the server heard, the tool call and the reply. Play the saved file: it’s the reply, spoken in the voice you set. The session in effect should show output_modalities: ["audio"], your Cartesia voice id, server_vad with create_response: true, and your instructions and tools as you sent them.
output
Step 3: give slow tools a line to say
An OpenAI Realtime agent often says “let me check” and calls a tool in the same response. Dialog-RSN-1 returns text or one tool call, never both, so the caller hears nothing until the tool returns. On a slow tool, that’s a long silence.Prompt
"poly_spoken": true, with a description that gives an example line. The model fills it in as part of the call, and the server speaks it while your tool runs.
- Your function is unchanged. The app takes the spoken argument out before it calls your function. Left in, your function gets an argument it doesn’t expect.
- The tool starts at once. It runs when
response.function_call_arguments.donearrives, not when the response ends. With a spoken line,response.donecomes only after the line has been said, so a tool started there loses that time. - The result goes back the same way. A
function_call_output, thenresponse.create. Agents send them once the response with the line is done.
output
OpenAI features with no match
Some OpenAI Realtime features have no match here. If your app uses one, the port needs more than a settings change. The full list is in the reference and its known limitations.Troubleshooting
For
401, 402 and other connection errors, see the quickstart’s Troubleshooting.

