Skip to main content

strands-xai

PyPI version Python Support License: MIT

xAI model provider for Strands Agents SDK

Features

  • Full Grok Model Support - Access all xAI Grok models (grok-4.5, grok-4.3, 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.5, 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.5 supports low/medium/high; grok-4.3 adds none
  • Prompt Cache Reporting - Cached input tokens surfaced as cacheReadInputTokens for accurate cost attribution
  • 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

Requirements

  • Python 3.10+
  • Strands Agents SDK 1.50.2+
  • xAI API key from xAI Console

Installation

pip install strands-agents strands-xai

Quick Start

Basic Usage

from 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.5",
)

# Create an agent
agent = Agent(model=model)

# Use the agent
result = agent("What is the capital of France?")
print(result)

With Streaming

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.5",
)

# 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")

With Server-Side Tools

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.5",
    xai_tools=[x_search(), web_search()],
)

agent = Agent(model=model)
result = agent("What are people saying about AI on X?")
print(result)

With Reasoning

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.5",
    reasoning_effort="high",  # grok-4.5: "low", "medium", or "high" (default "high")
)

agent = Agent(model=model)
result = agent("Solve this logic puzzle: If all roses are flowers...")
print(result)

Accepted levels differ per model:

Model Levels Default
grok-4.5 low, medium, high high
grok-4.3 none, low, medium, high low

Note: grok-4.5 has no none level — it always reasons; pass "low" if you want the cheapest/fastest setting. reasoning_effort is accepted only by grok-4.5 and grok-4.3. The xAI API returns INVALID_ARGUMENT if you pass it to grok-build-0.1, grok-4.20-0309-reasoning, or grok-4.20-0309-non-reasoning — those snapshots have their reasoning behavior baked in. On grok-4.20-multi-agent use agent_count instead — see the Multi-Agent Research section. Reasoning models do not accept presence_penalty, frequency_penalty, or stop in params.

What you get back

For every reasoning-capable model (grok-4.5, 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.

With Encrypted Reasoning

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.5",
    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_content is auto-enabled when xai_tools is 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.

Multi-Agent Research (grok-4.20-multi-agent)

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 — which xAIModel auto-enables whenever xai_tools is 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.

With Inline Citations

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.5",
    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 URLs

Vision (Image Understanding)

Analyze 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.5",  # 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.5, 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

Hybrid: Server-Side + Client-Side 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"

# Combine xAI tools with Strands tools
model = xAIModel(
    client_args={"api_key": "your-xai-api-key"},
    model_id="grok-4.5",
    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)

Configuration Options

Parameter Type Description
model_id str Grok model ID (e.g., "grok-4.5", "grok-4.3", "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 grok-4.5: "low", "medium", "high" (default "high"). grok-4.3 also accepts "none" (default "low")
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

Model Parameters

Common parameters you can pass in params:

model = xAIModel(
    client_args={"api_key": "your-xai-api-key"},
    model_id="grok-4.5",
    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
    }
)

Available Models

Model Context Vision Best For
grok-4.5 500K Frontier default — coding, agentic tasks, knowledge work ($2/$6 per MTok)
grok-4.3 1M Long context (1M) at lower cost, or when you need reasoning_effort="none" ($1.25/$2.50 per MTok)
grok-build-0.1 256K Agentic coding, early access — superseded by grok-4.5 ($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)

xAI's own guidance is to use grok-4.5 for everything text-based, including code. Its knowledge cutoff is February 1, 2026, and it is available in us-east-1 and us-west-2.

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.

Long-context pricing

Every current Grok model uses tiered long-context pricing: once a request's prompt reaches 200K tokens, all tokens in that request are billed at the higher rate.

Model < 200K prompt ≥ 200K prompt
grok-4.5 $2.00 in / $0.30 cached / $6.00 out $4.00 in / $0.60 cached / $12.00 out
grok-4.3 $1.25 in / $0.20 cached / $2.50 out $2.50 in / $0.40 cached / $5.00 out

Note that grok-4.5 is roughly 1.6× the input cost and 2.4× the output cost of grok-4.3, with a smaller (500K vs 1M) context window — pick it for capability, not for price or raw context length.

Prompt caching

Cached input tokens cost a fraction of fresh input ($0.30 vs $2.00 per MTok on grok-4.5), and this provider reports them to Strands as cacheReadInputTokens so cost backends can apply the discount:

result = agent("...")
print(result.metrics.accumulated_usage)
# {'inputTokens': 4120, 'outputTokens': 380, 'totalTokens': 4500, 'cacheReadInputTokens': 3712}

cacheReadInputTokens is the subset of inputTokens that was served from cache — it is not added on top (the same convention Strands' OpenAI and LiteLLM providers use). It also surfaces on the OpenTelemetry span as gen_ai.usage.cache_read_input_tokens.

xAI recommends pinning a conversation to one server so cache hits are reliable. The gRPC xai_sdk this provider wraps does not expose the Responses-API prompt_cache_key parameter, so there is no strands-xai config option for it; caching still works server-side, but hit rates depend on routing. You can pass the SDK's conversation_id through params for trace grouping:

model = xAIModel(model_id="grok-4.5", params={"conversation_id": "user-42-session-7"})

Keep the stable prefix of your prompt (system prompt, tool definitions) byte-identical across turns — any change to it invalidates the cache.

Model aliases

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.5 the forms are grok-4.5 / grok-4.5-latest; for the multi-agent line they are grok-4.20-multi-agent / grok-4.20-multi-agent-latest / grok-4.20-multi-agent-0309. Two extra aliases resolve to grok-4.5: grok-build-latest (the Grok Build coding agent's default, which is why grok-build-0.1 is effectively superseded) and the generic grok-latest flagship alias. 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.

Note: xai_sdk's ChatModel type alias does not yet list grok-4.5, but its model parameter is typed ChatModel | str, so passing "grok-4.5" is valid at runtime and under mypy. This provider does not maintain its own allow-list of model IDs — any current or future slug is forwarded as-is.

Retired model aliases

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

Server-Side Tools

xAI provides built-in tools executed on their infrastructure:

Available Tools

  • web_search() - Search the web for current information
  • x_search() - Search X (Twitter) for posts and trends
  • code_execution() - Execute Python code safely
  • collections_search() - Search uploaded document collections (RAG)

Basic Usage

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.5",
    xai_tools=[web_search(), x_search(), code_execution()],
)

agent = Agent(model=model)
result = agent("What's trending on X about AI?")

Combining with Client-Side Tools

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.5",
    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?")

Observability / OpenTelemetry

Using strands-xai with OpenTelemetry

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=1

Set 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).

Cost tracking and the qualified model id

You construct the model exactly as normal — xAIModel(model_id="grok-4.5"). Internally, the provider stores the provider-qualified id xai/grok-4.5 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.5); the xai/ prefix is stripped at the call site, so inference is unaffected.

You can pass either form ("grok-4.5" or "xai/grok-4.5") — normalization is idempotent. The only observable change is that model.get_config()["model_id"] now returns the qualified xai/grok-4.5.

Examples

See the examples directory for complete working examples.

Interactive Chat

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.py

Choose 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.5 with configurable effort)
  • Multi-agent research (grok-4.20-multi-agent)
  • Web search with citations

Quick Test

export XAI_API_KEY="your-xai-api-key"
python examples/test_grok_final.py

Or use the convenience script:

./run_examples.sh chat   # Interactive chat
./run_examples.sh test   # Quick test

Development

# 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_xai

Testing

Unit Tests

The 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 -v

Integration Tests with Real API

Test 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.py

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

Acknowledgments

Built for the Strands Agents community.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

strands_xai-0.5.0.tar.gz (42.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

strands_xai-0.5.0-py3-none-any.whl (20.7 kB view details)

Uploaded Python 3

File details

Details for the file strands_xai-0.5.0.tar.gz.

File metadata

  • Download URL: strands_xai-0.5.0.tar.gz
  • Upload date:
  • Size: 42.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for strands_xai-0.5.0.tar.gz
Algorithm Hash digest
SHA256 611316195176b9e1816ce11d170e6e01668d59a3d6de85b057df5d949baaf365
MD5 07f6b019c4e476eb4d17df7e3b559075
BLAKE2b-256 20253ffd0dfb1c82009c938fabb2484b1a9e921ae6869f0a17922d6dffbaa814

See more details on using hashes here.

Provenance

The following attestation bundles were made for strands_xai-0.5.0.tar.gz:

Publisher: publish.yml on Cerrix/strands-xai

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file strands_xai-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: strands_xai-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 20.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for strands_xai-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 18c617090b8aa6a2f79f41dbc4557426d0d95d0916788094e1ffe35db9f71b5f
MD5 419f591276af43795cb0fd84d2866fd4
BLAKE2b-256 ead17c9dbecfbfba8c753fe85d390bdbb0bcb7514524039c48a0465e5c5204d9

See more details on using hashes here.

Provenance

The following attestation bundles were made for strands_xai-0.5.0-py3-none-any.whl:

Publisher: publish.yml on Cerrix/strands-xai

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page