LangGraph x Nowledge Mem
Add identity-aware Context, Memory tools, and idempotent Thread capture to LangGraph agents without replacing their checkpointer.
LangGraph manages an agent's execution: checkpoints, interrupts, retries, and graph state. Nowledge Mem manages the durable state that should follow an agent across graphs and tools: its identity, active Space, Working Memory, governed memories, and searchable conversations.
The nowledge-mem-langgraph Python connector joins those two systems without making either pretend to be the other.
The ownership boundary
Keep your LangGraph checkpointer. Nowledge Mem is not a checkpointer or a BaseStore replacement. It injects transient context, provides identity-scoped MCP tools, and imports completed conversations as Mem Threads.
Install
pip install nowledge-mem-langgraphFor a remote Mem server or Nowledge Cloud workspace, configure the same endpoint and key used by your other Mem clients:
export NMEM_API_URL=https://your-mem-server
export NMEM_API_KEY=nmem_...
export NMEM_LANGGRAPH_APP_ID=customer-supportNMEM_LANGGRAPH_APP_ID is a stable application slug, not a release version. Keep it unchanged across deployments so the same LangGraph thread_id continues to resolve to the same Mem Thread.
LangChain create_agent
from dataclasses import dataclass
from langchain.agents import create_agent
from nowledge_mem_langgraph import NowledgeClient, NowledgeMiddleware
@dataclass
class AgentContext:
user_id: str
nowledge: dict[str, str]
mem = NowledgeClient()
agent = create_agent(
model="openai:gpt-5.4",
tools=await mem.tools(),
middleware=[NowledgeMiddleware(mem)],
context_schema=AgentContext,
)
result = await agent.ainvoke(
{"messages": [{"role": "user", "content": "What did we decide last week?"}]},
config={"configurable": {"thread_id": "ticket-1842"}},
context=AgentContext(
user_id="auth-user-42",
nowledge={
"agent_id": "support-triage",
"space_id": "customer-acme",
},
),
)This path provides the complete integration:
- The selected Agent's Context Bundle is read once per top-level turn.
- Context is added to the model request, never to checkpointed messages.
- Mem's bounded external-agent MCP tools are available to the model.
- Every tool call is forced back to the trusted invocation Agent and Space.
- The completed top-level conversation is imported through
POST /threads/import. - Exact replays become no-ops; later turns append only missing messages.
- Mem retrieval outputs remain visible in the Thread but are excluded from distillation, preventing recall from being learned again as new memory.
Both invoke() and ainvoke() support context injection and Thread sync. Mem MCP tools are loaded through the async langchain-mcp-adapters interface, so an agent that uses those tools should run with ainvoke() or astream().
Identity model
These values have different jobs:
| Value | What it identifies | Security role |
|---|---|---|
| API key | Workspace/member access | Authorization |
agent_id | Portable Nowledge AI Identity | Context, provenance, routing |
host_agent_id | LangGraph deployment identity | Host provenance |
space_id | Memory and retrieval scope | Scope inside authorized access |
LangGraph thread_id | Canonical conversation | Mem Thread identity |
LangGraph assistant_id | Server deployment/config instance | Metadata only |
| LangGraph authenticated user | Human/service principal | LangGraph authorization; never inferred as Agent identity |
Pass invocation-specific selectors under context.nowledge. The connector does not inspect prompts for identity. If an invocation supplies either Agent selector, it replaces the static Agent tuple rather than combining a runtime agent_id with an unrelated default host_agent_id.
When LangGraph Server provides graph_id and assistant_id, the connector can record langgraph:<graph_id>:<assistant_id> as host provenance. It does not use that value as a credential or split one conversation into multiple Threads.
Static defaults remain useful for a deployment dedicated to one Agent:
export NMEM_AGENT_ID=support-triage
export NMEM_HOST_AGENT_ID=langgraph:support:prod
export NMEM_SPACE=customer-acmeFor multi-tenant applications, use a key with the correct workspace permissions and pass Agent/Space selectors from trusted server-side context. Do not accept them directly from unvalidated client JSON.
Thread and subagent semantics
One LangGraph thread_id maps to one Mem Thread:
langgraph:<application_id>:<thread_id>assistant_id is deliberately absent from that key. LangGraph allows multiple assistants to run on the same Thread; changing model configuration must not fork the user's conversation history.
Subgraphs share the parent Thread and receive a nested checkpoint namespace. The middleware syncs only the top-level namespace, producing one readable conversation instead of one copy for the parent and every subagent.
Use a separate Thread only when the subagent is independently addressable and owns a durable conversation. In that case give it its own LangGraph thread_id and, when its behavior should differ, its own Mem agent_id.
Raw StateGraph
A raw graph can put model calls and completion boundaries anywhere, so the connector does not guess. Use the explicit helpers at boundaries you own:
from nowledge_mem_langgraph import NowledgeClient, NowledgeIdentity
mem = NowledgeClient()
identity = NowledgeIdentity(agent_id="researcher", space_id="project-atlas")
bundle = await mem.acontext_bundle(identity)
tools = await mem.tools()
# At the graph's real completion boundary:
await mem.async_thread(
thread_id=runtime.execution_info.thread_id,
messages=state["messages"],
identity=identity,
runtime=runtime,
)Inject bundle["rendered_markdown"] into the model request. Do not append it to a checkpointed message channel.
Reliability
Context reads and Thread sync fail open by default. A temporary Mem outage will not take down the customer-facing agent, but it is logged. Set fail_open=False when memory availability is a hard workflow requirement.
Failures never broaden scope or remove authentication. Thread sync is awaited rather than sent through an untracked background task, so serverless workers cannot exit before the import completes.
Existing deployments
Installing the connector does not change LangGraph checkpoints. It begins capturing from the messages still present in state. If a summarization policy removed older messages before the connector was installed, those deleted messages cannot be reconstructed; import an original transcript separately if one exists.
Do not use LangSmith traces as a transcript backfill. Traces contain nested runs, retries, and tool execution details, not the canonical user conversation.
Verify
- Run one turn with a stable LangGraph
thread_id. - Confirm the model request receives the expected Agent and Space Context Bundle.
- Call a Mem search tool and verify the request carries the same identity scope.
- Open Nowledge Mem Threads and find one
LangGraphThread. - Run the same state again; the import should report no duplicate messages.
- Run a nested subgraph; it should not create a second Mem Thread.
