Sessions: memory across runs with SQLiteSession
A session is a store that keeps a conversation's turns so a later run sees the earlier ones without you resending them.
Last updated: 28 Sep, 2026 · openai-agents 0.22.3
Each call to Runner.run_sync is one run. On its own a run starts blank. A session records each run's input and output under one id, then feeds that history back in on the next run, so the agent remembers the conversation.
Creating a SQLiteSession
from agents.memory import SQLiteSession
session = SQLiteSession("customer-1") # one id, one conversation
# pass the same object to each run to share its historyA model that reads the whole history
To show that the second run sees the first, the stand-in model scans every user message in its input for a name, then answers from it.
def _all_user_text(input):
if isinstance(input, str):
return input
parts = []
for it in input:
d = it if isinstance(it, dict) else it.__dict__
if d.get("role") == "user":
c = d.get("content")
parts.append(c if isinstance(c, str) else "")
return " ".join(parts)Running two turns with the same session
Both runs pass session=session. The first states a name; the second asks for it and gets it back, because the session replayed turn one into turn two.
agent = Agent(name="Shop", instructions="Remember the customer.", model=MemoModel())
session = SQLiteSession("customer-1")
print("Turn 1:", Runner.run_sync(agent, "Hi, I'm Sam.", session=session).final_output)
print("Turn 2:", Runner.run_sync(agent, "What is my name?", session=session).final_output)Two turns that share one memory
The whole program in one file. The name is stated once and recalled on the next run.
from agents import Agent, Runner, set_tracing_disabled
from agents.memory import SQLiteSession
from agents.models.interface import Model
from agents.items import ModelResponse
from agents.usage import Usage
from openai.types.responses import ResponseOutputMessage, ResponseOutputText
set_tracing_disabled(True)
def _msg(t):
return ResponseOutputMessage(id="m", role="assistant", type="message", status="completed",
content=[ResponseOutputText(text=t, type="output_text", annotations=[])])
def _all_user_text(input):
if isinstance(input, str):
return input
parts = []
for it in input:
d = it if isinstance(it, dict) else it.__dict__
if d.get("role") == "user":
c = d.get("content")
parts.append(c if isinstance(c, str) else " ".join(
(p if isinstance(p, dict) else p.__dict__).get("text", "") for p in c))
return " ".join(parts)
class MemoModel(Model):
async def get_response(self, system_instructions, input, model_settings, tools,
output_schema, handoffs, tracing, **k):
history = _all_user_text(input)
name = None
if "i'm " in history.lower():
name = history.lower().split("i'm ")[1].split()[0].strip(".,").capitalize()
if "name" in history.lower().split(".")[-1]:
reply = f"Your name is {name}." if name else "I don't know your name yet."
else:
reply = f"Nice to meet you, {name}." if name else "Hello."
return ModelResponse(output=[_msg(reply)], usage=Usage(), response_id=None)
async def stream_response(self, *a, **k):
raise NotImplementedError
agent = Agent(name="Shop", instructions="Remember the customer.", model=MemoModel())
session = SQLiteSession("customer-1")
print("Turn 1:", Runner.run_sync(agent, "Hi, I'm Sam.", session=session).final_output)
print("Turn 2:", Runner.run_sync(agent, "What is my name?", session=session).final_output)How the second turn knew the name
- Turn one stores its input and output in the session under
customer-1. - Turn two begins by loading that history, so the model's input holds both user messages, not only the new one.
- The model finds the name in the earlier message and answers, which is why memory survives across the two separate runs.
With a session vs without a session
| Run call | What the model sees | Result |
|---|---|---|
No session= | Only the current message | The name from an earlier run is gone |
Same session= | Every earlier turn plus the current one | The name is remembered |
When to keep a session
- A support chat where the customer sends several messages over time.
- Any agent that must recall a name, an order, or a choice made earlier in the conversation.
- Keeping separate customers apart by giving each one its own session id.
Related
- Previous: Output guardrails on the final answer
- Next: Streaming a run with run_streamed
- Reference: Sessions
- Run turn two without
session=sessionand see the name forgotten. - Change the id on turn two to
"customer-2"and watch the history reset. - Add a third turn that asks the name again and confirm it still answers.
Every expert started right here.