Skip to content
niadra
Integration · LangGraph

Memory for LangGraph agents.

NiadraMiddleware wraps every model call of the agent built by langchain.agents.create_agent: the pack goes into the system message, the turns are recorded and the history tools come along. Nothing is written to the graph's state: the checkpointer never stores a pack.

LangGraph's checkpointer persists one thread's state: this graph's messages, for this thread. A long-term memory store keeps what this agent decided to remember, in a namespace of your application. Neither knows what the customer told another vendor's voice agent nor what the billing agent did in the ERP.

Niadra stays outside the graph. The middleware appends the customer's context to the system message, with your instructions first, and the turn_block after the messages, on every model call. The state stays yours alone, and the checkpointer stays small.

The minimal example, as the documentation has it
pip install 'niadra[langgraph]'   # langgraph 1.2, langchain 1.4 and langchain-core 1.6 or newer, below 2
"""A LangGraph agent (langchain.agents.create_agent) with the customer's memory as middleware."""

import asyncio

from langchain.agents import create_agent

from niadra import AsyncNiadra, phone
from niadra.integrations.langgraph import NiadraMiddleware

niadra = AsyncNiadra(channel="chat")


async def main() -> None:
    async with niadra.conversation("thread-81", subject=phone("+5511912345678")) as conversation:
        agent = create_agent(
            "openai:gpt-4.1",
            system_prompt="You are Acme's agent.",
            middleware=[NiadraMiddleware(conversation)],
        )
        result = await agent.ainvoke(
            {"messages": [{"role": "user", "content": "Where is my replacement lid?"}]}
        )
        print(result["messages"][-1].content)
    await niadra.close()


asyncio.run(main())
  • Python

The same code is in examples/langgraph_agent.py in the SDK repositories, where it runs in CI against the framework's real types and Niadra's emulator. To try it without Niadra's cloud, niadra-mock and NIADRA_BASE_URL=http://127.0.0.1:8765.

How the adapter wires in

The five primitives of every Niadra integration, in this framework's extension points.

Context
The pack is appended to the system message, which keeps your instructions first, and the turn_block goes after the messages. Nothing is written to the graph's state. For the older create_react_agent, pre_model_hook=pre_model_hook(conversation) gives the model the same messages through llm_input_messages, again without touching state.
Turns
The customer's messages are recorded before the call, keyed by their position in the conversation, so the history the checkpointer replays is never recorded twice; the model's answer, with its usage_metadata, after it.
Tools
The middleware brings the history tools, and the agent memory tools, as its own tools, so create_agent offers them without you listing them.
Verification
conversation.verify() before invoking the agent.
Handoff
transferred_to_agent() and transferred_to_human() record the transfer; call them where the graph hands the conversation over.

What the agent receives

The context is compiled when the memory changes and served ready, with no AI model on the read. What another channel said during the conversation arrives as a delta, at the end of the prompt.

  • Who the customer is, by what the conversation has proven: the verification level decides what goes in
  • Facts, open items and promises, with the date and the channel they came from
  • What other agents did inside the company, confirmed by the system of record
  • Patterns computed by rule, with the evidence and the expiry
  • The three history tools: search, timeline and open an item, bound to the customer in your code
  • A receipt of every read, chained by SHA-256

What the adapter does not do

  • No BaseStore of its own: Niadra is not the graph's state store.
  • No separate node for LangGraph.js: withNiadraContext() in @niadra/sdk/langchain already gives the model node its context without writing it into the graph's checkpointed state.
  • Nothing here fails the agent: with Niadra slow or down, the model call goes on without the pack.
  • Tested against langgraph 1.2 and langchain 1.4 with a fake chat model and Niadra on the emulator.

Frequently asked questions

Can I keep the checkpointer and the store I already have?

You can, and should. The middleware touches neither the graph's state nor the store: the context enters the model call and leaves with it. What Niadra keeps is the company's memory of the customer, derived from the events of every channel.

And in LangGraph.js?

withNiadraContext() from @niadra/sdk/langchain gives the model node its context right before the call, without writing to state; the NiadraCallbackHandler records the answers. The full example is on the LangChain page.

Can every run of the agent become a turn record?

It can, with turn records switched on in the space: before_agent opens the turn, wrap_tool_call records each tool call and after_agent closes it with the model calls and their tokens. In a replay in your CI, the graph's tools answer from the record.

Do I have to change my model, my prompt or my vendor?

No. The adapter places the context after your instructions and the delta at the end of the prompt, in the extension points the framework already has. Your model, your prompt and your vendor stay the same, and switching any of them later does not erase the memory.

Where does the data live, and what does it cost?

The data stays in a single region, stated in the contract, encrypted with AES-256-GCM under a key exclusive to your company and protected in a FIPS 140-3 HSM. The price is per conversation or task in which an agent read the memory: US$ 2 to 3 per thousand, by volume, with reads, searches and system events included. Niadra is opening to companies by request, before the public launch.

Tell us what you are building.

A work email and two lines about your agents are enough. The people who write the code reply, with an early-access proposal for your case.

Rather tell us more about your company? Use the full form

Company email only. We use this data only to answer your request; to have it deleted, ask through this form.

The next agent can already show up knowing.

Niadra is opening to companies by request, before the public launch. Tell us what you are building: the people who reply are the people who write the code.