0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
27 small wins to finish your pathNext lesson →

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

python
from agents.memory import SQLiteSession

session = SQLiteSession("customer-1")   # one id, one conversation
# pass the same object to each run to share its history

A 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.

python
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.

python
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.

Example
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 callWhat the model seesResult
No session=Only the current messageThe name from an earlier run is gone
Same session=Every earlier turn plus the current oneThe 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.
Watch out. A different session id is a different conversation, so a typo in the id starts a blank history. Reuse the exact same id, and the same session object across the run calls, to keep one thread.
Try it yourself
  • Run turn two without session=session and 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.