How to: integrate with LangChain JS
The @neo4j-labs/agent-memory/integrations/langchain subpath exposes
two duck-typed adapters that fit common LangChain JS shapes:
-
Neo4jChatMessageHistory— slots intoRunnableWithMessageHistorywherever aBaseChatMessageHistoryis expected. -
Neo4jEntityRetriever— slots into retriever chains wherever aBaseRetriever-shaped object is expected.
A runnable example lives at
clients/typescript/examples/langchain.
Why duck-typed
LangChain JS evolves quickly and the published interfaces shift between
minor versions. Importing concrete base classes from @langchain/core
would bind us to a specific version; duck-typing lets these adapters
slot in regardless.
The cost: type information about the LangChain interfaces is not imported. If you want stronger types in your own app, cast at the call site:
import type { BaseChatMessageHistory } from "@langchain/core/chat_history";
import { Neo4jChatMessageHistory } from "@neo4j-labs/agent-memory/integrations/langchain";
const history: BaseChatMessageHistory =
new Neo4jChatMessageHistory(memory, conv.id) as unknown as BaseChatMessageHistory;
Chat message history
import { RunnableWithMessageHistory } from "@langchain/core/runnables";
import { Neo4jChatMessageHistory } from "@neo4j-labs/agent-memory/integrations/langchain";
const chain = baseChain.pipe(...);
const memoryChain = new RunnableWithMessageHistory({
runnable: chain,
getMessageHistory: (sessionId) => new Neo4jChatMessageHistory(memory, sessionId),
inputMessagesKey: "input",
historyMessagesKey: "history",
});
await memoryChain.invoke(
{ input: "Hello!" },
{ configurable: { sessionId: conv.id } },
);
Entity retriever
import { Neo4jEntityRetriever } from "@neo4j-labs/agent-memory/integrations/langchain";
const retriever = new Neo4jEntityRetriever(memory, { limit: 5 });
const docs = await retriever.invoke("Neo4j graph database");
// docs[i].pageContent === entity.description
// docs[i].metadata.name === entity.name