memtrust-cli 0.3.1__tar.gz → 0.3.2__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.
Files changed (109) hide show
  1. memtrust_cli-0.3.2/.gitignore +34 -0
  2. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/PKG-INFO +4 -4
  3. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/npm/memtrust-cli/package.json +1 -1
  4. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/pyproject.toml +20 -4
  5. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/__init__.py +1 -1
  6. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/adapters/mem0_direct_adapter.py +53 -0
  7. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/cli.py +36 -0
  8. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/tests/test_cli.py +46 -0
  9. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/tests/test_mem0_direct_adapter.py +48 -0
  10. memtrust_cli-0.3.1/.gitignore +0 -28
  11. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/.github/CODEOWNERS +0 -0
  12. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/.github/workflows/ci.yml +0 -0
  13. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/.github/workflows/publish-pypi.yml +0 -0
  14. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/.pre-commit-config.yaml +0 -0
  15. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/CHANGELOG.md +0 -0
  16. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/CONTRIBUTING.md +0 -0
  17. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/LICENSE +0 -0
  18. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/README.md +0 -0
  19. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/SECURITY.md +0 -0
  20. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/docs/assets/dev-to-demos/demo-1-zero-credentials.gif +0 -0
  21. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/docs/assets/dev-to-demos/demo-2-fictional-api-discovery.gif +0 -0
  22. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/docs/assets/dev-to-demos/demo-3-cli-surface.gif +0 -0
  23. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/docs/assets/dev-to-demos/demo-4-temporal-kg-tests.gif +0 -0
  24. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/docs/demo.gif +0 -0
  25. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/docs/methodology.md +0 -0
  26. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/docs/usage.gif +0 -0
  27. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/leaderboard/data.json +0 -0
  28. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/leaderboard/index.html +0 -0
  29. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/npm/memtrust-cli/LICENSE +0 -0
  30. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/npm/memtrust-cli/README.md +0 -0
  31. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/npm/memtrust-cli/bin/memtrust.js +0 -0
  32. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/npm/platforms/@memtrust-cli-darwin-arm64/LICENSE +0 -0
  33. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/npm/platforms/@memtrust-cli-darwin-arm64/README.md +0 -0
  34. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/npm/platforms/@memtrust-cli-darwin-arm64/package.json +0 -0
  35. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/npm/platforms/@memtrust-cli-darwin-x64/LICENSE +0 -0
  36. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/npm/platforms/@memtrust-cli-darwin-x64/README.md +0 -0
  37. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/npm/platforms/@memtrust-cli-darwin-x64/package.json +0 -0
  38. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/npm/platforms/@memtrust-cli-linux-arm64/LICENSE +0 -0
  39. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/npm/platforms/@memtrust-cli-linux-arm64/README.md +0 -0
  40. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/npm/platforms/@memtrust-cli-linux-arm64/package.json +0 -0
  41. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/npm/platforms/@memtrust-cli-linux-x64/LICENSE +0 -0
  42. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/npm/platforms/@memtrust-cli-linux-x64/README.md +0 -0
  43. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/npm/platforms/@memtrust-cli-linux-x64/package.json +0 -0
  44. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/npm/platforms/@memtrust-cli-win32-arm64/LICENSE +0 -0
  45. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/npm/platforms/@memtrust-cli-win32-arm64/README.md +0 -0
  46. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/npm/platforms/@memtrust-cli-win32-arm64/package.json +0 -0
  47. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/npm/platforms/@memtrust-cli-win32-x64/LICENSE +0 -0
  48. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/npm/platforms/@memtrust-cli-win32-x64/README.md +0 -0
  49. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/npm/platforms/@memtrust-cli-win32-x64/package.json +0 -0
  50. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/npm/scripts/fetch-binary.js +0 -0
  51. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/adapters/__init__.py +0 -0
  52. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/adapters/base.py +0 -0
  53. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/adapters/mem0_adapter.py +0 -0
  54. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/adapters/mempalace_adapter.py +0 -0
  55. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/adapters/openviking_adapter.py +0 -0
  56. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/adapters/zep_graphiti_adapter.py +0 -0
  57. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/adapters/zep_graphiti_selfhosted_adapter.py +0 -0
  58. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/evals/__init__.py +0 -0
  59. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/evals/compression.py +0 -0
  60. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/evals/contradiction.py +0 -0
  61. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/evals/crash_recovery.py +0 -0
  62. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/evals/embedder_cost.py +0 -0
  63. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/evals/embedding_drift.py +0 -0
  64. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/evals/episode_temporal_leak.py +0 -0
  65. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/evals/extraction_quality.py +0 -0
  66. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/evals/filter_injection.py +0 -0
  67. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/evals/language_degradation.py +0 -0
  68. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/evals/lock_contention.py +0 -0
  69. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/evals/locomo.py +0 -0
  70. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/evals/longmemeval.py +0 -0
  71. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/evals/mempalace_metadata_scale.py +0 -0
  72. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/evals/migration_rollback.py +0 -0
  73. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/evals/orphan_cleanup.py +0 -0
  74. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/evals/ranking_quality.py +0 -0
  75. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/evals/resource_sync_safety.py +0 -0
  76. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/evals/result_consistency.py +0 -0
  77. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/evals/scale_fixtures.py +0 -0
  78. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/evals/scale_stress.py +0 -0
  79. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/evals/stats_accuracy.py +0 -0
  80. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/evals/temporal_kg_boundary.py +0 -0
  81. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/receipt.py +0 -0
  82. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/scoring/__init__.py +0 -0
  83. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/scoring/cost_tracker.py +0 -0
  84. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/src/memtrust/scoring/llm_judge.py +0 -0
  85. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/tests/fixtures/compression_cases.json +0 -0
  86. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/tests/fixtures/contradiction_cases.json +0 -0
  87. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/tests/fixtures/crash_recovery_cases.json +0 -0
  88. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/tests/fixtures/embedding_drift_cases.json +0 -0
  89. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/tests/fixtures/extraction_quality_cases.json +0 -0
  90. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/tests/fixtures/filter_injection_cases.json +0 -0
  91. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/tests/fixtures/language_degradation_cases.json +0 -0
  92. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/tests/fixtures/locomo_sample.json +0 -0
  93. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/tests/fixtures/longmemeval_sample.json +0 -0
  94. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/tests/fixtures/migration_rollback_cases.json +0 -0
  95. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/tests/fixtures/orphan_cleanup_cases.json +0 -0
  96. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/tests/fixtures/ranking_quality_cases.json +0 -0
  97. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/tests/fixtures/resource_sync_cases.json +0 -0
  98. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/tests/fixtures/result_consistency_cases.json +0 -0
  99. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/tests/test_adapters.py +0 -0
  100. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/tests/test_compression.py +0 -0
  101. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/tests/test_episode_temporal_leak.py +0 -0
  102. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/tests/test_evals.py +0 -0
  103. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/tests/test_lock_contention.py +0 -0
  104. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/tests/test_mempalace_metadata_scale.py +0 -0
  105. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/tests/test_receipt.py +0 -0
  106. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/tests/test_scale_stress.py +0 -0
  107. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/tests/test_scoring.py +0 -0
  108. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/tests/test_stats_accuracy.py +0 -0
  109. {memtrust_cli-0.3.1 → memtrust_cli-0.3.2}/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/
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: memtrust-cli
3
- Version: 0.3.1
4
- Summary: Independent, reproducible benchmark harness for agent-memory backends
3
+ Version: 0.3.2
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,eval,evaluation,llm,memory
13
- Classifier: Development Status :: 3 - Alpha
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memtrust-cli",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "npx-runnable wrapper for the memtrust agent-memory benchmark harness. Bootstraps a verified copy of Astral's uv to fetch and run memtrust from PyPI -- no Python toolchain to provision by hand.",
5
5
  "bin": { "memtrust-cli": "bin/memtrust.js", "memtrust": "bin/memtrust.js" },
6
6
  "files": ["bin/", "LICENSE", "README.md"],
@@ -4,8 +4,8 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "memtrust-cli"
7
- version = "0.3.1"
8
- description = "Independent, reproducible benchmark harness for agent-memory backends"
7
+ version = "0.3.2"
8
+ description = "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."
9
9
  readme = "README.md"
10
10
  license = { text = "Apache-2.0" }
11
11
  requires-python = ">=3.11"
@@ -13,9 +13,13 @@ authors = [
13
13
  { name = "Rudrendu Paul" },
14
14
  { name = "Sourav Nandy" },
15
15
  ]
16
- keywords = ["llm", "agent", "memory", "benchmark", "eval", "evaluation"]
16
+ keywords = [
17
+ "agent-memory", "benchmark", "mem0", "mempalace", "zep", "graphiti",
18
+ "longmemeval", "locomo", "contradiction-detection", "llm-eval",
19
+ "memory-backend", "reproducible-benchmark", "ai-agents", "llm-memory",
20
+ ]
17
21
  classifiers = [
18
- "Development Status :: 3 - Alpha",
22
+ "Development Status :: 4 - Beta",
19
23
  "Intended Audience :: Developers",
20
24
  "License :: OSI Approved :: Apache Software License",
21
25
  "Programming Language :: Python :: 3",
@@ -108,6 +112,18 @@ memtrust = "memtrust.cli:main"
108
112
  [tool.hatch.build.targets.wheel]
109
113
  packages = ["src/memtrust"]
110
114
 
115
+ [tool.hatch.build.targets.sdist]
116
+ # Without an explicit exclude, hatchling's sdist sweeps in every file in
117
+ # the project directory that .gitignore doesn't exclude -- including
118
+ # npm/platforms/*/bin/'s locally-downloaded uv binaries (~50-70MB each
119
+ # across 6 platforms) whenever a contributor has them staged locally for
120
+ # an npm publish, ballooning the Python sdist to 100MB+ for a package
121
+ # that ships none of that. Excluded explicitly here (belt-and-suspenders
122
+ # on top of the .gitignore entry) so the sdist stays reproducible
123
+ # regardless of what a given contributor's working tree happens to have
124
+ # staged locally.
125
+ exclude = ["npm/platforms/*/bin"]
126
+
111
127
  [tool.ruff]
112
128
  line-length = 100
113
129
  target-version = "py311"
@@ -3,7 +3,7 @@
3
3
  from importlib.metadata import PackageNotFoundError, version
4
4
 
5
5
  try:
6
- __version__ = version("memtrust")
6
+ __version__ = version("memtrust-cli")
7
7
  except PackageNotFoundError:
8
8
  # Not installed at all (e.g. importing directly from a raw source
9
9
  # checkout with no `pip install -e .` run) -- there is no installed
@@ -307,6 +307,50 @@ disagree. `query()` also accepts an optional `threshold` keyword argument,
307
307
  forwarded straight
308
308
  through to the real `Memory.search()`.
309
309
 
310
+ ## Default LLM extraction is broken out of the box (mem0ai==2.0.12)
311
+
312
+ `Memory.from_config()` builds an LLM client for the `"llm"` config key
313
+ whenever the caller doesn't set one -- and until this adapter started
314
+ setting one explicitly, that meant relying on the installed package's own
315
+ defaults, which are broken for the median case: an operator who has only
316
+ set `OPENAI_API_KEY`, exactly the minimum viable setup the `Configuration`
317
+ section above documents.
318
+
319
+ Confirmed by reading the installed `mem0ai==2.0.12` source directly:
320
+
321
+ * `mem0/llms/openai.py::OpenAILLM.__init__` falls back to
322
+ `self.config.model = "gpt-5-mini"` whenever no model is configured.
323
+ * `mem0/llms/base.py::LLMBase._is_reasoning_model` decides whether to
324
+ send `temperature`/`top_p`/`max_tokens` at all, via a hardcoded set:
325
+ `{"o1", "o1-preview", "o3-mini", "o3", "gpt-5", "gpt-5o", "gpt-5o-mini",
326
+ "gpt-5o-micro"}`, plus an `o1-`/`o3-` prefix match. `"gpt-5-mini"` --
327
+ the actual default model string set two files away -- is not in that
328
+ set and matches neither prefix (`"gpt-5o-mini"` is a different string
329
+ from `"gpt-5-mini"`).
330
+ * `BaseLlmConfig.temperature` defaults to `0.1`. Because the
331
+ reasoning-model check above never fires for the real default model,
332
+ `generate_response()` sends `temperature=0.1` on every call.
333
+ * `gpt-5-mini` is a real OpenAI reasoning-tier model that only accepts
334
+ the API's default temperature (`1`) and rejects any other value with
335
+ a `400 Unsupported value: 'temperature' does not support 0.1 with
336
+ this model` error.
337
+
338
+ Net effect: a fresh install with nothing but `OPENAI_API_KEY` set fails
339
+ every single LLM-based fact-extraction call. `contradiction`,
340
+ `compression`, and `extraction_quality` all still complete -- mem0
341
+ catches and logs the extraction failure rather than raising -- but every
342
+ scoreable case comes back empty, which this project's evals report as
343
+ `N/A (no scoreable cases)` rather than a real result.
344
+
345
+ This adapter works around it the way `BaseLlmConfig`'s own docstring
346
+ says a caller should for a model its name heuristic can't classify: pass
347
+ `is_reasoning_model=True` explicitly in the `"llm"` config's `config`
348
+ dict, which `LLMBase._is_reasoning_model` checks *before* falling back to
349
+ the name heuristic. This doesn't change which model mem0 calls -- still
350
+ whatever mem0 itself defaults to, currently `gpt-5-mini` -- it only fixes
351
+ which request parameters get sent for it. No upstream mem0ai issue filed
352
+ for this specific mismatch as of this writing.
353
+
310
354
  ## Custom fact-extraction prompt passthrough
311
355
 
312
356
  `Mem0DirectAdapter.__init__` accepts an optional `custom_instructions`
@@ -687,6 +731,15 @@ class Mem0DirectAdapter(MemoryBackendAdapter):
687
731
  "provider": resolved_vector_store_provider,
688
732
  "config": built_vector_store_config,
689
733
  },
734
+ # Works around the installed package's own default-model /
735
+ # reasoning-model-detection mismatch -- see this module's
736
+ # "Default LLM extraction is broken out of the box" section
737
+ # above for the exact mem0ai==2.0.12 source citations. Setting
738
+ # `is_reasoning_model` explicitly does not pin a model; mem0
739
+ # still chooses its own default (`gpt-5-mini` as of this
740
+ # writing) -- this only fixes which request parameters get
741
+ # sent to it.
742
+ "llm": {"provider": "openai", "config": {"is_reasoning_model": True}},
690
743
  # `MemoryConfig.custom_instructions` (mem0/configs/base.py) is
691
744
  # the real, current top-level key -- mem0 renamed the field
692
745
  # from `custom_fact_extraction_prompt` to `custom_instructions`
@@ -29,6 +29,7 @@ from rich.table import Table
29
29
  from memtrust import __version__
30
30
  from memtrust.adapters import ADAPTER_REGISTRY
31
31
  from memtrust.adapters.base import BackendNotConfiguredError, MemoryBackendAdapter
32
+ from memtrust.adapters.mempalace_adapter import MemPalaceAdapter
32
33
  from memtrust.evals.compression import CompressionEvalResult, run_compression_eval
33
34
  from memtrust.evals.contradiction import ContradictionEvalResult, run_contradiction_eval
34
35
  from memtrust.evals.crash_recovery import CrashRecoveryEvalResult, run_crash_recovery_eval
@@ -55,6 +56,10 @@ from memtrust.evals.scale_stress import (
55
56
  run_scale_stress_eval,
56
57
  )
57
58
  from memtrust.evals.stats_accuracy import StatsAccuracyEvalResult, run_stats_accuracy_eval
59
+ from memtrust.evals.temporal_kg_boundary import (
60
+ TemporalKGBoundaryEvalResult,
61
+ run_temporal_kg_boundary_eval,
62
+ )
58
63
  from memtrust.receipt import (
59
64
  PUBLIC_KEY_ENV_VAR,
60
65
  ReceiptError,
@@ -96,6 +101,7 @@ ALL_EVALS = [
96
101
  "stats_accuracy",
97
102
  "orphan_cleanup",
98
103
  "result_consistency",
104
+ "temporal_kg_boundary",
99
105
  ]
100
106
 
101
107
 
@@ -869,6 +875,36 @@ def run(
869
875
  else:
870
876
  console.print(" N/A (no scoreable cases)")
871
877
 
878
+ if "temporal_kg_boundary" in eval_names:
879
+ console.print(f" Running Temporal-KG Boundary against {backend_name}...")
880
+ if isinstance(adapter, MemPalaceAdapter):
881
+ tkgb_result = run_temporal_kg_boundary_eval(adapter)
882
+ backend_report["evals"]["temporal_kg_boundary"] = _serialize_eval_result(
883
+ tkgb_result
884
+ )
885
+ dcr = tkgb_result.double_count_rate
886
+ if dcr is not None:
887
+ console.print(
888
+ f" double-count: {dcr:.1%} clean: {tkgb_result.clean_rate:.1%}"
889
+ f" self-report-agreement: {tkgb_result.self_report_agreement_rate:.1%}"
890
+ )
891
+ else:
892
+ console.print(" N/A (no scoreable cases)")
893
+ else:
894
+ # Only MemPalaceAdapter wires the kg_add/kg_invalidate/kg_query
895
+ # primitives this eval calls -- see temporal_kg_boundary.py's
896
+ # module docstring. Reported the same way resource_sync_safety
897
+ # reports its own backend-specific skip, above.
898
+ console.print(
899
+ " N/A (only applies to the mempalace backend, not "
900
+ f"{backend_name})"
901
+ )
902
+ backend_report["evals"]["temporal_kg_boundary"] = {
903
+ "status": "not_applicable",
904
+ "reason": f"temporal_kg_boundary only applies to the mempalace backend, "
905
+ f"not {backend_name}",
906
+ }
907
+
872
908
  report["results"][backend_name] = backend_report
873
909
  close = getattr(adapter, "close", None)
874
910
  if callable(close):
@@ -296,6 +296,52 @@ def test_run_resource_sync_safety_skips_cleanly_for_unsupported_backend(
296
296
  assert rss["n_files"] == 0
297
297
 
298
298
 
299
+ def test_temporal_kg_boundary_registered_in_eval_list() -> None:
300
+ assert "temporal_kg_boundary" in ALL_EVALS
301
+
302
+
303
+ def test_run_temporal_kg_boundary_skips_cleanly_with_no_credentials(tmp_path: Path) -> None:
304
+ """No backend is configured at all (the autouse fixture above clears
305
+ every credential env var), so this never reaches the eval-dispatch
306
+ code path -- exercises the CLI's "unknown eval name" contract in
307
+ reverse: temporal_kg_boundary must be a recognized eval name that
308
+ still exits 0 and reports every backend SKIPPED, same as `--eval all`
309
+ does above."""
310
+ runner = CliRunner()
311
+ out_path = tmp_path / "report.json"
312
+ result = runner.invoke(
313
+ main,
314
+ ["run", "--backends", "all", "--eval", "temporal_kg_boundary", "--output", str(out_path)],
315
+ )
316
+ assert result.exit_code == 0, result.output
317
+ assert "SKIPPED" in result.output
318
+ data = json.loads(out_path.read_text())
319
+ for backend_result in data["results"].values():
320
+ assert backend_result["status"] == "skipped"
321
+
322
+
323
+ def test_run_temporal_kg_boundary_not_applicable_for_non_mempalace_backend(
324
+ tmp_path: Path, monkeypatch: pytest.MonkeyPatch
325
+ ) -> None:
326
+ """mem0 has no kg_add/kg_invalidate/kg_query primitives (only
327
+ MemPalaceAdapter wires them -- see temporal_kg_boundary.py's module
328
+ docstring), so this exercises the CLI's backend-specific
329
+ not-applicable path, mirroring
330
+ test_run_resource_sync_safety_skips_cleanly_for_unsupported_backend
331
+ above."""
332
+ monkeypatch.setenv("MEM0_API_KEY", "test-key")
333
+ runner = CliRunner()
334
+ out_path = tmp_path / "report.json"
335
+ result = runner.invoke(
336
+ main,
337
+ ["run", "--backends", "mem0", "--eval", "temporal_kg_boundary", "--output", str(out_path)],
338
+ )
339
+ assert result.exit_code == 0, result.output
340
+ data = json.loads(out_path.read_text())
341
+ tkgb = data["results"]["mem0"]["evals"]["temporal_kg_boundary"]
342
+ assert tkgb["status"] == "not_applicable"
343
+
344
+
299
345
  def test_run_against_configured_backend_full_flow(
300
346
  tmp_path: Path, monkeypatch: pytest.MonkeyPatch, httpx_mock: HTTPXMock
301
347
  ) -> None:
@@ -1141,6 +1141,54 @@ def test_real_memory_config_accepts_and_stores_custom_instructions(
1141
1141
  assert config.custom_instructions == custom_prompt
1142
1142
 
1143
1143
 
1144
+ # ---------------------------------------------------------------------------
1145
+ # Real-package regression: the installed mem0ai==2.0.12's own default LLM
1146
+ # model ("gpt-5-mini", set in mem0/llms/openai.py) is not recognized by its
1147
+ # own reasoning-model name heuristic (mem0/llms/base.py's `reasoning_models`
1148
+ # set contains "gpt-5o-mini", a different string), so a fresh install with
1149
+ # only OPENAI_API_KEY set sends `temperature=0.1` to a model that only
1150
+ # accepts the API default and 400s on every call. See module docstring's
1151
+ # "Default LLM extraction is broken out of the box" section for the full
1152
+ # finding this pins.
1153
+ # ---------------------------------------------------------------------------
1154
+
1155
+
1156
+ def test_config_dict_sets_is_reasoning_model_to_work_around_mem0s_broken_default(
1157
+ monkeypatch: pytest.MonkeyPatch,
1158
+ ) -> None:
1159
+ monkeypatch.setenv("MEM0_DIRECT_EMBEDDER_PROVIDER", "fastembed")
1160
+ monkeypatch.setenv("MEM0_DIRECT_VECTOR_STORE_URL", "redis://localhost:6379")
1161
+
1162
+ adapter = Mem0DirectAdapter()
1163
+
1164
+ assert adapter._config_dict["llm"] == { # type: ignore[comparison-overlap]
1165
+ "provider": "openai",
1166
+ "config": {"is_reasoning_model": True},
1167
+ }
1168
+
1169
+
1170
+ def test_real_openai_llm_omits_temperature_when_is_reasoning_model_is_set(
1171
+ monkeypatch: pytest.MonkeyPatch,
1172
+ ) -> None:
1173
+ """Exercises the actual installed `mem0.llms.openai.OpenAILLM` and
1174
+ `mem0.configs.llms.openai.OpenAIConfig` classes directly with exactly
1175
+ the `"llm"` config shape `Mem0DirectAdapter._config_dict` produces --
1176
+ proving the workaround genuinely stops mem0's real `_get_supported_params`
1177
+ from including `temperature` for its own default model, not just that
1178
+ the config dict looks right in isolation.
1179
+ """
1180
+ monkeypatch.setenv("OPENAI_API_KEY", "sk-test-not-a-real-key")
1181
+
1182
+ from mem0.llms.openai import OpenAILLM
1183
+
1184
+ llm = OpenAILLM(config={"is_reasoning_model": True})
1185
+
1186
+ assert llm.config.model == "gpt-5-mini"
1187
+ params = llm._get_supported_params(messages=[{"role": "user", "content": "hi"}])
1188
+ assert "temperature" not in params
1189
+ assert "max_tokens" not in params
1190
+
1191
+
1144
1192
  # ---------------------------------------------------------------------------
1145
1193
  # Real-package regression: mem0ai/mem0#4297 (embedding-dimension mismatch).
1146
1194
  # Exercises the actual installed mem0.vector_stores.qdrant.Qdrant and
@@ -1,28 +0,0 @@
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
File without changes
File without changes
File without changes
File without changes
File without changes