jambonz Adds Speech-to-Speech Support for xAI's Grok Voice Think Fast 2.0

Dave Horton

We’re happy to announce that jambonz supports xAI’s Grok Voice Think Fast 2.0 as a first-class speech-to-speech vendor. If you run jambonz v11 or later with the mediajam media engine, you can connect any phone call to a Grok voice agent with a single verb.

Grok Voice Brings Speech-to-Speech Reasoning to Voice AI Agents

Grok Voice is a native speech-to-speech model: one model listens, reasons, and speaks over a single persistent connection. xAI’s pitch for the 2.0 generation is that it reasons while it talks, so a tool call can fire before the agent has finished its first sentence, instead of after a visible pause, along with better transcription accuracy and a more natural conversational feel than the 1.0 models.

The part we find most interesting for telephony is a setting the other vendors don’t expose: reasoning.effort, which takes high (the default) or none. That is an explicit dial for the tradeoff every voice-agent developer ends up making by hand (deliberation versus latency) and it can be set per session, so a support flow that reasons over tool output and a high-volume “where’s my order” flow can use the same model with different characters.

How to Add Grok Voice to a jambonz Call

If you’ve used the OpenAI Realtime API with jambonz, this will feel instantly familiar. xAI speaks an OpenAI-Realtime dialect, and jambonz exposes it the same way. Here’s a minimal application using the @jambonz/sdk WebSocket interface:

session
  .s2s({
    vendor: 'xai',
    // pinned deliberately, rather than relying on the grok-voice-latest alias
    model: 'grok-voice-think-fast-2.0',
    auth: {
      apiKey: process.env.XAI_API_KEY,
    },
    llmOptions: {
      session_update: {
        instructions: 'You are a friendly and helpful voice assistant. ' +
          'Keep your responses concise and conversational.',
        turn_detection: { type: 'server_vad' },
        audio: {
          output: { voice: 'eve' },
        },
        // xAI-specific: 'high' reasons before speaking, 'none' minimizes latency
        reasoning: { effort: 'high' },
      },
      // the agent speaks first
      response_create: {
        instructions: 'Greet the caller warmly and ask how you can help.',
      },
    },
    actionHook: '/s2s-complete',
  })
  .send();

A few practical notes:

xAI Grok Voice Documentation and Resources

As always, come find us in the jambonz community with questions. We’d love to hear what you build with it.

Frequently asked questions

What is Grok Voice Think Fast 2.0?

Grok Voice Think Fast 2.0 is xAI's native speech-to-speech model, served over a persistent WebSocket at api.x.ai. One model listens, reasons, and speaks, rather than chaining a separate speech-to-text engine, LLM, and text-to-speech engine. xAI reports that 2.0 improves on the 1.0 generation in reasoning, transcription accuracy, and conversational feel, and that it reasons in parallel with speaking so tool calls fire earlier in a turn.

Which model name should I use in the jambonz llm verb?

Set model to grok-voice-think-fast-2.0 explicitly rather than relying on the grok-voice-latest alias. Pinning the exact model name means your application's behavior does not change underneath you the next time xAI repoints the alias at a new generation.

How is Grok Voice different from OpenAI Realtime on jambonz?

xAI speaks the same OpenAI Realtime GA wire dialect, so llmOptions carries the same session_update and response_create payloads and your existing OpenAI Realtime application is most of the way there. Four differences matter in practice: session_update is required for xAI because audio is gated until the first session.updated arrives; turn_detection sits at the top level of session_update rather than under audio.input; a completed tool call arrives on response.function_call_arguments.done rather than response.output_item.done; and caller transcripts arrive on conversation.item.input_audio_transcription.updated, which is cumulative rather than incremental.

What is reasoning.effort and when should I change it?

reasoning.effort is an xAI-specific setting in session_update with two values, high (the default) and none. It is the clearest dial we have seen on any speech-to-speech vendor for trading deliberation against latency: leave it at high for calls where the agent has to reason over tool results or policy, and set it to none for high-volume flows where the fastest possible reply matters more. There is no equivalent knob on OpenAI Realtime, Gemini Live, or Deepgram Voice Agent.

Do I need to configure audio formats or codecs?

No, and you should not try. Audio on the wire to xAI is pcm16 at 24 kHz, and jambonz forces that format and rate regardless of what your session_update declares. Anything you set in session_update.audio.input.format or session_update.audio.output.format is overridden, so leave it out.

Can the agent use tools, MCP servers, and call transfer?

Yes. Tool and function calling follows the same shape as OpenAI's, declared in session_update.tools and routed to your toolHook. MCP tools, the runtime-injected handoff tool, and the runtime-injected hangup tool all work the same way with xAI as with every other speech-to-speech vendor jambonz supports.

Which voices are available?

The built-in voices are eve (the default), ara, rex, sal, and leo, selected via session_update.audio.output.voice. Custom voice IDs from xAI's Custom Voices API also work.