MemoryRouter / Documentation
LangChain
Add explicit retain and recall tools to Python LangChain applications with langchain-memoryrouter.
langchain-memoryrouter connects Python LangChain applications to persistent conversational memory across sessions. Use its tools when your agent should choose when to remember or search, or call them directly from your application for deterministic behavior.
The package is maintained by MemoryRouter. It does not replace your model provider, run an agent loop, or add memory automatically just because it is installed. For a graph that runs recall before the model and retain afterward, use the LangGraph guide.
Prerequisites
- Python 3.9 or newer according to the package metadata. Python 3.12 is a straightforward choice for a fresh environment; newer LangChain dependency releases can have their own Python requirements.
- A MemoryRouter account and Memory Key.
- Network access to
https://api.memoryrouter.ai. - Your usual LangChain model integration and provider credentials if you connect the tools to an LLM. The direct proof below needs no model-provider key.
Install and configure
python3.12 -m venv .venv
source .venv/bin/activate
python -m pip install 'langchain-memoryrouter==0.1.2'
export MEMORYROUTER_API_KEY='YOUR_MEMORYROUTER_KEY'Version 0.1.2 supplies create_memory_tools, create_recall_node, create_retain_node, MemoryRouterStore, MemoryRouterClient, and AsyncMemoryRouterClient. Its dependencies include langchain-core, langgraph, and httpx.
The environment variable is an application convention in these examples. The package does not read it automatically: pass it to memory_key explicitly. Keep the key on your server and out of source control, browser bundles, prompts, and logs.
Create the tools
import os
from langchain_memoryrouter import create_memory_tools
retain, recall = create_memory_tools(
memory_key=os.environ["MEMORYROUTER_API_KEY"],
default_limit=5,
)The tuple is ordered retain, recall:
| Tool | Input | Behavior |
|---|---|---|
memoryrouter_retain | messages, optional session_id | Sanitizes user and assistant text, then calls /v1/memory/ingest. |
memoryrouter_recall | query, optional limit and session_id | Calls /v1/memory/search and returns matching memory text. |
For a model that supports tools, add them to its existing tool set:
# `model` is your already-configured LangChain chat model.
model_with_tools = model.bind_tools([retain, recall])bind_tools() only supplies tool definitions to the model. Your agent executor must run returned tool calls and return their results to the model. If your application requires recall on every turn, call recall.invoke(...) before the model yourself or use LangGraph nodes. Do not assume an LLM will choose to remember every exchange.
Prove memory crosses sessions
Use a test vault and only this synthetic fact. These two scripts run in separate Python processes with different session IDs and the same Memory Key.
Save as retain_demo.py:
import os
from langchain_core.messages import AIMessage, HumanMessage
from langchain_memoryrouter import create_memory_tools
retain, _ = create_memory_tools(os.environ["MEMORYROUTER_API_KEY"])
print(retain.invoke({
"messages": [
HumanMessage(content="Synthetic test: Project Kestrel's launch color is copper."),
AIMessage(content="Noted: Project Kestrel uses copper for its launch color."),
],
"session_id": "langchain-proof-a",
}))Save as recall_demo.py:
import os
from langchain_memoryrouter import create_memory_tools
_, recall = create_memory_tools(os.environ["MEMORYROUTER_API_KEY"])
print(recall.invoke({
"query": "What launch color did we choose for Project Kestrel?",
"limit": 5,
"session_id": "langchain-proof-b",
}))Run the first script, allow ingestion to finish, then run the second:
python retain_demo.py
python recall_demo.pyThe first script should report Retained 2 conversation message(s). That confirms the ingest request succeeded, not that indexing has finished. The second should return memory containing Project Kestrel and copper. It does not pass the original conversation to the search call.
If no match appears yet, wait briefly and rerun only the recall script. Do not repeatedly ingest the same test. This is a runnable verification recipe, not a claim that it has been executed against your vault.
Multi-user applications
Map each authenticated application user to their own Memory Key on the server:
Authenticated app user -> server-side Memory Key lookup -> that user's toolsCreate a separate tool pair for each user's key. A session_id labels a conversation; it does not isolate users who share a key. Never accept a Memory Key or user-to-key mapping chosen by an untrusted client.
If you supply a custom client to create_memory_tools, configure that client with the same user's key. In 0.1.2, the tools use the supplied client's credentials rather than passing the factory's memory_key into every call.
Optional semantic store
Use MemoryRouterStore only where your code expects a LangChain BaseStore and accepts semantic search rather than exact key-value behavior:
import os
from langchain_memoryrouter import MemoryRouterStore
store = MemoryRouterStore(os.environ["MEMORYROUTER_API_KEY"])
store.mset([("synthetic-project-preference", "Project Kestrel uses copper.")])
# Search after ingestion is available.
print(store.search("Project Kestrel launch color", limit=3))mset()retains text. It is not an overwrite operation for a unique database key.mget()searches each supplied key as a query and returns the best matching content orNone.yield_keys()returns an empty iterator.mdelete()is a no-op in this adapter.- It is not a LangGraph checkpointer or a substitute for LangGraph's namespaced
BaseStoreAPI. Do not use it for exact IDs, inventory, or deletion guarantees.
Limitations and storage hygiene
- Tool and node retain paths keep human and assistant text. They drop system messages, tool-result messages, tool-call metadata, and non-text content. This is not a secret-redaction system: sensitive data in ordinary conversation text still needs your application's controls.
MemoryRouterClient.ingest()is a thin HTTP client. If you use it directly, prepare and sanitize the message list yourself.- Retrieval is semantic and can return no match. Persist only data you are entitled to store and treat retrieved content as data, not trusted instructions.
- These tool factories are synchronous.
AsyncMemoryRouterClientprovidesaingest,asearch, andapreparefor custom async applications. - This package does not expose reflection, consolidation, or arbitrary memory-ID deletion tools. See the API reference for the broader API.
- MemoryRouter is a hosted service. Using a local LangChain model does not keep the retained conversation local.
Troubleshooting
| Symptom | Check |
|---|---|
ModuleNotFoundError | Install with the same environment's python -m pip that runs your app. The import name is langchain_memoryrouter. |
Missing environment variable or memory_key is required | Export the key in the process environment and pass it explicitly to the factory or client. |
| HTTP authentication failure | Check that this is a MemoryRouter key, not an OpenAI or other model-provider key. Never paste the key into a public issue. |
No conversation text to retain. | Supply non-empty HumanMessage or AIMessage text, not only system or tool messages. |
No relevant memories found. | Confirm ingestion succeeded, allow indexing to finish, search for the synthetic project, and check both processes use the same key. |
| Model ignores the tools | Confirm your executor handles tool calls. Tool binding alone does not execute them. Use direct calls or graph nodes when execution must be deterministic. |
| HTTP 429 or a timeout | Honor Retry-After when present and use bounded backoff. The package does not implement an application retry policy. Avoid blindly replaying writes. |
| Unexpected user's memories | Check the server-side key mapping. Changing only session_id is not a tenant boundary. |