memtrust-cli 0.3.1__tar.gz → 0.3.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- memtrust_cli-0.3.3/.gitignore +34 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/CHANGELOG.md +69 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/CONTRIBUTING.md +43 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/PKG-INFO +174 -88
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/README.md +170 -84
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/docs/methodology.md +152 -24
- memtrust_cli-0.3.3/leaderboard/data.json +75 -0
- memtrust_cli-0.3.3/leaderboard/mem0_direct-2026-07-20.json +300 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/npm/memtrust-cli/package.json +7 -7
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/pyproject.toml +20 -4
- memtrust_cli-0.3.3/src/memtrust/__init__.py +26 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/adapters/mem0_direct_adapter.py +53 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/cli.py +60 -9
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/tests/test_cli.py +95 -1
- memtrust_cli-0.3.3/tests/test_init.py +67 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/tests/test_mem0_direct_adapter.py +48 -0
- memtrust_cli-0.3.1/.gitignore +0 -28
- memtrust_cli-0.3.1/leaderboard/data.json +0 -60
- memtrust_cli-0.3.1/src/memtrust/__init__.py +0 -11
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/.github/CODEOWNERS +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/.github/workflows/ci.yml +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/.github/workflows/publish-pypi.yml +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/.pre-commit-config.yaml +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/LICENSE +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/SECURITY.md +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/docs/assets/dev-to-demos/demo-1-zero-credentials.gif +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/docs/assets/dev-to-demos/demo-2-fictional-api-discovery.gif +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/docs/assets/dev-to-demos/demo-3-cli-surface.gif +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/docs/assets/dev-to-demos/demo-4-temporal-kg-tests.gif +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/docs/demo.gif +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/docs/usage.gif +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/leaderboard/index.html +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/npm/memtrust-cli/LICENSE +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/npm/memtrust-cli/README.md +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/npm/memtrust-cli/bin/memtrust.js +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/npm/platforms/@memtrust-cli-darwin-arm64/LICENSE +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/npm/platforms/@memtrust-cli-darwin-arm64/README.md +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/npm/platforms/@memtrust-cli-darwin-arm64/package.json +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/npm/platforms/@memtrust-cli-darwin-x64/LICENSE +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/npm/platforms/@memtrust-cli-darwin-x64/README.md +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/npm/platforms/@memtrust-cli-darwin-x64/package.json +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/npm/platforms/@memtrust-cli-linux-arm64/LICENSE +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/npm/platforms/@memtrust-cli-linux-arm64/README.md +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/npm/platforms/@memtrust-cli-linux-arm64/package.json +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/npm/platforms/@memtrust-cli-linux-x64/LICENSE +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/npm/platforms/@memtrust-cli-linux-x64/README.md +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/npm/platforms/@memtrust-cli-linux-x64/package.json +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/npm/platforms/@memtrust-cli-win32-arm64/LICENSE +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/npm/platforms/@memtrust-cli-win32-arm64/README.md +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/npm/platforms/@memtrust-cli-win32-arm64/package.json +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/npm/platforms/@memtrust-cli-win32-x64/LICENSE +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/npm/platforms/@memtrust-cli-win32-x64/README.md +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/npm/platforms/@memtrust-cli-win32-x64/package.json +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/npm/scripts/fetch-binary.js +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/adapters/__init__.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/adapters/base.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/adapters/mem0_adapter.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/adapters/mempalace_adapter.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/adapters/openviking_adapter.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/adapters/zep_graphiti_adapter.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/adapters/zep_graphiti_selfhosted_adapter.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/evals/__init__.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/evals/compression.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/evals/contradiction.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/evals/crash_recovery.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/evals/embedder_cost.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/evals/embedding_drift.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/evals/episode_temporal_leak.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/evals/extraction_quality.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/evals/filter_injection.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/evals/language_degradation.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/evals/lock_contention.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/evals/locomo.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/evals/longmemeval.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/evals/mempalace_metadata_scale.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/evals/migration_rollback.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/evals/orphan_cleanup.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/evals/ranking_quality.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/evals/resource_sync_safety.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/evals/result_consistency.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/evals/scale_fixtures.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/evals/scale_stress.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/evals/stats_accuracy.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/evals/temporal_kg_boundary.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/receipt.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/scoring/__init__.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/scoring/cost_tracker.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/src/memtrust/scoring/llm_judge.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/tests/fixtures/compression_cases.json +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/tests/fixtures/contradiction_cases.json +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/tests/fixtures/crash_recovery_cases.json +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/tests/fixtures/embedding_drift_cases.json +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/tests/fixtures/extraction_quality_cases.json +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/tests/fixtures/filter_injection_cases.json +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/tests/fixtures/language_degradation_cases.json +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/tests/fixtures/locomo_sample.json +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/tests/fixtures/longmemeval_sample.json +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/tests/fixtures/migration_rollback_cases.json +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/tests/fixtures/orphan_cleanup_cases.json +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/tests/fixtures/ranking_quality_cases.json +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/tests/fixtures/resource_sync_cases.json +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/tests/fixtures/result_consistency_cases.json +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/tests/test_adapters.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/tests/test_compression.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/tests/test_episode_temporal_leak.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/tests/test_evals.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/tests/test_lock_contention.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/tests/test_mempalace_metadata_scale.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/tests/test_receipt.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/tests/test_scale_stress.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/tests/test_scoring.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/tests/test_stats_accuracy.py +0 -0
- {memtrust_cli-0.3.1 → memtrust_cli-0.3.3}/tests/test_temporal_kg_boundary.py +0 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*.egg-info/
|
|
4
|
+
.eggs/
|
|
5
|
+
build/
|
|
6
|
+
dist/
|
|
7
|
+
.venv/
|
|
8
|
+
venv/
|
|
9
|
+
.env
|
|
10
|
+
.env.*
|
|
11
|
+
!.env.example
|
|
12
|
+
.pytest_cache/
|
|
13
|
+
.mypy_cache/
|
|
14
|
+
.ruff_cache/
|
|
15
|
+
.coverage
|
|
16
|
+
.coverage.*
|
|
17
|
+
htmlcov/
|
|
18
|
+
coverage.xml
|
|
19
|
+
*.log
|
|
20
|
+
.DS_Store
|
|
21
|
+
results/*/
|
|
22
|
+
!results/.gitkeep
|
|
23
|
+
node_modules/
|
|
24
|
+
.idea/
|
|
25
|
+
.vscode/
|
|
26
|
+
.claude/
|
|
27
|
+
uv.lock
|
|
28
|
+
memtrust-report-*.json
|
|
29
|
+
|
|
30
|
+
# Locally-downloaded uv binaries staged into the npm platform packages
|
|
31
|
+
# before `npm publish` -- real binaries, ~50-70MB each across 6 platforms,
|
|
32
|
+
# never meant to be committed or swept into the Python sdist. See
|
|
33
|
+
# npm/platforms/*/README.md for how each one is populated at publish time.
|
|
34
|
+
npm/platforms/*/bin/
|
|
@@ -3,6 +3,75 @@
|
|
|
3
3
|
All notable changes to this project are documented here. Format loosely follows
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
5
5
|
|
|
6
|
+
## [0.3.3] - 2026-07-21
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
|
|
10
|
+
- **`memtrust --version` was still broken on the `memtrust` mirror package.** 0.3.2's fix
|
|
11
|
+
hardcoded the distribution-name lookup to `"memtrust-cli"`, which fixed that package but broke
|
|
12
|
+
`pip install memtrust` the same way in reverse: that environment has no `memtrust-cli` entry in
|
|
13
|
+
its own installed-package metadata, so the lookup always missed and fell through to
|
|
14
|
+
`0.0.0+unknown` again. `src/memtrust/__init__.py` now tries `memtrust-cli` first, falls back to
|
|
15
|
+
`memtrust`, and only reports `0.0.0+unknown` if neither distribution name is installed.
|
|
16
|
+
Independently reproduced against a clean `pip install memtrust==0.3.2` before this fix.
|
|
17
|
+
- `memtrust run --help`'s `--eval` flag description was a hand-maintained string literal that had
|
|
18
|
+
drifted out of sync with the real `ALL_EVALS` list -- it was still missing `temporal_kg_boundary`
|
|
19
|
+
even though the eval itself worked correctly. Now generated directly from `ALL_EVALS`, so it
|
|
20
|
+
can't drift again.
|
|
21
|
+
- `npm/memtrust-cli/package.json`'s `optionalDependencies` pinned the 6 platform packages
|
|
22
|
+
(`@memtrust-cli/darwin-x64` etc.) to an exact `0.1.0`, which had already drifted from the
|
|
23
|
+
actually-published `0.1.1`. Changed to `^0.1.1` so patch releases of the platform packages
|
|
24
|
+
resolve automatically instead of drifting stale again.
|
|
25
|
+
- CI had been failing on every push since the 0.3.2 commit (`ruff format --check` alone, every
|
|
26
|
+
other job green) -- only `ruff check` had been run locally, not the separate formatting check.
|
|
27
|
+
- README.md's "Success stories" section cited MemPalace/mempalace#524 (@gaby) as the source of a
|
|
28
|
+
ChromaDB-network-dependency finding. That citation was fabricated: the real issue #524 is
|
|
29
|
+
titled "Remove Baldfaced Lies Please," filed by a different user, about unrelated content, and
|
|
30
|
+
no user named "gaby" has filed anything in that repository. The underlying technical claim
|
|
31
|
+
(documented separately in `mempalace_adapter.py`'s own module docstring) is real; the citation
|
|
32
|
+
attributing it to a specific reported issue was not. Removed the bullet. Every other citation in
|
|
33
|
+
the section (~32 across MemPalace, mem0, Zep/Graphiti, OpenViking, and one cross-project
|
|
34
|
+
citation) was independently re-verified against the live GitHub API and confirmed accurate.
|
|
35
|
+
- README.md's pasted `pytest --cov` output and coverage table were stale relative to the actual
|
|
36
|
+
test suite (585 passed / 93% vs. the real 589 passed / 93%); refreshed, and the table now notes
|
|
37
|
+
explicitly that it's an 11-of-33-module excerpt rather than implying completeness.
|
|
38
|
+
- README.md's mem0#4884 success-story bullet credited `LanguageDegradationSignal` without
|
|
39
|
+
disclosing that eval isn't wired into `memtrust run --eval` (it's `Mem0DirectAdapter`-specific,
|
|
40
|
+
requiring `query(explain=True)`) -- added the same honest not-yet-wired-in caveat this project
|
|
41
|
+
uses for every other eval in the same situation.
|
|
42
|
+
|
|
43
|
+
## [0.3.2] - 2026-07-20
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
|
|
47
|
+
- `memtrust --version` always printed `0.0.0+unknown`, even when properly installed,
|
|
48
|
+
because `src/memtrust/__init__.py` read `importlib.metadata.version("memtrust")`
|
|
49
|
+
instead of `version("memtrust-cli")`, the actual installed distribution name. Now
|
|
50
|
+
reads the correct key and matches `pip show memtrust-cli`.
|
|
51
|
+
- The Python sdist ballooned to 142MB because `npm/platforms/*/bin/` (locally-staged
|
|
52
|
+
`uv` binaries used to build the npm platform packages, ~350MB across 6 platforms)
|
|
53
|
+
was untracked and ungitignored, so hatchling's default sdist inclusion swept it in.
|
|
54
|
+
Excluded via `.gitignore` and an explicit `[tool.hatch.build.targets.sdist]` exclude.
|
|
55
|
+
- `Mem0DirectAdapter` now passes `is_reasoning_model=True` to work around a real
|
|
56
|
+
`mem0ai==2.0.12` bug: its default LLM model (`gpt-5-mini`) is not recognized by its
|
|
57
|
+
own reasoning-model detection (which checks for the different string
|
|
58
|
+
`gpt-5o-mini`), so every LLM-based extraction call sent `temperature=0.1` to a model
|
|
59
|
+
that only accepts the API default, 400ing on every call out of the box for anyone
|
|
60
|
+
with just `OPENAI_API_KEY` set.
|
|
61
|
+
|
|
62
|
+
### Added
|
|
63
|
+
|
|
64
|
+
- `temporal_kg_boundary` is now wired into `memtrust run --eval`, gated to the
|
|
65
|
+
`mempalace` backend (reports `not_applicable` against any other backend).
|
|
66
|
+
- First live benchmark result: `mem0_direct` (self-hosted `mem0ai`, local Qdrant,
|
|
67
|
+
OpenAI embeddings/extraction) run against `contradiction`, `compression`, and
|
|
68
|
+
`extraction_quality`. See README.md's "Benchmarks" section for the numbers.
|
|
69
|
+
|
|
70
|
+
### Changed
|
|
71
|
+
|
|
72
|
+
- `pyproject.toml`: `Development Status :: 4 - Beta` (was Alpha), expanded PyPI
|
|
73
|
+
keywords, refreshed description.
|
|
74
|
+
|
|
6
75
|
## [0.3.0] - 2026-07-17
|
|
7
76
|
|
|
8
77
|
### Changed
|
|
@@ -109,6 +109,49 @@ conversion (or a second loader function) is needed.
|
|
|
109
109
|
4. Every claim in a PR description about a score or benchmark number must be reproducible from a
|
|
110
110
|
command someone else can run. "I ran X and got Y" needs the X.
|
|
111
111
|
|
|
112
|
+
## Release process
|
|
113
|
+
|
|
114
|
+
There are three packages, not one, and CI only automates one of them. Missing any of the other two
|
|
115
|
+
silently breaks something for someone -- this is written down because it has already happened.
|
|
116
|
+
|
|
117
|
+
1. Bump the version in `pyproject.toml` (and `npm/memtrust-cli/package.json` in the same PR if a
|
|
118
|
+
matching npm publish is planned -- see step 4).
|
|
119
|
+
2. Before pushing, run the full local check list: `ruff check .`, `ruff format --check .` (a
|
|
120
|
+
separate step from `ruff check` -- CI fails on formatting alone even when linting passes),
|
|
121
|
+
`mypy --strict src/memtrust`, `pytest --cov=memtrust --cov-report=term-missing
|
|
122
|
+
--cov-fail-under=80`, `pip-audit`.
|
|
123
|
+
3. **PyPI has two packages kept in lockstep, and CI only publishes one of them.**
|
|
124
|
+
`.github/workflows/publish-pypi.yml` (triggered by a GitHub Release) publishes whatever
|
|
125
|
+
`pyproject.toml`'s `[project].name` currently says -- `memtrust-cli`, the canonical name. The
|
|
126
|
+
separate mirror package literally named `memtrust` (which `npm/memtrust-cli/bin/memtrust.js`
|
|
127
|
+
pins its `uv tool run --from` call to) has no CI automation at all and must be published
|
|
128
|
+
manually every release: temporarily set `name = "memtrust"` in `pyproject.toml`, `uv build && uv
|
|
129
|
+
publish`, then revert the name back to `memtrust-cli`. Skipping this step doesn't break
|
|
130
|
+
`memtrust-cli`'s own release, but it does mean the npm wrapper starts fetching a stale PyPI
|
|
131
|
+
version the next time someone bumps `npm/memtrust-cli/package.json` without also doing this.
|
|
132
|
+
4. **npm publish is also manual, and its own version must exactly match the PyPI release it
|
|
133
|
+
pins to.** `npm/memtrust-cli/package.json`'s version is not independent -- `bin/memtrust.js`
|
|
134
|
+
reads it directly to build `uv tool run --from memtrust==<that version>`, so bumping the npm
|
|
135
|
+
package's version without a matching live PyPI `memtrust` release (step 3) breaks the wrapper
|
|
136
|
+
for every subsequent install. Publish PyPI first, confirm both `memtrust-cli` and `memtrust`
|
|
137
|
+
are live (`pip index versions memtrust-cli`, or the PyPI JSON API if the simple index is
|
|
138
|
+
lagging), then `npm publish npm/memtrust-cli --access public`.
|
|
139
|
+
5. **Building the sdist from a working tree that has locally-downloaded platform binaries staged
|
|
140
|
+
for npm publish will silently balloon it.** If `npm/platforms/*/bin/` has real `uv` binaries in
|
|
141
|
+
it (staged for an npm publish, ~50-70MB each across 6 platforms), `pyproject.toml`'s
|
|
142
|
+
`[tool.hatch.build.targets.sdist]` exclude should already keep them out -- but if that exclude
|
|
143
|
+
is ever removed, `uv build`'s sdist output size is the tripwire: it should be a few MB, not
|
|
144
|
+
100MB+.
|
|
145
|
+
6. The 6 `@memtrust-cli/<platform>` packages have their own independent version numbers, not tied
|
|
146
|
+
to `memtrust-cli`'s. `npm/memtrust-cli/package.json`'s `optionalDependencies` should use a caret
|
|
147
|
+
range (`^0.1.1`, not an exact `0.1.0`) so a platform-package patch release resolves
|
|
148
|
+
automatically instead of drifting stale again.
|
|
149
|
+
7. Create the GitHub Release last, after both registries are confirmed live -- this is what
|
|
150
|
+
triggers `publish-pypi.yml`. If `memtrust-cli` was already published manually before the
|
|
151
|
+
Release exists (e.g. to unblock testing), that workflow run will fail with a harmless
|
|
152
|
+
"File already exists" 400 from PyPI -- expected, not a regression, since the file it's trying
|
|
153
|
+
to upload is already there.
|
|
154
|
+
|
|
112
155
|
## Code of conduct
|
|
113
156
|
|
|
114
157
|
Be direct, be specific, assume good faith. Disagreement about a methodology choice is welcome and
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: memtrust-cli
|
|
3
|
-
Version: 0.3.
|
|
4
|
-
Summary: Independent, reproducible benchmark harness for agent-memory backends
|
|
3
|
+
Version: 0.3.3
|
|
4
|
+
Summary: Independent, reproducible benchmark harness for agent-memory backends (MemPalace, Mem0, Zep/Graphiti, OpenViking): runs LongMemEval, LoCoMo, contradiction-detection, and a dozen other evals against all four and publishes the raw logs, not vendor-curated numbers.
|
|
5
5
|
Project-URL: Homepage, https://github.com/RudrenduPaul/memtrust
|
|
6
6
|
Project-URL: Issues, https://github.com/RudrenduPaul/memtrust/issues
|
|
7
7
|
Project-URL: Author - Rudrendu Paul, https://github.com/RudrenduPaul
|
|
@@ -9,8 +9,8 @@ Project-URL: Author - Sourav Nandy, https://github.com/Sourav-nandy-ai
|
|
|
9
9
|
Author: Rudrendu Paul, Sourav Nandy
|
|
10
10
|
License: Apache-2.0
|
|
11
11
|
License-File: LICENSE
|
|
12
|
-
Keywords: agent,benchmark,
|
|
13
|
-
Classifier: Development Status ::
|
|
12
|
+
Keywords: agent-memory,ai-agents,benchmark,contradiction-detection,graphiti,llm-eval,llm-memory,locomo,longmemeval,mem0,memory-backend,mempalace,reproducible-benchmark,zep
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
14
|
Classifier: Intended Audience :: Developers
|
|
15
15
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
16
16
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -45,12 +45,13 @@ Description-Content-Type: text/markdown
|
|
|
45
45
|
|
|
46
46
|
# memtrust
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
Agent memory backends each publish their own benchmark numbers, on different tests, measured
|
|
49
|
+
different ways. memtrust runs the same evals against all four and publishes the raw logs. Run
|
|
50
|
+
against the vendors, not by them.
|
|
50
51
|
|
|
51
52
|
[](https://github.com/RudrenduPaul/memtrust/actions/workflows/ci.yml)
|
|
52
53
|
[](https://github.com/RudrenduPaul/memtrust/blob/main/LICENSE)
|
|
53
|
-
[](https://pypi.org/project/memtrust-cli/)
|
|
54
55
|
[](https://pypi.org/project/memtrust-cli/)
|
|
55
56
|
|
|
56
57
|
```bash
|
|
@@ -77,22 +78,23 @@ memtrust run --backends mempalace,mem0,zep,openviking --eval all
|
|
|
77
78
|
|
|
78
79
|
If you've compared agent-memory backends recently, you've probably noticed each one leads with a
|
|
79
80
|
different accuracy number, on a different benchmark, measured a different way. MemPalace's own
|
|
80
|
-
community already flagged the problem in public. Issue [#27](https://github.com/
|
|
81
|
-
on the MemPalace repository, opened April 7, 2026 and still open, documents a
|
|
82
|
-
LongMemEval
|
|
83
|
-
|
|
84
|
-
ChromaDB's default embeddings doing the work
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
81
|
+
community already flagged the problem in public. Issue [#27](https://github.com/MemPalace/mempalace/issues/27)
|
|
82
|
+
on the MemPalace repository, opened April 7, 2026 and still open, documents that a headline 100%
|
|
83
|
+
LongMemEval figure, measured with Haiku reranking, wasn't reproducible from the repository's own
|
|
84
|
+
benchmark scripts and was pulled from the README as unverifiable. A separate 96.6% figure people
|
|
85
|
+
cite everywhere turns out to be mostly ChromaDB's default embeddings doing the work in raw mode,
|
|
86
|
+
not MemPalace's own architecture. A "lossless" compression claim (the "AAAK" mode) drops the same
|
|
87
|
+
LongMemEval score from 96.6% to 84.2% in practice, a 12.4 percentage point gap. Two internal pull
|
|
88
|
+
requests attempting to fix the reporting problem, #433 and #729, were both closed without merging
|
|
89
|
+
on April 12, 2026 -- #729 within seven minutes of being opened. As of this writing, the issue has
|
|
90
|
+
233 thumbs-up reactions and 39 comments.
|
|
88
91
|
|
|
89
92
|
None of that means MemPalace, or any other backend, doesn't work. It means nobody outside the
|
|
90
93
|
vendor had run the same test, the same way, against every option, and published the raw logs.
|
|
91
94
|
|
|
92
95
|
memtrust does that. It runs LongMemEval, LoCoMo, and a growing set of evals built specifically for
|
|
93
|
-
this project --
|
|
94
|
-
|
|
95
|
-
CLI yet. The two that matter most for understanding what this project is actually for:
|
|
96
|
+
this project -- 17 of them as of this writing, all registered in the CLI's `--eval` flag. The two
|
|
97
|
+
that matter most for understanding what this project is actually for:
|
|
96
98
|
contradiction detection, because neither LongMemEval nor LoCoMo tests the question that actually
|
|
97
99
|
matters once a memory system sits underneath a production agent -- what happens when a new fact
|
|
98
100
|
contradicts an old one? Does the backend flag the conflict? Silently overwrite the old fact with no
|
|
@@ -102,13 +104,21 @@ test claims like the "lossless" one above: it stores content, retrieves it, and
|
|
|
102
104
|
reconstruction fidelity rather than semantic accuracy, per operating mode a backend exposes (see
|
|
103
105
|
`MemoryBackendAdapter.supported_modes`) -- the mechanism that would let a contributor with live
|
|
104
106
|
MemPalace credentials actually reproduce the 12.4-point compressed-mode accuracy drop
|
|
105
|
-
mempalace/mempalace#27 documents, instead of just citing it. **Neither has been run against
|
|
106
|
-
|
|
107
|
+
mempalace/mempalace#27 documents, instead of just citing it. **Neither has been run against a live
|
|
108
|
+
MemPalace instance as of this writing** -- both have, however, been run against a live
|
|
109
|
+
self-hosted `mem0ai` install; see "Benchmarks" below. The other evals -- ranking quality,
|
|
107
110
|
crash recovery, extraction quality, embedding drift, scale/volume stress, lock contention, stats
|
|
108
111
|
accuracy, orphan cleanup, result consistency, migration rollback, filter injection, resource-sync
|
|
109
112
|
safety, and temporal-KG boundary detection -- each grew out of a specific real bug report against
|
|
110
113
|
one of the four tracked backends; see "Success stories" below for the full list.
|
|
111
114
|
|
|
115
|
+
**Where this stands right now, in one place:** [live benchmark results](#benchmarks) for one
|
|
116
|
+
backend (`mem0_direct`, self-hosted `mem0ai`), including a real bug this project's own attempt to
|
|
117
|
+
get those numbers surfaced in mem0's default configuration; and [197 real GitHub issues and PRs](#success-stories)
|
|
118
|
+
filed against MemPalace, Mem0, Zep/Graphiti, and OpenViking independently root-caused against this
|
|
119
|
+
codebase -- 55 (28%) PASS, 16 (8%) PARTIAL, 42 (21%) a genuine capability gap, 84 (43%) not
|
|
120
|
+
applicable, every verdict re-verified by a reviewer independent of whoever built the fix.
|
|
121
|
+
|
|
112
122
|
## What it does
|
|
113
123
|
|
|
114
124
|
Every command below was actually run against this repo, with zero vendor API keys configured, to
|
|
@@ -116,11 +126,11 @@ produce the output shown. Nothing here is simulated.
|
|
|
116
126
|
|
|
117
127
|
```
|
|
118
128
|
$ memtrust run --backends mempalace,mem0,zep,openviking --eval all
|
|
119
|
-
memtrust 0.
|
|
129
|
+
memtrust 0.3.3 -- run_id=mt_2026-07-21T004232Z
|
|
120
130
|
Backends: mempalace, mem0, zep, openviking Evals: longmemeval, locomo, contradiction,
|
|
121
131
|
resource_sync_safety, compression, ranking_quality, scale_stress, embedding_drift, crash_recovery,
|
|
122
132
|
extraction_quality, migration_rollback, filter_injection, lock_contention, stats_accuracy,
|
|
123
|
-
orphan_cleanup, result_consistency
|
|
133
|
+
orphan_cleanup, result_consistency, temporal_kg_boundary
|
|
124
134
|
|
|
125
135
|
mempalace: SKIPPED (not configured) -- mempalace is not configured: environment variable
|
|
126
136
|
MEMPALACE_STORAGE_PATH is not set. Skipping this backend. See docs/methodology.md for setup
|
|
@@ -135,17 +145,19 @@ instructions.
|
|
|
135
145
|
|
|
136
146
|
Cost: $0.00 (no LLM-judged evals ran -- structural evals only, or judge not configured)
|
|
137
147
|
|
|
138
|
-
Full report: memtrust-report-2026-07-
|
|
148
|
+
Full report: memtrust-report-2026-07-20.json
|
|
139
149
|
```
|
|
140
150
|
|
|
141
151
|
That's the real, reproducible behavior of a fresh clone with no credentials: every backend reports
|
|
142
152
|
SKIPPED, the command exits cleanly, and a valid JSON report is still written. `memtrust --version`
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
153
|
+
now correctly prints `0.3.3`, matching `pip show memtrust-cli`. Earlier releases printed
|
|
154
|
+
`0.0.0+unknown` even when properly installed, because `src/memtrust/__init__.py` read
|
|
155
|
+
`importlib.metadata.version("memtrust")` while the installed distribution is actually named
|
|
156
|
+
`memtrust-cli` -- kept in the FAQ below for the record rather than deleted, since silently erasing
|
|
157
|
+
a bug the moment it's fixed is exactly the kind of curation this project exists to push back on in
|
|
158
|
+
other people's benchmarks. Set the relevant environment variable for any backend you want to
|
|
159
|
+
actually test (`MEM0_API_KEY`, `ZEP_API_KEY`, `OPENVIKING_API_KEY`, `MEMPALACE_STORAGE_PATH`) and
|
|
160
|
+
that backend runs for real against its live API instead of being skipped.
|
|
149
161
|
|
|
150
162
|
The eval logic itself is proven offline, against the bundled synthetic fixtures and, for several
|
|
151
163
|
adapters, the real installed vendor packages with only the network boundary mocked, by the test
|
|
@@ -153,29 +165,33 @@ suite:
|
|
|
153
165
|
|
|
154
166
|
```
|
|
155
167
|
$ pytest --cov=memtrust --cov-report=term-missing
|
|
156
|
-
...
|
|
168
|
+
... (33 module rows total; the 11 most relevant to this README are shown below)
|
|
157
169
|
Name Stmts Miss Cover
|
|
158
170
|
-------------------------------------------------------------------------------------
|
|
159
|
-
src/memtrust/adapters/base.py
|
|
160
|
-
src/memtrust/adapters/mempalace_adapter.py
|
|
171
|
+
src/memtrust/adapters/base.py 305 16 95%
|
|
172
|
+
src/memtrust/adapters/mempalace_adapter.py 254 15 94%
|
|
161
173
|
src/memtrust/adapters/mem0_adapter.py 140 12 91%
|
|
162
|
-
src/memtrust/adapters/mem0_direct_adapter.py
|
|
174
|
+
src/memtrust/adapters/mem0_direct_adapter.py 277 34 88%
|
|
163
175
|
src/memtrust/adapters/openviking_adapter.py 178 18 90%
|
|
164
176
|
src/memtrust/adapters/zep_graphiti_adapter.py 63 3 95%
|
|
165
|
-
src/memtrust/adapters/zep_graphiti_selfhosted_adapter.py
|
|
177
|
+
src/memtrust/adapters/zep_graphiti_selfhosted_adapter.py 161 24 85%
|
|
166
178
|
src/memtrust/evals/contradiction.py 127 2 98%
|
|
167
179
|
src/memtrust/evals/compression.py 86 1 99%
|
|
168
|
-
src/memtrust/evals/temporal_kg_boundary.py 90
|
|
180
|
+
src/memtrust/evals/temporal_kg_boundary.py 90 3 97%
|
|
169
181
|
src/memtrust/receipt.py 118 10 92%
|
|
170
182
|
-------------------------------------------------------------------------------------
|
|
171
|
-
TOTAL
|
|
183
|
+
TOTAL 4147 276 93%
|
|
172
184
|
|
|
173
|
-
|
|
185
|
+
589 passed, 8 skipped in 3.57s
|
|
174
186
|
```
|
|
175
187
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
188
|
+
This is an excerpt, not the full table -- the weakest-covered module in the repo,
|
|
189
|
+
`evals/mempalace_metadata_scale.py` (70%), isn't one of the 11 shown above; run the command
|
|
190
|
+
yourself for the complete per-module breakdown.
|
|
191
|
+
|
|
192
|
+
589 passing tests across 33 source modules, 93% overall statement coverage, 98% on the
|
|
193
|
+
contradiction-detection eval, 99% on compression/round-trip fidelity, 97% on the temporal-KG
|
|
194
|
+
boundary eval, 85-95% across the adapter layer. The 8 skips are live-`mempalace`-package tests that
|
|
179
195
|
only run with the optional `mempalace-direct` extra installed (`pip install -e
|
|
180
196
|
'.[dev,mempalace-direct]'`). Every test mocks its HTTP or wire
|
|
181
197
|
layer, or uses an in-memory fake backend -- none of them touch a real network, though a meaningful
|
|
@@ -210,16 +226,11 @@ Commands:
|
|
|
210
226
|
|
|
211
227
|
| Command | Flags | What it does |
|
|
212
228
|
|---|---|---|
|
|
213
|
-
| `memtrust run` | `--backends TEXT` comma-separated list or `all` (default `all`) · `--eval TEXT` comma-separated from `longmemeval,locomo,contradiction,resource_sync_safety,compression,ranking_quality,scale_stress,embedding_drift,crash_recovery,extraction_quality,migration_rollback,filter_injection,lock_contention,stats_accuracy,orphan_cleanup,result_consistency`, or `all` (default `all`) · `--output FILE` (defaults to `./memtrust-report-<date>.json`) · `--locomo-dataset-path FILE` points the LoCoMo eval at a real, downloaded `locomo10.json` instead of the bundled synthetic fixture (memtrust does not bundle or auto-fetch the real dataset) · `--locomo-exclude-question-ids-file FILE` excludes known-bad-ground-truth LoCoMo question IDs from scoring · `--scale-stress-n-records INTEGER` (default `500`) sets how many synthetic records the scale-stress eval stores and re-queries · `--sign FILE` writes a signed `<output>.receipt.json` alongside the report, proving it was produced by the holder of the given Ed25519 private key | Runs the eval suite against the requested backends. A backend without its credential env var set prints `SKIPPED` and the run continues -- this command never crashes on missing credentials. |
|
|
229
|
+
| `memtrust run` | `--backends TEXT` comma-separated list or `all` (default `all`) · `--eval TEXT` comma-separated from `longmemeval,locomo,contradiction,resource_sync_safety,compression,ranking_quality,scale_stress,embedding_drift,crash_recovery,extraction_quality,migration_rollback,filter_injection,lock_contention,stats_accuracy,orphan_cleanup,result_consistency,temporal_kg_boundary`, or `all` (default `all`) · `--output FILE` (defaults to `./memtrust-report-<date>.json`) · `--locomo-dataset-path FILE` points the LoCoMo eval at a real, downloaded `locomo10.json` instead of the bundled synthetic fixture (memtrust does not bundle or auto-fetch the real dataset) · `--locomo-exclude-question-ids-file FILE` excludes known-bad-ground-truth LoCoMo question IDs from scoring · `--scale-stress-n-records INTEGER` (default `500`) sets how many synthetic records the scale-stress eval stores and re-queries · `--sign FILE` writes a signed `<output>.receipt.json` alongside the report, proving it was produced by the holder of the given Ed25519 private key | Runs the eval suite against the requested backends. A backend without its credential env var set prints `SKIPPED` and the run continues -- this command never crashes on missing credentials. `temporal_kg_boundary` only applies to the `mempalace` backend (the only adapter that wires `kg_add`/`kg_invalidate`/`kg_query`); requesting it against any other backend reports `not_applicable`, not an error. |
|
|
214
230
|
| `memtrust report REPORT_PATH` | positional path to a prior JSON report | Reads a report written by `memtrust run` and prints a formatted summary. |
|
|
215
231
|
| `memtrust keygen` | -- | Generates a new Ed25519 keypair for signing reports with `run --sign`. |
|
|
216
232
|
| `memtrust verify RECEIPT_PATH` | -- | Verifies a signed receipt produced by `memtrust run --sign`; a tampered or mismatched receipt fails verification. |
|
|
217
|
-
| `memtrust --version` | -- | Prints the installed version
|
|
218
|
-
|
|
219
|
-
The temporal-KG boundary eval (`src/memtrust/evals/temporal_kg_boundary.py`,
|
|
220
|
-
`run_temporal_kg_boundary_eval()`) is not yet wired into `--eval`'s known-eval list -- it exists as
|
|
221
|
-
a tested module and a MemPalace-specific capability, callable directly, not yet a `memtrust run
|
|
222
|
-
--eval temporal_kg_boundary` option. See its own section below.
|
|
233
|
+
| `memtrust --version` | -- | Prints the installed version (currently `0.3.3`). |
|
|
223
234
|
|
|
224
235
|
Every line above came straight from running `memtrust --help`, `memtrust run --help`, and
|
|
225
236
|
`memtrust report --help` against this repo. Nothing here is invented.
|
|
@@ -249,10 +260,10 @@ section below until a live run actually produces them:
|
|
|
249
260
|
|
|
250
261
|
| Backend | GitHub stars | Self-reported description |
|
|
251
262
|
|---|---|---|
|
|
252
|
-
| [MemPalace](https://github.com/MemPalace/mempalace) | 57,
|
|
253
|
-
| [Mem0](https://github.com/mem0ai/mem0) |
|
|
254
|
-
| [Zep / Graphiti](https://github.com/getzep/graphiti) | 28,
|
|
255
|
-
| [OpenViking](https://github.com/volcengine/OpenViking) |
|
|
263
|
+
| [MemPalace](https://github.com/MemPalace/mempalace) | 57,512 | "The best-benchmarked open-source AI memory system. And it's free." |
|
|
264
|
+
| [Mem0](https://github.com/mem0ai/mem0) | 61,318 | "Universal memory layer for AI Agents" |
|
|
265
|
+
| [Zep / Graphiti](https://github.com/getzep/graphiti) | 28,978 | "Build Real-Time Knowledge Graphs for AI Agents" |
|
|
266
|
+
| [OpenViking](https://github.com/volcengine/OpenViking) | 27,016 | "Self-evolving Context Database for AI Agents. Unify Agent Memory, Knowledge RAG and Skills." |
|
|
256
267
|
|
|
257
268
|
None of these numbers say anything about which backend handles a contradicted fact correctly --
|
|
258
269
|
that's the whole reason the harness exists. Star count measures adoption, not correctness.
|
|
@@ -287,8 +298,9 @@ similarity ratio (`fidelity_ratio()`, via `difflib.SequenceMatcher` -- not an LL
|
|
|
287
298
|
"lossless" claim is a literal-reconstruction claim, not a semantic one). This is what would let a
|
|
288
299
|
contributor with live MemPalace credentials point `memtrust run --eval compression` at it and
|
|
289
300
|
reproduce a "raw vs AAAK" fidelity gap directly. **As of this writing this eval has not been run
|
|
290
|
-
against
|
|
291
|
-
|
|
301
|
+
against a live MemPalace instance** -- it has been run against a live self-hosted `mem0ai` install
|
|
302
|
+
(mean fidelity 31.6%, see "Benchmarks" below); see `docs/methodology.md` for the same
|
|
303
|
+
live-credentials caveat that applies to every other eval and backend not yet measured live.
|
|
292
304
|
|
|
293
305
|
## The eval built from MemPalace's own bug: temporal-KG boundary detection
|
|
294
306
|
|
|
@@ -311,18 +323,76 @@ shipped in a released `mempalace` version as of this adapter's live-verified 3.5
|
|
|
311
323
|
lands under the package's `[Unreleased]` changelog section. `tests/test_temporal_kg_boundary.py`
|
|
312
324
|
proves the *classification logic* is correct against two hand-written fake implementations that
|
|
313
325
|
reproduce the confirmed pre-#1914 (closed-interval) and post-#1914 (half-open-interval) SQL
|
|
314
|
-
comparison exactly. **This has not been run against a live MemPalace instance.** It
|
|
315
|
-
|
|
316
|
-
|
|
326
|
+
comparison exactly. **This has not been run against a live MemPalace instance.** It is wired into
|
|
327
|
+
`memtrust run --eval temporal_kg_boundary` (see "Commands" above); against any backend other than
|
|
328
|
+
`mempalace`, it reports `not_applicable` rather than an error.
|
|
317
329
|
|
|
318
330
|
## Benchmarks
|
|
319
331
|
|
|
320
|
-
**
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
332
|
+
**Live results: mem0_direct (self-hosted), July 2026.** MemPalace, Zep, and OpenViking are still
|
|
333
|
+
not yet measured against a live backend -- see "Backend coverage" below for the confidence level
|
|
334
|
+
on each adapter. Mem0 has one real result, produced against the actual `mem0ai` OSS library
|
|
335
|
+
running self-hosted -- in-process, via `Mem0DirectAdapter`, backed by a local Qdrant instance and
|
|
336
|
+
the OpenAI API for embeddings and extraction -- not against Mem0's hosted Platform API. Keep that
|
|
337
|
+
distinction in mind before reading this as a claim about the hosted product.
|
|
338
|
+
|
|
339
|
+
```
|
|
340
|
+
$ export MEM0_DIRECT_EMBEDDER_PROVIDER=openai
|
|
341
|
+
$ export MEM0_DIRECT_VECTOR_STORE_PROVIDER=qdrant
|
|
342
|
+
$ export MEM0_DIRECT_VECTOR_STORE_URL=http://localhost:6333
|
|
343
|
+
$ memtrust run --backends mem0_direct --eval contradiction,compression,extraction_quality
|
|
344
|
+
memtrust 0.3.2 -- run_id=mt_2026-07-20T210918Z
|
|
345
|
+
Backends: mem0_direct Evals: contradiction, compression, extraction_quality
|
|
346
|
+
|
|
347
|
+
mem0_direct: configured, running evals...
|
|
348
|
+
Running Contradiction-Detection against mem0_direct...
|
|
349
|
+
flagged: 0.0% silent-overwrite: 100.0% served-stale: 0.0% empty-or-lost: 0.0%
|
|
350
|
+
Running Compression/Round-Trip-Fidelity against mem0_direct...
|
|
351
|
+
fidelity by mode -- default: 31.6%
|
|
352
|
+
Running Extraction-Quality against mem0_direct...
|
|
353
|
+
junk-retained: 0.0% valid-lost: 100.0%
|
|
354
|
+
feedback-loop-duplicate: 0.0%
|
|
355
|
+
|
|
356
|
+
Cost: $0.00 (no LLM-judged evals ran -- structural evals only, or judge not configured)
|
|
357
|
+
```
|
|
324
358
|
|
|
325
|
-
|
|
359
|
+
The full raw report is committed at `leaderboard/mem0_direct-2026-07-20.json`, and `leaderboard/data.json`
|
|
360
|
+
carries the contradiction numbers into the static leaderboard site (`mempalace`/`mem0`/`zep`/`openviking`
|
|
361
|
+
still show `not_measured` there; `mem0_direct` is the one real row).
|
|
362
|
+
|
|
363
|
+
What that means case by case, not just the percentage:
|
|
364
|
+
|
|
365
|
+
- **Contradiction detection, 7/7 cases: every contradicting fact silently overwrote the old one.**
|
|
366
|
+
0% were flagged as a conflict, 0% served stale, 0% empty-or-lost. Tell it your meeting moved from
|
|
367
|
+
2pm to 3pm and it stores the new fact with no signal that anything changed -- this is exactly the
|
|
368
|
+
question LongMemEval and LoCoMo don't test, and exactly what "Why this exists" above is about.
|
|
369
|
+
- **Compression/round-trip fidelity, 5 cases: 31.6% mean literal character-level reconstruction.**
|
|
370
|
+
This is expected, not a defect -- mem0's design goal is semantic fact extraction, not verbatim
|
|
371
|
+
storage, so a literal-reconstruction score was never going to be high. It quantifies what "not
|
|
372
|
+
built for lossless storage" concretely means for this backend: ask it what you said and you get
|
|
373
|
+
the gist back, not your words.
|
|
374
|
+
- **Extraction quality, 15 cases (12 deliberately junk, 3 deliberately valid): 0% junk retained,
|
|
375
|
+
100% of the valid cases lost.** All 12 junk inputs (boot-file restating, cron heartbeat noise,
|
|
376
|
+
system dumps, hallucinated-profile bait) were correctly rejected. All 3 valid-content cases were
|
|
377
|
+
also dropped -- stored but never came back on retrieval. The valid-side sample is small (n=3);
|
|
378
|
+
treat this as a signal worth digging into further, not a settled number.
|
|
379
|
+
|
|
380
|
+
**A real bug this run surfaced in mem0ai itself, not in memtrust.** Getting any of the numbers
|
|
381
|
+
above required a fix first: a fresh `mem0ai==2.0.12` install with nothing but `OPENAI_API_KEY` set
|
|
382
|
+
fails every single LLM-based extraction call, out of the box, for anyone. mem0's own default model
|
|
383
|
+
(`mem0/llms/openai.py`: `self.config.model = "gpt-5-mini"`) is a reasoning-tier model that only
|
|
384
|
+
accepts the API's default temperature, but mem0's own reasoning-model detection
|
|
385
|
+
(`mem0/llms/base.py`'s `reasoning_models` set) checks for the string `"gpt-5o-mini"`, not
|
|
386
|
+
`"gpt-5-mini"` -- two different strings, so the check never fires, and mem0 sends `temperature=0.1`
|
|
387
|
+
on every call regardless. The result is a `400 Unsupported value: 'temperature' does not support
|
|
388
|
+
0.1 with this model` error on every extraction call, silently caught by mem0 and reported by
|
|
389
|
+
memtrust as `N/A (no scoreable cases)` rather than a real result. `Mem0DirectAdapter` now works
|
|
390
|
+
around it by passing `is_reasoning_model=True` explicitly -- mem0's own documented override for
|
|
391
|
+
exactly this situation -- see `src/memtrust/adapters/mem0_direct_adapter.py`'s "Default LLM
|
|
392
|
+
extraction is broken out of the box" section for the full citation. No upstream mem0ai issue filed
|
|
393
|
+
for this as of this writing.
|
|
394
|
+
|
|
395
|
+
To reproduce this or measure the remaining three backends:
|
|
326
396
|
|
|
327
397
|
```bash
|
|
328
398
|
export MEM0_API_KEY=... # and/or
|
|
@@ -403,13 +473,8 @@ LongMemEval/LoCoMo datasets). Nothing leaves your machine unless you choose to p
|
|
|
403
473
|
|
|
404
474
|
### npx (agent-native)
|
|
405
475
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
> this repo is built, tested, and passes both `npm pack --dry-run` and `npm publish --dry-run`
|
|
409
|
-
> cleanly (re-verified this session), but has not actually been pushed to the npm registry yet --
|
|
410
|
-
> `npm install memtrust-cli` still 404s as of this writing. The command below is the real,
|
|
411
|
-
> working distribution path once that publish happens; nothing about it is speculative except the
|
|
412
|
-
> "it's live on npm" part.
|
|
476
|
+
Both PyPI and npm are live. `pip install memtrust-cli` works today, and so does the `npx` command
|
|
477
|
+
below -- `npm install memtrust-cli` no longer 404s.
|
|
413
478
|
|
|
414
479
|
For CI and agent runners that have Node.js available but not necessarily a Python toolchain:
|
|
415
480
|
|
|
@@ -429,9 +494,11 @@ first use. What it removes is no Python toolchain to provision by hand -- `npx m
|
|
|
429
494
|
handles the interpreter and package fetch for you via a bundled, verified copy of Astral's
|
|
430
495
|
[`uv`](https://github.com/astral-sh/uv). Each platform package bundles a genuine, SHA-256-verified
|
|
431
496
|
copy of `uv`'s own GitHub release binary (fetched at npm package-publish time, never at end-user
|
|
432
|
-
install time), and its `bin` shim runs `uv tool run --from memtrust memtrust
|
|
433
|
-
transparently bootstraps a Python interpreter and installs
|
|
434
|
-
the first run.
|
|
497
|
+
install time), and its `bin` shim runs `uv tool run --from memtrust==<pinned version> memtrust
|
|
498
|
+
<args>`, which transparently bootstraps a Python interpreter and installs that exact pinned
|
|
499
|
+
`memtrust` release from PyPI, caching it after the first run. The npm package is pinned to its own
|
|
500
|
+
version -- bump `npm/memtrust-cli/package.json`'s version when a new PyPI release ships, and every
|
|
501
|
+
subsequent install resolves to that exact release, not whatever happens to be newest at run time.
|
|
435
502
|
|
|
436
503
|
## What a hosted trust layer would add
|
|
437
504
|
|
|
@@ -488,7 +555,7 @@ commit than remember to run them by hand.
|
|
|
488
555
|
## FAQ
|
|
489
556
|
|
|
490
557
|
**What is memtrust, and what actually makes it different from reading a vendor's own benchmark
|
|
491
|
-
page?** It's a CLI harness that runs the same evals (LongMemEval, LoCoMo, and
|
|
558
|
+
page?** It's a CLI harness that runs the same evals (LongMemEval, LoCoMo, and 15 others registered
|
|
492
559
|
in `--eval`, including a contradiction-detection eval none of the four tracked backends publish a
|
|
493
560
|
number for) against MemPalace, Mem0, Zep/Graphiti, and OpenViking, and prints the raw output rather
|
|
494
561
|
than a curated summary. The differentiator isn't a proprietary scoring model; it's that nobody
|
|
@@ -524,20 +591,37 @@ those four backends make about themselves. If you need broad RAG or prompt-evalu
|
|
|
524
591
|
RAGAS or a similar framework is the right tool; if you need to check whether a memory backend
|
|
525
592
|
silently drops or overwrites a contradicted fact, memtrust is the one built for that question.
|
|
526
593
|
|
|
527
|
-
**Why
|
|
528
|
-
This
|
|
529
|
-
PyPI into a clean virtualenv and running `pip show memtrust-cli`
|
|
530
|
-
`memtrust --version`
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
594
|
+
**Why did `memtrust --version` used to print a version that didn't match what pip said I
|
|
595
|
+
installed?** This was a real, shipped bug through 0.3.1, not a hypothetical one: installing
|
|
596
|
+
`memtrust-cli` from PyPI into a clean virtualenv and running `pip show memtrust-cli` reported the
|
|
597
|
+
correct version, but `memtrust --version` printed `0.0.0+unknown` regardless, because
|
|
598
|
+
`src/memtrust/__init__.py` read `importlib.metadata.version("memtrust")` -- the wrong distribution
|
|
599
|
+
name -- instead of `version("memtrust-cli")`, the name the package is actually installed under.
|
|
600
|
+
0.3.2's fix was itself incomplete: it hardcoded the lookup to `"memtrust-cli"`, which broke the
|
|
601
|
+
separate `memtrust` mirror package (see "Can I `pip install memtrust` instead of
|
|
602
|
+
`memtrust-cli`?" below) the same way in reverse -- a `pip install memtrust` environment has no
|
|
603
|
+
`memtrust-cli` entry in its own installed-package metadata at all, so the lookup always missed and
|
|
604
|
+
fell through to the same `0.0.0+unknown` fallback. Fixed for real in 0.3.3: the lookup now tries
|
|
605
|
+
`memtrust-cli` first, falls back to `memtrust`, and only reports `0.0.0+unknown` if neither
|
|
606
|
+
distribution name is installed. `memtrust --version` now matches `pip show` under either package
|
|
607
|
+
name.
|
|
608
|
+
|
|
609
|
+
**Can I `pip install memtrust` instead of `memtrust-cli`?** Yes -- `memtrust` is a real, separate
|
|
610
|
+
PyPI package, kept at the same version as `memtrust-cli` on every release, publishing the identical
|
|
611
|
+
source. It exists because the npm wrapper's `bin/memtrust.js` pins `uv tool run --from
|
|
612
|
+
memtrust==<version>` (not `memtrust-cli`), so a working `npx memtrust-cli` depends on the
|
|
613
|
+
`memtrust` name staying live and in sync. `memtrust-cli` is the name to lead with in new
|
|
614
|
+
documentation, since the `-cli` suffix makes it unambiguous as a CLI tool at a glance; `memtrust`
|
|
615
|
+
is a legitimate, supported install path, not a typo or a squatted name.
|
|
534
616
|
|
|
535
617
|
**Has memtrust actually been run against a live memory backend, or is this all synthetic?** Both,
|
|
536
618
|
and the README doesn't blur the line. The eval logic itself is proven against bundled synthetic
|
|
537
619
|
fixtures and, for several adapters, real installed vendor packages with only the network boundary
|
|
538
|
-
mocked (see the pytest coverage table above).
|
|
539
|
-
|
|
540
|
-
"Benchmarks"
|
|
620
|
+
mocked (see the pytest coverage table above). One backend has a real live result: `mem0_direct`,
|
|
621
|
+
the self-hosted `mem0ai` OSS library (not Mem0's hosted Platform API), run against contradiction,
|
|
622
|
+
compression, and extraction-quality -- see "Benchmarks" above for the exact numbers and a real bug
|
|
623
|
+
that run surfaced in `mem0ai` itself. MemPalace, the hosted Mem0 Platform API, Zep, and OpenViking
|
|
624
|
+
have not yet been run against a live backend with real credentials as of this writing. The
|
|
541
625
|
"Backend coverage" table gives a per-adapter confidence level (high/medium/low) for exactly this
|
|
542
626
|
reason; run it yourself against your own credentials to get a live-verified number.
|
|
543
627
|
|
|
@@ -547,7 +631,7 @@ and requires you to preserve the license and copyright notice and to note any ch
|
|
|
547
631
|
the code. It does not require you to open-source your own product just because you depend on
|
|
548
632
|
memtrust.
|
|
549
633
|
|
|
550
|
-
**How do I get real accuracy numbers
|
|
634
|
+
**How do I get real accuracy numbers for the backends still marked "not yet measured"?** Set the
|
|
551
635
|
credential environment variable for whichever backend you want to test
|
|
552
636
|
(`MEMPALACE_STORAGE_PATH`, `MEM0_API_KEY`, `ZEP_API_KEY`, `OPENVIKING_API_KEY`, plus
|
|
553
637
|
`MEMTRUST_JUDGE_API_KEY` for LLM-judged evals like LongMemEval and LoCoMo), then run
|
|
@@ -607,10 +691,6 @@ shipped in the open rather than quietly. See "Backend coverage" above for the fu
|
|
|
607
691
|
(@JosefAschauer): an `authored_at` chronology tie-break fix for `_hybrid_rank`. memtrust's ranking
|
|
608
692
|
classifier now credits a top-level `authored_at` field, not just one nested under `metadata`, as
|
|
609
693
|
a genuine ranking-driving signal.
|
|
610
|
-
- [#524](https://github.com/MemPalace/mempalace/issues/524) (@gaby): a buried-comment report that
|
|
611
|
-
"no API key required" doesn't mean "no network required" -- ChromaDB's default embedder still
|
|
612
|
-
needs to download a model on first use, which silently breaks airgapped setups. The adapter's
|
|
613
|
-
module docstring now says so explicitly.
|
|
614
694
|
|
|
615
695
|
**mem0**
|
|
616
696
|
- [#5973](https://github.com/mem0ai/mem0/pull/5973) (@abhay-codes07, superseded by
|
|
@@ -635,7 +715,13 @@ shipped in the open rather than quietly. See "Backend coverage" above for the fu
|
|
|
635
715
|
update) against this taxonomy.
|
|
636
716
|
- [#4884](https://github.com/mem0ai/mem0/issues/4884) (@wangjiawei-vegetable): a hardcoded
|
|
637
717
|
English-only tokenizer silently degrading non-Latin-script retrieval. A new
|
|
638
|
-
`LanguageDegradationSignal` and non-Latin-script fixtures now catch this shape
|
|
718
|
+
`LanguageDegradationSignal` and non-Latin-script fixtures now catch this shape --
|
|
719
|
+
`Mem0DirectAdapter`-specific (it reads `query(explain=True)`'s real per-result diagnostic
|
|
720
|
+
fields, a capability only that adapter exposes) and, like `embedder_cost.py`'s cost-attribution
|
|
721
|
+
eval and `episode_temporal_leak.py`'s Graphiti-specific eval, not yet wired into `memtrust run
|
|
722
|
+
--eval`'s general list; call `run_language_degradation_eval()` directly, or see the
|
|
723
|
+
`test_query_language_degradation_*` tests in `tests/test_mem0_direct_adapter.py`, until that CLI
|
|
724
|
+
surface exists.
|
|
639
725
|
|
|
640
726
|
**Zep / Graphiti**
|
|
641
727
|
- [#1489](https://github.com/getzep/graphiti/issues/1489) (@brentkearney): a bi-temporal
|