xAI Grok Voice
XaiRealtimeModel brings Grok Voice into the typed,
server-side realtime agent loop. Start with the realtime quickstart or the
text-to-audio example.
To use Grok Voice, install pydantic-ai-slim with the xai-realtime optional group. Alongside
xai-sdk, the bundle includes the openai package, because Grok Voice’s realtime API reuses the
OpenAI Realtime protocol’s event types:
pip install "pydantic-ai-slim[xai-realtime]"
uv add "pydantic-ai-slim[xai-realtime]"
Set XAI_API_KEY as described in the xAI model documentation.
Use provider='xai' or pass an
XaiProvider with api_key=. Custom api_host is
unsupported, and a provider constructed with only xai_client= cannot open the WebSocket because
the connection requires the API key.
Use a Grok Voice ID such as grok-voice-latest or a pinned grok-voice-think-* model.
grok-voice-latest follows xAI’s current flagship and can change underneath an application; pin a
version when behavior must remain stable. Use the
official xAI voice documentation for the canonical
model list.
XaiRealtimeModelSettings — the realtime
counterpart of model run settings — extends the
shared settings:
from pydantic_ai.realtime.xai import XaiRealtimeModel, XaiRealtimeModelSettings
settings = XaiRealtimeModelSettings(
xai_voice='eve',
turn_detection={'sensitivity': 'low'},
input_transcription_model='auto',
)
model = XaiRealtimeModel('grok-voice-latest', settings=settings)
xai_voice selects the provider voice; when unset, xAI picks its own server-side default
(currently eve). For an exact server-VAD threshold, prefix padding, or silence duration, set
xai_turn_detection= with ServerVAD; it fully overrides
shared turn_detection. xAI echoes create_response: False
back but still responds when the user stops speaking, so use turn_detection=False for
push-to-talk instead.
xAI accepts the shared max_tokens and parallel_tool_calls settings but ignores them: replies
aren’t capped, and the model can still call several tools at once.
Input transcription defaults to 'auto'. Unlike the incremental
deltas described in live captions, xAI sends cumulative transcript
snapshots that can revise earlier words, so caption UIs should render the full
TranscriptUpdate.transcript rather than
append deltas.
grok-voice-latest and grok-voice-think-* models support the shared
thinking setting. The provider exposes
only 'high' and 'none': every enabled effort maps to 'high', while False maps to 'none'.
Other Grok Voice models ignore the setting.
| Feature | Support | Notes |
|---|---|---|
| Audio format | Limited parameter support | Mono PCM16 at 24 kHz by default, input and output; the other PCM rates xAI lists (8 to 48 kHz) by setting audio_input_sample_rate and audio_output_sample_rate through profile=. The API also offers G.711 and Opus, which Pydantic AI does not expose |
| Text output | Unsupported | Grok Voice always produces audio |
| Image input | Unsupported | Grok Voice doesn’t see images: xAI accepts an image item but ignores it, so send() rejects images with a UserError before sending |
| Manual turns | Full feature support | turn_detection=False plus commit/create verbs |
| Interruption | Limited parameter support | interrupt() works, and played_bytes= also discards the unheard audio; played_ms raises, because xAI’s truncation is unreliable at barge-in |
| Input transcription | Full feature support | Dedicated provider path; 'auto' by default |
| Native tools | Unsupported | xAI offers web search, X search, file search, and MCP tools, which Pydantic AI does not expose yet; configure local fallbacks for web capabilities |
| Async tool calls | Full feature support | Grok Voice keeps talking, and answers the user, while a tool runs |
| Usage | Full feature support | Audio-token buckets and billable_audio_seconds in RunUsage.details |
| Reconnection | Full feature support | Pydantic AI replays completed local history into a new conversation; in-flight media is lost |
See Audio, images, and transcripts, Turns and interruptions, Tools, and Connection lifecycle for the provider-agnostic workflows.
Grok Voice is not currently available through the Pydantic AI Gateway. Connect
through provider='xai' or an XaiProvider.
A conversation that runs past xAI’s maximum duration ends with a max_duration error, and the
session raises a RealtimeError instead of reconnecting.
- Grok Voice always speaks: its profile reports
supports_text_output=False, sooutput_modality='text'raises aUserErrorbefore connecting. Read the answer from the transcript on theSpeechPart. - xAI documents
conversation.item.truncateand confirms it withconversation.item.truncated, but in our testing it only takes effect once the response has ended, and not reliably even then. Sent just before the cancel, as barge-in needs, it changes nothing, so the profile reportssupports_output_truncation=False.interrupt(played_bytes=...)still discards the unheard audio and cancels the response, while a plaininterrupt()only cancels. Either way xAI keeps everything generated up to the cancel, which can be more than the user heard. - The protocol resembles OpenAI Realtime, but feature support comes from the xAI model profile; avoid assuming every OpenAI behavior is available.