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.

Your agent app

OpenAI Agents SDK

run()
Agent
Tools
Handoffs
a few lines around run()
Session storage layer

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.

MemorySession's design
  • 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
Where it hits the wall
  • 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.

The patternagent-run.ts
// 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: shared

Long-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.messages

Personal 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: userId

Install in 3 steps

From npm install to the first persisted run, in under five minutes.

1

Install the client

npm install dialogue-db
2

Set the API key

DIALOGUE_DB_API_KEY=...
3

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)
)
Get Your Free API Key

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

1

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.

2

Recalls memory for this user

db.searchMemories returns an envelope; the values in results[].item.value go into the agent this turn.

3-4

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.

5

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.

Reference codesrc/index.ts
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
}
The mapper, both directionssrc/persist.ts
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 productionNo, in-process onlyYesFacts onlyYes, every message
Multi-user isolationBy session ID onlyBy session IDBy user IDNamespaces, first-class
Long-term memory across sessionsNoNoYesYes, Memory objects
Semantic search over past runsNoBuild it yourselfFacts onlyEvery message and memory
Same store for messages + memoryN/AMessages onlyTwo services to runYes, 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 SDKDialogueDB
Session items / RunResult itemsdialogue
Message itemmessage
Agent user (from your auth)namespace
Tool callmessage with tool metadata
Handoff between agentsshared namespace
User context to remembermemory

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.

The model callrun() → LLM

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
DialogueDB never sees any of this
The save callsaveMessages → DialogueDB

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)
Never: API keys, user auth tokens, model prompts, unrelated app data

Frequently asked questions

One API for messages, memory, and search

Add it to your OpenAI Agents SDK app in minutes.