Skip to main content

langchain-membase

Membase long-term memory for LangChain and LangGraph (Python).

Membase keeps a person's memory in their own account: named Memories (containers) that learn from their notes, files and conversations, plus a profile of standing facts. This package gives a LangChain app three ways to use it:

Piece LangChain type What it does
MembaseRetriever BaseRetriever a Membase search as Documents, each citing its Memory in metadata["container_name"]
MembaseToolkit (membase_tools()): MembaseSearchTool, MembaseSaveTool, MembaseProfileTool BaseToolkit / BaseTool agent tools: search, save (only when the user asks), read the profile
MembaseRecallMiddleware LangChain v1 AgentMiddleware time-boxed recall added to the system message before the model call of a create_agent agent

There is deliberately no delete or forget tool, and the package never confirms a destructive action. It also does not implement LangGraph's BaseStore: Membase is a memory that learns, not a key-value store (there is no get-by-key), so it is offered as retrieval and tools instead.

Install

pip install langchain-membase             # retriever + tools (needs langchain-core)
pip install 'langchain-membase[agents]'   # + the create_agent middleware (needs langchain>=1.1)

Python 3.10+. Get a key in the Membase app under Connect › Developer keys and set it:

export MEMBASE_API_KEY=mbk_...

A Read key can search and read the profile (if its owner ticked it); saving needs a Read & write key. One key is one person's account.

Retriever

from langchain_membase import MembaseRetriever

retriever = MembaseRetriever(k=5)                     # MEMBASE_API_KEY from the environment
docs = retriever.invoke("what did we decide about the ledger")
for d in docs:
    print(d.metadata["container_name"], "·", d.page_content)
  • k (1–50) is the number of passages in all; unset lets Membase cover every Memory in reach.
  • container="mv-…" limits the search to one Memory (its id from client.containers.list()). Both can also be passed per call: retriever.invoke(q, k=3, container="mv-…").
  • If no passage comes back and some Memory could not answer (no model, dormant), the retriever raises MembaseUnavailableError instead of returning []: that is not evidence of "no memory". When some Memories answered, it returns their passages and logs the rest.
  • A 403 (membase.PermissionDeniedError) means the key's owner narrowed or revoked it; do not retry with that key.

It works anywhere a retriever does, e.g. in an LCEL chain:

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough

def cite(docs):
    return "\n".join(f"[{d.metadata['container_name']}] {d.page_content}" for d in docs)

prompt = ChatPromptTemplate.from_template("Memory:\n{memory}\n\nQuestion: {question}")
chain = {"memory": retriever | cite, "question": RunnablePassthrough()} | prompt | llm

Agent tools

from langchain.agents import create_agent
from langchain_membase import MembaseToolkit

agent = create_agent("openai:gpt-5", tools=MembaseToolkit().get_tools())   # or membase_tools()
agent.invoke({"messages": [{"role": "user", "content": "What did we pick for the ledger?"}]})
Tool Arguments Notes
membase_search query, optional container (a Memory's name) passages as - [Memory name] text; the raw response is the ToolMessage artifact; Memories that could not answer are reported
membase_save content (the user's words), static, optional container the description tells the model to save only when the user asks; static=true records a standing fact in the profile; with several Memories in reach it needs a container (or a default container= id on the tool) and says which names exist
membase_profile optional topic standing and recently changed facts; only for a key whose owner ticked the profile

MembaseToolkit(save=False, profile=False) (or membase_tools(client, save=False, profile=False)) leaves tools out; container= and k= set defaults. Errors come back as the tool's answer (handle_tool_error=True), so the model can tell the user, e.g. "this Membase key was narrowed or revoked".

Explicit tool calls use the SDK's own timeout (90 s): the first search after a quiet spell takes longer while the user's memory wakes.

Recall middleware (LangChain v1)

from langchain.agents import create_agent
from langchain_membase import MembaseRecallMiddleware, membase_tools

agent = create_agent(
    "openai:gpt-5",
    tools=membase_tools(),
    system_prompt="You are a helpful assistant.",
    middleware=[MembaseRecallMiddleware(k=5, timeout=8.0)],
)

Before the model call, the middleware searches Membase for the latest user message and appends the passages (each with its Memory) to the system message of that request.

  • Time-boxed and fail-open: it waits at most timeout seconds (8 by default). On a timeout, a 403 or any other error it logs a warning on the langchain_membase logger and the model runs without memory. A search that ran past the budget finishes in the background, which wakes the memory for the next turn.
  • Once per user message: model calls that follow tool calls in the same turn reuse the result.
  • Nothing is persisted: the recall lives in the model request only, never in the agent's state or checkpoint.
  • No automatic writes by default. capture_turns=True (opt-in) saves the user's own message(s) of each turn, once, as a note in container=, in the background. Assistant replies are never saved, so an AI answer is not learned as a fact about the user.

Many users

A Membase key belongs to one person, so a multi-user app holds one key (or one local directory) per end user and passes client_for, a function from user id to that user's client. Every class and membase_tools() accept it. The user id is read from the run:

from functools import lru_cache
from membase import Membase
from langchain_membase import MembaseRecallMiddleware, MembaseRetriever, membase_tools

@lru_cache(maxsize=1024)            # reuse each user's client (and its connection pool)
def client_for(user_id: str) -> Membase:
    return Membase(api_key=load_user_key(user_id))   # that user's key, never another's

retriever = MembaseRetriever(client_for=client_for)
retriever.invoke("...", config={"configurable": {"user_id": "alice"}})

agent = create_agent(
    model,
    tools=membase_tools(client_for=client_for),
    middleware=[MembaseRecallMiddleware(client_for=client_for)],
)
agent.invoke({"messages": [...]}, config={"configurable": {"user_id": "alice"}})

The user id is taken from config["configurable"]["user_id"], or from a LangGraph run context with a user_id field (create_agent(..., context_schema=Ctx) and agent.invoke(..., context=Ctx(user_id="alice"))). With client_for set, a call that carries no user id raises MissingUserIdError (the middleware logs it and skips recall); it never falls back to another client. client_for and client/api_key/local are mutually exclusive.

Without client_for, one client serves every call. That suits a personal agent (your own key, your own memory), not a multi-user app.

Local mode keeps each person in their own directory: client_for=lambda uid: Membase(local=f"/data/membase/{uid}") (pip install 'unibaseio-membase[local]', Python 3.12+, and an LLM key such as OPENAI_API_KEY).

Configuration

Every class takes client=Membase(...), or api_key= / base_url= / local=; otherwise MEMBASE_API_KEY and MEMBASE_BASE_URL come from the environment. The API host defaults to https://api.app.membase.com.

Development

uv venv .venv && uv pip install --python .venv/bin/python -e . \
  'langchain>=1.1' langgraph langchain-tests pytest pytest-asyncio ruff
.venv/bin/python -m pytest              # offline: the real SDK over httpx.MockTransport
MEMBASE_API_KEY=mbk_... .venv/bin/python examples/live_smoke.py   # against the real API
uv build

The offline suite includes LangChain's standard tests (langchain-tests) for the retriever and the three tools, and runs the tools and the middleware inside a real create_agent (LangGraph) graph with a scripted chat model.

Licence

MIT

Metadata

Release files for langchain-membase 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for langchain-membase 0.1.0
File Size Uploaded Provenance Actions
langchain_membase-0.1.0.tar.gz 23.1 kB Without provenance Details for langchain_membase-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for langchain-membase 0.1.0
File Interpreter ABI Platform Actions
langchain_membase-0.1.0-py3-none-any.whl Python 3 none any Details for langchain_membase-0.1.0-py3-none-any.whl

Total release size: 41.7 kB

Release files / langchain_membase-0.1.0.tar.gz

Download URL langchain_membase-0.1.0.tar.gz
Size 23.1 kB
Tags Source
SHA-256 checksum
How to use checksums
f4de2aaa62cc8634247ac1910cbb039b99afff010f7bc7b95594130b5f538538
BLAKE2b-256 checksum
How to use checksums
3debbe17d4b8ba42f37d742ffb06a97cd15b0421cecc5be2cea0d359735d3d04
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.12

Release files / langchain_membase-0.1.0-py3-none-any.whl

Download URL langchain_membase-0.1.0-py3-none-any.whl
Size 18.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1c0d9d15dc0c061e0117b4343a1f1790dd5d82b75667ed4392a2a44688ffa48a
BLAKE2b-256 checksum
How to use checksums
40b5ec1126b805ff6094228346030fd835e8400ba26c97617cbb137ed4825902
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.12

Security for langchain-membase 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page