OpenAI Agents SDK Integration
Managed session storage and memory for the OpenAI Agents SDK
DialogueDB is the session backend for OpenAI Agents SDK apps in production. One integration replaces the storage layer, memory service, user isolation logic, and vector search you would otherwise assemble yourself.
OpenAI Agents SDK
DialogueDB
Messages
persist across deploys
Memory
carries between sessions
Namespaces
isolate every user
Search
by meaning
Where MemorySession stops
MemorySession works until
the first restart
The default Session backend keeps the transcript inside the process that created it.
Here is exactly where that design starts pushing back.
- In-process memory, gone when the process exits
- One session ID per conversation, no user model
- Message history only, no memory abstraction
- Retrieval is by ID, no semantic query
- Serverless and multi-instance deploys each get their own copy, never shared
- No namespace or tenant model to isolate one user from another
- Nothing to carry facts about a user across sessions
- Recalling "what did we discuss about X" needs a separate search stack
What replaces it, and what it adds
DialogueDB is the session backend when MemorySession runs out
And it delivers three things MemorySession was never trying to do.
Session storage that survives production
A managed database backing every run, not an in-process array. Every message survives redeploys, cold starts, and multi-instance workers.
Namespaces for multi-user agent runs
Pass a namespace on every save and every read. No cross-user leakage, no WHERE clauses in your agent code.
Memory that carries across sessions and handoffs
Structured Memory objects live independently of message history. Agents in the same namespace share the same memory during handoffs.
Semantic search over every past run
Query past messages, memories, and tool calls by meaning. No vector database to run, no embeddings pipeline to build.
The integration pattern
Five steps around the run. No adapter, no protocol implementation.
Load history, optionally search memory, run the agent as normal, save the result. A few calls around run(), and nothing about your agent code has to change.
// 1. Load past messages, rebuild the run items
const dialogue = await db.getOrCreateDialogue({ id, namespace })
await dialogue.loadMessages({ order: "asc" })
const history = fromStoredMessages(dialogue.messages)
// 2. Optionally recall relevant memory
const { results } = await db.searchMemories(userInput, { namespace, limit: 3 })
const memories = results.map((r) => String(r.item.value))
// 3. Inject into instructions
const agent = buildAgent(memories)
// 4. Run the agent, seeded with that history
const result = await run(agent, [
...history,
{ type: "message", role: "user", content: userInput },
])
// 5. Persist what this turn added
await dialogue.saveMessages(
toStoredMessages(result.history.slice(history.length))
)DialogueDB does not implement OpenAI's Session protocol as a drop-in class. The pattern above is the whole integration.
What this unlocks in your agent app
Six use cases the integration makes shorter to build.
Support agents that carry ticket history
Every past conversation about a customer is a load call away. The agent picks up mid-thread without you re-hydrating context.
db.getOrCreateDialogue()Onboarding assistants that build a user profile
As the assistant learns preferences and answers, save them as Memory objects. The next session starts with a real profile, not a blank slate.
db.createMemory()Multi-agent teams with clean handoffs
Two or more agents pointing at the same namespace share the same message history and memory. The handoff carries context by default.
namespace: sharedLong-running research agents
Agents that spend hours or days on a task can crash, redeploy, and pick up exactly where they stopped. No lost work.
dialogue.messagesPersonal assistants with real memory
Recall what the user said last week or last month by meaning, not by keyword. Answer as if the assistant had been listening the whole time.
db.searchMessages()Multi-tenant SaaS with agent isolation
One codebase, many customers, each with their own namespace. No cross-tenant leakage, no WHERE clauses in agent code.
namespace: userIdInstall in 3 steps
From npm install to the first persisted run, in under five minutes.
Install the client
npm install dialogue-dbSet the API key
DIALOGUE_DB_API_KEY=...Save after the run
// result, history, dialogue, and your
// toStoredMessages mapper from the
// pattern above
const added = result.history
.slice(history.length)
await dialogue.saveMessages(
toStoredMessages(added)
)No credit card. Free tier to start. Starter is $29/month when usage grows.
The reference example
A TypeScript sample repo that persists an agent conversation to DialogueDB and reloads it on the next turn, with tool calls intact. Clone it, plug in your API key, and see it work locally.
What turn() does, in the order it runs
Loads the conversation from scratch
db.getOrCreateDialogue and loadMessages fetch every prior turn back out of DialogueDB. A fresh process after a redeploy or a cold start reads the same history.
Recalls memory for this user
db.searchMemories returns an envelope; the values in results[].item.value go into the agent this turn.
Runs the agent, seeded with that history
run() is handed the rebuilt items plus the new user input, so the agent picks up exactly where it left off.
Persists only what this turn added
saveMessages writes the items result.history gained this turn onto the same dialogue, tool calls and tool results included.
import { run } from "@openai/agents"
import { DialogueDB } from "dialogue-db"
import { buildAgent } from "./agent"
// agent.ts builds the agent with model: "gpt-4o" and two tools
import { fromStoredMessages, toStoredMessages } from "./persist"
const db = new DialogueDB({ apiKey: process.env.DIALOGUE_DB_API_KEY! })
const namespace = "user_123" // namespace is the user id
async function turn(id: string, userInput: string) {
// 1. Load prior history and rebuild the run items
const dialogue = await db.getOrCreateDialogue({ id, namespace })
await dialogue.loadMessages({ order: "asc" })
const history = fromStoredMessages(dialogue.messages)
// 2. Recall memory the caller chose to store
const { results } = await db.searchMemories(userInput, { namespace, limit: 3 })
const recalled = results.map((r) => String(r.item.value))
// 3-4. Run the agent, seeded with that history
const result = await run(buildAgent(recalled), [
...history,
{ type: "message", role: "user", content: userInput },
])
// 5. Persist only what this turn added
await dialogue.saveMessages(
toStoredMessages(result.history.slice(history.length)),
)
return result.finalOutput
}import { protocol, type AgentInputItem } from "@openai/agents"
export const toStoredMessages = (items: AgentInputItem[]) =>
items.map((item) => ({
role: "role" in item ? item.role : "assistant", // storage label only; replay never reads it
content: item, // stored verbatim, so tool calls survive
}))
export const fromStoredMessages = (rows: readonly { content: unknown }[]) =>
rows.map((row) => protocol.ModelItem.parse(row.content))Uses the OpenAI Agents SDK. Loads prior history, seeds the run with it, and persists the items the run added, with tool calls preserved.
Where DialogueDB fits
Session and memory options for OpenAI Agents SDK apps, side by side.
| MemorySession SDK default | Persistent sessions OpenAIConversationsSession, or bring your own | Standalone memory Mem0, Zep | DialogueDB | |
|---|---|---|---|---|
| Persists messages in production | No, in-process only | Yes | Facts only | Yes, every message |
| Multi-user isolation | By session ID only | By session ID | By user ID | Namespaces, first-class |
| Long-term memory across sessions | No | No | Yes | Yes, Memory objects |
| Semantic search over past runs | No | Build it yourself | Facts only | Every message and memory |
| Same store for messages + memory | N/A | Messages only | Two services to run | Yes, one API |
If you know the OpenAI Agents SDK, you already know DialogueDB
The concepts map one-to-one to what the Agents SDK already exposes.
| OpenAI Agents SDK | DialogueDB |
|---|---|
Session items / RunResult items | dialogue |
| Message item | message |
| Agent user (from your auth) | namespace |
| Tool call | message with tool metadata |
| Handoff between agents | shared namespace |
| User context to remember | memory |
DialogueDB does not ship as a drop-in Session class. The pattern is dialogue.saveMessages() after each run(), then the mapped items back in on the next run.
What DialogueDB sees
Two independent calls, two different payloads
Model provider calls run directly from your server to whichever LLM you have configured. DialogueDB sits alongside that request path, not inside it. Only what you explicitly hand it ever reaches it.
Fires from inside run(). Goes straight to OpenAI, Anthropic, xAI, or whatever provider your agent uses.
What the model provider gets
- Your model provider API key
- System prompt and tool definitions
- Full conversation input for this turn
Fires after run() resolves. Sends only what you explicitly pass to the SDK.
What DialogueDB gets
- Message content, role, and tool metadata
- Dialogue ID and the namespace scoping this user
- Memory values and labels (when you call createMemory)
Frequently asked questions
One API for messages, memory, and search
Add it to your OpenAI Agents SDK app in minutes.