Realtime Voice — Provider API
Reference for authors implementing aRealtimeVoiceProviderPlugin — the contract
the Gateway uses to bridge client audio to a voice backend.
Plugin registration
Register your provider in the plugin entry file:RealtimeVoiceProviderPlugin:
SDK imports
All types and helpers export fromopenclaw/plugin-sdk:
RealtimeVoiceBridgeCreateRequest
The argument to createBridge():
RealtimeVoiceBridge interface
Your createBridge() return value must implement:
Callback timing invariant
Callbacks must not be fired synchronously duringcreateBridge() execution.
The session runtime assigns the returned bridge to a local variable only after createBridge()
returns. If onReady or onToolCall fires during construction, the guard checks (if (!bridge))
silently discard the event. All callbacks must be deferred to after connect() is called.
Close reasons
Tool calls
When the voice model triggers a function call, emitonToolCall:
talk.realtime.toolResult. The Gateway calls
bridge.submitToolResult(callId, result, options). Options:
willContinue: boolean— whether the client will send another tool result before expecting a responsesuppressResponse: boolean— submit without asking the provider for a new assistant response
Audio formats
Two format constants are exported fromopenclaw/plugin-sdk:
The Gateway relay always uses
REALTIME_VOICE_AUDIO_FORMAT_PCM16_24KHZ. Emit onAudio buffers at 24 kHz PCM16. If your backend uses a different rate, negotiate it in connect() and resample — the relay contract is fixed. Declare both formats in capabilities.inputAudioFormats / capabilities.outputAudioFormats if your provider supports them.
Browser sessions (optional)
For WebRTC / provider-websocket / managed-room transports, implementcreateBrowserSession:
createBrowserSession is absent and a client requests a non-relay transport, the Gateway
returns UNAVAILABLE — it never silently downgrade to relay.
Agent consult tool
The SDK ships a built-in function tool (openclaw_agent_consult) that voice providers can
expose to the voice model. When the model calls it, the Gateway delegates the request to the
configured WednesdayAI agent — enabling tool use, memory lookups, workspace actions, and
current-information retrieval from within a voice session.
Enabling the consult tool
The session gateway handler passes resolved tools tocreateBridge. Include the consult
tool by calling resolveRealtimeVoiceAgentConsultTools from openclaw/plugin-sdk:
Consult tool policies
Configure via
talk.providers.<id>.consultToolPolicy in openclaw.json.
Handling a consult tool call
When the voice model callsopenclaw_agent_consult, the provider receives a toolCall event.
The Gateway then calls bridge.submitToolResult with the delegated agent’s answer. Providers do
not need to implement this themselves — the session runtime handles the delegation loop.
However, providers can emit an interim spoken instruction while the agent runs using
buildRealtimeVoiceAgentConsultWorkingResponse:
Reference implementations
Production provider — the bundled OpenAI Realtime provider is the first production implementation. It covers the full bridge contract: WebSocket lifecycle, server-VAD barge-in signalling, tool calls, audio framing, and post-close race guard. Use it as a starting point when implementing a new production provider. Minimal test stub — the bundledtalk-voice extension ships a fakeRealtimeVoiceProvider
for integration testing. It covers the full lifecycle: connect → audio → transcript →
toolCall → submitToolResult → close. Use addRealtimeVoiceProvider(fakeRealtimeVoiceProvider)
in tests; this helper is part of the internal test suite and is not exported from the public SDK.
RealtimeVoiceTool schema
Tools declared by the client at session start:
createBridge(req.tools) and may register them with the
voice backend. Providers that self-configure their toolset from registered config may ignore
the client-declared tools — declare this in capabilities.supportsToolCalls.
Provider config resolution flow
resolveConfig is optional. If omitted, rawConfig (the JSON object under
talk.providers.<id>) is passed as-is to isConfigured and createBridge.