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 anextractor, this shim stores each message verbatim (mem0'sinfer=Falsebehaviour) and emits aUserWarningonce per instance. Passextractor=LLMExtractor(chat_fn)(any chat function:chat_fn(messages) -> str, optionally async; its reply must be{"memory": [{"text": ...}]}) or anyextractor(messages, existing_texts, prompt) -> facts.strict_infer=Trueraises 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, norerankerprovider objects (pass a callable(query, results, top_k) -> results).explain=Truereturnsscore_details={"semantic": score}. - Not supported:
memory_type="procedural_memory"(raisesNotImplementedError),timestampandreference_date(raiseValueError, as mem0 OSS does), vision messages (non-string content is skipped),chat,project. - History is a SQLite file with mem0's
historyschema (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 thantop_kresults.top_kabovemax_fetchraisesValueErrorforsearch.
Limits¶
get_allneeds enumeration, which the service does not have. Each record carries a hash bucket (_mem0_bucket,bucketsof them, default 32). One query is tried first; if it hits the service's per-query cap, each bucket is queried, so up tobuckets * max_fetch(3,200 by default) records per filter are reachable and aRuntimeWarningis raised if a bucket is itself full. Keepbucketsconstant for the life of a store.top_kis 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_allandresethave 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 (
updateis 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.