This runner compares memo-stack / Infinity Context with mem0 using the same high-level pipeline used by public memory benchmark runners:
ingest -> search -> answer -> judge
It is separate from the existing public-benchmark command. The existing
runner checks retrieval and evidence coverage. This runner preserves each
pipeline stage for side-by-side accuracy, retrieval, latency, token/context and
failure analysis.
MEMORY_SERVICE_TOKEN=... \
MEM0_API_KEY=... \
MEMORY_OPENAI_API_KEY=... \
MEMORY_COMPARISON_ANSWERER_MODEL=... \
MEMORY_COMPARISON_JUDGE_MODEL=... \
MEMORY_COMPARISON_ANSWERER_INPUT_USD_PER_1M=... \
MEMORY_COMPARISON_ANSWERER_OUTPUT_USD_PER_1M=... \
MEMORY_COMPARISON_JUDGE_INPUT_USD_PER_1M=... \
MEMORY_COMPARISON_JUDGE_OUTPUT_USD_PER_1M=... \
python -m infinity_context_server.eval memory-comparison-benchmark \
--dataset ./datasets/locomo10.json \
--memo-api-url http://127.0.0.1:7788 \
--mem0-url http://127.0.0.1:8888 \
--mem0-api-key-env MEM0_API_KEY \
--benchmark locomo \
--locomo-ingest-mode official-turns \
--max-cases 20 \
--capability single-hop \
--top-k 200 \
--top-k-cutoff 10 \
--top-k-cutoff 20 \
--top-k-cutoff 50 \
--top-k-cutoff 200 \
--answerer-provider openai \
--judge-provider openai \
--answerer-input-usd-per-1m 2.50 \
--answerer-output-usd-per-1m 10.00 \
--judge-input-usd-per-1m 2.50 \
--judge-output-usd-per-1m 10.00 \
--allow-live \
--allow-paid-llm \
--run-id locomo-side-by-side-sandbox-001 \
--report-out .e2e-artifacts/memory-comparison-locomo.json--mem0-url is the self-hosted mem0 OSS REST server base URL. The adapter uses
the OSS endpoints POST /memories, POST /search and DELETE /memories; it
does not target the hosted mem0 Platform /v3 API.
For OSS search requests, the adapter sends scoped entity ids through filters
and sends both limit and top_k for the requested retrieval count, because
the lightweight mem0 wrapper accepts limit while the SDK-level API names the
same control top_k.
Memo-stack comparison requests use the hidden service-token
/v1/context/benchmark-search endpoint so top_k=200 is not silently reduced
by public API caps. The public /v1/context fallback is still capped to
max_facts <= 100, max_chunks <= 200 and token_budget <= 16000; report
metadata records limited_by_http_api_caps=true if that fallback is used.
Use deterministic answer/judge for a no-paid dry run by omitting
--answerer-provider openai, --judge-provider openai and --allow-paid-llm.
Do not use full LoCoMo as the normal development loop. Full LoCoMo is reserved for final reports or major milestones after fast gates are green. For retrieval, temporal and multi-hop work, use a small deterministic case set and a compact report first:
Run the sanitized preflight before touching live benchmark state:
MEMORY_SERVICE_TOKEN=local-dev-token \
python -m infinity_context_server.eval memory-comparison-benchmark \
--dataset ./datasets/locomo10.json \
--memo-api-url http://127.0.0.1:7788 \
--mem0-url http://127.0.0.1:8888 \
--benchmark locomo \
--locomo-ingest-mode official-turns \
--case-set locomo-fast \
--report-mode compact \
--top-k 200 \
--top-k-cutoff 10 \
--top-k-cutoff 20 \
--top-k-cutoff 50 \
--top-k-cutoff 200 \
--allow-live \
--preflight-onlyAdd --preflight-probe-services when Docker services are expected to be up.
The non-managed probe verifies the memo-stack API health endpoint at
--memo-api-url and the mem0 OSS OpenAPI contract for /memories and /search
at --mem0-url, so swapped ports fail before ingest or search state is touched.
For a managed mem0 benchmark runtime, set the non-secret marker
MEM0_BENCHMARK_REQUIRE_RUNTIME_CONTRACT=1 and configure the secret
MEM0_BENCHMARK_PROBE_TOKEN. The marker selects managed mode independently of
the secret, so a missing, empty or whitespace-only token fails before any HTTP
request. Preflight first sends a cryptographic nonce to
POST /benchmark/auth-challenge
using X-Benchmark-Probe-Token, verifies the nonce SHA-256 and response HMAC,
and only then runs the existing health/OpenAPI probes. The HMAC message is
exactly mem0-benchmark-auth-challenge.v1\n<nonce>. A missing token fails before
any service request. The credential-bearing challenge is allowed only for HTTPS
targets or loopback HTTP targets. Reports expose only readiness, reason codes,
path and status metadata, never the token, nonce or signature.
The LoCoMo dataset is not vendored in this repository; stage it at the path
passed to --dataset
or update that flag before treating preflight output as service readiness. The
preflight prints only boolean secret readiness, never token values. Treat
ready_for_locomo_fast=false as a blocker for the short LoCoMo fast run and
any longer LoCoMo run. For --locomo-ingest-mode official-turns, fast readiness
also requires an official LoCoMo-shaped JSON dataset with conversation session
turns and at least 10 scored QA cases in each requested fast group; arbitrary
non-LoCoMo JSON and underfilled groups leave ready_for_locomo_fast=false.
MEMORY_SERVICE_TOKEN=local-dev-token \
python -m infinity_context_server.eval memory-comparison-benchmark \
--dataset ./datasets/locomo10.json \
--memo-api-url http://127.0.0.1:7788 \
--mem0-url http://127.0.0.1:8888 \
--benchmark locomo \
--locomo-ingest-mode official-turns \
--case-set locomo-fast \
--report-mode compact \
--top-k 200 \
--top-k-cutoff 10 \
--top-k-cutoff 20 \
--top-k-cutoff 50 \
--top-k-cutoff 200 \
--allow-live \
--runtime-timeout-seconds 180 \
--run-id locomo-fast-sandbox-001 \
--report-out .e2e-artifacts/memory-comparison-locomo-fast.jsonLoCoMo fast case sets default to the same short internal runtime budget when
--runtime-timeout-seconds is omitted. If the gate exceeds that budget, the
runner writes a failed report with a runtime blocker instead of relying on an
external job timeout that can leave no artifact.
Fast case sets:
locomo-fast: 10 scored questions from each LoCoMo group.locomo-fast-temporal: 10 temporal questions.locomo-fast-single-hop: 10 single-hop questions.locomo-fast-multi-hop: 10 multi-hop questions.locomo-fast-open-domain: 10 open-domain questions.
--report-mode compact omits full per-case retrieval payloads and keeps metrics,
aggregate diagnostics and the first failure-analysis entries. Use
--report-mode full only when inspecting individual retrieved memories.
Fast gate for true top-k: with top_k=200, memo-stack metadata should show
benchmark_search=true, applied_max_facts=200,
applied_max_chunks=200, limited_by_http_api_caps=false, and top_50 should
not be identical to top_200.
For LoCoMo official-turn runs, the memo-stack benchmark backend also mirrors
memory-only input turns into raw-turn documents. That gives the retrieval layer
both canonical facts and chunk evidence from the same source conversation, so
hybrid/source-mix diagnostics can prove whether retrieval is using more than
postgres_facts. The fast gate is backend_metrics["memo-stack"]["source_mix_gate"]:
source_mix_ok=true, only_postgres_facts=false, and non-zero chunk/vector source
counts.
Temporal fast gate: official-turn memory metadata is copied into fact/document
source refs as time_start_ms/time_end_ms, and operation diagnostics expose
source_timestamp plus session fields. backend_metrics["memo-stack"] ["temporal_metadata_gate"]["temporal_metadata_ok"] must be true before tuning
temporal behavior. For temporal queries, memo-stack search metadata should also
show temporal_rerank.applied=true when timestamped evidence is present; boosted
items carry diagnostics.temporal_rerank_boosted=true.
Temporal query decomposition also adds session/date/time surfaces and avoids
treating calendar words like Friday as people. Sequence evidence with
session_4, date: or D4:3 gets a bounded temporal sequence boost.
Relative temporal evidence such as yesterday, today, tomorrow,
last week, next month or 2 weekends ago also gets the bounded temporal
text boost, because LoCoMo answers often depend on relative dates in dialogue
turns rather than absolute timestamps in the sentence itself.
Temporal search focus also carries bounded relative-date surfaces such as
last, today, yesterday, tomorrow, weekend and week, so lexical
backends can retrieve date-bearing dialogue turns before rerank sees them.
Typed time intent distinguishes duration, temporal_sequence,
relative_time, explicit_time and generic temporal_lookup, so diagnostics
can separate Friday/month evidence from yesterday/ago/last-week evidence.
Benchmark query decomposition and rerank gate: memo-stack expands the search
query into a bounded question-only fanout, merges/dedupes retrieved evidence,
and applies a benchmark-only rerank from the question text, not ground truth
answers. It boosts entity/action overlap, temporal surfaces, multi-query matches
and multi-hop support, then reports
backend_metrics["memo-stack"]["benchmark_rerank_gate"]. The gate should show
benchmark_rerank_ok=true and uses_ground_truth=false.
Multi-query candidate merging is handled by candidate_fusion.v1. It keeps the
best occurrence for each item/source-ref/text key, but adds bounded confidence
from repeated query hits, reciprocal-rank fusion and retrieval-source diversity.
The HTTP metadata still exposes the compatibility name multi_query_merge, but
the payload includes schema_version: candidate_fusion.v1 plus per-item
benchmark_candidate_fusion diagnostics.
When query-plan roles are available, fusion also records per-candidate
benchmark_query_roles, benchmark_bridge_query_hit and aggregate
query_role_counts, without adding a single-query score boost. This makes
bridge/temporal retrieval provenance visible in fast diagnostics while keeping
ranking changes tied to evidence strength.
The rerank implementation keeps separate responsibilities for candidate
feature extraction, final score/cap policy, focused intent policies and focused
evidence-shape policies, so new benchmark diagnostics can be added without
turning the main rerank path into a case-specific monolith.
Rerank scoring now also emits benchmark_rerank_policy.v2 diagnostics on each
boosted memory. The policy table breaks the final bounded boost into
EntitySpeakerPolicy, RelationCoveragePolicy, TemporalPolicy,
PreferenceIntentPolicy, FocusedTurnPolicy, EvidenceBundlePolicy,
AnswerabilityPolicy, MultiHopPolicy and ContrastIntentPolicy, including
per-policy reason codes.
Query fanout now emits query_plan.v2 diagnostics. The plan keeps bounded
question-only candidates with roles such as original_question,
expanded_focus, compact_relation, typed temporal support roles such as
duration_temporal_support, explicit_temporal_support,
relative_temporal_support and temporal_sequence_support,
visual_temporal_support, multi_hop_bridge and multi_hop_support, dedupes
equivalent queries, caps fanout by priority while preserving query-type
diversity, and records a leakage guard that forbids answer terms as planner
inputs. For question-marker multi-hop cases such as why and how, the bridge
query uses generic question-only bridge surfaces such as reason/process/support
plus grounded entity/relation terms, so bridge evidence can enter retrieval
without answer-key terms. If semantic candidates would fill the whole fanout,
the planner keeps room for lexical/raw-turn-oriented candidates and reports any
delayed roles under dropped_type_limit_roles.
Typed temporal query roles still include the generic temporal_support reason
code plus time_kind:<kind>, so diagnostics can group broad temporal behavior
or debug duration/explicit/relative/sequence gaps separately.
Query planning now starts from a typed retrieval_intent.v1 contract and then
renders the backwards-compatible query_profile dict used by older tests and
reports. The intent captures entity surfaces, speaker surfaces, relation
surfaces, typed relation facets such as preference, status_profile,
identity_profile, causal, support_goal, activity, exchange,
communication, temporal, visual and contrast, temporal kind, evidence
needs and risk flags from question-only signals. query_decomposition,
benchmark_rerank and query_integrity metadata expose this intent for
diagnostics, but query-integrity token overlap continues to score only the
explicit query/profile token fields. Quality
diagnostics also group fast-loop metrics by relation:<category>, so broad
evidence needs such as inference_support can be debugged by relation class.
Questions with compare/between/different/previous/former surfaces now carry
evidence_need=contrast, while plain current or still questions do not
become contrast queries by themselves. Contrast intent adds a bounded
contrast_support query-plan role that searches for current-vs-previous
evidence using question-only surfaces such as current, previous, before and
earlier, so old/new evidence can enter retrieval before rerank sees candidate
text.
Candidate features consume the same relation facets and report
relation_category_hits plus category coverage. RelationCoveragePolicy uses a
small bounded category-coverage boost only when the category hit is grounded by
relation evidence, so category labels do not lift generic mentions by
themselves.
Each reranked item now also carries candidate_evidence_features.v1
diagnostics. These features describe whether the item is a direct speaker turn
or broad summary, source-ref density, duplicate key, source type, retrieval
sources, relation coverage, temporal/visual/preference evidence flags and
focused-turn score. They also include a bounded answerability_score with
reason codes derived only from question intent and retrieved evidence:
entity/relation satisfaction, provenance, intent satisfaction and conflict or
broad-summary penalties. The score is diagnostic-first and the ranking boost is
eligible only when relation grounding is strong enough, so generic entity
mentions do not beat denser evidence. Text-derived contrast/currentness signals
are tracked separately as negation_surface, currentness_surface,
stale_surface and contrast_surface. Metadata-backed stale/conflict remains a
penalty, while textual "used to / but now / no longer / current" evidence can
be selected as contrast or temporal support instead of being treated as bad
evidence. The rerank policy consumes these typed features instead of recomputing
candidate facts inline, which makes the next evidence-bundle planner step
possible without adding more one-off scoring code.
For typed contrast questions, answerability also checks whether the retrieved
item carries explicit old-vs-current surfaces. Current-only evidence can remain
partial support, while before/previous plus current/now evidence satisfies the
contrast intent more strongly.
Candidate feature diagnostics also emit source_locality_score and locality
reason codes. Direct, narrow turn evidence scores higher than broad summaries
with many turn refs, so answerability and fast diagnostics can distinguish
precise provenance from wide "related turns" context without using answer keys.
Evidence bundles are now assembled by evidence_bundle_planner.v1 rather than
by inline top-k sorting. The planner deduplicates mirrored source refs, selects
one primary item, keeps specialized roles such as temporal_support,
contrast, bridge and entity_disambiguation, caps repeated generic source
types and repeated retrieval sources, then greedily prefers items that add
uncovered required refs or query-support terms before taking redundant
high-strength items. For multi-hop cases, bridge evidence is selected from
question-only support terms plus grounded entity/relation hits, so intermediate
facts can beat generic high-score context without using answer keys. It emits
reason codes plus role/source-type, retrieval-source and coverage counts in
evidence_bundle["bundle_planner"].
Bundle candidate eligibility also accepts feature-backed evidence that has
sufficient answerability, source locality and grounded entity/relation/temporal
or contrast signals, even when it has fewer than two query-support term hits.
This lets entity-disambiguation and temporal support reach the planner without
using expected answers. Query role labels alone are not enough to enter the
bundle. Selected bundle items include eligibility_reason_codes, so compact
reports can distinguish answer/evidence-term matches from feature-backed
selection.
Benchmark expected terms and LoCoMo evidence refs are post-hoc coverage labels
only: they are recorded on selected items and used by fast metrics, but they do
not make an item eligible, primary or stronger during bundle planning.
Question-support matching accepts safe morphology for single-word terms, for
example research matching researched or researching, so bundle selection
does not rely on exact inflection matches or judged answer labels.
Benchmark answer/judge adapters consume answer_context.v1, which is derived
from selected evidence-bundle items within the current cutoff. If no selected
bundle item is available for that cutoff, the adapter falls back to the raw
retrieval slice. Cutoff metrics keep memories_evaluated as the raw top-k count
and add answer_context diagnostics separately, so top-k gate checks remain
about retrieval breadth while prompts stay compact and evidence-first.
Backend metrics aggregate this as answer_context_metrics.v1, including
evidence-bundle context rate, fallback reasons, average context memory count and
context/raw compression ratio by cutoff. Answer-context diagnostics also report
source-ref counts and coverage rates, while quality diagnostics aggregate this
as answer_context_provenance.v1, so fast reports show whether selected
evidence actually reached the prompt-facing context with provenance intact.
Planned evidence prompt lines include the selected item role, original rank,
retrieval order, answerability, typed support counts such as bridge, contrast,
location, causal, inference, preference and visual, and planner reason codes,
so answer adapters see
provenance and evidence function without accessing benchmark labels.
If a grounded multi-hop bridge item also carries temporal/session surfaces, it
keeps the bridge role instead of being swallowed by temporal_support; a
plain bridge-query hit without entity/relation grounding remains ordinary
support. This keeps bundle completeness tied to evidence function rather than
query label alone.
Each retrieval payload also includes diagnostic-only query_integrity metadata
with expected-answer token overlap in terms added by query expansion and rerank
profile terms, excluding tokens already present in the original question. It is
computed after search and does not affect retrieval. Backend metrics aggregate
it under query_integrity_gate; use it to audit possible benchmark leakage
before full LoCoMo runs. The gate includes query-side overlap_token_total,
profile-side profile_overlap_token_total, and sample case lists with the
highest-overlap case ids and terms first, so fast runs identify which added
query or rerank-profile terms need review without changing retrieval behavior.
Evidence bundle diagnostics count LoCoMo evidence refs from retrieved
source_refs as well as text, so canonical facts and raw-turn chunks are scored
against the same D*:* support ids. Expected/evidence/support matching uses
normalized token boundaries, so diagnostics do not count substring accidents as
recall.
Action terms are expanded with question-only variants such as
research -> looked into/check out, so wording drift between a LoCoMo question
and the original dialogue is tested in the fast loop.
Compact queries also preserve common surface forms such as researching when a
lexical backend would otherwise miss a normalized stem-only query.
The same question-only normalization handles common LoCoMo typos and stems like
persue -> pursue, educaton -> education, decided -> decide and
planned -> plan.
Normalized stems remain internal rerank/profile signals. Outbound decomposed
search queries render full surface words such as figuring, registered,
dress and thrilled, so lexical backends do not have to match artificial
stem fragments like figur, register, dres or thrill.
Education/field queries also surface the dialogue-style edu abbreviation
when the question asks what field a person might pursue.
Preference and political queries keep dialogue-like surfaces such as fan,
rights and conservatives for lexical backends.
Named speakers also get a bounded boost when retrieved evidence is a direct
turn by the primary speaker in the question, for example D2:8 Caroline: ...,
rather than a third-party mention of the same name or a turn by another
mentioned person. Direct speaker evidence that also covers relation terms gets
an extra bounded relation boost, so a direct turn can beat a higher-raw-score
third-party topic mention without injecting answer text.
Focused dialogue turns with one or two D*:* refs get an additional bounded
granularity boost, while broad observation/event summaries do not. This helps
raw LoCoMo turns outrank wide session summaries when both mention the same
person and topic.
When a direct speaker turn covers three or more relation/profile terms, the
bounded cap is slightly higher for focused turns, because dense first-party
evidence is more trustworthy than repeated generic topic matches from broader
session chunks.
Excited/adoption/process questions also get a small focused-turn affect/outcome
boost when the turn itself combines question-derived affect and outcome surfaces
such as thrilled plus make/create. This lifts first-party "what are they
excited about" evidence without adding judged answer nouns to the query.
Song/enjoyment questions get the same treatment for focused turns that contain
question-derived preference surfaces such as fan plus like, so music-taste
evidence can beat generic love/like turns without adding answer terms like
classical or music.
Topic-like capitalized entities such as LGBTQ, Dr. Seuss, The Four Seasons or Vivaldi remain search terms but are filtered out of speaker
surfaces, so query expansion does not invent impossible speakers like
Vivaldi:. The compact relation fallback query uses speaker surfaces when they
are available, while the original and expanded queries still keep all topic
entities. This gives exact-title searches a chance without forcing fallback
queries to spend most slots on entities that the evidence may not repeat.
Common person aliases in LoCoMo-style questions are expanded before search, for
example Mel -> Melanie, so direct speaker evidence is not missed when a
question uses a nickname. Duration questions such as how long are treated as
temporal and can boost evidence containing 5 years, 2 months or similar
duration surfaces.
Question-provided numeric and ordinal tokens such as 4 or 18th are kept as
retrieval/profile terms, but answer-only numbers are not injected into search
queries. Compact temporal relation queries also keep concrete question surfaces
such as 4 year ago when they help bridge a relative-date question to a
source turn.
Current-friend duration questions expand current into known, year and
been, so evidence phrased as known these friends for 4 years is retrieved
without polluting ordinary friend-meeting queries.
Marriage-duration questions also expand married/marriage into wedding,
year, anniversary, bride and dress, so evidence phrased as 5 years already or a wedding caption can be retrieved even when it does not repeat
husband or married. The compact query prioritizes year, bride and
dress, and keeps already as a generic duration surface, before weaker
marriage terms for these duration cases.
Inference questions drop modal words from entity extraction, so Would Caroline
still searches for speaker/entity Caroline, not the impossible speaker
Would Caroline:. Preference questions such as more interested in... add
preference/outdoor surfaces and can boost direct preference evidence over a
generic mention of the alternative.
Profile and attribute questions add question-only topic surfaces for identity,
relationship status, books/bookshelf, political leaning and religion, so fast
LoCoMo cases do not collapse to a bare person-name query. Generic verbs such as
consider are dropped from the final relation subquery when a stronger topic
relation is present, so considered religious prioritizes religious/faith
evidence instead of generic consideration mentions.
Relationship-status questions use generic status surfaces such as parent,
breakup, family, kid, friend, support, challenge, dating,
partner and married without injecting the judged status word itself. The
compact query places those status surfaces before generic relationship/status
terms.
Identity profile questions expand into generic identity surfaces such as
support, inspiring, story, gender, accepted, courage, pride,
self, person, background and community, matching identity evidence
without injecting the judged identity phrase.
Political-leaning questions expand into non-answer domain surfaces such as
conservatives, rights, LGBTQ, transition, comment, upset, support,
social, activism and policy, so evidence phrased as rights or
conservative reactions can be retrieved without hardcoding the judged answer.
Religious-profile questions prioritize direct dialogue surfaces such as
church, religious conservatives, think, journey, changing and
acceptance before weaker generic faith terms, so church-art evidence is not
lost when it is phrased as a personal journey rather than a belief label.
Fast LoCoMo topic chains also expand adoption/agency/support, kids/preferences,
music/song and necklace/symbol questions with bounded, question-shaped surfaces.
Kids/preference queries use generic animal, bones, exhibit, learning,
children, family, preference, interest and like surfaces instead of
injecting concrete liked things.
Song queries use piece, composer, instrumental, orchestra and original
title/composer entities instead of injecting judged genre phrases such as
classical music.
Necklace/symbol queries use generic symbol/meaning/message/value plus
evidence-shape surfaces such as gift, grandma, roots, reminder,
family, support and special instead of injecting judged values such as
love, faith or strength. Symbolic-meaning evidence now has typed
diagnostics and a bounded rerank signal only when a meaning surface such as
represent, symbol, mean or reminder appears with object context such as
necklace, gift, grandma or root.
Relation hits are deduped before rerank, and dense topic evidence can get a
bounded relation boost even when the evidence sentence does not repeat the named
person.
Adoption-agency support questions can still use support-shaped surfaces such as
folks, help, LGBTQ and inclusive when the question itself asks who the
agency supports. Choice/reason questions use generic reason, cause, fit,
value, spoke and decision surfaces instead of injecting the judged reason.
The rerank profile applies the same filter, so support/inclusivity terms do not
silently affect benchmark-only reranking for choice/reason questions.
Adoption-process excitement questions prioritize action/process surfaces such as
make, create, thrilled and process before generic agency/support
surfaces, without injecting judged family/kids wording into search or rerank.
Adoption-decision reaction questions prioritize generic reaction surfaces such
as reaction, response, opinion, feel, lovely and luck rather than
injecting judged sentiment words like amazing, awesome or mom. The compact
query keeps think and family context while moving generic decision/adopt
terms behind reaction signals.
Emotion-response questions that explicitly ask how someone felt or what they
were excited about now expose a typed emotion_response facet. Candidate
answerability requires actual emotion/response evidence such as felt,
reaction, nervous, thrilled or upset, and topic-only direct turns get a
bounded missing-emotion cap instead of satisfying the question through entity and
topic overlap alone.
Generic activity questions render non-answer activity-family surfaces such as
hobby, partake, class, paint, swim, run, violin, kid, photo,
creative, fun, express, refresh, therapeutic, pastime and leisure
instead of injecting concrete per-case answer tuples. Specific activity terms
are still used when they are present in the question itself, for example a
pottery signup date question.
Camping-place questions add generic camping context such as family, unplug,
connection and close, while avoiding judged location terms like beach,
mountains or forest.
Bookshelf questions include generic books, kids, stories, reading and
bookshelf surfaces, while keeping title/person entities from the original
question. They avoid injecting judged genre phrases such as classic children.
Book/read questions also render reading as an outbound surface, so evidence
phrased as loved reading... is reachable without relying on backend stemming.
Writing/career and counseling inference questions also get explicit
question-only surfaces such as write, writing, looking, book, books,
job, jobs, option, support, similar and issue, so open-domain
LoCoMo cases do not rely only on generic pursue/career terms or injected
answer wording.
Writing/career rerank also gives a focused-turn affinity boost when retrieved
evidence contains safe book/read signals plus guide, motivate or discover;
it does not add answer-side reading terms to the outbound query. Retrieved
focused turns that explicitly mention an alternative counseling or mental-health
jobs path get an evidence-only career-contrast boost, while those counseling
terms are not injected into the query profile.
Several LoCoMo inference rerank boosts are evidence-only and do not change the
outbound query: durable outdoor preference turns (always look forward,
highlight, meteor memories), support-motivation turns (support I got,
huge difference, improved my life), direct research-goal turns, visual
identity turns, political-context turns, adoption-agency support turns and
conference-plan time turns, plus relationship-status context turns with breakup,
family, parenting or support context. These boosts only apply to focused direct
turns with matching question-derived relation terms.
Focused evidence-shape boosts also cover kids preference evidence, explicit
bookshelf collections, personality-trait reactions, bad roadtrip incidents,
charity-race self-care realizations, adoption-decision reactions, friend-duration
answers, birthday-memory turns, broad activity coverage, destress-running
evidence and career-contrast evidence. The fast gate expects these signals to
lift the exact evidence turn without changing the query integrity report.
Broad activity coverage includes evidence-only surfaces such as painting,
swimming, running/reading/violin and camping/unplug turns, so generic activity
questions can keep multiple distinct activities in the short context window.
Career/education questions expand career, field and path into safe work
surfaces such as work, working, profession, job, option, support,
similar, issue and keen, matching official evidence wording like career options, working with... or support those with similar issues without
hardcoding the answer. Field/pursue and career-path compact queries prioritize
those work/support surfaces before weaker school-like terms such as study.
Career-path questions also include broad decision wording such as think and
figure, so evidence phrased as thinking of working... or figuring out the details is reachable without adding answer-specific career labels. The compact
career-path query promotes these support surfaces before weaker base action
terms such as decide/pursue.
Counterfactual support questions preserve question-only surfaces such as
received, got, help, support, growing, journey and childhood, so
retrieval can find causal support evidence instead of only generic
counseling/career mentions. Their compact query prioritizes got/help/growing
before weaker pursue/receive/grow base terms.
Other open-domain fast cases avoid name-only search by adding question-only
surfaces for personality/trait/describe and
roadtrip/accident/son/family/safe/trip/past/weekend/soon, without hardcoding
expected answer words.
Personality-trait questions also add generic trait evidence surfaces such as
care, real, help, drive, concern and thank, matching LoCoMo praise
phrased as care about being real, drive to help or thank you for your concern without injecting the expected answer tuple.
Preference questions involving parks expand park into enjoy, nature,
camping, trip, campfire, marshmallow, story, meteor, sky, summer,
hike and trail, so national-park evidence expressed as camping-trip,
campfire or meteor-shower memories is still retrieved.
Hike-count questions treat hike as activity evidence and add generic
occurrence surfaces such as trail, waterfall, went, spot, weekend and
summer, so repeated hike turns can beat generic hiking-topic mentions without
adding answer numbers.
Future home-move desire questions use generic current-goal surfaces such as
goal, hope, plan, future and soon, and do not require
location_support unless the question asks where, from or origin. This keeps
old origin evidence from satisfying current-goal inference without adding
answer-specific judged outcomes.
Self-care prioritization questions render generic wellness surfaces such as
routine, refreshes, present, balance, rest, relax and wellness,
instead of injecting specific hobbies from the judged answer.
Summer-plan questions prioritize generic planning rationale surfaces such as
dream, family, loving, home, future, upcoming, season, goal,
want and going, instead of injecting concrete plan contents like
researching adoption agencies. The agency -> agencies query alias remains
available only when agency is already a question-derived term.
Temporal event questions add action surfaces such as run/race/charity/last,
meet/friends, speech/school/event/talk, sign/signed/class/pottery,
go to/support group/went, move/home/country/relocated,
conference/month/community and
destress/stress/relax/unwind/class/clear/mind/headspace/run/farther,
so date questions do not collapse to person + when + date only.
Temporal rerank evidence distinguishes spoken/content time surfaces from
provenance-only labels such as date: or turn references, so a topic-only
timestamped memory does not satisfy temporal support without actual temporal
content such as yesterday, an explicit day/month/year, or a duration.
Registration paraphrases such as register and enroll share typed event
surfaces with sign up, including signup, class, course, lesson and
workshop, so class-registration evidence can outrank sign or schedule
distractors without adding the requested date or specific class answer.
Participation paraphrases such as visit, attend, join and participate
also get typed event/place surfaces, so evidence like visited the studio or
joined the group can be distinguished from topic-only studio/group mentions.
When a question is both temporal and visual, the bounded fanout prioritizes a
combined query such as person + paint + sunrise + when + date before generic
person + when + date. Paint/image date questions also render painting and
caption as outbound surfaces, so caption evidence phrased as a painting of... can match without requiring the backend to stem paint. Entity-less
relation questions, for example charity race awareness, still get an action-only
subquery and relation boost. Raise-awareness queries render raising/raised
surfaces so lexical retrieval can match common morphology around raising awareness.
Follow-up event questions such as What did Melanie realize after the charity race? add generic realize/lesson/reflection/thought/event/journey surfaces
instead of injecting the realized conclusion. Direct-speaker relation evidence
gets a higher bounded rerank cap so exact evidence can beat a higher raw-score
registration or topic distractor. Dense relation coverage also gets a small
bounded boost when one memory covers many question-derived relation and variant
terms, or multiple high-signal topic terms such as LGBTQ rights and
conservative.
Standalone years such as 2022 count as temporal evidence surfaces, and dated
temporal evidence gets a higher bounded rerank cap so repeated generic matches
do not beat specific dated evidence.
Visual/image questions add image/photo/show query surfaces and boost retrieved
caption evidence such as Sharing image or image shows, so LoCoMo image
answers do not lose to generic topic mentions. Paint/sunrise date questions also
get relation boost from question terms, while generic painting questions do not
inherit sunrise unless it appears in the question.
Evidence recall is aggregated at backend_metrics[*]["evidence_term_recall"]
and in each by_group bucket when LoCoMo evidence ids are available. Use this
as the primary fast-loop quality number before looking at LLM answer accuracy.
Evidence and expected-term matching is punctuation-insensitive for benchmark
diagnostics, so LGBTQ+ individuals and LGBTQ individuals count as the same
retrieved evidence phrase.
Multi-hop fast gate: each evaluation includes an evidence_bundle with primary
and supporting retrieved items. For category 1 LoCoMo cases,
backend_metrics["memo-stack"]["multi_hop_bundle_gate"] reports bundle
completion rate, average supporting evidence count and bundle evidence recall.
Bundles also include question-only query_support_terms and
query_support_term_recall, so fast reports show whether retrieved memories are
useful support for the asked question even before LLM answer scoring.
backend_metrics["memo-stack"]["evidence_ref_rank_gate"] reports how many
scored evidence-ref cases have all required refs in top1/top2/top3/top5 planned
bundle items, plus focused top5 coverage. Use this before full LoCoMo because
it shows retrieval position failures directly.
backend_metrics["memo-stack"]["quality_diagnostics"] emits
quality_diagnostics.v2: per-intent accuracy/recall, bundle-incomplete reason
counts, policy contribution totals, false-positive categories and query leakage
samples. This is the main debugging table for deciding the next retrieval fix
without rerunning full LoCoMo.
It also includes evidence_feature_table, aggregating candidate feature
surfaces across retrieved items: direct speaker turns, broad summaries,
contrast/currentness/negation/stale surfaces, source-type counts,
retrieval-source counts, answerability-score average and answerability reason
counts. This makes fast runs show whether failures come from missing evidence,
weak provenance, one retrieval path dominating the bundle or evolving-fact
handling.
query_role_effectiveness_table compares query-plan roles across retrieved
candidates and selected bundle items. It reports candidate counts, lifted counts,
selected-item counts, selection/lift rates, selected bundle roles and
bridge-query-hit counts per role. Use it to see whether roles such as
multi_hop_bridge, duration_temporal_support,
relative_temporal_support, explicit_temporal_support or
contrast_support are producing selected evidence or only retrieval noise.
The same table also emits role-family counts, grouping typed temporal roles
back under temporal_support for high-level fast-gate reading.
bundle_quality_table aggregates the planner's evidence_bundle_quality.v1
payload across the run: confidence-band counts, average confidence, average risk
penalty, bridge, location, contrast and source-proximity evidence counts, risk
reason counts and compact weak samples. This keeps the fast loop focused on
evidence-package quality even when a bundle is technically complete.
Fast-gate payloads also expose compact bundle_support_counts and
bundle_support_bundle_counts, so short runs show whether bridge, causal,
inference, location, preference, visual, contrast and source-proximity support
actually reached selected bundles.
The same diagnostics include rerank_lift_table, a candidate-level explanation
of why retrieved memories were lifted. It counts positive score signals, active
policy names, policy reason codes, relation-category hits, low-answerability
lifts, broad-summary lifts and conflict/stale lifts, plus compact samples with
case id, item id, rank, score, source type and policy reasons. Samples
intentionally omit full memory text, so compact fast reports can be inspected
for ranking mistakes without copying source content into the aggregate table.
backend_metrics["memo-stack"]["fast_gate"] emits fast_gate.v1 with explicit
locomo-fast thresholds: zero query/profile leakage, all refs top5 40/40,
focused refs top5 40/40, all refs top3 at least 39/40, top2 at least 36/40,
top1 at least 30/40 and evidence bundle complete 40/40. Do not start full
LoCoMo while ready_for_full_locomo=false. When bundle-quality payloads are
present, the gate also requires quality diagnostics for every fast case and a
medium/high bundle-quality band for every fast case, so weak complete bundles
cannot silently pass the fast loop. The same fast-gate payload includes
bundle_gap_breakdown.v1, which surfaces incomplete-bundle reason counts and a
filtered bridge-gap view for missing_bridge, bridge entity/relation gaps,
temporal bridge gaps and weak source locality. Use this as the next-action map
when evidence_bundle_complete or bundle quality blocks full LoCoMo.
Fast gate also includes query_role_gap_breakdown.v1, a compact diagnostic
derived from query_role_effectiveness_table. It reports candidate roles that
were retrieved but not lifted, not selected into the evidence bundle, or had
bridge-query hits that never reached selected evidence. This is diagnostic-only,
not a hard gate, and should guide the next planner/rerank fix when roles such as
typed temporal support roles or multi_hop_bridge produce candidates but
disappear before bundle assembly. For contrast cases, it should show whether
contrast_support candidates are retrieved but then lost before bundle
selection.
Query support terms include expanded entity surfaces such as Mel -> Melanie,
and bundle items are ordered primary evidence first, then by bounded bundle
strength, while preserving the original retrieval rank in each item. The primary
bundle item is selected after scoring all candidates, so a stronger lower-ranked
piece of evidence can become primary instead of locking the first weak evidence
hit as primary. Primary selection now considers answerability after direct
focused evidence, so a source-backed candidate that can actually support an
answer wins ties over a weaker overlap-only candidate.
Evidence bundles deduplicate mirrored fact/raw-turn hits by source refs, using
order-insensitive unique source-ref sets, and fall back to normalized text when
source refs are absent. This prevents the memo-stack official-turn mirror from
inflating multi-hop bundle completeness by counting the same retrieved turn
twice.
Bundle planner diagnostics also include bundle_quality with
evidence_bundle_quality.v1. It scores the selected evidence package, not the
answer: primary/support presence, focused or direct-speaker evidence, source-ref
provenance, source/retrieval diversity and answerability raise confidence;
low-answerability, broad-summary-only and conflict/stale evidence add explicit
risk reason codes. Use this with rerank_lift_table to catch cases where a
bundle is technically complete but too weak or too broad for reliable answering.
Use replay when retrieval is already captured and you only want to compare
answerer, judge, cutoff logic or prompt changes. Replay never calls memo-stack or
mem0, so it does not require --allow-live, MEMORY_SERVICE_TOKEN,
MEM0_API_KEY or Docker services:
python -m infinity_context_server.eval memory-comparison-replay \
--report .e2e-artifacts/memory-comparison-locomo-fast-full.json \
--report-mode compact \
--top-k-cutoff 10 \
--top-k-cutoff 20 \
--top-k-cutoff 50 \
--top-k-cutoff 200 \
--primary-cutoff 200 \
--run-id locomo-fast-replay-001 \
--report-out .e2e-artifacts/memory-comparison-locomo-fast-replay.jsonReplay requires a full source report because compact reports intentionally omit the per-case retrieval payloads needed by answerer and judge experiments.
For local manual runs without an OpenAI API key, use Codex CLI as the answerer and judge:
MEMORY_SERVICE_TOKEN=local-dev-token \
python -m infinity_context_server.eval memory-comparison-benchmark \
--dataset ./datasets/locomo10.json \
--memo-api-url http://127.0.0.1:7788 \
--mem0-url http://127.0.0.1:8888 \
--benchmark locomo \
--locomo-ingest-mode official-turns \
--max-cases 20 \
--top-k 200 \
--top-k-cutoff 10 \
--top-k-cutoff 20 \
--top-k-cutoff 50 \
--top-k-cutoff 200 \
--answerer-provider codex \
--judge-provider codex \
--answerer-model gpt-5.5 \
--judge-model gpt-5.5 \
--codex-timeout-seconds 180 \
--allow-live \
--run-id locomo-side-by-side-codex-sandbox-001 \
--report-out .e2e-artifacts/memory-comparison-locomo-codex.jsonThe Codex provider shells out to codex exec with --ephemeral,
--ignore-user-config, --ignore-rules, --sandbox read-only and
approval_policy="never". It uses only prompt evidence and estimates token
usage locally because Codex CLI does not expose benchmark token usage through
this adapter.
For the pinned setup, explicit env -u safety, preflight, 8-case/32-call
command, resource floor and publication limits, follow
Mem0 OSS No-Key Canary.
MEM0_API_KEY is not required for an engineering canary against a local
Mem0 OSS server whose ingress authentication is explicitly disabled. Leave the
variable unset, point --mem0-url at that isolated server, and keep
--answerer-provider codex plus --judge-provider codex so answer and
judge calls use the Codex subscription runtime instead of an OpenAI API key.
The local Mem0 process still needs extraction and embedding providers. Configure
both with local models, for example Ollama, before running the live canary. Do
not silently fall back to an external provider key. Start with the bounded
8-case canary and the normal --allow-live safety gate; do not run full
LoCoMo or LongMemEval as a development loop.
This no-key route proves the HTTP pipeline and local OSS behavior, but it is not
an authoritative Mem0 Platform comparison. The tracked
benchmarks/mem0-platform-adapter still requires an account-issued upstream
MEM0_API_KEY; the key cannot be generated locally. Use Platform or a frozen,
identical OSS model/runtime stack before publishing an apples-to-apples quality
claim.
Decision rule:
- offline/mock tests: no Mem0 key and no real Mem0 backend;
- local auth-disabled Mem0 OSS: no Mem0 key, local extraction and embeddings;
- hosted Mem0 Platform: upstream
MEM0_API_KEYis mandatory; - Codex subscription replaces answer/judge credentials only, not Mem0 Platform credentials or a local OSS extraction/embedding provider.
infinity-context-managed-live-canary is the executable, fail-closed managed
canary entrypoint. It is deliberately separate from the plain local Mem0 OSS
lane above. The managed target must implement the benchmark challenge, runtime
attestation, witness, lifecycle and cleanup contracts used by the production
runner. A stock auth-disabled Mem0 OSS server is not sufficient.
Run infinity-context-managed-production-pre-readiness first. Notify the
operator who owns subscription capacity, review its bounded plan, and only then
run the live command with all three acknowledgements:
env -u MEM0_API_KEY \
infinity-context-managed-live-canary \
--dataset /private/official-locomo10.json \
--profile mem0-locomo-top200-v1 \
--case-id '<official-case-id>' \
--run-id managed-locomo-canary-001 \
--infinity-api-url http://127.0.0.1:7788 \
--mem0-api-url http://127.0.0.1:8888 \
--subscription-runtime-url http://127.0.0.1:8890 \
--max-total-tokens 250000 \
--mem0-runtime-implementation-sha256 '<reviewed-adapter-sha256>' \
--allow-live \
--allow-paid-llm \
--operator-notified \
--mem0-local-auth-disabled-managed \
--allow-mem0-host 127.0.0.1--subscription-runtime-url is a pathless loopback origin such as
http://127.0.0.1:8890. The CLI appends /v1/chat/completions itself, so do
not pass /v1 or a specific endpoint. This differs from the adapter's
MEM0_OSS_SUBSCRIPTION_BRIDGE_URL, which is an OpenAI-compatible bridge base
URL and therefore includes /v1, for example http://127.0.0.1:19090/v1.
Required private environment values are MEMORY_EVAL_AUTH_TOKEN (or
MEMORY_SERVICE_TOKEN), MEM0_BENCHMARK_PROBE_TOKEN, and
SUBSCRIPTION_RUNTIME_BRIDGE_BEARER_TOKEN. MEM0_API_KEY is also required
unless --mem0-local-auth-disabled-managed is set. That exception is accepted
only for an explicitly listed numeric IPv4 loopback host such as
--allow-mem0-host 127.0.0.1; localhost and IPv6 targets are rejected. In
this keyless lane the CLI ignores an ambient MEM0_API_KEY; use env -u MEM0_API_KEY to make the operator intent explicit. It denotes an auth-disabled
managed wrapper with the full runtime contract, not ordinary OSS. The CLI never
reads an OpenAI API key.
The canary accepts one to eight unique cases, reserves four benchmark provider
calls per case, performs exactly one separate readiness attempt, caps benchmark
tokens at 2,000,000 and sets an admission deadline of at most two hours. An
adapter request already in flight is not preempted by that deadline; it remains
bounded by its request timeout. --operator-notified is an operator
acknowledgement, not a sealed proof that binds the reviewed pre-readiness plan.
Every run reports publishable=false. Any missing flag, credential, exact
dataset binding, readiness proof, runtime attestation or cleanup evidence fails
closed.
The managed public report contains a recomputed paired_quality proof only
after the judge outcomes are sealed against the exact execution manifest. It
reports per-backend total, correct, and accuracy; paired memo-stack win,
tie, and mem0-win counts; accuracy delta; exact lane coverage; the manifest and
judge-outcome hashes; and a deterministic completeness commitment.
It never returns case aliases, real case IDs, questions, gold answers, candidate answers, raw judge output, or individual judge-result hashes. A missing, duplicate, mismatched, or score/verdict-inconsistent lane fails the projection. The report recomputes these aggregates rather than accepting a serialized aggregate from a runner or adapter.
Model defaults:
--answerer-provider codexand--judge-provider codexdefault togpt-5.5, orMEMORY_COMPARISON_CODEX_MODELwhen set.- mem0's benchmark README lists common benchmark defaults as
gpt-4ofor answerer/judge, while its published OSS extraction-model LongMemEval table says those runs used GPT-5 as answerer and judge. - Local Codex accounts may not expose literal
gpt-5; if so,gpt-5.5is the closest currently usable Codex-side approximation, not an exact reproduction.
--locomo-ingest-mode rich-documentsis the default legacy mode. It uses the normalized public benchmark documents, including derived LoCoMo observations, summaries and per-turn documents. This is useful for retrieval canaries but is heavier than mem0's official LoCoMo runner.--locomo-ingest-mode official-turnsis the mem0-style mode for officiallocomo10.json: one chronological conversation turn becomes one ingest memory/message chunk, image captions and visual queries are appended like the official mem0 runner, and session dates are embedded in the turn text. By default the adapter does not send the separatetimestampparameter because current mem0 OSSMemory.addrejects it without the mem0 temporal API path. Use--mem0-send-timestampsonly when the target mem0 wrapper supports it.
--allow-liveis required before the command calls memo-stack or mem0 HTTP endpoints.--preflight-onlyprints sanitized dataset, auth, URL, LLM and fast-readiness checks without ingesting, searching or resetting live benchmark state.--preflight-probe-servicesadds unauthenticated memo-stack health and mem0 OSS OpenAPI contract probes when local Docker services should already be running.MEM0_BENCHMARK_REQUIRE_RUNTIME_CONTRACT=1activates the managed runtime contract independently of its secret. Accepted true values are1,true,yesandon; false values are0,false,noandoff. Invalid marker values fail closed.MEM0_BENCHMARK_PROBE_TOKENsupplies the auth-challenge secret. Its key presence also selects managed mode defensively, including when its value is empty or whitespace-only, so malformed secret configuration cannot silently fall back to the unauthenticated OSS probe.- Managed mode without
--preflight-probe-servicesfails closed. --allow-paid-llmis required before OpenAI answerer or judge calls.--answerer-provider codex/--judge-provider codexdo not require--allow-paid-llmor an OpenAI API key, but they do consume the local Codex account/session quota.- OpenAI models are explicit: pass
--answerer-model/--judge-modelor setMEMORY_COMPARISON_ANSWERER_MODEL/MEMORY_COMPARISON_JUDGE_MODEL. - OpenAI key is read from
MEMORY_OPENAI_API_KEYby default, withOPENAI_API_KEYas fallback. Do not commit keys or generated raw provider payloads. - Codex mode only replaces the benchmark answerer/judge. A self-hosted mem0 OSS backend still needs its own extraction and embedding providers. The mem0 default uses OpenAI; for a fully no-OpenAI run, configure mem0 with a local provider such as Ollama and make sure the required local models are running.
- Optional mem0 OSS API key is read from
MEM0_API_KEYby default and sent asX-API-Keywhen present. Leave it unset only for explicitly auth-disabled local mem0 servers. - By default the runner deletes the isolated mem0
user_id/run_idbefore ingest. That mem0 endpoint requires an admin-capable key orAUTH_DISABLED=true. If you only have a non-admin API key, pass--mem0-skip-resetand use a fresh--run-idso the run still uses isolated state. - Token cost reporting uses explicit USD-per-1M-token rates from CLI flags or
MEMORY_COMPARISON_*_USD_PER_1Menv vars. The runner does not hardcode provider prices. - Token cost scope is answerer/judge only. Backend-internal ingest/search provider costs are reported as unmeasured because they are not observable through the generic HTTP comparison ports.
- The memo-stack backend isolates state with a run-specific benchmark space.
- The mem0 backend uses a run-specific
user_id/run_idand deletes that isolated user/run at startup by default. - The mem0 ingest payload includes source metadata such as
source_external_id,source_id,session_keyanddia_idwhen available. If the mem0 server returns that metadata on search, the report can compute evidence-ref diagnostics on the mem0 side too. - Corpus reuse is keyed by memory scope, thread and source content fingerprint; failed ingests are not cached for later questions in the same conversation.
- Any nonzero backend
items_failedingest result is scored as aningest_failedstage failure and does not proceed to search for that case.
The JSON report includes:
- per-backend accuracy and category/group breakdown;
- LoCoMo category 5 reported in
by_categorywith unscored counts but excluded from scored accuracy; - retrieved memory count, retrieval recall and missing expected terms;
- ingest/search/generation/judge latency averages;
- context token estimates, answerer/judge token usage and configured token cost;
- memo-stack vs mem0 deltas for accuracy, retrieval recall, retrieved count, latency, context tokens and token cost;
- configured top-k cutoff metrics, with pre-cutoff stage failures counted as failed scored cases;
- per-case failure analysis with backend, group, score, retrieval recall and missing terms;
- backend reset/ingest/search/answer/judge exceptions as scored stage failures with redacted error metadata.
- failed HTTP ingest operations include status code, reason phrase and a short redacted response preview when the backend returns one.