How to Implement Stateful Multi-Turn Conversations with the Gemini Interactions API
Set store: true on your first request to persist the interaction, then pass the returned id as previous_interaction_id in subsequent calls to maintain conversation context across turns.
The Gemini Interactions API provides a server-managed conversation layer that automatically retains chat history, eliminating the need to manually resend the full message transcript with each request. According to the google/skills repository, this stateful approach uses the unified Google Gen AI SDK to handle persistent multi-turn dialogues through simple identifier linking.
Prerequisites and SDK Setup
You must use the unified Google Gen AI SDK to access the Interactions API. Legacy packages are explicitly not supported.
- Python:
google-genai >= 2.0.0 - TypeScript/JavaScript:
@google/genai >= 2.0.0
Legacy packages such as google-cloud-aiplatform or google-generativeai will not work for Interactions API calls. As documented in skills/cloud/gemini-interactions-api/SKILL.md, all client-side code should initialize using the new unified SDK.
Core Concepts of Stateful Conversation
State Persistence with store and previous_interaction_id
When you set store: true on a request, the service persists the interaction in the Gemini Enterprise Agent Platform and returns an id. To continue the conversation, include this id as previous_interaction_id (or previousInteractionId in TypeScript) in the next request.
This creates a chain of linked interactions where the server automatically retrieves prior user utterances, tool calls, and system messages without requiring you to resend the full transcript.
Turn-Scoped Parameters
Critical parameters such as tools, system_instruction, and generation_config are not retained between turns. You must supply these on every request to ensure the model has the correct context and capabilities for each specific turn.
Implementing Multi-Turn Conversations in Python
The following example demonstrates a two-turn conversation where the first interaction is stored and the second references it via previous_interaction_id.
from google import genai
# Initialise the unified SDK (environment variables already set)
client = genai.Client()
# Turn 1 – store the conversation
turn1 = client.interactions.create(
model="gemini-3-flash-preview",
input="Hi! My name is Alice. I'm building an AI agent.",
store=True,
)
print("Turn 1:", turn1.steps[-1].content[0].text)
# Turn 2 – reference the stored state
turn2 = client.interactions.create(
model="gemini-3-flash-preview",
input="What did I tell you about myself?",
previous_interaction_id=turn1.id,
)
print("Turn 2:", turn2.steps[-1].content[0].text)
Source: skills/cloud/gemini-interactions-api/SKILL.md
Working with Streaming Responses
Add stream: true to receive incremental response chunks, which is ideal for real-time UI updates. The endpoint returns an iterable (Python) or async generator (TypeScript) that yields chunks as they are generated.
import { GoogleGenAI } from "@google/genai";
const ai = new GoogleGenAI();
const stream = await ai.interactions.create({
model: "gemini-3-flash-preview",
input: "Write a short poem about debugging.",
stream: true,
});
for await (const chunk of stream) {
if (chunk.steps) {
const step = chunk.steps[chunk.steps.length - 1];
if (step.content && step.content[0].text) {
process.stdout.write(step.content[0].text);
}
}
}
console.log(); // finish line
Advanced Patterns
Structured JSON Output with Pydantic
The API supports typed JSON responses using Pydantic models in Python. Specify the response_format parameter with your model class.
from google import genai
from pydantic import BaseModel, Field
class Book(BaseModel):
title: str = Field(description="Book title")
author: str = Field(description="Book author")
year_published: int
client = genai.Client()
interaction = client.interactions.create(
model="gemini-3-flash-preview",
input="Recommend a sci-fi classic.",
response_format=Book,
)
print(interaction.steps[-1].content[0].text) # → valid JSON matching Book schema
Function Calling with State Preservation
When the model requests a tool call, you execute the function and send the result back in a follow-up turn, preserving continuity via previous_interaction_id.
def get_stock_price(ticker: str) -> float:
return {"GOOG": 175.5}.get(ticker.upper(), 100.0)
client = genai.Client()
# Turn 1 – ask the model a question and provide the tool
first = client.interactions.create(
model="gemini-3-flash-preview",
input="What is the price of GOOG?",
tools=[get_stock_price],
)
# Detect tool request
if first.steps[-1].tool_calls:
call = first.steps[-1].tool_calls[0]
price = get_stock_price(call.args["ticker"])
# Turn 2 – send the result back, referencing the previous interaction
second = client.interactions.create(
model="gemini-3-flash-preview",
input=f"The price of {call.args['ticker']} is ${price}.",
previous_interaction_id=first.id,
)
print(second.steps[-1].content[0].text)
Raw REST API Implementation
If you cannot use the SDK, the Interactions API accepts standard HTTP POST requests to the v1beta1 endpoint. The payload includes agent, input, store, and previous_interaction_id fields.
PROJECT_ID="my-project"
AGENT_ID="projects/${PROJECT_ID}/locations/global/agents/my-agent"
ACCESS_TOKEN=$(gcloud auth print-access-token)
# First turn – store interaction
curl -X POST "https://aiplatform.googleapis.com/v1beta1/projects/${PROJECT_ID}/locations/global/interactions" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"agent": "'"${AGENT_ID}"'",
"input": [{"role":"user","content":[{"type":"text","text":"Hello, I'm Sam."}]}],
"store": true
}' | jq .id > prev_id.txt
# Second turn – continue conversation
PREV_ID=$(cat prev_id.txt)
curl -X POST "https://aiplatform.googleapis.com/v1beta1/projects/${PROJECT_ID}/locations/global/interactions" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"agent": "'"${AGENT_ID}"'",
"input": [{"role":"user","content":[{"type":"text","text":"What did I just say?"}]}],
"previous_interaction_id": "'"${PREV_ID}"'"
}'
Summary
- Use the unified SDK (
google-genaior@google/genai>= 2.0.0) as legacy packages are not supported for the Interactions API. - Enable state persistence by setting
store: trueon the initial request to receive a persistent interactionid. - Link subsequent turns by passing the previous interaction's
idasprevious_interaction_idin following requests. - Resend turn-scoped parameters (
tools,system_instruction,generation_config) on every request since they are not retained server-side. - Support streaming and structured output by setting
stream: trueorresponse_formatas needed.
Frequently Asked Questions
What happens if I don't set store: true on the first turn?
The interaction will not be persisted to the Gemini Enterprise Agent Platform. Subsequent requests will not be able to reference this turn via previous_interaction_id, effectively treating each request as a stateless, independent call with no memory of prior context.
Do I need to resend system instructions and tools on every turn?
Yes. Parameters such as system_instruction, tools, and generation_config are turn-scoped and are not retained between interactions. You must include them in every request to ensure the model behaves consistently across the conversation chain.
Can I use the legacy Google AI Python SDK with the Interactions API?
No. According to skills/cloud/gemini-interactions-api/SKILL.md, packages like google-generativeai and google-cloud-aiplatform are not supported for Interactions API calls. You must migrate to the unified google-genai SDK (Python) or @google/genai (TypeScript) version 2.0.0 or higher.
How does the Interactions API handle function calling across multiple turns?
When the model generates a tool_calls request in one turn, you execute the function locally and send the result back in a subsequent turn using previous_interaction_id to link to the prior interaction. This preserves the conversation continuity while allowing the model to incorporate the function result into its final response.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →