Skip to content

mem0 drop-in

holographic_integrations.mem0 provides Memory and AsyncMemory with the mem0ai 2.x method signatures and return shapes, backed by Holographic Memory. It does not import mem0.

from holographic_integrations.mem0 import Memory   # was: from mem0 import Memory
m = Memory()                                        # hms-server on 127.0.0.1:8080, 384-dim hashing embedder
m.add("I love hiking", user_id="alice", infer=False)
m.search("hiking", filters={"user_id": "alice"})    # {"results": [...]}

Install: pip install "holographic-integrations[mem0]" (the extra only adds mem0ai for the conformance test; the shim itself needs no extra).

Tested against mem0ai 2.2.1, Python 3.12, a real hms-server built from this repository. tests/mem0/test_mem0_conformance.py runs one scenario (add, get, get_all, search, update, history, delete, delete_all) through real mem0 (local qdrant, offline) and through the shim and requires identical result shapes, key by key; tests/mem0/test_mem0_shim.py covers behaviour against the server.

Surface

add, search, get, get_all, update, delete, delete_all, history, reset, close, from_config, context managers; AsyncMemory has the same as coroutines (aclose() closes the HTTP client; close() closes only the history file).

Follows mem0 2.x validation: search/get_all take filters={"user_id"|"agent_id"|"run_id": ...} (top-level entity arguments raise), ids are trimmed and may not contain whitespace, top_k/threshold ranges, expiration_date (hidden unless show_expired=True), actor ids from message name, system messages skipped on verbatim adds, identity keys in metadata ignored.

Configuration (HMS knobs)

Memory(
    hms=HmsConfig(url=..., api_key=..., tenant_id=..., collection=..., embedder=..., input_dim=...,
                  text_queries=False, zero_trust_key="", max_fetch=100),
    extractor=None, reranker=None, history_db_path=":memory:", buckets=32, strict_infer=False,
)

Memory.from_config accepts a mem0-style dict: vector_store: {"provider": "hms", "config": {url, api_key, tenant_id, collection_name, embedding_model_dims, ...}}, embedder: {"provider": "hashing"|"custom", "config": {...}}, llm (a chat callable), history_db_path, custom_instructions. Any other provider (qdrant, openai, ...) raises ValueError instead of being ignored. The encoder is yours: pass embedder= an object with dim, embed_documents, embed_query; the default hashing embedder is lexical, not semantic. With text_queries=True and a server built with local-models, the service embeds text itself (wire-level only; not exercised here).

Differences from mem0 (read these)

  • add(infer=True) is not what mem0 does by default. mem0 asks an LLM to extract facts. Without an extractor, this shim stores each message verbatim (mem0's infer=False behaviour) and emits a UserWarning once per instance. Pass extractor=LLMExtractor(chat_fn) (any chat function: chat_fn(messages) -> str, optionally async; its reply must be {"memory": [{"text": ...}]}) or any extractor(messages, existing_texts, prompt) -> facts. strict_infer=True raises instead of storing verbatim. The extraction prompt is this package's, not mem0's, and extraction is additive with hash de-duplication (no update/delete decisions). Nothing is sent anywhere except to the function you supply.
  • Scores are cosine similarity, not mem0's blended semantic/BM25/entity score; threshold (default 0.1) applies to cosine. No entity boosting, no reranker provider objects (pass a callable (query, results, top_k) -> results). explain=True returns score_details={"semantic": score}.
  • Not supported: memory_type="procedural_memory" (raises NotImplementedError), timestamp and reference_date (raise ValueError, as mem0 OSS does), vision messages (non-string content is skipped), chat, project.
  • History is a SQLite file with mem0's history schema (history_db_path, default in-memory). It is local to the shim, not stored in HMS.
  • Metadata filters: v2 syntax (AND/OR/NOT, eq ne gt gte lt lte in nin contains icontains, "*"). Entity ids and top-level equalities run in the service before ranking; every other term runs in the client on an over-fetched candidate list (overfetch * top_k, at most the service's --max-top-k, default 100), so such a query can return fewer than top_k results. top_k above max_fetch raises ValueError for search.

Limits

  • get_all needs enumeration, which the service does not have. Each record carries a hash bucket (_mem0_bucket, buckets of them, default 32). One query is tried first; if it hits the service's per-query cap, each bucket is queried, so up to buckets * max_fetch (3,200 by default) records per filter are reachable and a RuntimeWarning is raised if a bucket is itself full. Keep buckets constant for the life of a store. top_k is honoured (default 20). Tested at the cap minus one, at the cap, above it and at 2.5 pages with --max-top-k 10.
  • delete_all and reset have no such ceiling: they list and delete batch by batch until nothing remains.
  • The service accepts at most 64 KiB of text and metadata per record and ids of 256 bytes; mem0 ids are UUIDs. A memory with the same id replaces the old one (update is get, edit, replace).
  • No concurrency control: two writers updating one memory race, last write wins.
  • Memory ids are scoped by the HMS collection (default none) inside the tenant. Documents written by other clients lack the reserved keys and are invisible here.