LangChain Integration

Drop-in chat history and memory for LangChain

A managed chat history for LangChain chains and agents. Long-term user memory and semantic search included, no vector database to run.

BufferMemory
ConversationSummaryMemory
RunnableWithMessageHistory

implements BaseListChatMessageHistory

DialogueChatHistory

Backed by DialogueDB

Messages

Memory

Search

Where the default chat history stops

The default chat history is scoped to a single process

Every LangChain memory class delegates to a chat history object. The default, InMemoryChatMessageHistory, keeps messages in an in-process array and drops them on restart. Fine for local development, and short on the guarantees a chatbot needs when it runs on serverless, in a container, or across multiple worker instances.

How the default is built
  • Every message lives in a plain array on one instance
  • One chain instance per session, no shared state model
  • Message history only, nothing for facts or preferences
  • Retrieval walks the array, no semantic query
Where it hits the wall
  • Restarts, deploys, and serverless cold starts wipe every user
  • Multi-instance workers don't see each other's history
  • Nothing to carry facts about a user across sessions
  • "What did we discuss about X" needs a separate search stack

What DialogueDB adds

A managed chat history for LangChain, plus three things the defaults leave out

The chat history class implements the interface every LangChain memory surface already accepts, so nothing about the chain changes. DialogueDB then covers the three concerns the defaults leave for the developer to solve.

Chat history that survives every restart

Every message from every user persists to DialogueDB. Chains and agents keep their context across deploys, cold starts, and multi-instance workers.

Namespaces for multi-user chains

Pass a namespace on every read and write. Conversations, memory, and search stay isolated per user, tenant, or workspace at the data layer.

Memory that carries across sessions

Store facts and preferences the assistant should remember beyond a single conversation. Retrieve them on the next run to seed the system prompt.

Semantic search over past runs

Query past messages and memory by meaning, not keyword. Inject into a prompt or expose as a tool the agent can call, no vector database to run.

The integration pattern

Add DialogueChatHistory to the memory constructor, and the chain runs exactly as it did before

One line in the constructor persists every message the chain touches. Two optional calls around the run cover long-term memory and semantic search, and nothing else about the chain code has to change.

The patternchain-run.ts
const db = new DialogueDB()

// 1. Construct DialogueChatHistory
const history = new DialogueChatHistory({
  dialogueId: sessionId,
  namespace: userId,
})

// 2. Wire it into the memory class
const memory = new BufferMemory({
  chatHistory: history,
  returnMessages: true,
})

// 3. Search memory (optional)
const facts = await db.searchMemories(
  userInput, { namespace: userId }
)

// 4. Run the chain
const chain = new ConversationChain({ llm, memory })
const result = await chain.call({ input: userInput })

// 5. Save new facts (optional)
await db.createMemory({ value: newFact, namespace: userId })

What this unlocks in your LangChain app

Six patterns the integration makes shorter to build.

Chatbots that survive every deploy

A chain that talked to a user yesterday picks up the same conversation today, even if the process restarted in between.

DialogueChatHistory

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.

dialogueId

Onboarding chains with real user profiles

As the assistant learns preferences and answers, store them as Memory objects. The next session starts with a profile, not a blank slate.

db.createMemory()

Agent conversations that pick up where they stopped

On restart, the agent reloads every prior message from DialogueDB and continues with full context of what the last run said and answered.

DialogueChatHistory

Multi-tenant SaaS with per-user isolation

One codebase, many customers, each with their own namespace. No cross-tenant leakage, no WHERE clauses in your chain code.

namespace: userId

Recall past runs by meaning

Search over every past conversation, scoped to a namespace. Answer "what did we discuss about X" even when the reader phrased it differently.

db.searchMessages()

Install in 3 steps

From npm install to the first message that survives a restart, in under five minutes.

1

Install the client

npm install dialogue-db
2

Set the API key

DIALOGUE_DB_API_KEY=...
3

Drop in the chat history

new BufferMemory({
  chatHistory: new DialogueChatHistory({
    dialogueId: sessionId,
    namespace: userId,
  }),
})

Copy the class from the examples repo.

Get Your Free API Key

No credit card. Free tier to start. Starter is $29/month when usage grows.

The reference example

A LangChain example repo with two runnable samples, cloneable and locally runnable in about a minute.

Read the DialogueChatHistory class

The full implementation lives in the same example repo. Select a section to jump to its lines.

src/lib/dialogue-history.ts
import { BaseListChatMessageHistory } from "@langchain/core/chat_history"
import { BaseMessage, HumanMessage, AIMessage, SystemMessage } from "@langchain/core/messages"
import { DialogueDB, type Dialogue } from "dialogue-db"
 
export class DialogueChatHistory extends BaseListChatMessageHistory {
lc_namespace = ["langchain", "stores", "message", "dialoguedb"]
 
private db = new DialogueDB()
private dialogue: Dialogue | null = null
 
constructor(private opts: { dialogueId: string; namespace: string }) { super() }
 
private async ensureDialogue() {
this.dialogue ??= await this.db.getOrCreateDialogue({
id: this.opts.dialogueId, namespace: this.opts.namespace
})
return this.dialogue
}
 
async getMessages(): Promise<BaseMessage[]> {
const dialogue = await this.ensureDialogue()
await dialogue.loadMessages({ order: "asc" })
return dialogue.messages.map((m) => {
const content = typeof m.content === "string" ? m.content : JSON.stringify(m.content)
switch (m.role) {
  case "user": return new HumanMessage(content)
  case "assistant": return new AIMessage(content)
  case "system": return new SystemMessage(content)
  default: return new HumanMessage(content)
}
})
}
 
async addMessage(message: BaseMessage): Promise<void> {
const dialogue = await this.ensureDialogue()
const role = toRole(message)
await dialogue.saveMessage({ role, content: typeof message.content === "string" ? message.content : JSON.stringify(message.content) })
}
}
Condensed view. Full source at github.com/dialoguedb/examples.

Where DialogueDB fits

Options for LangChain chat history and cross-session memory, side by side.

InMemoryChatMessageHistory
LangChain default
Redis or SQL history
@langchain/community classes
Standalone memory service
Facts and preferences only
DialogueDB
Persists messagesNo, in-processYesFacts onlyYes, every message
Multi-user isolationNoneBring your ownBy user IDNamespaces, first-class
Long-term memory across sessionsNoNoYesYes, Memory objects
Semantic search over past runsNoBuild it yourselfFacts onlyEvery message and memory
Infra to runNone (in-process)Redis or DB you hostTheir managed serviceManaged

If you know LangChain, you already know DialogueDB

The concepts map one-to-one to what LangChain already exposes.

LangChainDialogueDB
BaseListChatMessageHistoryDialogueChatHistory
HumanMessage, AIMessage, SystemMessagemessage with role
Session identifier from your appdialogueId
User from your auth layernamespace
Tool call on an AIMessagemessage content and metadata (extend the class to serialize)
Facts the assistant should carrymemory

Frequently asked questions

One API for messages, memory, and search

Add it to your LangChain app in minutes.