Skip to main content
The Realtime protocol exposes one public speech-to-speech model: kugel-agent-1. You choose instructions, function tools, a numeric voice identifier, and the audio wire format. Recognition, turn detection, reasoning, speech planning, and synthesis providers remain server-managed.
The standard TTS ingress process does not mount these routes, and this repository does not ship a combined production image. An operator must compose the agent behind the authenticated Realtime ingress before these endpoints are available. The standalone agent socket is an unauthenticated, loopback-only debugging surface and is disabled unless explicitly enabled.

Authenticate

Server applications can connect with their project API key:
Do not expose an API key in browser code. Exchange it on your server for a five-minute, project-scoped client secret:
The browser then connects with the returned value:
See Authentication for API-key handling.

Configure a session

The server first sends session.created. Select a numeric voice identifier before requesting output:
The server acknowledges an applied update with session.updated. When present, instructions is the instruction character count and tools lists the session’s declared tool names; the server does not echo the full effective configuration. The selected voice is applied to synthesis and becomes immutable when the first output begins. Per-message voice overrides are not supported.
Provider names, recognition models, transcription configuration, and turn detection are not public session fields. Unknown or internal fields fail with an explicit error event.

Send audio

Supported formats are: For JSON transport, send:
For binary transport, send the audio bytes as a binary WebSocket frame. The server emits input_audio_buffer.speech_started and input_audio_buffer.speech_stopped and automatically commits a detected speech boundary. A client may also explicitly commit the current buffer:
Use input_audio_buffer.clear to discard buffered, uncommitted audio. Clearing input does not cancel an active response; use response.cancel for that. Each commit produces input_audio_buffer.committed, transcription updates, and one completed user conversation item through the deployment’s private perception runtime. Recognition candidates, confidence values, provider versions, endpoint scores, and endpointing controls remain server-side.

Request an agent response

After a committed user turn, request model-authored speech with:
The private response runtime receives the latest committed transcript, instructions, and configured tools. A committed user turn is required. Only a Speaker-authored clause associated with that turn enters the serialized TTS and playout path; private reasoning is not sent directly to synthesis. Per-response instructions and tools are not supported in this version. Supplying response configuration returns a not_implemented error and does not start a response:
When the Thinker selects a configured function, the server emits a function_call conversation item followed by response.function_call_arguments.done. Return the exact call_id:
The runtime rejects unknown, duplicate, malformed, and reused call IDs. A valid result continues the private Thinker/Speaker response lifecycle. To report that client-side tool execution failed, return a JSON object whose only field is a non-empty string named error, for example "{\"error\":\"user not found\"}". The runtime exposes that as a failed tool outcome rather than a successful result, allowing the agent to recover without claiming that the operation succeeded. For identity-bearing arguments such as account IDs, declare identity_arguments alongside the JSON schema:
Every identity argument must name a declared property. If recognition still has plausible spellings for one of these values, the call is rejected rather than dispatching an ambiguous identity to the client tool.

Speak exact fixed text

A force_message speaks client-authored text directly. Sending the item is the entire request; do not follow it with response.create.
The text is sent to synthesis exactly as supplied after JSON decoding. V1 accepts exactly one nonempty output_text part with at most 2,000 Unicode code points. It does not accept SSML, audio parts, tool calls, or per-message voices. Fixed speech uses the same serialized output floor as agent-authored speech. If interruptible is false, caller audio received during playback is discarded and the server emits kugel.input_audio.suppressed.

Response lifecycle

A successful audio response uses this lifecycle:
With base64 output, each response.output_audio.delta contains encoded audio. With binary output, audio chunks are raw binary frames and lifecycle metadata remains JSON. The final transcript for a fixed message equals its supplied text. response.done is emitted only after the client reports a terminal played span; sending bytes to a socket is not treated as audible playout. Audio deltas are emitted incrementally as synthesis produces them. response.output_audio_transcript.done is ordered behind the final audio frame for its clause. Clients should not send a terminal playout acknowledgement until they have received this marker and actually played the scheduled audio. When final reasoning takes longer than the Speaker’s bridge decision, one response can contain two separately identified clauses: a short Speaker-authored bridge followed by the substantive answer. After playing audio, report the exact cumulative sample and Unicode-code-point cut:
Set completed only when the full text and produced audio were played. Partial acknowledgements update history with the exact prefix but do not release the output floor. When caller speech interrupts an interruptible response, the server estimates the heard prefix from emitted samples and synthesis word timestamps, emits response.output_audio.done for that prefix, and then emits response.cancelled. Do not acknowledge a response after it is cancelled. Offsets that regress, exceed produced output, or identify another item fail explicitly. Cancel the active or named interruptible response with:
The server emits response.cancelled after recording its best estimate of the heard prefix. Speech beyond that prefix is not added to conversation history. conversation.item.truncate is reserved by the schema but is not implemented by the current shared runtime.

Client events

Server events

Client-driven conversation.item.truncate is schema-reserved but is not handled by the current shared runtime.