
Stream agentic tool calls on the Grok API
Stream agentic tool calls on the Grok API
For server-side tools (web_search, x_search, code_execution, collections search, MCP), stream the request so you see each tool call as it happens, watch reasoning token counts, and get the final answer without waiting for the full agent loop in silence. Synchronous sample() / non-streaming Responses still work when you only need the finished text.
Stream with the xAI SDK
import os
from xai_sdk import Client
from xai_sdk.chat import user
from xai_sdk.tools import code_execution, web_search, x_search
client = Client(api_key=os.getenv("XAI_API_KEY"))
chat = client.chat.create(
model="grok-4.6",
tools=[web_search(), x_search(), code_execution()],
include=["verbose_streaming"],
)
chat.append(user("What are the latest updates from xAI?"))
is_thinking = True
for response, chunk in chat.stream():
for tool_call in chunk.tool_calls:
print(f"\nCalling tool: {tool_call.function.name}")
if response.usage.reasoning_tokens and is_thinking:
print(f"\rThinking... ({response.usage.reasoning_tokens} tokens)", end="", flush=True)
if chunk.content and is_thinking:
print("\n\nFinal Response:")
is_thinking = False
if chunk.content and not is_thinking:
print(chunk.content, end="", flush=True)
print("\nCitations:", response.citations)
Synchronous (wait for the end)
response = chat.sample()
print(response.content)
print(response.citations)
print(response.usage)
print(response.server_side_tool_usage)
Responses API (curl)
curl https://api.x.ai/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $XAI_API_KEY" \
-d '{
"model": "grok-4.6",
"input": [{"role": "user", "content": "what is the latest update from xAI?"}],
"tools": [{"type": "web_search"}, {"type": "x_search"}]
}'
With the SDK, set store_messages=True on chat.create when you want a Responses-backed conversation you can continue with previous_response_id.
Opt in to tool outputs
By default, server-side tool outputs are omitted (they can be large). Pass include to receive them:
| Tool (xAI SDK) | include value |
|---|---|
web_search |
web_search_call_output |
x_search |
x_search_call_output |
code_execution |
code_execution_call_output |
collections_search |
collections_search_call_output |
attachment_search |
attachment_search_call_output |
mcp |
mcp_call_output |
Responses API names differ for some tools — for example collections search is file_search with include value file_search_call.results, and code execution is code_interpreter with code_interpreter_call.outputs. MCP outputs are always returned on Responses.
chat = client.chat.create(
model="grok-4.6",
tools=[code_execution()],
include=["code_execution_call_output"],
)
Pitfalls
- Reading only
chunk.contentand ignoringchunk.tool_calls— you miss the live tool trail. - Expecting tool outputs without
include— invocations show up; outputs stay internal unless you opt in. - Using Vercel AI SDK for every advanced pattern — some mixed client/server flows still need the xAI or OpenAI SDK (Mix client-side and server-side tools).