State is any kind of data that needs to be maintained throughout runs in a session.
A simple yet common use case for Agents is to manage lists, items and other “information” for a user. For example, a shopping list, a todo list, a wishlist, etc.
This can be easily managed using the session_state
. The Agent can access or update the session_state
in tool calls and exposes them to the Model via the system message.
The session state is then persisted in the configured database and made available across runs within that session.
Understanding Agent “Statelessness”: Agents in Agno don’t maintain working state between different sessions or runs, but they do provide state management capabilities:
- The
session_state
parameter on Agent
provides the default state template for new sessions
- The
get_session_state()
method retrieves the session state of a particular session from the database
- Working state is managed per run and persisted to the database per session
- The agent instance (or attributes thereof) itself is not modified during runs
State Management
Agno provides a powerful and elegant state management system. Here’s how it works:
- You can set the Agent’s
session_state
parameter with a dictionary of default state variables.
- You update the
session_state
dictionary in tool calls or other functions.
- You share the current
session_state
with the LLM via the system message by referencing state variables in description
and instructions
.
- You can pass
session_state
to agent.run()
, which takes precedence over the agent’s default state.
- The
session_state
is stored per session in your database and persists across runs within that session.
- When switching sessions via
session_id
in agent.run()
, the appropriate session state is loaded from the database.
Here’s an example of an Agent managing a shopping list:
from agno.agent import Agent
from agno.db.sqlite import SqliteDb
from agno.models.openai import OpenAIChat
# Define a tool that adds an item to the shopping list
def add_item(session_state, item: str) -> str:
"""Add an item to the shopping list."""
session_state["shopping_list"].append(item)
return f"The shopping list is now {session_state['shopping_list']}"
# Create an Agent that maintains state
agent = Agent(
model=OpenAIChat(id="gpt-5-mini"),
# Database to store sessions and their state
db=SqliteDb(db_file="tmp/agents.db"),
# Initialize the session state with an empty shopping list
session_state={"shopping_list": []},
tools=[add_item],
# You can use variables from the session state in the instructions
instructions="Current state (shopping list) is: {shopping_list}",
markdown=True,
)
# Example usage
agent.print_response("Add milk, eggs, and bread to the shopping list", stream=True)
print(f"Final session state: {agent.get_session_state()}")
The session_state
variable is automatically passed to the tool as an
argument. Any updates to it is automatically reflected in the shared state.
Session state is also shared between members of a team when using Team
. See
Teams for more information.
Maintaining state across multiple runs within a session
A big advantage of sessions is the ability to maintain state across multiple runs within the same session. For example, let’s say the agent is helping a user keep track of their shopping list.
You have to configure your storage via the db
parameter for state to be persisted across runs.
from textwrap import dedent
from agno.agent import Agent
from agno.db.sqlite import SqliteDb
from agno.models.openai import OpenAIChat
# Define tools to manage our shopping list
def add_item(session_state, item: str) -> str:
"""Add an item to the shopping list and return confirmation."""
# Add the item if it's not already in the list
if item.lower() not in [i.lower() for i in session_state["shopping_list"]]:
session_state["shopping_list"].append(item) # type: ignore
return f"Added '{item}' to the shopping list"
else:
return f"'{item}' is already in the shopping list"
def remove_item(session_state, item: str) -> str:
"""Remove an item from the shopping list by name."""
# Case-insensitive search
for i, list_item in enumerate(session_state["shopping_list"]):
if list_item.lower() == item.lower():
session_state["shopping_list"].pop(i)
return f"Removed '{list_item}' from the shopping list"
return f"'{item}' was not found in the shopping list"
def list_items(session_state) -> str:
"""List all items in the shopping list."""
shopping_list = session_state["shopping_list"]
if not shopping_list:
return "The shopping list is empty."
items_text = "\n".join([f"- {item}" for item in shopping_list])
return f"Current shopping list:\n{items_text}"
# Create a Shopping List Manager Agent that maintains state
agent = Agent(
model=OpenAIChat(id="gpt-5-mini"),
# Initialize the session state with an empty shopping list (default session state for all sessions)
session_state={"shopping_list": []},
db=SqliteDb(db_file="tmp/example.db"),
tools=[add_item, remove_item, list_items],
# You can use variables from the session state in the instructions
instructions=dedent("""\
Your job is to manage a shopping list.
The shopping list starts empty. You can add items, remove items by name, and list all items.
Current shopping list: {shopping_list}
"""),
markdown=True,
)
# Example usage
agent.print_response("Add milk, eggs, and bread to the shopping list", stream=True)
print(f"Session state: {agent.get_session_state()}")
agent.print_response("I got bread", stream=True)
print(f"Session state: {agent.get_session_state()}")
agent.print_response("I need apples and oranges", stream=True)
print(f"Session state: {agent.get_session_state()}")
agent.print_response("whats on my list?", stream=True)
print(f"Session state: {agent.get_session_state()}")
agent.print_response(
"Clear everything from my list and start over with just bananas and yogurt",
stream=True,
)
print(f"Session state: {agent.get_session_state()}")
Agentic Session State
Agno provides a way to allow the agent to automatically update the session state.
Simply set the enable_agentic_state
parameter to True
.
from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.db.sqlite import SqliteDb
agent = Agent(
db=SqliteDb(db_file="tmp/agents.db"),
model=OpenAIChat(id="gpt-5-mini"),
session_state={"shopping_list": []},
add_session_state_to_context=True, # Required so the agent is aware of the session state
enable_agentic_state=True, # Adds a tool to manage the session state
)
agent.print_response("Add milk, eggs, and bread to the shopping list", stream=True)
print(f"Session state: {agent.get_session_state()}")
Don’t forget to set add_session_state_to_context=True
to make the session
state available to the agent’s context.
Using state in instructions
You can reference variables from the session state in your instructions.
Don’t use the f-string syntax in the instructions. Directly use the {key}
syntax, Agno substitutes the values for you.
from textwrap import dedent
from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.db.sqlite import SqliteDb
agent = Agent(
db=SqliteDb(db_file="tmp/agents.db"),
model=OpenAIChat(id="gpt-5-mini"),
# Initialize the session state with a variable
session_state={"user_name": "John"},
# You can use variables from the session state in the instructions
instructions="Users name is {user_name}",
markdown=True,
)
agent.print_response("What is my name?", stream=True)
Changing state on run
When you pass session_id
to the agent on agent.run()
, it will switch to the session with the given session_id
and load any state that was set on that session.
This is useful when you want to continue a session for a specific user.
from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.db.sqlite import SqliteDb
agent = Agent(
db=SqliteDb(db_file="tmp/agents.db"),
model=OpenAIChat(id="gpt-5-mini"),
instructions="Users name is {user_name} and age is {age}",
)
# Sets the session state for the session with the id "user_1_session_1"
agent.print_response("What is my name?", session_id="user_1_session_1", user_id="user_1", session_state={"user_name": "John", "age": 30})
# Will load the session state from the session with the id "user_1_session_1"
agent.print_response("How old am I?", session_id="user_1_session_1", user_id="user_1")
# Sets the session state for the session with the id "user_2_session_1"
agent.print_response("What is my name?", session_id="user_2_session_1", user_id="user_2", session_state={"user_name": "Jane", "age": 25})
# Will load the session state from the session with the id "user_2_session_1"
agent.print_response("How old am I?", session_id="user_2_session_1", user_id="user_2")
Overwriting the state in the db
By default, if you pass session_state
to the run methods, this new state will be merged with the session_state
in the db.
You can change that behavior if you want to overwrite the session_state
in the db:
overwriting_session_state_in_db.py
from agno.agent import Agent
from agno.db.sqlite import SqliteDb
from agno.models.openai import OpenAIChat
# Create an Agent that maintains state
agent = Agent(
model=OpenAIChat(id="gpt-4o-mini"),
db=SqliteDb(db_file="tmp/agents.db"),
markdown=True,
# Set the default session_state. The values set here won't be overwritten.
session_state={},
# Adding the session_state to context for the agent to easily access it
add_session_state_to_context=True,
# Allow overwriting the stored session state with the session state provided in the run
overwrite_db_session_state=True,
)
# Let's run the agent providing a session_state. This session_state will be stored in the database.
agent.print_response(
"Can you tell me what's in your session_state?",
session_state={"shopping_list": ["Potatoes"]},
stream=True,
)
print(f"Stored session state: {agent.get_session_state()}")
# Now if we pass a new session_state, it will overwrite the stored session_state.
agent.print_response(
"Can you tell me what is in your session_state?",
session_state={"secret_number": 43},
stream=True,
)
print(f"Stored session state: {agent.get_session_state()}")
Developer Resources