OpenAI Agents SDK Memory
The first drop-in Session implementation from any memory vendor: durable server-side conversation history for Runner.run(..., session=...) that survives restarts and follows multi-agent handoffs — plus per-run memory instructions, five agent memory tools, and async helpers.
What the integration provides
| Layer | What it does |
|---|---|
MemorySyncSession | A drop-in implementation of the SDK’s Session protocol: the runner reads history before each run and appends the new items after it — kept durably server-side in conversation history, exactly as the SDK wrote them, shared across handoffs. User messages are also sent to fact extraction, so the durable facts in them become the user’s long-term memories; assistant replies are not stored as memories. |
memory_instructions | Dynamic instructions that inject recalled memory context per run — the SDK’s documented hook for dynamic system prompts. |
| Agent tools | create_memory_tools() — five structured tools (add, search, list, update, delete) the model can call, which never raise. |
| Helpers | get_memory_context, search_memories, save_turn — async, for hand-wired setups. |
| Mem0 | Supermemory | Zep | MemorySync | |
|---|---|---|---|---|
| Session protocol implementation | ✗ docs recipe only | ✗ nothing shipped | ✗ example file only | ✓ the first drop-in session=... |
| Automatic history across handoffs | ✗ manual saves in outer code | ✗ | ✗ manual add_message per turn | ✓ automatic with a correct Session |
| Long-term memory extraction | ✓ (tools — the LLM decides) | ✗ | ✓ (~10s graph delay) | ✓ automatic, server-side |
| Retry-safe transcript writes | — | — | — | ✓ total AND partial batch failures converge |
| Pattern | 2 tools | — | manager class + instructions paste | session + instructions + 5 tools + helpers |
Install
pip install openai-agents-memorysync openai-agents
Set MEMORYSYNC_API_KEY in the environment, or pass api_key explicitly. The package never imports the Agents SDK at runtime (the Session contract is a structural protocol), so it never constrains which SDK version you run — openai-agents is a peer you install alongside it. Python 3.10+. This is a Python surface — for TypeScript agents use the Vercel AI SDK or Mastra integrations.
The drop-in session
from agents import Agent, Runnerfrom openai_agents_memorysync import MemorySyncSessionagent = Agent(name="Assistant",instructions="You are a helpful assistant.",)session = MemorySyncSession("thread-42", # the conversationuser_id="customer-7", # the end user it belongs to — required)# First conversationawait Runner.run(agent, "I'm vegetarian and I fly aisle.", session=session)# Any later run — same session id, any process, any deployresult = await Runner.run(agent, "Book my trip: flight plus a dinner spot.", session=session)# The model saw the full prior history — no manual .to_input_list() plumbing.
Items come back exactly as the SDK wrote them — assistant messages, function calls, tool outputs, reasoning items — because the runner feeds them straight back to the model; the test suite checks this item for item against OpenAI’s own SQLiteSession. Conversation history is not memory: it never shows up in memory search, recall or the memory list. Each session is stored under its own server-side owner, so clear_session() can only ever reach that one conversation, and function-call JSON never reaches the user’s long-term memories. Pass long_term=False to keep a session out of long-term memory.
Multi-agent handoffs
from agents import Agent, Runnerfrom openai_agents_memorysync import MemorySyncSessionspecialist = Agent(name="Specialist",instructions="You handle travel bookings end to end.",)triage = Agent(name="Triage",instructions="Route travel questions to the specialist.",handoffs=[specialist],)session = MemorySyncSession("thread-42", user_id="customer-7")# The handoff happens INSIDE one run — triage and specialist share# this session, and the handoff itself is part of the transcript.result = await Runner.run(triage, "Book my usual trip.", session=session)# A later run — by any agent — gets the full cross-agent history.await Runner.run(specialist, "Add a dinner reservation.", session=session)
The Agents SDK shares one session across every agent in a run — so with a correct Session implementation, cross-handoff memory needs no extra code. No competitor offers this: their patterns save manually after each turn in outer code.
Long-term memory in instructions
from agents import Agent, Runnerfrom openai_agents_memorysync import memory_instructionsagent = Agent(name="Assistant",instructions=memory_instructions("You are a helpful assistant.",user_id="customer-7",),)# Every run now starts with what MemorySync knows about this user:# You are a helpful assistant.## Relevant memories about this user from previous conversations:# - Is vegetarian# - Flies aisle# Multi-user servers resolve identity per request instead:agent = Agent(name="Assistant",instructions=memory_instructions("You are a helpful assistant.",user_id=lambda ctx: ctx.context.user_id, # your context object),)
Recall failing means the run proceeds with the base instructions — reported through onError, never thrown. Modes: "profile" (default — an overview of the user: the newest facts, listed, so it works without any query text), "query" (semantic recall for the text your prompt resolver returns), "full" (both). Pair it with a MemorySyncSession and the user’s messages reach long-term memory automatically. Version note: 1.0.3 made profile mode a listing — 1.0.1 searched with a generic overview prompt, which matched nothing for most users, so the default injected no memory.
Agent memory tools
from agents import Agent, Runnerfrom openai_agents_memorysync import create_memory_toolsagent = Agent(name="Assistant",instructions="Use the memory tools to remember durable facts.",tools=create_memory_tools(user_id="customer-7"),)await Runner.run(agent, "Remember that I prefer aisle seats.")# Untrusted agents: search + list only.create_memory_tools(user_id="customer-7", read_only=True)
| Tool | What it does | Failure behaviour |
|---|---|---|
add_memory | Save one durable fact; duplicate saves answer “already stored”. | Readable error string — never raises. |
search_memory | Semantic search with relevance scores. | Readable error string. |
list_memories | Newest-first listing. | Readable error string. |
update_memory | Change tags/importance. Memory text is immutable. | Readable error string. |
delete_memory | Permanent delete by id, scoped to the configured user. | Readable error string. |
Same five operations, same response strings as the LangChain, AI SDK, CrewAI and Mastra tool sets — an agent moved between frameworks keeps behaving the same way. All tools are async, so they never block the runner’s event loop.
Standalone helpers
For hand-wired setups: the same recall pipeline as memory_instructions and the same long-term persistence as the session, callable directly. save_turn sends the user message to fact extraction; assistant is accepted and not stored as a memory. Mixing styles is safe — every surface sends the same turn seeds, so the same user message sent for the same session through both MemorySyncSession and save_turn is extracted once.
from openai_agents_memorysync import (get_memory_context,save_turn,search_memories,)# 1. Prompt-ready context block ("" for a new user)context = await get_memory_context("what should I cook?", user_id="customer-7")# 2. Scored raw results — distilled facts, not transcript turnshits = await search_memories("dietary preferences", user_id="customer-7")# [{"id": "m_123", "text": "Is vegetarian", "score": 0.62}, ...]# 3. Explicit persistence — RAISES on failure (an explicit call is# owed the truth), unlike the session's degrading long-term plane.await save_turn(user_id="customer-7",user="I'm vegetarian",assistant="Noted!",session_id="thread-42",)
Public API
| Export | Kind | Notes |
|---|---|---|
MemorySyncSession | Session class | session_id + required user_id; long_term, allow_clear, on_error optional. Implements get_items, add_items, pop_item, clear_session. |
memory_instructions | Instructions factory | user_id (string or per-run resolver); mode, k, template, prompt, on_error optional. |
create_memory_tools | Tool factory | Five @function_tools; read_only=True returns search + list only. |
get_memory_context | Async helper | Prompt-ready context block, "" for a new user. |
search_memories | Async helper | Scored {id, text, score} results. |
save_turn | Async helper | Sends the user message for fact extraction, idempotently — raises on failure. |
MemorySyncAPIError | Exception | Carries the HTTP status and server detail. |
Supported versions
| Package | Registry | Requires | Runtime |
|---|---|---|---|
openai-agents-memorysync 1.1.0 | PyPI | openai-agents (installed separately) | Python 3.10+ |
The test suite drives a REAL Runner — including an item-for-item parity oracle against OpenAI’s own SQLiteSession — and CI re-runs it against the latest openai-agents release on every push, so a protocol change upstream fails our pipeline before it can fail your agent.