Skip to main content

Realtime Voice — Provider API

Reference for authors implementing a RealtimeVoiceProviderPlugin — the contract the Gateway uses to bridge client audio to a voice backend.

Plugin registration

Register your provider in the plugin entry file:
The provider object must implement RealtimeVoiceProviderPlugin:

SDK imports

All types and helpers export from openclaw/plugin-sdk:

RealtimeVoiceBridgeCreateRequest

The argument to createBridge():

RealtimeVoiceBridge interface

Your createBridge() return value must implement:

Callback timing invariant

Callbacks must not be fired synchronously during createBridge() 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, emit onToolCall:
The client executes the function and sends back 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 response
  • suppressResponse: boolean — submit without asking the provider for a new assistant response

Audio formats

Two format constants are exported from openclaw/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, implement createBrowserSession:
If 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 to createBridge. 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 calls openclaw_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 bundled talk-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:
The provider receives these in 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.