cortexm 0.6.1__tar.gz → 0.6.5__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.
- cortexm-0.6.5/PKG-INFO +204 -0
- cortexm-0.6.5/README.md +161 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/__init__.py +1 -1
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/api/memory.py +61 -7
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bridge/extractor.py +24 -1
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bridge/fallback.py +19 -1
- cortexm-0.6.5/cortexm/bridge/fst_real.py +270 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bridge/reader.py +71 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bridge/writer.py +11 -32
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/config.py +51 -2
- cortexm-0.6.5/cortexm/experimental/__init__.py +29 -0
- cortexm-0.6.5/cortexm/experimental/coherence.py +123 -0
- cortexm-0.6.5/cortexm/experimental/graph_recall.py +193 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/federation/hlc.py +2 -2
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/mcp/server.py +91 -58
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/migrate/importers.py +22 -15
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/plugins/verbatim.py +21 -14
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/provenance/cose.py +14 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/provenance/vc.py +10 -0
- cortexm-0.6.5/cortexm/py.typed +1 -0
- cortexm-0.6.5/cortexm/security/hamming_attestation.py +291 -0
- cortexm-0.6.5/cortexm/security/zk_proofs.py +670 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/text/embedder.py +95 -4
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/text/idiolect.py +38 -6
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/text/labse.py +35 -1
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/text/tokenizer.py +7 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/trace/store.py +40 -8
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/vsa/palace.py +5 -4
- cortexm-0.6.5/cortexm.egg-info/PKG-INFO +204 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm.egg-info/SOURCES.txt +12 -3
- cortexm-0.6.5/cortexm.egg-info/requires.txt +24 -0
- cortexm-0.6.5/cortexm.egg-info/top_level.txt +1 -0
- cortexm-0.6.5/pyproject.toml +68 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_arxiv_improvements.py +25 -66
- cortexm-0.6.5/tests/test_experimental_v064.py +231 -0
- cortexm-0.6.5/tests/test_infrastructure_regressions.py +70 -0
- cortexm-0.6.5/tests/test_mcp_zk_tools.py +117 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_permission.py +3 -3
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_reddit_steals_round3.py +2 -1
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_research_steals_round2.py +19 -3
- cortexm-0.6.5/tests/test_v065_bench_fixes.py +374 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_wal_recovery.py +2 -0
- cortexm-0.6.5/tests/test_zk_soundness.py +190 -0
- cortexm-0.6.5/tests/test_zk_sql.py +144 -0
- cortexm-0.6.1/PKG-INFO +0 -134
- cortexm-0.6.1/README.md +0 -99
- cortexm-0.6.1/context_m.py +0 -17
- cortexm-0.6.1/cortexm/security/zk_hamming.py +0 -142
- cortexm-0.6.1/cortexm/security/zk_sql.py +0 -485
- cortexm-0.6.1/cortexm.egg-info/PKG-INFO +0 -134
- cortexm-0.6.1/cortexm.egg-info/requires.txt +0 -10
- cortexm-0.6.1/cortexm.egg-info/top_level.txt +0 -2
- cortexm-0.6.1/pyproject.toml +0 -59
- cortexm-0.6.1/tests/test_zk_sql.py +0 -326
- {cortexm-0.6.1 → cortexm-0.6.5}/LICENSE +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/accel.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/api/__init__.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/api/chaos.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/api/long_recall.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bench/__init__.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bench/abilities.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bench/baselines.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bench/beam_loader.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bench/generator.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bench/harness.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bench/messy.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bench/micro.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bench/ood.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bench/run.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bridge/__init__.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bridge/dates.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bridge/decoders.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bridge/enrich.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bridge/fst.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bridge/fusion.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bridge/ir_pro.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bridge/multilingual.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bridge/negation.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bridge/onnx_runtime.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bridge/patterns.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bridge/ppr.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bridge/prefilter.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bridge/query_extract.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bridge/query_rewrite.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bridge/recognizers.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bridge/rerank.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bridge/slang.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/bridge/synonyms.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/cli.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/cognition/__init__.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/cognition/abstraction.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/cognition/analogy.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/cognition/engine.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/cognition/gaps.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/cognition/scanner.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/cortexm.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/creator.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/enterprise/__init__.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/enterprise/audit.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/enterprise/governance.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/errors.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/features/__init__.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/features/git.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/features/prefetch.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/features/zk.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/federation/__init__.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/federation/crdt.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/federation/fabric.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/federation/node.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/federation/schema_report.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/federation/transport.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/index/__init__.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/index/nsg.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/kernel.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/markdown_io.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/mcp/__init__.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/metrics.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/migrate/__init__.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/pipeline.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/plugins/__init__.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/plugins/security.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/plugins/structured.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/provenance/__init__.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/provenance/agent.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/provenance/scitt.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/router.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/security/__init__.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/security/crypto.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/security/hashes.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/security/injection.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/security/mind.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/security/permission.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/security/pii.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/security/rbac.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/security/sandbox.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/server/__init__.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/server/metrics.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/server/rest.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/server/sparql.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/text/__init__.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/text/dissim.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/text/fuzzy.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/trace/__init__.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/trace/blob_arena.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/trace/consolidate.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/trace/contradictions.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/trace/dedup.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/trace/edges.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/trace/fact.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/trace/fade.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/trace/lifecycle.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/trace/rebuild.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/trace/rules.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/trace/structural.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/trace/tmt.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/trajectory_view.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/util.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/vsa/__init__.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/vsa/attribution.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/vsa/cleanup.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/vsa/codecs.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/vsa/hologram_overlay.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/vsa/index.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/vsa/ops.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/vsa/role_vectors.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/vsa/slb.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/vsa/tlsh_trie.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm/vsa/working_memory.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm.egg-info/dependency_links.txt +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/cortexm.egg-info/entry_points.txt +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/setup.cfg +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_bench_infra.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_bm25_chunk_recall_and_inspect_cli.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_cognition_and_provenance.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_engineering_push_2026_08_28.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_enterprise.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_fabric.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_federation.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_fusion_security.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_kernel.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_kinship_extraction.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_labse.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_list_superseded_intent.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_migration.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_new_modules.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_nsg.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_ppr.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_public_api_smoke.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_rerank.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_research_steals.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_rust_accel.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_sandbox_enrich.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_sparql_rest_v2.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_tier443_abstention_fix.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_v060_ir_pro.py +0 -0
- {cortexm-0.6.1 → cortexm-0.6.5}/tests/test_verbatim.py +0 -0
cortexm-0.6.5/PKG-INFO
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cortexm
|
|
3
|
+
Version: 0.6.5
|
|
4
|
+
Summary: Context-M: deterministic, auditable, zero-cost memory for AI agents
|
|
5
|
+
Author-email: Context-M Team <dev@context-m.ai>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/ssmurfgg04-gif/context-m
|
|
8
|
+
Project-URL: Documentation, https://github.com/ssmurfgg04-gif/context-m#readme
|
|
9
|
+
Project-URL: Repository, https://github.com/ssmurfgg04-gif/context-m
|
|
10
|
+
Project-URL: Issues, https://github.com/ssmurfgg04-gif/context-m/issues
|
|
11
|
+
Keywords: memory,ai,agents,deterministic,audit,zk
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: numpy>=1.24.0
|
|
24
|
+
Requires-Dist: cryptography>=41.0.0
|
|
25
|
+
Requires-Dist: fastecdsa>=2.3.0
|
|
26
|
+
Provides-Extra: blake3
|
|
27
|
+
Requires-Dist: blake3>=0.3.0; extra == "blake3"
|
|
28
|
+
Provides-Extra: crypto
|
|
29
|
+
Requires-Dist: cryptography>=41.0.0; extra == "crypto"
|
|
30
|
+
Provides-Extra: fst
|
|
31
|
+
Requires-Dist: marisa-trie>=1.2.0; extra == "fst"
|
|
32
|
+
Provides-Extra: test
|
|
33
|
+
Requires-Dist: pytest>=7.0; extra == "test"
|
|
34
|
+
Requires-Dist: pytest-cov>=4.0; extra == "test"
|
|
35
|
+
Provides-Extra: all
|
|
36
|
+
Requires-Dist: blake3>=0.3.0; extra == "all"
|
|
37
|
+
Requires-Dist: cryptography>=41.0.0; extra == "all"
|
|
38
|
+
Requires-Dist: fastecdsa>=2.3.0; extra == "all"
|
|
39
|
+
Requires-Dist: marisa-trie>=1.2.0; extra == "all"
|
|
40
|
+
Requires-Dist: pytest>=7.0; extra == "all"
|
|
41
|
+
Requires-Dist: pytest-cov>=4.0; extra == "all"
|
|
42
|
+
Dynamic: license-file
|
|
43
|
+
|
|
44
|
+
<div align="center">
|
|
45
|
+
<h1>cortexm</h1>
|
|
46
|
+
<h3>Deterministic agent memory. μ=0. Free, local, forever. Same result every time.</h3>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<div align="center">
|
|
50
|
+
<a href="https://github.com/ssmurfgg04-gif/context-m/actions/workflows/test.yml"><img src="https://github.com/ssmurfgg04-gif/context-m/actions/workflows/test.yml/badge.svg?branch=main" alt="Tests"></a>
|
|
51
|
+
<a href="https://pypi.org/project/cortexm/"><img src="https://img.shields.io/pypi/v/cortexm?color=%2334D058&label=pypi" alt="PyPI"></a>
|
|
52
|
+
<a href="https://pypi.org/project/cortexm/"><img src="https://img.shields.io/pypi/pyversions/cortexm.svg?color=%2334D058" alt="Python"></a>
|
|
53
|
+
<a href="https://github.com/ssmurfgg04-gif/context-m/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-Apache%202.0-blue.svg" alt="License"></a>
|
|
54
|
+
<a href="https://www.npmjs.com/package/dsh-cortexm"><img src="https://img.shields.io/npm/v/dsh-cortexm?color=%2334D058&label=npm%20%7Cdsh" alt="npm"></a>
|
|
55
|
+
<a href="https://github.com/ssmurfgg04-gif/context-m/blob/main/AGENTS.md"><img src="https://img.shields.io/badge/AGENTS.md-2026-2f2f2f?logo=github" alt="AGENTS.md"></a>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<br>
|
|
59
|
+
|
|
60
|
+
> **cortexm remembers what you tell it. Forever. For free. On your machine. Same result every time.**
|
|
61
|
+
|
|
62
|
+
Mem0-compatible drop-in: `from mem0 import Memory` → `from cortexm import Memory`. Zero LLM calls at ingest. Zero LLM calls at retrieval. Zero monthly cost. Every retrieved fact carries a BLAKE3 hash chain back to the source text. One `.db` file you own.
|
|
63
|
+
|
|
64
|
+
### Quick start
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pip install cortexm # works offline, no API keys, single command
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from cortexm import Memory # Mem0-compatible surface
|
|
72
|
+
|
|
73
|
+
m = Memory()
|
|
74
|
+
m.add("I work at Google", user_id="alice")
|
|
75
|
+
m.search("Where does Alice work?", user_id="alice")
|
|
76
|
+
# → [Memory — Known facts]
|
|
77
|
+
# - (Alice, works_at, Google) [valid 2026-08-27→∞; conf 0.92;
|
|
78
|
+
# id 3f2a91c2; src #a1b2c3d4; "I work at Google"]
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Canonical LongMemEval — μ=0, $0, on a 4GB laptop
|
|
82
|
+
|
|
83
|
+
| | cortexm v0.6.4 (measured, clean) | MemPalace (honest E2E) |
|
|
84
|
+
|---|---|---|
|
|
85
|
+
| **canonical LongMemEval (500-Q full corpus)** | **95.8% (479/500)** | ~96.6% (retrieval-only, no QA) |
|
|
86
|
+
| single_session | 95.51% | — |
|
|
87
|
+
| knowledge_update | 98.72% | — |
|
|
88
|
+
| multi_session | 94.74% | — |
|
|
89
|
+
| temporal_reasoning | 95.49% | — |
|
|
90
|
+
| LLM calls (ingest + retrieval + judge) | 0 | 0 |
|
|
91
|
+
| monthly cost | $0 | $0 |
|
|
92
|
+
| determinism | byte-exact across 3× runs | byte-exact |
|
|
93
|
+
| owns your data | ✓ single `.db` file | ✓ |
|
|
94
|
+
|
|
95
|
+
**Full 500-question results — v0.6.4, the first full-corpus run that actually completed.**
|
|
96
|
+
|
|
97
|
+
> **Honesty correction #1 (v0.6.4):** the v0.6.2 README claimed 97.4% (487/500), but that number was never measured — the full-500 workflow shipped in the same commit with a broken dataset-download step and died on every invocation. The real slices from that era scored **0.943**.
|
|
98
|
+
>
|
|
99
|
+
> **Honesty correction #2 (v0.6.5):** the v0.6.4 README claimed 94.4% (472/500) — that number was **contaminated**. The aggregate step globbed `benchmarks/results/canonical_slice_*.json` on a checkout that also contained stale partial slices from earlier local runs; "later slice wins" silently let 100 v0.6.3-era results override fresh v0.6.4 shards (the evidence: 100 results carried `learned 2026-08-29` ingest dates inside a run that happened on 08-31, and 8 of the 28 "failures" pass on the fresh shards). Re-aggregated from the five real shard artifacts only: **0.958 (479/500)**. v0.6.5 makes this structurally impossible — shards aggregate from a clean directory, the aggregate script refuses verdict-flipping duplicates (exit 2), and every aggregate is stamped with git sha + per-file counts (`benchmarks/results/canonical_full.json` → `aggregate_provenance`).
|
|
100
|
+
|
|
101
|
+
| Subtask | Score | Notes |
|
|
102
|
+
|---|---|---|
|
|
103
|
+
| **Overall (clean aggregate)** | **0.958 (479/500)** | 21 real failures, all diagnosed and fixed in v0.6.5 (below) |
|
|
104
|
+
| knowledge_update | 0.9872 | 1 failure |
|
|
105
|
+
| temporal_reasoning | 0.9549 | 6 failures on relative-time anchors |
|
|
106
|
+
| single_session | 0.9551 | 7 failures on assistant-reply recall |
|
|
107
|
+
| multi_session | 0.9474 | 7 failures on sum/difference derivation |
|
|
108
|
+
|
|
109
|
+
### What the 21 failures taught us (v0.6.5 — all boring fixes, Pareto-first)
|
|
110
|
+
|
|
111
|
+
Every one of the 21 real failures was reproduced, root-caused, and fixed with the *boring* mechanism — no new models, no embedder swap, nothing dropped:
|
|
112
|
+
|
|
113
|
+
1. **Assistant messages were truncated at 800 chars — segment them instead.** 7 single_session answers ("Veja", "Absinthe", "Nu, pogodi!", "@jessica\_poole\_jewellery", "Hoop Dance", the 27th-of-100 parameter, the two sad songs) sat at byte 817–1764 of long assistant replies. `split_long_message()` now cuts at sentence boundaries into ≤2000-char segments — zero content loss, and each segment is a *better* BM25 unit than the whole reply.
|
|
114
|
+
2. **Relative-time questions need calendar math, not vocabulary.** "two weeks ago" / "last Saturday" / "10 days ago" answer chunks share no query terms ("music event" vs "saw Queen live with my parents"). The runner now ingests each session's `haystack_date` as the chunk timestamp, resolves the question's relative phrase against `question_date`, and pulls every chunk in the resolved window. 6/6 temporal failures fixed — including the subtle one: on a Saturday, "last Saturday" means 7 days back, not today.
|
|
115
|
+
3. **"How much did I save?" is a difference, not a sum.** `save on X = original − paid`; the judge now treats save/difference-in-price-between/how-old-was-I-when/how-long-had-I-been as pair-difference derivations. Word-number answers ("Two months", "three") parse too.
|
|
116
|
+
4. **The subset-sum judge dropped the real summands.** Number-dense contexts (687 extracted numbers) hit the brute-force 20-amount truncation — "1,456 + 542 = 1,998" was judged underivable because both summands sat at index 63 and 88. Replaced with a bitset DP bounded by the *target* (O(unique_amounts × target/64) — microseconds, finds any subset, no truncation).
|
|
117
|
+
5. **Markdown escapes broke literal matching.** The haystack says `@jessica\_poole\_jewellery`, the answer says `@jessica_poole_jewellery`. The judge normalizes escapes in the *context* before matching (answers untouched).
|
|
118
|
+
6. **Aggregation retrieval missed "total number of" / "how much did I spend" phrasings** and only scored `$`-amounts — view-count sums (1,456 + 542) and gift totals ($200 + $100) never enriched. Both gate patterns and plain-number scoring added, plus plural-tolerant topic matching ("gifts" → "gift card").
|
|
119
|
+
|
|
120
|
+
**Verification:** all 21 failures re-run through the exact production runner path (`_run_one_question`, fresh per-question DB) — **21/21 pass locally**. The 20-shard full-500 revalidation runs on GitHub Actions (below) and auto-commits the measured number.
|
|
121
|
+
|
|
122
|
+
Run the full 500-Q benchmark via GitHub Actions: `.github/workflows/longmemeval_canonical_full.yml` — **20 shards × 25 questions** in parallel (the v0.6.5 layout; wall-clock ≈ one shard), contamination-guarded aggregation, results auto-committed.
|
|
123
|
+
|
|
124
|
+
### How cortexm compares (search-momentum table, honest numbers)
|
|
125
|
+
|
|
126
|
+
VoiceMem ([xzf-thu/VoiceMem](https://github.com/xzf-thu/VoiceMem), Aug 2026) popularized the side-by-side memory-system comparison. We borrowed the format — every competitor number below is quoted from their README/tech report, our numbers are measured, and **the benchmarks are different, so rows are labeled, not conflated**:
|
|
127
|
+
|
|
128
|
+
| | cortexm v0.6.5 | VoiceMem v0.0.1 | Mem0 |
|
|
129
|
+
|---|---|---|---|
|
|
130
|
+
| memory benchmark | **LongMemEval-S, 500-Q full corpus: 95.8%** (μ=0, deterministic judge) | LoCoMo 91.2% (top-5, LLM-judged) | LoCoMo 61.68% (top-200, as reported by VoiceMem) |
|
|
131
|
+
| LLM calls at ingest | **0** (μ=0 deterministic extractor) | OpenAI API required for extraction | LLM extractor required |
|
|
132
|
+
| retrieval | local, deterministic | local | cloud or local |
|
|
133
|
+
| retrieval latency (p50, warmed corpus) | **~50 ms** on a 636-message corpus, 2-CPU VM (1.6 ms on small corpora) | 134 ms | 1,440 ms (as reported by VoiceMem) |
|
|
134
|
+
| memory tokens injected per query | ~1.1k (top-10 structured facts) | 430 | 6,956 (as reported by VoiceMem) |
|
|
135
|
+
| voice pipeline required | **No — text-first.** Works with any front-end; if you have voice, bring your own ASR | Yes — native (ASR + VAD + speaker ID + emotion, streaming) | No |
|
|
136
|
+
| runs fully offline, no API keys | **Yes** | No (ingest needs OpenAI) | No |
|
|
137
|
+
| answer determinism | byte-exact, same result every time | — | — |
|
|
138
|
+
| provenance on every fact | BLAKE3 hash chain to source text | — | — |
|
|
139
|
+
| license | Apache 2.0 | Apache 2.0 | Apache 2.0 |
|
|
140
|
+
|
|
141
|
+
> **Why no voice?** VoiceMem's pitch is memory *for voice agents* — it owns the ASR, voiceprint, scene, and emotion stack. cortexm's pitch is memory *as a substrate*: it's voice-agnostic and modality-agnostic by design. You don't need to route your users' audio through a memory system to get long-term recall — paste the transcript (or the ASR of your choice) and the trace/VSA/verbatim tiers do the remembering. If you're building a real-time voice agent and want memory co-located with the VAD loop, VoiceMem is the specialized tool; if you want deterministic, auditable memory under any front-end — text today, voice tomorrow, whatever comes next — that's this.
|
|
142
|
+
|
|
143
|
+
### Known boundaries (the short list)
|
|
144
|
+
|
|
145
|
+
> Full detail: [`docs/FAILURE_MODES.md`](docs/FAILURE_MODES.md) — every failure tied to a public benchmark question.
|
|
146
|
+
|
|
147
|
+
1. **The extractor is a 61-pattern lookup, not a language model.** Phrasings outside the pattern library are silently dropped at ingest (e.g. "Anna has a cat named Whiskers") — they remain retrievable via verbatim/BM25 chunk recall, but never become structured facts. This is the price of μ=0: no generativity, no fabrication, no drift.
|
|
148
|
+
2. **ZK proofs are trusted-prover attestations.** The v0.6.4 backend (Pedersen + Sigma protocols on secp256k1) is sound at the commitment layer — challenges are bound to announcements, both OR-proof branches verify, H has no known discrete log, thresholds are enforced — but the linkage between committed values and store rows is established at prove-time by the prover. Verify the integration layer before trusting it against a malicious host.
|
|
149
|
+
3. **Set membership reveals the leaf index.** The value stays hidden (random-blinding Pedersen + equality proof); the position in the set does not. Position-hiding needs a ZK-friendly Merkle construction — documented future work.
|
|
150
|
+
4. **No cross-user inference, ever.** Every fact is scoped by `user_id`; the scope sandbox turns empty scopes into empty results (not unrestricted fallbacks). This is a feature, and it also means no "insight across users" stories.
|
|
151
|
+
5. **Compression tiers are documented, not default.** int8/binary quantization trade recall for space (see `docs/COMPRESSION.md`); the default build keeps full-precision embeddings because the benchmark headroom doesn't justify the loss yet.
|
|
152
|
+
6. **Judge coverage is rule-based.** The deterministic judge answers via strategy dispatch (bool/list/nugget/sum_or_diff/percentage/numeric_agg/holiday/paren). Questions outside those strategies score 0 even when retrieval succeeded — the failure is honest, the number is real.
|
|
153
|
+
|
|
154
|
+
### When to use cortexm vs Mem0 / Zep / Chroma
|
|
155
|
+
|
|
156
|
+
- **Use cortexm if** you want $0 queries, byte-exact determinism, full ownership of your data (one `.db` file you can back up), and traceable provenance on every retrieved fact (BLAKE3 hash chain + `EXTRACTED_FROM` audit edge).
|
|
157
|
+
- **Use Mem0** for a 1-line cloud-managed setup where you don't care about per-query cost or determinism, and you're OK with the LLM extractor occasionally fabricating facts you can't audit.
|
|
158
|
+
- **Use Zep** for long-term graph memory across many users with cloud SaaS pricing when byte-exact replay isn't a requirement.
|
|
159
|
+
- **Use Chroma** when you only need a vector DB (cortexm ships a vector DB inside, but Chroma is a fine standalone choice).
|
|
160
|
+
|
|
161
|
+
### Drop-in plugins (already shipped)
|
|
162
|
+
|
|
163
|
+
- **Mem0-compatible surface**: `from cortexm import Memory` — drop-in for `from mem0 import Memory`
|
|
164
|
+
- **LangChain**: [`plugins/langchain`](plugins/langchain) → `context-m-langchain` on PyPI
|
|
165
|
+
- **LlamaIndex**: [`plugins/llamaindex`](plugins/llamaindex) → postprocessor
|
|
166
|
+
- **OpenAI Agents SDK**: [`plugins/openai_agents`](plugins/openai_agents)
|
|
167
|
+
- **Claude Code**: [`plugins/context-m-claude`](plugins/context-m-claude) — session lifecycle hooks
|
|
168
|
+
- **MCP server**: `cortexm serve` (stdio JSON-RPC, zero extra dependencies)
|
|
169
|
+
- **REST server**: `cortexm serve-rest` — OpenAPI 3.1, bearer auth, Prometheus `/metrics`
|
|
170
|
+
- **Migration**: `cortexm migrate --from mem0|zep|chroma --path ...`
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
### Documentation
|
|
175
|
+
|
|
176
|
+
The README is intentionally short. Everything else lives in `docs/`:
|
|
177
|
+
|
|
178
|
+
| Doc | What's in it |
|
|
179
|
+
|---|---|
|
|
180
|
+
| [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) | Layer 1 Symbolic Trace + Layer 2 VSA Palace + μ=0 Bridge in detail |
|
|
181
|
+
| [`docs/BENCHMARKS.md`](docs/BENCHMARKS.md) | Full Tier 1-4 results: OOD, in-distribution, real-GitHub, canonical LongMemEval |
|
|
182
|
+
| [`docs/METHODOLOGY.md`](docs/METHODOLOGY.md) | How every headline number was measured + honest scope |
|
|
183
|
+
| [`docs/FAILURE_MODES.md`](docs/FAILURE_MODES.md) | Where the μ=0 extractor breaks on real phrasing (read before citing any number) |
|
|
184
|
+
| [`docs/RESEARCH.md`](docs/RESEARCH.md) | Literature lineage: every paper we adopted, aligned, or rejected (with reasons) |
|
|
185
|
+
| [`docs/SECURITY.md`](docs/SECURITY.md) | InjecMEM + MINJA defenses, scope sandbox, PermissionGate, provenance model |
|
|
186
|
+
| [`docs/ENTERPRISE.md`](docs/ENTERPRISE.md) | PII firewall, encryption at rest, RBAC, audit, GDPR, backup/DR, REST API |
|
|
187
|
+
| [`docs/DEPLOYMENT.md`](docs/DEPLOYMENT.md) | SDK / MCP / REST / Docker / K8s / Helm runbooks |
|
|
188
|
+
| [`docs/COMPRESSION.md`](docs/COMPRESSION.md) | Storage tiers (int8 / binary / rabitq / pq) + measured trade-offs |
|
|
189
|
+
| [`docs/ROADMAP.md`](docs/ROADMAP.md) | Phase status vs the strategic plan |
|
|
190
|
+
| [`docs/GOVERNANCE.md`](docs/GOVERNANCE.md) | Foundation governance + licensing commitments |
|
|
191
|
+
| [`docs/PLAYBOOK_v2.md`](docs/PLAYBOOK_v2.md) | Migration playbook from Mem0 / Zep / Chroma |
|
|
192
|
+
|
|
193
|
+
### Examples & tests
|
|
194
|
+
|
|
195
|
+
- [`examples/`](examples/) — runnable scripts, offline, no API keys (01_quickstart → 20_agent_session)
|
|
196
|
+
- [`tests/`](tests/) — 733 tests: fabric + enterprise + PPR + concurrency + sandbox + enrichment + WAL crash-recovery + migration + CRDT federation + Rust parity + ZK soundness/forgery + public-API smoke
|
|
197
|
+
- [`cortexm/experimental/`](cortexm/experimental/) — deterministic research borrows (graph recall, coherence) — μ=0 or it doesn't ship
|
|
198
|
+
- [`leaderboard/`](leaderboard/) — self-hosted benchmark site (rebuild: `python leaderboard/build.py`; open `leaderboard/index.html`)
|
|
199
|
+
- [`AGENTS.md`](AGENTS.md) — how AI coding agents should interact with this repo (2026 standard)
|
|
200
|
+
- [`CONTRIBUTING.md`](CONTRIBUTING.md) — contribution guide
|
|
201
|
+
|
|
202
|
+
### License
|
|
203
|
+
|
|
204
|
+
Apache 2.0 — open core done right: the memory fabric is and stays open; federated sync and the audit UI are the enterprise tier.
|
cortexm-0.6.5/README.md
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<h1>cortexm</h1>
|
|
3
|
+
<h3>Deterministic agent memory. μ=0. Free, local, forever. Same result every time.</h3>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
<div align="center">
|
|
7
|
+
<a href="https://github.com/ssmurfgg04-gif/context-m/actions/workflows/test.yml"><img src="https://github.com/ssmurfgg04-gif/context-m/actions/workflows/test.yml/badge.svg?branch=main" alt="Tests"></a>
|
|
8
|
+
<a href="https://pypi.org/project/cortexm/"><img src="https://img.shields.io/pypi/v/cortexm?color=%2334D058&label=pypi" alt="PyPI"></a>
|
|
9
|
+
<a href="https://pypi.org/project/cortexm/"><img src="https://img.shields.io/pypi/pyversions/cortexm.svg?color=%2334D058" alt="Python"></a>
|
|
10
|
+
<a href="https://github.com/ssmurfgg04-gif/context-m/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-Apache%202.0-blue.svg" alt="License"></a>
|
|
11
|
+
<a href="https://www.npmjs.com/package/dsh-cortexm"><img src="https://img.shields.io/npm/v/dsh-cortexm?color=%2334D058&label=npm%20%7Cdsh" alt="npm"></a>
|
|
12
|
+
<a href="https://github.com/ssmurfgg04-gif/context-m/blob/main/AGENTS.md"><img src="https://img.shields.io/badge/AGENTS.md-2026-2f2f2f?logo=github" alt="AGENTS.md"></a>
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<br>
|
|
16
|
+
|
|
17
|
+
> **cortexm remembers what you tell it. Forever. For free. On your machine. Same result every time.**
|
|
18
|
+
|
|
19
|
+
Mem0-compatible drop-in: `from mem0 import Memory` → `from cortexm import Memory`. Zero LLM calls at ingest. Zero LLM calls at retrieval. Zero monthly cost. Every retrieved fact carries a BLAKE3 hash chain back to the source text. One `.db` file you own.
|
|
20
|
+
|
|
21
|
+
### Quick start
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pip install cortexm # works offline, no API keys, single command
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
from cortexm import Memory # Mem0-compatible surface
|
|
29
|
+
|
|
30
|
+
m = Memory()
|
|
31
|
+
m.add("I work at Google", user_id="alice")
|
|
32
|
+
m.search("Where does Alice work?", user_id="alice")
|
|
33
|
+
# → [Memory — Known facts]
|
|
34
|
+
# - (Alice, works_at, Google) [valid 2026-08-27→∞; conf 0.92;
|
|
35
|
+
# id 3f2a91c2; src #a1b2c3d4; "I work at Google"]
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Canonical LongMemEval — μ=0, $0, on a 4GB laptop
|
|
39
|
+
|
|
40
|
+
| | cortexm v0.6.4 (measured, clean) | MemPalace (honest E2E) |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| **canonical LongMemEval (500-Q full corpus)** | **95.8% (479/500)** | ~96.6% (retrieval-only, no QA) |
|
|
43
|
+
| single_session | 95.51% | — |
|
|
44
|
+
| knowledge_update | 98.72% | — |
|
|
45
|
+
| multi_session | 94.74% | — |
|
|
46
|
+
| temporal_reasoning | 95.49% | — |
|
|
47
|
+
| LLM calls (ingest + retrieval + judge) | 0 | 0 |
|
|
48
|
+
| monthly cost | $0 | $0 |
|
|
49
|
+
| determinism | byte-exact across 3× runs | byte-exact |
|
|
50
|
+
| owns your data | ✓ single `.db` file | ✓ |
|
|
51
|
+
|
|
52
|
+
**Full 500-question results — v0.6.4, the first full-corpus run that actually completed.**
|
|
53
|
+
|
|
54
|
+
> **Honesty correction #1 (v0.6.4):** the v0.6.2 README claimed 97.4% (487/500), but that number was never measured — the full-500 workflow shipped in the same commit with a broken dataset-download step and died on every invocation. The real slices from that era scored **0.943**.
|
|
55
|
+
>
|
|
56
|
+
> **Honesty correction #2 (v0.6.5):** the v0.6.4 README claimed 94.4% (472/500) — that number was **contaminated**. The aggregate step globbed `benchmarks/results/canonical_slice_*.json` on a checkout that also contained stale partial slices from earlier local runs; "later slice wins" silently let 100 v0.6.3-era results override fresh v0.6.4 shards (the evidence: 100 results carried `learned 2026-08-29` ingest dates inside a run that happened on 08-31, and 8 of the 28 "failures" pass on the fresh shards). Re-aggregated from the five real shard artifacts only: **0.958 (479/500)**. v0.6.5 makes this structurally impossible — shards aggregate from a clean directory, the aggregate script refuses verdict-flipping duplicates (exit 2), and every aggregate is stamped with git sha + per-file counts (`benchmarks/results/canonical_full.json` → `aggregate_provenance`).
|
|
57
|
+
|
|
58
|
+
| Subtask | Score | Notes |
|
|
59
|
+
|---|---|---|
|
|
60
|
+
| **Overall (clean aggregate)** | **0.958 (479/500)** | 21 real failures, all diagnosed and fixed in v0.6.5 (below) |
|
|
61
|
+
| knowledge_update | 0.9872 | 1 failure |
|
|
62
|
+
| temporal_reasoning | 0.9549 | 6 failures on relative-time anchors |
|
|
63
|
+
| single_session | 0.9551 | 7 failures on assistant-reply recall |
|
|
64
|
+
| multi_session | 0.9474 | 7 failures on sum/difference derivation |
|
|
65
|
+
|
|
66
|
+
### What the 21 failures taught us (v0.6.5 — all boring fixes, Pareto-first)
|
|
67
|
+
|
|
68
|
+
Every one of the 21 real failures was reproduced, root-caused, and fixed with the *boring* mechanism — no new models, no embedder swap, nothing dropped:
|
|
69
|
+
|
|
70
|
+
1. **Assistant messages were truncated at 800 chars — segment them instead.** 7 single_session answers ("Veja", "Absinthe", "Nu, pogodi!", "@jessica\_poole\_jewellery", "Hoop Dance", the 27th-of-100 parameter, the two sad songs) sat at byte 817–1764 of long assistant replies. `split_long_message()` now cuts at sentence boundaries into ≤2000-char segments — zero content loss, and each segment is a *better* BM25 unit than the whole reply.
|
|
71
|
+
2. **Relative-time questions need calendar math, not vocabulary.** "two weeks ago" / "last Saturday" / "10 days ago" answer chunks share no query terms ("music event" vs "saw Queen live with my parents"). The runner now ingests each session's `haystack_date` as the chunk timestamp, resolves the question's relative phrase against `question_date`, and pulls every chunk in the resolved window. 6/6 temporal failures fixed — including the subtle one: on a Saturday, "last Saturday" means 7 days back, not today.
|
|
72
|
+
3. **"How much did I save?" is a difference, not a sum.** `save on X = original − paid`; the judge now treats save/difference-in-price-between/how-old-was-I-when/how-long-had-I-been as pair-difference derivations. Word-number answers ("Two months", "three") parse too.
|
|
73
|
+
4. **The subset-sum judge dropped the real summands.** Number-dense contexts (687 extracted numbers) hit the brute-force 20-amount truncation — "1,456 + 542 = 1,998" was judged underivable because both summands sat at index 63 and 88. Replaced with a bitset DP bounded by the *target* (O(unique_amounts × target/64) — microseconds, finds any subset, no truncation).
|
|
74
|
+
5. **Markdown escapes broke literal matching.** The haystack says `@jessica\_poole\_jewellery`, the answer says `@jessica_poole_jewellery`. The judge normalizes escapes in the *context* before matching (answers untouched).
|
|
75
|
+
6. **Aggregation retrieval missed "total number of" / "how much did I spend" phrasings** and only scored `$`-amounts — view-count sums (1,456 + 542) and gift totals ($200 + $100) never enriched. Both gate patterns and plain-number scoring added, plus plural-tolerant topic matching ("gifts" → "gift card").
|
|
76
|
+
|
|
77
|
+
**Verification:** all 21 failures re-run through the exact production runner path (`_run_one_question`, fresh per-question DB) — **21/21 pass locally**. The 20-shard full-500 revalidation runs on GitHub Actions (below) and auto-commits the measured number.
|
|
78
|
+
|
|
79
|
+
Run the full 500-Q benchmark via GitHub Actions: `.github/workflows/longmemeval_canonical_full.yml` — **20 shards × 25 questions** in parallel (the v0.6.5 layout; wall-clock ≈ one shard), contamination-guarded aggregation, results auto-committed.
|
|
80
|
+
|
|
81
|
+
### How cortexm compares (search-momentum table, honest numbers)
|
|
82
|
+
|
|
83
|
+
VoiceMem ([xzf-thu/VoiceMem](https://github.com/xzf-thu/VoiceMem), Aug 2026) popularized the side-by-side memory-system comparison. We borrowed the format — every competitor number below is quoted from their README/tech report, our numbers are measured, and **the benchmarks are different, so rows are labeled, not conflated**:
|
|
84
|
+
|
|
85
|
+
| | cortexm v0.6.5 | VoiceMem v0.0.1 | Mem0 |
|
|
86
|
+
|---|---|---|---|
|
|
87
|
+
| memory benchmark | **LongMemEval-S, 500-Q full corpus: 95.8%** (μ=0, deterministic judge) | LoCoMo 91.2% (top-5, LLM-judged) | LoCoMo 61.68% (top-200, as reported by VoiceMem) |
|
|
88
|
+
| LLM calls at ingest | **0** (μ=0 deterministic extractor) | OpenAI API required for extraction | LLM extractor required |
|
|
89
|
+
| retrieval | local, deterministic | local | cloud or local |
|
|
90
|
+
| retrieval latency (p50, warmed corpus) | **~50 ms** on a 636-message corpus, 2-CPU VM (1.6 ms on small corpora) | 134 ms | 1,440 ms (as reported by VoiceMem) |
|
|
91
|
+
| memory tokens injected per query | ~1.1k (top-10 structured facts) | 430 | 6,956 (as reported by VoiceMem) |
|
|
92
|
+
| voice pipeline required | **No — text-first.** Works with any front-end; if you have voice, bring your own ASR | Yes — native (ASR + VAD + speaker ID + emotion, streaming) | No |
|
|
93
|
+
| runs fully offline, no API keys | **Yes** | No (ingest needs OpenAI) | No |
|
|
94
|
+
| answer determinism | byte-exact, same result every time | — | — |
|
|
95
|
+
| provenance on every fact | BLAKE3 hash chain to source text | — | — |
|
|
96
|
+
| license | Apache 2.0 | Apache 2.0 | Apache 2.0 |
|
|
97
|
+
|
|
98
|
+
> **Why no voice?** VoiceMem's pitch is memory *for voice agents* — it owns the ASR, voiceprint, scene, and emotion stack. cortexm's pitch is memory *as a substrate*: it's voice-agnostic and modality-agnostic by design. You don't need to route your users' audio through a memory system to get long-term recall — paste the transcript (or the ASR of your choice) and the trace/VSA/verbatim tiers do the remembering. If you're building a real-time voice agent and want memory co-located with the VAD loop, VoiceMem is the specialized tool; if you want deterministic, auditable memory under any front-end — text today, voice tomorrow, whatever comes next — that's this.
|
|
99
|
+
|
|
100
|
+
### Known boundaries (the short list)
|
|
101
|
+
|
|
102
|
+
> Full detail: [`docs/FAILURE_MODES.md`](docs/FAILURE_MODES.md) — every failure tied to a public benchmark question.
|
|
103
|
+
|
|
104
|
+
1. **The extractor is a 61-pattern lookup, not a language model.** Phrasings outside the pattern library are silently dropped at ingest (e.g. "Anna has a cat named Whiskers") — they remain retrievable via verbatim/BM25 chunk recall, but never become structured facts. This is the price of μ=0: no generativity, no fabrication, no drift.
|
|
105
|
+
2. **ZK proofs are trusted-prover attestations.** The v0.6.4 backend (Pedersen + Sigma protocols on secp256k1) is sound at the commitment layer — challenges are bound to announcements, both OR-proof branches verify, H has no known discrete log, thresholds are enforced — but the linkage between committed values and store rows is established at prove-time by the prover. Verify the integration layer before trusting it against a malicious host.
|
|
106
|
+
3. **Set membership reveals the leaf index.** The value stays hidden (random-blinding Pedersen + equality proof); the position in the set does not. Position-hiding needs a ZK-friendly Merkle construction — documented future work.
|
|
107
|
+
4. **No cross-user inference, ever.** Every fact is scoped by `user_id`; the scope sandbox turns empty scopes into empty results (not unrestricted fallbacks). This is a feature, and it also means no "insight across users" stories.
|
|
108
|
+
5. **Compression tiers are documented, not default.** int8/binary quantization trade recall for space (see `docs/COMPRESSION.md`); the default build keeps full-precision embeddings because the benchmark headroom doesn't justify the loss yet.
|
|
109
|
+
6. **Judge coverage is rule-based.** The deterministic judge answers via strategy dispatch (bool/list/nugget/sum_or_diff/percentage/numeric_agg/holiday/paren). Questions outside those strategies score 0 even when retrieval succeeded — the failure is honest, the number is real.
|
|
110
|
+
|
|
111
|
+
### When to use cortexm vs Mem0 / Zep / Chroma
|
|
112
|
+
|
|
113
|
+
- **Use cortexm if** you want $0 queries, byte-exact determinism, full ownership of your data (one `.db` file you can back up), and traceable provenance on every retrieved fact (BLAKE3 hash chain + `EXTRACTED_FROM` audit edge).
|
|
114
|
+
- **Use Mem0** for a 1-line cloud-managed setup where you don't care about per-query cost or determinism, and you're OK with the LLM extractor occasionally fabricating facts you can't audit.
|
|
115
|
+
- **Use Zep** for long-term graph memory across many users with cloud SaaS pricing when byte-exact replay isn't a requirement.
|
|
116
|
+
- **Use Chroma** when you only need a vector DB (cortexm ships a vector DB inside, but Chroma is a fine standalone choice).
|
|
117
|
+
|
|
118
|
+
### Drop-in plugins (already shipped)
|
|
119
|
+
|
|
120
|
+
- **Mem0-compatible surface**: `from cortexm import Memory` — drop-in for `from mem0 import Memory`
|
|
121
|
+
- **LangChain**: [`plugins/langchain`](plugins/langchain) → `context-m-langchain` on PyPI
|
|
122
|
+
- **LlamaIndex**: [`plugins/llamaindex`](plugins/llamaindex) → postprocessor
|
|
123
|
+
- **OpenAI Agents SDK**: [`plugins/openai_agents`](plugins/openai_agents)
|
|
124
|
+
- **Claude Code**: [`plugins/context-m-claude`](plugins/context-m-claude) — session lifecycle hooks
|
|
125
|
+
- **MCP server**: `cortexm serve` (stdio JSON-RPC, zero extra dependencies)
|
|
126
|
+
- **REST server**: `cortexm serve-rest` — OpenAPI 3.1, bearer auth, Prometheus `/metrics`
|
|
127
|
+
- **Migration**: `cortexm migrate --from mem0|zep|chroma --path ...`
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
### Documentation
|
|
132
|
+
|
|
133
|
+
The README is intentionally short. Everything else lives in `docs/`:
|
|
134
|
+
|
|
135
|
+
| Doc | What's in it |
|
|
136
|
+
|---|---|
|
|
137
|
+
| [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) | Layer 1 Symbolic Trace + Layer 2 VSA Palace + μ=0 Bridge in detail |
|
|
138
|
+
| [`docs/BENCHMARKS.md`](docs/BENCHMARKS.md) | Full Tier 1-4 results: OOD, in-distribution, real-GitHub, canonical LongMemEval |
|
|
139
|
+
| [`docs/METHODOLOGY.md`](docs/METHODOLOGY.md) | How every headline number was measured + honest scope |
|
|
140
|
+
| [`docs/FAILURE_MODES.md`](docs/FAILURE_MODES.md) | Where the μ=0 extractor breaks on real phrasing (read before citing any number) |
|
|
141
|
+
| [`docs/RESEARCH.md`](docs/RESEARCH.md) | Literature lineage: every paper we adopted, aligned, or rejected (with reasons) |
|
|
142
|
+
| [`docs/SECURITY.md`](docs/SECURITY.md) | InjecMEM + MINJA defenses, scope sandbox, PermissionGate, provenance model |
|
|
143
|
+
| [`docs/ENTERPRISE.md`](docs/ENTERPRISE.md) | PII firewall, encryption at rest, RBAC, audit, GDPR, backup/DR, REST API |
|
|
144
|
+
| [`docs/DEPLOYMENT.md`](docs/DEPLOYMENT.md) | SDK / MCP / REST / Docker / K8s / Helm runbooks |
|
|
145
|
+
| [`docs/COMPRESSION.md`](docs/COMPRESSION.md) | Storage tiers (int8 / binary / rabitq / pq) + measured trade-offs |
|
|
146
|
+
| [`docs/ROADMAP.md`](docs/ROADMAP.md) | Phase status vs the strategic plan |
|
|
147
|
+
| [`docs/GOVERNANCE.md`](docs/GOVERNANCE.md) | Foundation governance + licensing commitments |
|
|
148
|
+
| [`docs/PLAYBOOK_v2.md`](docs/PLAYBOOK_v2.md) | Migration playbook from Mem0 / Zep / Chroma |
|
|
149
|
+
|
|
150
|
+
### Examples & tests
|
|
151
|
+
|
|
152
|
+
- [`examples/`](examples/) — runnable scripts, offline, no API keys (01_quickstart → 20_agent_session)
|
|
153
|
+
- [`tests/`](tests/) — 733 tests: fabric + enterprise + PPR + concurrency + sandbox + enrichment + WAL crash-recovery + migration + CRDT federation + Rust parity + ZK soundness/forgery + public-API smoke
|
|
154
|
+
- [`cortexm/experimental/`](cortexm/experimental/) — deterministic research borrows (graph recall, coherence) — μ=0 or it doesn't ship
|
|
155
|
+
- [`leaderboard/`](leaderboard/) — self-hosted benchmark site (rebuild: `python leaderboard/build.py`; open `leaderboard/index.html`)
|
|
156
|
+
- [`AGENTS.md`](AGENTS.md) — how AI coding agents should interact with this repo (2026 standard)
|
|
157
|
+
- [`CONTRIBUTING.md`](CONTRIBUTING.md) — contribution guide
|
|
158
|
+
|
|
159
|
+
### License
|
|
160
|
+
|
|
161
|
+
Apache 2.0 — open core done right: the memory fabric is and stays open; federated sync and the audit UI are the enterprise tier.
|
|
@@ -18,7 +18,7 @@ Plugin kernel: ``from cortexm import Context, mount_default``
|
|
|
18
18
|
|
|
19
19
|
from __future__ import annotations
|
|
20
20
|
|
|
21
|
-
__version__ = "0.6.
|
|
21
|
+
__version__ = "0.6.5"
|
|
22
22
|
|
|
23
23
|
# μ=0 protocol counter: number of LLM invocations used by this process.
|
|
24
24
|
# The BEAM-honest protocol requires this to stay 0 during ingest & retrieval.
|
|
@@ -53,13 +53,15 @@ class Memory:
|
|
|
53
53
|
config = dataclasses.replace(config, **changes)
|
|
54
54
|
self.config = config
|
|
55
55
|
self.store = TraceStore(config.db_path, HashProvider(config.hash_provider),
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
56
|
+
wal_sync=getattr(config, "wal_sync", "normal"),
|
|
57
|
+
pragma_cache_mb=getattr(config, "pragma_cache_mb", 64),
|
|
58
|
+
pragma_mmap_mb=getattr(config, "pragma_mmap_mb", 256),
|
|
59
|
+
pragma_threads=getattr(config, "pragma_threads", 4),
|
|
60
|
+
pragma_temp_in_memory=getattr(config, "pragma_temp_in_memory", True),
|
|
61
|
+
pragma_locking_exclusive=getattr(config, "pragma_locking_exclusive", False))
|
|
62
|
+
# FIX 2: Allow passing a shared embedder for persistent workers
|
|
63
|
+
shared_embedder = getattr(config, "_shared_embedder", None)
|
|
64
|
+
self.palace = MemoryPalace(config, self.store, embedder=shared_embedder)
|
|
63
65
|
self.extractor = Extractor(config)
|
|
64
66
|
self.prefetcher = Prefetcher()
|
|
65
67
|
self.writer = MemoryWriter(config, self.store, self.palace, self.extractor)
|
|
@@ -157,6 +159,51 @@ class Memory:
|
|
|
157
159
|
self._maybe_run_fade_under_pressure(user_id)
|
|
158
160
|
return out
|
|
159
161
|
|
|
162
|
+
def add_batch(self, messages_list, *, user_id: str | None = None,
|
|
163
|
+
agent_id: str | None = None, run_id: str | None = None,
|
|
164
|
+
metadata: dict | None = None, timestamp=None, **kw) -> dict:
|
|
165
|
+
"""μ=0 batch ingest. Accepts a list of messages (each str | list[str] | dict).
|
|
166
|
+
|
|
167
|
+
Wraps the entire batch in a single transaction — much faster than
|
|
168
|
+
calling add() repeatedly. All messages share the same user_id/agent_id/run_id.
|
|
169
|
+
|
|
170
|
+
Returns the same dict format as add()."""
|
|
171
|
+
user_id = user_id or self.config.default_user_id
|
|
172
|
+
ts = parse_ts(timestamp) if timestamp else None
|
|
173
|
+
if self.pii_guard.mode != "off":
|
|
174
|
+
# Apply PII to each message list
|
|
175
|
+
processed = []
|
|
176
|
+
for msgs in messages_list:
|
|
177
|
+
processed.append(self._apply_pii(msgs))
|
|
178
|
+
if processed[-1] is None:
|
|
179
|
+
self.audit_log.log("memory.add_batch", resource=user_id,
|
|
180
|
+
outcome="blocked_pii",
|
|
181
|
+
meta={"reason": "pii_mode=block"})
|
|
182
|
+
return {"results": [], "blocked": "pii_policy"}
|
|
183
|
+
messages_list = processed
|
|
184
|
+
|
|
185
|
+
# Single transaction for the entire batch
|
|
186
|
+
self.store.begin_batch()
|
|
187
|
+
try:
|
|
188
|
+
all_results = []
|
|
189
|
+
total_facts = 0
|
|
190
|
+
for messages in messages_list:
|
|
191
|
+
out = self.writer.add(messages, user_id=user_id, agent_id=agent_id,
|
|
192
|
+
run_id=run_id, ts=ts, metadata=metadata, **kw)
|
|
193
|
+
all_results.extend(out.get("results", []))
|
|
194
|
+
total_facts += out.get("stats", {}).get("facts_inserted", 0)
|
|
195
|
+
self.store.end_batch()
|
|
196
|
+
self.reader.invalidate_caches()
|
|
197
|
+
if self.config.audit_actions == "all":
|
|
198
|
+
self.audit_log.log("memory.add_batch", resource=user_id,
|
|
199
|
+
meta={"facts": total_facts})
|
|
200
|
+
return {"event": "ADD_BATCH", "results": all_results,
|
|
201
|
+
"stats": {"messages": len(messages_list),
|
|
202
|
+
"facts_inserted": total_facts, "llm_calls": 0}}
|
|
203
|
+
except Exception:
|
|
204
|
+
self.store.rollback()
|
|
205
|
+
raise
|
|
206
|
+
|
|
160
207
|
# ------------------------------------------------------------ mem.edit()
|
|
161
208
|
def edit(self, fact_id: str, new_text: str, *,
|
|
162
209
|
edited_by: str = "user", reason: str | None = None) -> dict:
|
|
@@ -1027,6 +1074,13 @@ class Memory:
|
|
|
1027
1074
|
return {"loaded": False, "reason": "file_empty_or_corrupt"}
|
|
1028
1075
|
|
|
1029
1076
|
def close(self) -> None:
|
|
1077
|
+
# Close sidecar arena first on Windows (mmap holds file lock, prevents unlink)
|
|
1078
|
+
try:
|
|
1079
|
+
arena = getattr(self, "blob_arena", None)
|
|
1080
|
+
if arena is not None:
|
|
1081
|
+
arena.close()
|
|
1082
|
+
except Exception:
|
|
1083
|
+
pass
|
|
1030
1084
|
self.palace.close()
|
|
1031
1085
|
self.store.close()
|
|
1032
1086
|
|
|
@@ -113,6 +113,29 @@ def _bitap_trigger_match(sent: str, max_edits: int = 2) -> bool:
|
|
|
113
113
|
class Extractor:
|
|
114
114
|
def __init__(self, config) -> None:
|
|
115
115
|
self.cfg = config
|
|
116
|
+
self._trigger_automaton = None
|
|
117
|
+
try:
|
|
118
|
+
import ahocorasick
|
|
119
|
+
automaton = ahocorasick.Automaton()
|
|
120
|
+
for word in _BITAP_TRIGGERS:
|
|
121
|
+
automaton.add_word(word, word)
|
|
122
|
+
automaton.make_automaton()
|
|
123
|
+
self._trigger_automaton = automaton
|
|
124
|
+
except ImportError:
|
|
125
|
+
# Package is a runtime dependency; retain the regex fallback for
|
|
126
|
+
# constrained embedded deployments with a partial installation.
|
|
127
|
+
pass
|
|
128
|
+
|
|
129
|
+
def _strict_trigger_match(self, sent: str) -> bool:
|
|
130
|
+
if self._trigger_automaton is None:
|
|
131
|
+
return bool(_TRIGGER.search(sent))
|
|
132
|
+
lowered = sent.lower()
|
|
133
|
+
for end, word in self._trigger_automaton.iter(lowered):
|
|
134
|
+
start = end - len(word) + 1
|
|
135
|
+
if (start == 0 or not lowered[start - 1].isalnum()) and \
|
|
136
|
+
(end + 1 == len(lowered) or not lowered[end + 1].isalnum()):
|
|
137
|
+
return True
|
|
138
|
+
return bool(_DATE_TRIGGER.search(sent)) or bool(_TRIGGER.search(sent))
|
|
116
139
|
|
|
117
140
|
# ------------------------------------------------------------------
|
|
118
141
|
def extract(self, text: str, ctx: ExtractionContext) -> list[Candidate]:
|
|
@@ -184,7 +207,7 @@ class Extractor:
|
|
|
184
207
|
# against the sentence with up to N edits. This stays deterministic
|
|
185
208
|
# (Wu-Manber is bitwise, no learned weights) and <50μs on a typical
|
|
186
209
|
# sentence — same order as the regex itself.
|
|
187
|
-
trigger_fired =
|
|
210
|
+
trigger_fired = self._strict_trigger_match(sent)
|
|
188
211
|
bitap_widened = False
|
|
189
212
|
if not trigger_fired:
|
|
190
213
|
if (not getattr(self.cfg, "bitap_trigger_enabled", True)
|
|
@@ -163,6 +163,11 @@ class TinyTransformerFallback:
|
|
|
163
163
|
self.seed = seed & 0xFFFFFFFFFFFFFFFF
|
|
164
164
|
self.max_tokens = max_tokens
|
|
165
165
|
self.tables = _HashedTables(self.seed)
|
|
166
|
+
# Relation labels are drawn from a small, stable vocabulary. The
|
|
167
|
+
# fallback evaluates every label for every pattern miss, so caching
|
|
168
|
+
# their deterministic embeddings avoids repeating the same attention
|
|
169
|
+
# computation dozens of times per sentence.
|
|
170
|
+
self._relation_embeddings: dict[str, np.ndarray] = {}
|
|
166
171
|
|
|
167
172
|
# ------------------------------------------------------------------
|
|
168
173
|
def _tokenize(self, text: str) -> list[str]:
|
|
@@ -213,6 +218,19 @@ class TinyTransformerFallback:
|
|
|
213
218
|
n = float(np.linalg.norm(pooled))
|
|
214
219
|
return pooled / n if n > 0 else pooled
|
|
215
220
|
|
|
221
|
+
def _relation_embedding(self, relation: str) -> np.ndarray:
|
|
222
|
+
"""Return the deterministic embedding for a relation label.
|
|
223
|
+
|
|
224
|
+
Relation labels are immutable strings and ``embed`` has no mutable
|
|
225
|
+
input-dependent state, so retaining this vector is semantically
|
|
226
|
+
equivalent to recomputing it on every fallback invocation.
|
|
227
|
+
"""
|
|
228
|
+
hit = self._relation_embeddings.get(relation)
|
|
229
|
+
if hit is None:
|
|
230
|
+
hit = self.embed(relation.replace("_", " "))
|
|
231
|
+
self._relation_embeddings[relation] = hit
|
|
232
|
+
return hit
|
|
233
|
+
|
|
216
234
|
# ------------------------------------------------------------------
|
|
217
235
|
def extract_candidates(self, sent: str, *,
|
|
218
236
|
subject_hint: str | None = None,
|
|
@@ -251,7 +269,7 @@ class TinyTransformerFallback:
|
|
|
251
269
|
rels = relations or _DEFAULT_RELATIONS
|
|
252
270
|
rel_scores = []
|
|
253
271
|
for r in rels:
|
|
254
|
-
r_emb = self.
|
|
272
|
+
r_emb = self._relation_embedding(r)
|
|
255
273
|
score = float(np.dot(sent_emb, r_emb))
|
|
256
274
|
rel_scores.append((r, score, r_emb))
|
|
257
275
|
rel_scores.sort(key=lambda x: -x[1])
|