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 turn after it — stored durably server-side, byte-for-byte, shared across handoffs. User/assistant text also lands in long-term memory automatically. |
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 | ✓ free with a correct Session |
| Long-term memory extraction | ✓ (tools — the LLM decides) | ✗ | ✓ (~10s graph delay) | ✓ automatic, deterministic |
| 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 are stored and returned byte-for-byte — assistant messages, function calls, tool outputs, reasoning items — because the runner feeds them straight back to the model. Each session lives in its own server-side namespace, so clear_session() can only ever reach that one conversation, and function-call JSON never pollutes the user’s long-term memories.
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:# - human: I'm vegetarian and I fly 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), "query" (recall for text your prompt resolver returns), "full" (both). Pair it with a MemorySyncSession and the exchange persists automatically; the two surfaces share idempotency seeds, so nothing double-stores.
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 and the same idempotent persistence as the session, callable directly. Mixing styles is safe — every surface writes the same idempotency seeds.
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 resultshits = await search_memories("dietary preferences", user_id="customer-7")# [{"id": "m_123", "text": "human: I'm 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 | Explicit idempotent persist — raises on failure. |
MemorySyncAPIError | Exception | Carries the HTTP status and server detail. |
Supported versions
| Package | Registry | Requires | Runtime |
|---|---|---|---|
openai-agents-memorysync 1.0.0 | PyPI | openai-agents installed alongside (any current 0.x — no version pin by design) | 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.