Sessions and state
In Genkit, agent state includes message history, custom application state, artifacts, session identity, and snapshot lineage. Choose the state strategy before building the client because it determines who owns continuity between turns.
State strategies
Section titled “State strategies”Genkit agents can keep conversation continuity in one of two ways:
Server-managed state means the agent has a store (for example FileSessionStore or InMemorySessionStore). The server persists messages, custom state, and artifacts between turns. Clients continue the chat by sending a session_id (loads latest state) or snapshot_id (loads exact state). Use this for long-running chat applications, multi-turn generators, background detached tasks, or any workflow where client payload size should remain small.
Client-managed state means the agent has no store. The server returns the full session at the end of each turn, and the client must echo that state back on the next turn using chat(messages=..., state=..., artifacts=...). Use this when your client app or another system already owns persistence, when you need stateless server deployments, or when you want to encrypt conversation data outside Genkit.
In both modes, AgentChat tracks continuity for you. Server-managed chats carry forward a session_id / snapshot_id. Client-managed chats carry forward messages, custom state, and artifacts.
Understand session state
Section titled “Understand session state”Session state has three main fields:
customis your application-specific data. Use it for lightweight status variables, preferences, selected options, or list state that tools or the model needs across turns. Keep this payload small as it is serialized in every snapshot and client payload.messagesis the accumulated message history. The runtime appends user prompts and model completions automatically.artifactsis a list of structured, versioned outputs generated by the agent or tools. Use artifacts for larger outputs that the user might download or inspect independently.
Custom state vs. artifacts
Section titled “Custom state vs. artifacts”- Use custom state for lightweight control parameters and variables that direct the agent’s next model call or UI rendering. Keep it small.
- Use artifacts for files, patches, or comprehensive reports that the agent produces. Do not store large documents directly in custom state.
Modify custom state
Section titled “Modify custom state”Tools and custom agents can update custom state using session.update_custom(). With a state_schema, chat.state, response.state, and streamed chunk.custom come back as that Pydantic model. Genkit automatically diffs the result and streams RFC 6902 JSON Patches to the client mid-stream.
from pydantic import BaseModel
class TaskItem(BaseModel): id: int title: str done: bool = False
class TaskState(BaseModel): tasks: list[TaskItem] = [] next_id: int = 1
sess = ai.current_session()assert sess is not None
def mutate(custom: TaskState | None) -> TaskState: state = custom or TaskState() next_id = state.next_id new_task = TaskItem(id=next_id, title='Buy milk') return TaskState(tasks=[*state.tasks, new_task], next_id=next_id + 1)
await sess.update_custom(mutate)Keep custom state serializable, and provide the matching state_schema when defining your agent so the typed state is validated at load time.
Server-managed stores
Section titled “Server-managed stores”Add a store when defining your agent to enable server-managed persistence:
from genkit.agent import FileSessionStore
store = FileSessionStore('.sessions')
weather_agent = ai.define_agent( name='weatherAgent', model='googleai/gemini-flash-latest', system='You are a helpful weather assistant.', store=store,)On every successful turn, the store saves a completed snapshot capturing the conversation’s exact state. If a turn fails, the resume handle stays on the last successful snapshot so the next turn does not continue from a broken partial state.
For store choices, see Session stores.
Snapshots
Section titled “Snapshots”Read a snapshot directly by ID or fetch the latest snapshot in a session:
snapshot = await weather_agent.get_snapshot(snapshot_id='snapshot-123')latest = await weather_agent.get_snapshot(session_id='session-123')Snapshot lifecycle
Section titled “Snapshot lifecycle”| Status | Meaning |
|---|---|
pending | A detached background invocation is still running. |
completed | The snapshot captures a settled, resumable state. |
failed | The invocation failed. Error details are stored on the snapshot. |
aborted | The detached invocation was canceled. |
expired | A pending snapshot heartbeat went stale, so the background worker is presumed dead. |
Only completed snapshots are valid resume points. Other statuses are useful for UI progress indicators and background tracking.
Resume by session or snapshot
Section titled “Resume by session or snapshot”To continue a server-managed conversation from the latest leaf, pass the session_id:
chat = weather_agent.chat(session_id='user-session-123')await chat.send('What is the weather in Tokyo?')To branch from a specific historical point, pass the snapshot_id (or use load_chat(snapshot_id=...)):
branch = await weather_agent.load_chat(snapshot_id='snapshot-abc-456')await branch.send('Assume the user changed their mind.')Client-managed state
Section titled “Client-managed state”If your agent does not use a server store, capture messages, custom state, and artifacts yourself, then pass them back:
chat = weather_agent.chat()res = await chat.send('My name is Ada. Remember it.')
messages, state, artifacts = chat.messages, chat.state, chat.artifacts
resumed = weather_agent.chat(messages=messages, state=state, artifacts=artifacts)await resumed.send('What is my name?')Live custom state
Section titled “Live custom state”When custom state changes during a turn, the runtime streams incremental RFC 6902 JSON Patch chunks. AgentChat applies them automatically, yielding the updated state on chunk.custom and chat.state.
turn = task_agent.chat().send_stream('Add buy milk to my list.')
async for chunk in turn.stream: if chunk.custom is not None: update_todo_list_ui(chunk.custom)Artifacts
Section titled “Artifacts”Record independent artifacts from tools or custom agents using the active session:
from genkit import Part, TextPartfrom genkit.agent import Artifact
sess = ai.current_session()assert sess is not None
await sess.add_artifacts([ Artifact( name='report.md', parts=[Part(root=TextPart(text='# Research Report\nThis is the content.'))], )])Artifacts with identical names overwrite earlier ones, while unnamed artifacts are appended to the session.
Client transforms
Section titled “Client transforms”Use state_transform and chunk_transform to redact or reshape what leaves the server before it reaches a client:
from genkit.agent import SessionState
def redact_state(state: SessionState) -> SessionState: # Drop secrets before the client sees them. return state
agent = ai.define_agent( name='supportAgent', model='googleai/gemini-flash-latest', system='Help customers.', state_transform=redact_state,)