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. Python only; in JavaScript, LangGraph.js uses withNiadraContext() from LangChain.
Install
The five primitives
For the older
langgraph.prebuilt.create_react_agent, pass pre_model_hook=pre_model_hook(conversation): it gives the model the same messages through llm_input_messages, again without touching state; record the turns with the NiadraCallbackHandler from niadra.integrations.langchain.
Minimal example
examples/langgraph_agent.py.
Agent memory
NiadraMiddleware(conversation, agent_memory=True) puts the agent’s own notes right before the customer’s context and adds search_agent_memory (and remember, with write) to the tools. See Agent memory.
Turn records
With theturns feature on in the space (it ships on), the NiadraMiddleware with turns=True records each agent run as a turn record: before_agent opens the turn, wrap_tool_call records each tool call by the provider’s id and after_agent closes it with the model calls and their tokens. In LangGraph.js, the NiadraCallbackHandler of @niadra/sdk/langchain with turns: true does the same. In a replay, the graph’s tools answer from the record in Python, and in JavaScript the ones passed through recordTools(). A turn never waits for Niadra and never repeats the conversation’s text.
Limits
- No
BaseStoreof its own: Niadra is not the graph’s state store. - No separate node for LangGraph.js:
withNiadraContext()in@niadra/sdk/langchainalready 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
langgraph1.2 andlangchain1.4 with a fake chat model and Niadra on the emulator.
Next steps
LangChain
the runnable and the callback handler, in Python and in JavaScript.
Internal agents
tasks, objects and actions that close open items.

