Skip to main content
The @atomicmemory/langgraph adapter provides node factories for LangGraph JS graphs and framework-agnostic helpers you can call inside any node body. Rather than coupling to LangGraph’s runtime, the node factories emit plain async (state) => Partial<state> functions that you register with .addNode() — which means the adapter does not import @langchain/langgraph at runtime and is completely insulated from LangGraph version churn. The peer declaration is there to document the intended consumer; pin the version in your application.

Installation

pnpm add @atomicmemory/langgraph @atomicmemory/sdk @langchain/langgraph

Three surfaces at a glance

SurfaceUse when
createMemoryRetrieveNode()You want a graph node that searches AtomicMemory and merges the rendered context into state before the model call.
createMemoryIngestNode()You want a graph node that persists the completed turn into AtomicMemory after the model call.
searchMemory() / ingestTurn()You want to call AtomicMemory directly inside a node body, an edge condition, or a standalone helper.

Minimal end-to-end example

The example below wires a three-node graph: memory retrieval → model call → memory ingest. The extractor callbacks (getQuery, applyContext, getMessages, getCompletion) decouple the adapter from your state schema — use whatever channels your graph already exposes.
import { StateGraph, MessagesAnnotation } from '@langchain/langgraph';
import { MemoryClient } from '@atomicmemory/sdk';
import {
  createMemoryRetrieveNode,
  createMemoryIngestNode,
} from '@atomicmemory/langgraph';

const memory = new MemoryClient({
  providers: { atomicmemory: { apiUrl: process.env.ATOMICMEMORY_URL!, apiKey: process.env.ATOMICMEMORY_KEY! } },
});
await memory.initialize();

const scope = { user: 'pip', namespace: 'my-graph' };

const retrieve = createMemoryRetrieveNode<
  typeof MessagesAnnotation.State,
  { context: string | null }
>(memory, {
  scope,
  getQuery: (state) => {
    const last = [...state.messages].reverse().find((m) => m.getType?.() === 'human');
    return typeof last?.content === 'string' ? last.content : '';
  },
  applyContext: (_state, context) => ({ context }),
});

const ingest = createMemoryIngestNode<
  typeof MessagesAnnotation.State,
  Record<string, never>
>(memory, {
  scope,
  getMessages: (state) =>
    state.messages.map((m) => ({
      role: m.getType?.() === 'human' ? 'user' : 'assistant',
      content: typeof m.content === 'string' ? m.content : '',
    })),
  getCompletion: (state) => {
    const last = state.messages.at(-1);
    return typeof last?.content === 'string' ? last.content : '';
  },
});

const graph = new StateGraph(MessagesAnnotation)
  .addNode('retrieve', retrieve)
  .addNode('model', async () => ({ /* your model call */ }))
  .addNode('ingest', ingest)
  .addEdge('__start__', 'retrieve')
  .addEdge('retrieve', 'model')
  .addEdge('model', 'ingest')
  .compile();

Framework-agnostic helpers

If you need to call AtomicMemory from within a node body rather than at the node-factory level, the helpers are available as named exports:
import { searchMemory, ingestTurn } from '@atomicmemory/langgraph';

// Inside any node body:
const { context } = await searchMemory(memory, { query, scope });

await ingestTurn(memory, { messages, completion: text, scope });
ingestTurn() excludes system messages by default. Opt in via includeRoles only when your system content is genuinely user-authored material worth remembering.

Scope binding

Scope is fixed at factory time. Agents and downstream nodes cannot rebind to a different user or namespace by mutating graph state — this is an intentional security boundary.

Agent-callable tools

If you also want memory_search and memory_ingest as agent-callable tools (for use in a LangGraph tool node, for example), use the @atomicmemory/langchain adapter. LangGraph consumes the same tool()-shaped objects that @atomicmemory/langchain produces, so you can combine both adapters in a single graph.
Use @atomicmemory/langgraph for the retrieve/ingest lifecycle nodes and @atomicmemory/langchain for the agent-callable tool pair. They share the same MemoryClient instance and scope — construct MemoryClient once and pass it to both.