
Continue agentic tool chats across turns
Continue agentic tool chats across turns
When Grok runs web search, X search, or other server-side tools, follow-up prompts need the prior reasoning, tool calls, and tool results — plain chat history is not enough. Official Advanced Usage docs give two paths: store the agentic state on xAI (store_messages=True + previous_response_id), or keep encrypted agentic content on the client (use_encrypted_content=True). Plain Responses chaining without tools is covered in Chain Responses with previous_response_id. Mixed client/server tools: Mix client-side and server-side tools on Grok.
Advanced agentic patterns are not supported in the Vercel AI SDK yet; use the xAI SDK or OpenAI SDK.
Store on the server
- First turn:
store_messages=Trueso the service keeps reasoning, server-side tool calls, and tool results. - Later turn:
previous_response_id=response.idfrom the turn you want to resume.
The follow-up may change tools, model, or other settings — the agentic state still rehydrates from the stored response.
import os
from xai_sdk import Client
from xai_sdk.chat import user
from xai_sdk.tools import 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()],
store_messages=True,
)
chat.append(user("What is xAI?"))
for response, chunk in chat.stream():
if chunk.content:
print(chunk.content, end="", flush=True)
print("\nUsage:", response.server_side_tool_usage)
chat = client.chat.create(
model="grok-4.6",
tools=[web_search(), x_search()],
previous_response_id=response.id,
)
chat.append(user("What is its latest mission?"))
for response, chunk in chat.stream():
if chunk.content:
print(chunk.content, end="", flush=True)
print("\nUsage:", response.server_side_tool_usage)
Stored responses follow the same retention window as other Responses API history (see chain guide). Past that window, use the encrypted path below.
Keep encrypted state on the client (ZDR-friendly)
- First turn:
use_encrypted_content=Trueso the reply includes encrypted reasoning and encrypted tool output with the final content. - Before the next sample/stream:
chat.append(response), then append the new user turn.
chat = client.chat.create(
model="grok-4.6",
tools=[web_search(), x_search()],
use_encrypted_content=True,
)
chat.append(user("What is xAI?"))
for response, chunk in chat.stream():
if chunk.content:
print(chunk.content, end="", flush=True)
chat.append(response)
chat.append(user("What is its latest mission?"))
for response, chunk in chat.stream():
if chunk.content:
print(chunk.content, end="", flush=True)
Treat the encrypted blobs as opaque. For Responses API include: ["reasoning.encrypted_content"] without tools, see Use encrypted reasoning content.
Pitfalls
- Resending only user/assistant text drops tool transcripts — follow-ups then “forget” what search already found.
previous_response_idneeds a stored prior response; ZDR /store: falseteams should useuse_encrypted_contentinstead.- Client-side tool pauses reset
max_turnson the next request — see the mix-tools how-to.