xAI model provider for Strands Agents SDK
- Full Grok Model Support - Access all xAI Grok models (grok-4.3, grok-build-0.1, grok-4.20-multi-agent, etc.)
- Multi-Agent Research - Orchestrate 4 or 16 collaborating agents with grok-4.20-multi-agent
- Vision Support - Analyze images with vision-capable models (grok-4.3, grok-build-0.1, grok-4.20-*)
- Server-Side Tools - Use xAI's built-in tools (web_search, x_search, code_execution, collections_search)
- Configurable Reasoning - grok-4.3 supports
none/low/medium/highreasoning effort - Encrypted Reasoning - Preserve sub-agent and reasoning state across turns via
use_encrypted_content - Streaming Support - Real-time response streaming with full event handling
- Hybrid Tool Usage - Combine xAI server-side tools with Strands client-side tools
- Multi-Turn Context - Seamless conversation history with encrypted content preservation
- Type Safe - Full type hints and mypy support
- Python 3.10+
- Strands Agents SDK 1.41.0+
- xAI API key from xAI Console
pip install strands-agents strands-xaifrom strands_xai import xAIModel
from strands import Agent
# Initialize xAI model
model = xAIModel(
client_args={"api_key": "your-xai-api-key"}, # or set XAI_API_KEY env var
model_id="grok-4.3",
)
# Create an agent
agent = Agent(model=model)
# Use the agent
result = agent("What is the capital of France?")
print(result)from strands_xai import xAIModel
from strands import Agent
from strands.handlers.callback_handler import PrintingCallbackHandler
model = xAIModel(
client_args={"api_key": "your-xai-api-key"},
model_id="grok-4.3",
)
# Streaming happens automatically with callback handlers
agent = Agent(
model=model,
callback_handler=PrintingCallbackHandler()
)
# Text streams to console in real-time
result = agent("Tell me a story")from strands_xai import xAIModel
from strands import Agent
from xai_sdk.tools import x_search, web_search
# Use xAI's built-in tools (executed on xAI servers)
model = xAIModel(
client_args={"api_key": "your-xai-api-key"},
model_id="grok-4.3",
xai_tools=[x_search(), web_search()],
)
agent = Agent(model=model)
result = agent("What are people saying about AI on X?")
print(result)from strands_xai import xAIModel
from strands import Agent
# Configurable reasoning depth
model = xAIModel(
client_args={"api_key": "your-xai-api-key"},
model_id="grok-4.3",
reasoning_effort="high", # "none", "low" (default), "medium", or "high"
)
agent = Agent(model=model)
result = agent("Solve this logic puzzle: If all roses are flowers...")
print(result)Note:
reasoning_effortis only accepted bygrok-4.3. The xAI API returnsINVALID_ARGUMENTif you pass it togrok-build-0.1,grok-4.20-0309-reasoning, orgrok-4.20-0309-non-reasoning— those snapshots have their reasoning behavior baked in. Ongrok-4.20-multi-agentuseagent_countinstead — see the Multi-Agent Research section. Reasoning models do not acceptpresence_penalty,frequency_penalty, orstopinparams.
For every reasoning-capable model (grok-4.3, grok-build-0.1, grok-4.20-0309-reasoning, grok-4.20-multi-agent), the SDK streams three signals that this provider surfaces to Strands automatically:
| xAI SDK channel | Strands location | Notes |
|---|---|---|
chunk.reasoning_content |
reasoningContent.reasoningText.text content blocks |
A summarized trace of the model's thinking — typically a few hundred characters, and always far shorter than the billed reasoning_tokens would imply. The full chain-of-thought is not exposed (older models like grok-3-mini streamed the raw trace; current Grok models only return this summary). |
usage.reasoning_tokens |
metadata usage.reasoningTokens |
Billed reasoning-token count, even when the summary is short. |
final_response.encrypted_content (only when use_encrypted_content=True) |
reasoningContent.redactedContent |
Encrypted full reasoning state, restored verbatim on the next turn for multi-turn context preservation. |
grok-4.20-0309-non-reasoning emits none of the above (reasoning_tokens is zero and the reasoning channels stay empty), as expected for an inference-only snapshot.
For multi-turn conversations with reasoning state preserved across turns:
from strands_xai import xAIModel
from strands import Agent
model = xAIModel(
client_args={"api_key": "your-xai-api-key"},
model_id="grok-4.3",
reasoning_effort="medium",
use_encrypted_content=True, # Preserves reasoning across turns
)
agent = Agent(model=model)
# First turn
result1 = agent("Think through this problem: 2+2")
print(result1)
# Second turn - reasoning context preserved
result2 = agent("Now multiply that by 3")
print(result2)Note:
use_encrypted_contentis auto-enabled whenxai_toolsis set so server-side tool state is preserved. You only need to pass it explicitly if you want encrypted reasoning preservation without server-side tools.
Beta: The multi-agent API is currently in beta on xAI. The interface and behavior may change as it iterates — expect occasional breaking changes.
Orchestrate multiple AI agents that collaborate on research tasks:
from strands_xai import xAIModel
from strands import Agent
from xai_sdk.tools import web_search, x_search
# 4 agents for focused queries, 16 for deep research
model = xAIModel(
client_args={"api_key": "your-xai-api-key"},
model_id="grok-4.20-multi-agent",
xai_tools=[web_search(), x_search()],
agent_count=4, # or 16 for comprehensive analysis
)
agent = Agent(model=model)
result = agent("Research the latest breakthroughs in quantum computing")
print(result)Notes:
- The multi-agent model does not support client-side tools (function calling) or
max_tokens.- Only the leader agent's output is returned by default. Sub-agent reasoning, tool calls, and outputs are encrypted and only preserved when
use_encrypted_content=True— whichxAIModelauto-enables wheneverxai_toolsis set, so multi-turn context is kept intact.- All tokens consumed by the leader and every sub-agent are billed (input, output, and reasoning), and each agent's server-side tool calls also count against your tool usage. Expect usage to scale with
agent_count.
Get sources cited directly in responses:
from strands_xai import xAIModel
from strands import Agent
from xai_sdk.tools import web_search
model = xAIModel(
client_args={"api_key": "your-xai-api-key"},
model_id="grok-4.3",
xai_tools=[web_search()],
include=["inline_citations"], # Enable citations
)
agent = Agent(
model=model,
system_prompt="You are a helpful assistant. Always cite sources."
)
result = agent("What are the latest developments in AI?")
print(result)
# Output includes inline citations like [1], [2] with source URLsAnalyze images with vision-capable models:
from strands_xai import xAIModel
from strands import Agent
model = xAIModel(
client_args={"api_key": "your-xai-api-key"},
model_id="grok-4.3", # Vision-capable model
)
agent = Agent(model=model)
# Read image bytes
with open("image.png", "rb") as f:
image_bytes = f.read()
# Send image as content block
message = [
{"text": "What's in this image?"},
{"image": {"format": "png", "source": {"bytes": image_bytes}}}
]
result = agent(message)
print(result)Vision-capable models: grok-4.3, grok-build-0.1, grok-4.20-0309-reasoning, grok-4.20-0309-non-reasoning, grok-4.20-multi-agent, grok-4.20-multi-agent-0309
from strands_xai import xAIModel
from strands import Agent, tool
from xai_sdk.tools import x_search
@tool
def get_weather(city: str) -> str:
"""Get weather for a city."""
return f"Weather in {city}: Sunny, 22°C"
# Combine xAI tools with Strands tools
model = xAIModel(
client_args={"api_key": "your-xai-api-key"},
model_id="grok-4.3",
xai_tools=[x_search()],
)
agent = Agent(model=model, tools=[get_weather])
result = agent("What's the weather in Paris and what are people tweeting about it?")
print(result)| Parameter | Type | Description |
|---|---|---|
model_id |
str |
Grok model ID (e.g., "grok-4.3", "grok-build-0.1", "grok-4.20-multi-agent") |
client_args |
dict |
Arguments for xAI client (api_key, timeout, etc.) |
params |
dict |
Model parameters (temperature, max_tokens, etc.). Reasoning models reject presence_penalty, frequency_penalty, and stop. |
xai_tools |
list |
Server-side tools from xai_sdk.tools |
reasoning_effort |
str |
"none", "low" (default), "medium", or "high" for grok-4.3 |
use_encrypted_content |
bool |
Preserve reasoning / sub-agent state across turns (auto-enabled when xai_tools is set) |
include |
list |
Optional xAI features (e.g., ["inline_citations"]) |
agent_count |
int |
Number of agents (4 or 16) for grok-4.20-multi-agent |
Common parameters you can pass in params:
model = xAIModel(
client_args={"api_key": "your-xai-api-key"},
model_id="grok-4.3",
params={
"temperature": 0.7, # 0.0-2.0, controls randomness
"max_tokens": 2048, # Maximum tokens in response
"top_p": 0.9, # Nucleus sampling
"frequency_penalty": 0, # -2.0 to 2.0
"presence_penalty": 0, # -2.0 to 2.0
}
)| Model | Context | Vision | Best For |
|---|---|---|---|
grok-4.3 |
1M | ✅ | Flagship — agentic tool calling, configurable reasoning ($1.25/$2.50 per MTok) |
grok-build-0.1 |
256K | ✅ | Agentic coding, early access ($1/$2 per MTok) |
grok-4.20-multi-agent |
1M | ✅ | Multi-agent research — rolling alias |
grok-4.20-multi-agent-0309 |
1M | ✅ | Multi-agent research — pinned snapshot ($1.25/$2.50 per MTok) |
grok-4.20-0309-reasoning |
1M | ✅ | Pinned 4.20 reasoning snapshot ($1.25/$2.50 per MTok) |
grok-4.20-0309-non-reasoning |
1M | ✅ | Pinned 4.20 inference snapshot ($1.25/$2.50 per MTok) |
Pricing is shown as input/output per million tokens. Dated *-0309 IDs are pinned snapshots; the unsuffixed grok-4.20-multi-agent is a rolling alias that points to the latest stable revision. See xAI documentation for the authoritative pricing and rate-limit reference.
xAI follows a consistent alias convention for every model line:
| Form | Resolves to | Use when |
|---|---|---|
<modelname> |
latest stable version | recommended default — picks up patches automatically |
<modelname>-latest |
latest version (may include preview features) | you want the bleeding edge |
<modelname>-<date> |
a specific dated snapshot | reproducibility-critical workloads that must not move |
So for grok-4.3 the three forms are grok-4.3 / grok-4.3-latest / a future grok-4.3-<date>; for the multi-agent line they are grok-4.20-multi-agent / grok-4.20-multi-agent-latest / grok-4.20-multi-agent-0309. The generic grok-latest alias also resolves to the current flagship (grok-4.3 today). Pass any of these as model_id — the SDK forwards the string verbatim, so you control which side of the rolling/pinned trade-off you take.
The following slugs were retired on 2026-05-15 and now silently redirect (and are billed) at grok-4.3 or grok-build-0.1 rates. Update your code to migrate explicitly:
| Retired slug | Now routed to |
|---|---|
grok-4-1-fast-reasoning, grok-4-fast-reasoning, grok-4-0709, grok-4, grok-4-latest |
grok-4.3 with reasoning_effort="low" |
grok-4-1-fast-non-reasoning, grok-4-fast-non-reasoning, grok-3 |
grok-4.3 with reasoning_effort="none" |
grok-3-mini and all grok-3-mini-* variants |
grok-4.3 |
grok-code-fast-1, grok-code-fast, grok-code-fast-1-0825 |
grok-build-0.1 |
xAI provides built-in tools executed on their infrastructure:
web_search()- Search the web for current informationx_search()- Search X (Twitter) for posts and trendscode_execution()- Execute Python code safelycollections_search()- Search uploaded document collections (RAG)
from strands_xai import xAIModel
from strands import Agent
from xai_sdk.tools import web_search, x_search, code_execution
model = xAIModel(
client_args={"api_key": "your-xai-api-key"},
model_id="grok-4.3",
xai_tools=[web_search(), x_search(), code_execution()],
)
agent = Agent(model=model)
result = agent("What's trending on X about AI?")Mix xAI server-side tools with your own Strands tools:
from strands_xai import xAIModel
from strands import Agent, tool
from xai_sdk.tools import x_search
@tool
def get_weather(city: str) -> str:
"""Get weather for a city."""
return f"Weather in {city}: Sunny, 22°C"
model = xAIModel(
client_args={"api_key": "your-xai-api-key"},
model_id="grok-4.3",
xai_tools=[x_search()], # Server-side
)
agent = Agent(
model=model,
tools=[get_weather] # Client-side
)
# Agent can use both types of tools
result = agent("What's the weather in Paris and what are people saying about it on X?")Strands instruments each model call and emits spans with correct token usage. The underlying xai_sdk also has its own OpenTelemetry instrumentation, which emits a duplicate chat.stream span for the same call. That extra span reports token usage in xAI's raw form (output excludes reasoning, total includes it), which can make trace-level totals inconsistent in observability tools.
When running strands-xai with any OpenTelemetry backend, disable xai_sdk's own tracing so only Strands' spans are exported:
export XAI_SDK_DISABLE_TRACING=1Set it in your environment before starting the process — xai_sdk binds its tracer at import time, so setting it from Python after import has no effect. With this set, traces contain a single clean span tree and token totals reconcile (input + output == total, with reasoning folded into output).
You construct the model exactly as normal — xAIModel(model_id="grok-4.3"). Internally, the provider stores the provider-qualified id xai/grok-4.3 in its config, and that is what appears on the trace as gen_ai.request.model. This is intentional: cost backends (LiteLLM, SideSeat, etc.) price Grok under the qualified key xai/<model> — there is no bare grok-* price key — so the qualified id is what lets them attach a non-zero cost. The xAI SDK itself is always called with the bare id (grok-4.3); the xai/ prefix is stripped at the call site, so inference is unaffected.
You can pass either form ("grok-4.3" or "xai/grok-4.3") — normalization is idempotent. The only observable change is that model.get_config()["model_id"] now returns the qualified xai/grok-4.3.
See the examples directory for complete working examples.
Full-featured interactive chat with 10 different agent configurations:
export XAI_API_KEY="your-xai-api-key"
cd strands-xai
source .venv/bin/activate
python examples/interactive_chat.pyChoose from:
- Simple (non-streaming)
- Streaming with debug mode
- Client-side tools (calculator, weather)
- Server-side tools (X search, web search)
- Hybrid (both server and client tools)
- Reasoning models (grok-4.3 with configurable effort)
- Multi-agent research (grok-4.20-multi-agent)
- Web search with citations
export XAI_API_KEY="your-xai-api-key"
python examples/test_grok_final.pyOr use the convenience script:
./run_examples.sh chat # Interactive chat
./run_examples.sh test # Quick test# Clone the repository
git clone https://github.com/Cerrix/strands-xai.git
cd strands-xai
# Install with dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Run tests with coverage
pytest --cov=strands_xai --cov-report=html
# Format code
ruff format .
# Lint code
ruff check .
# Type check
mypy src/strands_xaiThe package includes a comprehensive unit test suite:
# Run all tests
pytest
# Run with coverage
pytest --cov=strands_xai --cov-report=html
# Run specific test
pytest tests/test_xai.py::TestBuildChat -vTest with your xAI API key using the example scripts:
export XAI_API_KEY="your-xai-api-key"
# Interactive testing
python examples/interactive_chat.py
# Quick functionality test
python examples/test_grok_final.pyContributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.
Built for the Strands Agents community.