Skip to content

Fix mem0 search returning nothing, and the OSS extractor on transformers 5.x - #50

Merged
matrixarkai merged 2 commits into
mainfrom
oss/mem0-search-and-oss-extractor
Aug 19, 2026
Merged

Fix mem0 search returning nothing, and the OSS extractor on transformers 5.x#50
matrixarkai merged 2 commits into
mainfrom
oss/mem0-search-and-oss-extractor

Conversation

@bjmeetsfo

Copy link
Copy Markdown
Collaborator

Three defects found by calling every public API end to end — all 39 MCP tools and all 11 mem0.Memory methods — against a real store and the real /v1 gateway ASGI app, rather than the stub gateway the existing tests use.

1. mem0.search() returned nothing, for every query

_reshape_search_results reads selected_refs. A ContextPack now serves its refs groupedgroups: [{type, n, items: [{text, ...}]}] — and emits no selected_refs key at all. So mem0's primary read API returned {"results": []} on a store that plainly had matching content (search_raw showed it).

Both shapes are accepted now. A group's type is carried into each item's metadata as ref_type, so callers keep the event/entity distinction the flat shape gave them.

2. mem0.search() results were not addressable

Fixing (1) exposed this. Group items carry no id — source_ref is deliberately classified as debug-only lineage and stripped from serving items — so results got synthetic ref-N-… ids. Feeding those back into get / update / delete, which is mem0's documented flow, failed with found: false, HTTP 500, and deleted: false.

Real ids are recovered from get_all by exact text match: one extra request, made only when a synthetic id is actually present. Items that match nothing keep the synthetic id on purpose — a derived entity ref ("preference: drink is matcha") is a projection of a memory, not an addressable memory, and inventing an id for it would only move the failure downstream.

3. The OSS causal-LM extractor could not run on transformers ≥ 5

apply_chat_template(..., return_tensors="pt") returns a BatchEncoding on transformers 5.x where it used to return a bare tensor. The result was passed positionally into generate(), which read .shape off a dict-like and raised a bare AttributeError with no indication of the cause — segment_provider=oss was simply unusable.

Both shapes are accepted now. Verified against Qwen2.5-7B-Instruct on transformers 5.15.0.

Why the tests missed all three

test_mem0_complete.py exercises the mem0 client against a stub BaseHTTPRequestHandler that returns hand-written selected_refs payloads, so it only ever tested request shaping and never saw a real pack. Nothing at all covered oss_model_memory_segments.

Verification

  • 8 tests added. 4 of the mem0 tests and 2 of the extractor tests fail on the unfixed code, with the original errors.
  • Full mem0 + extractor suite on this branch: 29 passing.
  • API sweep: 53/53 (39 MCP tools + 11 mem0 methods + variants), against a real store and the real gateway.
  • Correctness checks on retrieve/search beyond non-emptiness — grounding, per-user scoping in both directions, id resolution, limit, and agreement between search and search_raw: 13/13.

🤖 Generated with Claude Code

…ers 5.x

Three defects found by calling every public API end to end against a real store
and the real /v1 gateway, rather than the fake gateway the tests use.

mem0 search() returned {"results": []} for EVERY query. _reshape_search_results
reads `selected_refs`, but a ContextPack now serves its refs GROUPED --
groups: [{type, n, items: [{text, ...}]}] -- and emits no `selected_refs` key at
all. mem0's primary read API therefore returned nothing while search_raw plainly
showed content. Both pack shapes are now accepted; a group's `type` is carried
into each item's metadata as `ref_type` so callers keep the event/entity
distinction the flat shape gave them.

mem0 search() results were not addressable. Fixing the above exposed it: group
items carry no id, because `source_ref` is classified as debug-only lineage and
stripped from serving items, so results got synthetic `ref-N-...` ids. Feeding
those back into get/update/delete -- mem0's documented flow -- failed with
found:false, HTTP 500 and deleted:false. Real ids are now recovered from
get_all by exact text match: one extra request, made only when a synthetic id is
actually present. Items that match nothing keep the synthetic id on purpose, as
a derived entity ref ("preference: drink is matcha") is a projection of a memory
rather than an addressable memory.

The OSS causal-LM extractor could not run at all on transformers >= 5.
apply_chat_template(..., return_tensors="pt") now returns a BatchEncoding rather
than a bare tensor, and the result was passed positionally to generate(), which
read .shape off a dict-like and raised a bare AttributeError. Both shapes are
accepted now. Verified with Qwen2.5-7B-Instruct on transformers 5.15.0.

Tests: 8 added. 4 of the mem0 tests and 2 of the extractor tests fail on the
unfixed code with the original errors. The existing mem0 suite exercised the
client against a stub HTTP handler returning hand-written selected_refs, so it
only ever tested request shaping and could not see either search defect.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@bjmeetsfo
bjmeetsfo requested a review from superhaiou as a code owner August 19, 2026 00:31
one_pass_memory_extraction falls back to the deterministic rules when the
configured LLM provider raises, which is the right behaviour. But the result it
returned still carried understanding_provider: <the configured provider>, so the
payload claimed an LLM had produced entities that rules had actually produced.

That is not a cosmetic label. The extraction client timeout is 30s by default
(MATRIXARK_EXTRACTION_TIMEOUT_SEC) and a 7B model on CPU needs minutes per call,
so every call times out, silently falls back, and reports success with the LLM's
name on it. Measuring "LLM extraction quality" against such a store measures the
deterministic path instead -- which is exactly what happened here before the
timeout was traced: a full quality run attributed to Qwen2.5-7B had in fact made
zero successful model calls.

The fallback now reports understanding_provider: "deterministic" and records what
was asked for and why it failed, in understanding_provider_requested and
understanding_provider_error. Callers that never inspected those fields are
unaffected; callers that trusted understanding_provider now get the truth.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@matrixarkai
matrixarkai merged commit 1cf1fc4 into main Aug 19, 2026
3 of 5 checks passed
@matrixarkai
matrixarkai deleted the oss/mem0-search-and-oss-extractor branch August 19, 2026 01:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants