04Connect
Realtime API
Connect any OpenAI Realtime client to a Cuelo agent.
Cuelo serves the OpenAI Realtime API (GA) over WebSocket at:
ws://127.0.0.1:4141/v1/realtimeExisting Realtime clients and SDKs work unchanged. Point them at Cuelo instead
of api.openai.com. Beta clients that send OpenAI-Beta: realtime=v1 get the
beta event names.
Audio
PCM16, mono, 24 kHz, base64 in input_audio_buffer.append and
response.output_audio.delta. The engine resamples internally for each
provider.
What's different from OpenAI
- Turn detection is Cuelo's. The agent's controllers decide end of turn,
interruptions and backchannels. The client's
turn_detectionsettings are accepted but not applied. You still getinput_audio_buffer.speech_startedandspeech_stopped. - Server tools are invisible. Tools from
config.cuelorun on the server. The client only hears the result. - Interruptions. When the agent is interrupted, the server sends
input_audio_buffer.speech_startedso clients stop playback. Then it ends the response with statuscancelled. Drop any audio you haven't played. - Backchannels arrive as normal output audio while the user is speaking.
Client events
| Event | Supported |
|---|---|
session.update | instructions, tools, audio.output.voice |
input_audio_buffer.append | yes |
input_audio_buffer.commit | yes: asks the agent to reply now (push-to-talk) |
input_audio_buffer.clear | acknowledged with input_audio_buffer.cleared |
conversation.item.create | user text messages, and function_call_output for client tools |
conversation.item.truncate | acknowledged; the engine tracks interrupted replies itself |
response.create | yes: makes the agent speak, e.g. first, before the user |
response.cancel | yes |
Server events
session.created, session.updated, conversation.item.added/done,
input_audio_buffer.speech_started/speech_stopped/committed/cleared,
conversation.item.input_audio_transcription.completed, response.created,
response.output_item.added/done, response.content_part.added/done,
response.output_audio.delta/done, response.output_audio_transcript.delta/done,
response.function_call_arguments.done, response.done and error.
Tools
Tools a client declares in session.update run in the client:
-
The response ends with a
function_calloutput item (call_id,name,arguments). -
The client runs it and sends:
{ "type": "conversation.item.create", "item": { "type": "function_call_output", "call_id": "call_123", "output": "{\"ok\":true}" } } -
The agent continues on its own. A following
response.createis accepted and ignored.
Examples
import asyncio, base64
from openai import AsyncOpenAI
async def main():
client = AsyncOpenAI(base_url="http://127.0.0.1:4141/v1", api_key="unused")
async with client.realtime.connect(model="cuelo") as conn:
await conn.session.update(session={
"type": "realtime",
"instructions": "You are a concise barista.",
})
await conn.response.create() # speak first
async for event in conn:
if event.type == "response.output_audio.delta":
play(base64.b64decode(event.delta)) # PCM16 24 kHz
elif event.type == "input_audio_buffer.speech_started":
stop_playback() # interrupted
asyncio.run(main())The dashboard's Talk page (observer/src/demo/realtime.ts) is a complete
browser client with AudioWorklets for capture and playback, a good starting
point.
Turning it off
serve.api: none serves only your own routes from src/api.py. See
Custom endpoints.