agmem 0.1.6__py3-none-any.whl → 0.2.1__py3-none-any.whl
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.
- {agmem-0.1.6.dist-info → agmem-0.2.1.dist-info}/METADATA +15 -8
- {agmem-0.1.6.dist-info → agmem-0.2.1.dist-info}/RECORD +25 -16
- memvcs/__init__.py +1 -1
- memvcs/cli.py +1 -1
- memvcs/commands/daemon.py +37 -1
- memvcs/commands/distill.py +6 -0
- memvcs/coordinator/__init__.py +5 -0
- memvcs/coordinator/server.py +239 -0
- memvcs/core/compression_metrics.py +248 -0
- memvcs/core/delta.py +258 -0
- memvcs/core/distiller.py +76 -61
- memvcs/core/fast_similarity.py +404 -0
- memvcs/core/federated.py +13 -2
- memvcs/core/gardener.py +8 -68
- memvcs/core/pack.py +192 -34
- memvcs/core/privacy_validator.py +187 -0
- memvcs/core/protocol_builder.py +198 -0
- memvcs/core/remote.py +82 -2
- memvcs/core/zk_proofs.py +62 -5
- memvcs/health/__init__.py +25 -0
- memvcs/health/monitor.py +452 -0
- {agmem-0.1.6.dist-info → agmem-0.2.1.dist-info}/WHEEL +0 -0
- {agmem-0.1.6.dist-info → agmem-0.2.1.dist-info}/entry_points.txt +0 -0
- {agmem-0.1.6.dist-info → agmem-0.2.1.dist-info}/licenses/LICENSE +0 -0
- {agmem-0.1.6.dist-info → agmem-0.2.1.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agmem
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Agentic Memory Version Control System - Git for AI agent memories
|
|
5
5
|
Home-page: https://github.com/vivek-tiwari-vt/agmem
|
|
6
6
|
Author: agmem Team
|
|
@@ -10,7 +10,7 @@ Project-URL: Homepage, https://github.com/vivek-tiwari-vt/agmem
|
|
|
10
10
|
Project-URL: Documentation, https://github.com/vivek-tiwari-vt/agmem#readme
|
|
11
11
|
Project-URL: Repository, https://github.com/vivek-tiwari-vt/agmem
|
|
12
12
|
Project-URL: Bug Tracker, https://github.com/vivek-tiwari-vt/agmem/issues
|
|
13
|
-
Keywords: ai,agent,memory,version-control,git,vcs,llm,merkle,audit,encryption,differential-privacy,trust,multi-agent
|
|
13
|
+
Keywords: ai,agent,memory,version-control,git,vcs,llm,merkle,audit,encryption,differential-privacy,trust,multi-agent,health-monitoring,delta-encoding,ipfs,federated
|
|
14
14
|
Classifier: Development Status :: 3 - Alpha
|
|
15
15
|
Classifier: Intended Audience :: Developers
|
|
16
16
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -71,6 +71,10 @@ Provides-Extra: ipfs
|
|
|
71
71
|
Requires-Dist: requests>=2.28.0; extra == "ipfs"
|
|
72
72
|
Provides-Extra: ipfs-daemon
|
|
73
73
|
Requires-Dist: ipfshttpclient>=0.8.0; extra == "ipfs-daemon"
|
|
74
|
+
Provides-Extra: coordinator
|
|
75
|
+
Requires-Dist: fastapi>=0.100.0; extra == "coordinator"
|
|
76
|
+
Requires-Dist: uvicorn[standard]>=0.22.0; extra == "coordinator"
|
|
77
|
+
Requires-Dist: pydantic>=2.0.0; extra == "coordinator"
|
|
74
78
|
Provides-Extra: all
|
|
75
79
|
Requires-Dist: mcp>=1.0.0; extra == "all"
|
|
76
80
|
Requires-Dist: cryptography>=41.0.0; extra == "all"
|
|
@@ -88,6 +92,7 @@ Requires-Dist: networkx>=3.0; extra == "all"
|
|
|
88
92
|
Requires-Dist: tiktoken>=0.5.0; extra == "all"
|
|
89
93
|
Requires-Dist: presidio-analyzer>=2.2.0; extra == "all"
|
|
90
94
|
Requires-Dist: requests>=2.28.0; extra == "all"
|
|
95
|
+
Requires-Dist: pydantic>=2.0.0; extra == "all"
|
|
91
96
|
Dynamic: author
|
|
92
97
|
Dynamic: home-page
|
|
93
98
|
Dynamic: license-file
|
|
@@ -132,13 +137,15 @@ agmem solves all of these problems with a familiar Git-like interface.
|
|
|
132
137
|
- ✅ **Tamper-evident audit trail** — Append-only hash-chained log (init, add, commit, checkout, merge, push, pull, config); `agmem audit` and `agmem audit --verify`
|
|
133
138
|
- ✅ **Multi-agent trust** — Trust store (full / conditional / untrusted) per public key; applied on pull/merge; clone copies remote keys
|
|
134
139
|
- ✅ **Conflict resolution** — `agmem resolve` with ours/theirs/both; conflicts persisted in `.mem/merge/`; path-safe
|
|
135
|
-
- ✅ **Differential privacy** — Epsilon/delta budget in `.mem/privacy_budget.json`; `--private` on `agmem distill` and `agmem garden`; noise
|
|
140
|
+
- ✅ **Differential privacy** — Epsilon/delta budget in `.mem/privacy_budget.json`; `--private` on `agmem distill` and `agmem garden`; noise applies to fact-level data only (metadata fields excluded)
|
|
136
141
|
- ✅ **Pack files & GC** — `agmem gc [--repack]` (reachable from refs, prune loose, optional pack file + index); ObjectStore reads from pack when loose missing
|
|
137
142
|
- ✅ **Multi-provider LLM** — OpenAI and Anthropic via `memvcs.core.llm`; config/repo or env; used by gardener, distiller, consistency, merge
|
|
138
143
|
- ✅ **Temporal querying** — Point-in-time and range queries in temporal index; frontmatter timestamps
|
|
139
|
-
- ✅ **Federated collaboration** — `agmem federated push|pull`;
|
|
140
|
-
- ✅ **Zero-knowledge proofs** — `agmem prove` (hash/signature-based): keyword containment (Merkle set membership), memory freshness (signed timestamp)
|
|
141
|
-
- ✅ **Daemon health** —
|
|
144
|
+
- ✅ **Federated collaboration** — `agmem federated push|pull`; protocol-compliant summaries (agent_id, timestamp, topic_counts, fact_hashes); optional DP on outbound; coordinator API in docs/FEDERATED.md
|
|
145
|
+
- ✅ **Zero-knowledge proofs** — `agmem prove` (hash/signature-based): keyword containment (Merkle set membership), memory freshness (signed timestamp). **Note:** Current implementation is proof-of-knowledge with known limitations; see docs for migration to true zk-SNARKs.
|
|
146
|
+
- ✅ **Daemon health** — 4-point health monitoring (storage, redundancy, staleness, graph consistency) with periodic checks; visible warnings and JSON reports
|
|
147
|
+
- ✅ **Delta encoding** — 5-10x compression for similar objects using Levenshtein distance and SequenceMatcher; enabled in GC repack with multi-tier similarity filtering
|
|
148
|
+
- ✅ **Performance safeguards** — Multi-tier similarity filter (length ratio + SimHash) avoids O(n²×m²) worst-case comparisons
|
|
142
149
|
- ✅ **GPU acceleration** — Vector store detects GPU for embedding model when available
|
|
143
150
|
- ✅ **Optional** — `serve`, `daemon` (watch + auto-commit), `garden` (episode archival), MCP server; install extras as needed
|
|
144
151
|
|
|
@@ -469,8 +476,8 @@ The following 18 capabilities are implemented (or stubbed) per the agmem feature
|
|
|
469
476
|
|
|
470
477
|
| # | Feature | Description |
|
|
471
478
|
|---|---------|-------------|
|
|
472
|
-
| **7** | **Differential privacy** | Epsilon/delta budget per repo in `.mem/privacy_budget.json`. **Usage:** `agmem distill --private`, `agmem garden --private`; blocks when budget exceeded. Config: `differential_privacy.max_epsilon`, `delta`. |
|
|
473
|
-
| **8** | **
|
|
479
|
+
| **7** | **Differential privacy** | Epsilon/delta budget per repo in `.mem/privacy_budget.json`. **Usage:** `agmem distill --private`, `agmem garden --private`; blocks when budget exceeded. Config: `differential_privacy.max_epsilon`, `delta`. **Note:** Now correctly applied to actual facts during extraction, not metadata counts. |
|
|
480
|
+
| **8** | **Cryptographic proofs (proof-of-knowledge)** | Hash/signature-based proofs for keyword containment (Merkle set membership) and memory freshness (signed timestamp). **Command:** `agmem prove --memory <path> --property keyword\|freshness --value <v> [-o out]`. **IMPORTANT:** These are proof-of-knowledge, not true zero-knowledge proofs. Keyword proof leaks word count and allows verifier to test other words. Freshness proof relies on forgeable filesystem mtime. See `memvcs/core/zk_proofs.py` for details and migration path to zk-SNARKs. |
|
|
474
481
|
|
|
475
482
|
### Tier 4 — Storage and distribution
|
|
476
483
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
agmem-0.1.
|
|
2
|
-
memvcs/__init__.py,sha256=
|
|
3
|
-
memvcs/cli.py,sha256=
|
|
1
|
+
agmem-0.2.1.dist-info/licenses/LICENSE,sha256=X_S6RBErW-F0IDbM3FAEoDB-zxExFnl2m8640rTXphM,1067
|
|
2
|
+
memvcs/__init__.py,sha256=PwF2IkjOfw5nZCDcZdsNKns-h-FEvRahAqNd37Ti8_8,193
|
|
3
|
+
memvcs/cli.py,sha256=WPjhbevcOc_w_7SEXV5oitbEA5kYY5lHWgyTOq6x8sU,6075
|
|
4
4
|
memvcs/commands/__init__.py,sha256=A2D6xWaO6epU7iV4QSvqvF5TspnwRyDN7NojmGatPrE,510
|
|
5
5
|
memvcs/commands/add.py,sha256=k9eM7qf2NFvneiJkFQNiAYFB2GgKmyPw_NXmkCxblQE,8736
|
|
6
6
|
memvcs/commands/audit.py,sha256=E6m54B726tqDQR3rrgRXWrjE-seu2UocqrFxN1aHkY4,1680
|
|
@@ -11,10 +11,10 @@ memvcs/commands/checkout.py,sha256=xaYZSbCQ-MyLWPtwA2FdH6WqGMI3oF3R2JmCufGBVFg,3
|
|
|
11
11
|
memvcs/commands/clean.py,sha256=e0OhSQdHfFnOPTRbyKbM8IcX4yJD5n_kaBKjIeoaRBo,1973
|
|
12
12
|
memvcs/commands/clone.py,sha256=aB0LcugIWJE9IEez6y70KlpZu4eIF2EdXZxE24jXyac,3260
|
|
13
13
|
memvcs/commands/commit.py,sha256=W4ulVZuEETJh1SHpscaQfNjyQMqeIE0AYZIbMbTrsq4,6801
|
|
14
|
-
memvcs/commands/daemon.py,sha256=
|
|
14
|
+
memvcs/commands/daemon.py,sha256=FlPBh41v-S__QhC68FzRYbsumARQgLbP2904k7jaZ6k,12522
|
|
15
15
|
memvcs/commands/decay.py,sha256=QcgOTMJZxrfw_AOz94YHA3LGoNXRMDn69TxWlUrpSw4,2421
|
|
16
16
|
memvcs/commands/diff.py,sha256=KcgD57_fae4uvQ8G9ZbXmLpAYYIDiWiBuVcjsDtyE1U,5480
|
|
17
|
-
memvcs/commands/distill.py,sha256=
|
|
17
|
+
memvcs/commands/distill.py,sha256=eO9n2KxBaIhdvKBnqcrgYH5aoJ7dR5C2WNge_z6ITlw,3330
|
|
18
18
|
memvcs/commands/federated.py,sha256=Zj4kxHnjdIs1xu4v7B8XosQXNYK8Alv4I0kJQpmJe6Y,1840
|
|
19
19
|
memvcs/commands/fsck.py,sha256=AdJBMLA2myQ0cJJcjUgsYptsE3qvX4JQc9UAwVmSHlA,7772
|
|
20
20
|
memvcs/commands/garden.py,sha256=8JiLe3JRkOhY-N-h-IDuvdJiECiSElnUzXVtxtU2QgY,4050
|
|
@@ -46,30 +46,37 @@ memvcs/commands/timeline.py,sha256=JkuhsQ-6wPWbsjlbJb_qM4mEkxkxcWWzniXXQB4Qtec,4
|
|
|
46
46
|
memvcs/commands/tree.py,sha256=vdULq4vIXA_4gNfMnHn_Y78BwE0sJoeTBOnFJR3WsZ4,4927
|
|
47
47
|
memvcs/commands/verify.py,sha256=04CVW5NYWkUlPJ5z1Kci6dfQFM6UmPTGZh9ZextFLMc,3887
|
|
48
48
|
memvcs/commands/when.py,sha256=bxG_tEYnZNBTl2IPkoxpc2LUEbO_5ev1hRvEzxQQDmc,4773
|
|
49
|
+
memvcs/coordinator/__init__.py,sha256=XJEXEXJFvvhtRInPeyAC9bFNXGbshSrtuK6wZo3wS6g,139
|
|
50
|
+
memvcs/coordinator/server.py,sha256=M0wnww0EbtxuDaunP29LJDCnsTm1mcOn7h_fqZbQy5c,7550
|
|
49
51
|
memvcs/core/__init__.py,sha256=dkIC-4tS0GhwV2mZIbofEe8xR8uiFwrxslGf1aXwhYg,493
|
|
50
52
|
memvcs/core/access_index.py,sha256=HhacnzSUASzRV2jhDHkwRFoPS3rtqh9n9yE1VV7JXpk,5596
|
|
51
53
|
memvcs/core/audit.py,sha256=8APkm9Spl_-1rIdyRQz1elyxOeK3nlpwm0CLkpLlhTE,3732
|
|
54
|
+
memvcs/core/compression_metrics.py,sha256=0JrbkCGr0hnaKlmPLqv5WVLwO3emOEz2iFhdMTDNTNY,9835
|
|
52
55
|
memvcs/core/compression_pipeline.py,sha256=Vzr5v_0pgAG20C8znC0-Ho5fEwBoaTOLddxMTldd64M,5564
|
|
53
56
|
memvcs/core/config_loader.py,sha256=j-jgLDp2TRzWN9ZEZebfWSfatevBNYs0FEb3ud1SIR8,8277
|
|
54
57
|
memvcs/core/consistency.py,sha256=YOG8xhqZLKZCLbai2rdcP0KxYPNGFv5RRMwrQ6qCeyc,7462
|
|
55
58
|
memvcs/core/constants.py,sha256=WUjAb50BFcF0mbFi_GNteDLCxLihmViBm9Fb-JMPmbM,220
|
|
56
59
|
memvcs/core/crypto_verify.py,sha256=DTuC7Kfx6z2b8UWOWziBTqP633LrjXbdtGmBBqrJTF0,10424
|
|
57
60
|
memvcs/core/decay.py,sha256=ROGwnqngs7eJNkbKmwyOdij607m73vpmoJqzrIDLBzk,6581
|
|
61
|
+
memvcs/core/delta.py,sha256=obXzojUSc2HaEUqH3L_1LF-GcJ63Wr_yYvIPM8iyeSg,7865
|
|
58
62
|
memvcs/core/diff.py,sha256=koEHTLciIUxYKVJVuvmY0GDXMgDgGZP_qg5RayhF-iE,13226
|
|
59
|
-
memvcs/core/distiller.py,sha256=
|
|
63
|
+
memvcs/core/distiller.py,sha256=wwY3xQVRBjVfxnOUIwMsQCSeQ2tlG68w2-KiCwkF9yo,13844
|
|
60
64
|
memvcs/core/encryption.py,sha256=epny_nlW6ylllv1qxs1mAcFq-PrLIisgfot4llOoAqw,5289
|
|
61
|
-
memvcs/core/
|
|
62
|
-
memvcs/core/
|
|
65
|
+
memvcs/core/fast_similarity.py,sha256=phgjxkSchJg7om9AFFSMbtP6bSidyRy-vVrR3XyMmDQ,13934
|
|
66
|
+
memvcs/core/federated.py,sha256=qwvfhNgga-lHadbinAfKPI4oAl0RMn5ab01ChmQTP1s,5863
|
|
67
|
+
memvcs/core/gardener.py,sha256=bpoJbK6PJ6nvK3ytj23jpMUBUB7Nn_fB80Ap1E7-Nv8,17041
|
|
63
68
|
memvcs/core/hooks.py,sha256=XF9z8J5sWjAcuOyWQ2nuvEzK0UV8s4ThrcltaBZttzw,5448
|
|
64
69
|
memvcs/core/ipfs_remote.py,sha256=xmEO14bn_7Ej-W5jhx2QJyBd-ljj9S2COOxMmcZBiTs,6643
|
|
65
70
|
memvcs/core/knowledge_graph.py,sha256=GY27e1rgraF2zMpz_jsumdUtpgTRk48yH5CAEQ3TDl4,16416
|
|
66
71
|
memvcs/core/merge.py,sha256=x2eSaxr4f63Eq00FCJ6DDe2TZU8H5yHQpzKzMhYsaFw,19871
|
|
67
72
|
memvcs/core/objects.py,sha256=Xgw1IpQnJLCG5o_7gDHVQ-TNGR9CSpDYWRXzLgLSuec,11006
|
|
68
|
-
memvcs/core/pack.py,sha256=
|
|
73
|
+
memvcs/core/pack.py,sha256=jtbeBh625K6nshPgBGf7zelU-BhvK5-t5NYBJPoYfgs,15961
|
|
69
74
|
memvcs/core/pii_scanner.py,sha256=T6gQ1APFrSDk980fjnv4ZMF-UztbJgmUFSwGrwWixEw,10802
|
|
70
75
|
memvcs/core/privacy_budget.py,sha256=fOPlxoKEAmsKtda-OJCrSaKjTyw7ekcqdN7KfRBw1CY,2113
|
|
76
|
+
memvcs/core/privacy_validator.py,sha256=g3l1zxSIxkjMYJMwL5yfuDY5FFjmkm6HZ2Wo4xBiEkQ,6795
|
|
77
|
+
memvcs/core/protocol_builder.py,sha256=b_5FphgmMdp7qP34ws3U2agXEoeYzTBjSgsQqd2Jx6Y,7713
|
|
71
78
|
memvcs/core/refs.py,sha256=4Nx2ZVRa_DzfUZ4O1AwzOHEjoGAEICJKqSd9GxaiD_g,16754
|
|
72
|
-
memvcs/core/remote.py,sha256=
|
|
79
|
+
memvcs/core/remote.py,sha256=sZbAO9JEaDJM96PylB0CjpmR5UxWYdoXlq86sj3R2gU,22228
|
|
73
80
|
memvcs/core/repository.py,sha256=NzC2UFPv6ePxi5lfiSKyZFLclH4bJpWJz88pY7tDiv4,20605
|
|
74
81
|
memvcs/core/schema.py,sha256=_CrEWCdArc0yDJ04GT7fyvjHqkal7gegdFSsFOjVpBc,15287
|
|
75
82
|
memvcs/core/staging.py,sha256=dptdGi_74lhDkcGqGVU39ZyTkb25j-Rnkz0GWi83W1k,7221
|
|
@@ -77,7 +84,7 @@ memvcs/core/temporal_index.py,sha256=81hZHlVElp2UpXjseFVCdDUwxGM45zIU-y1dDlOhFHI
|
|
|
77
84
|
memvcs/core/test_runner.py,sha256=7-0jCvji63JRbVfy3LNQWIQ7VL5weulOoG7SY1-YJbw,11496
|
|
78
85
|
memvcs/core/trust.py,sha256=msx80Cl3bxyQTY8mFUKWY9P6l3zb1s8FafympgHwtpo,3494
|
|
79
86
|
memvcs/core/vector_store.py,sha256=yUAp5BlaAtjkrtsdY1I-vmAp_YIFgJykBoNlp5hcg0I,11063
|
|
80
|
-
memvcs/core/zk_proofs.py,sha256=
|
|
87
|
+
memvcs/core/zk_proofs.py,sha256=tvJnj5oLTNQ_wFIGcMuuVF5faigIX_32U_HojNMoNp0,7623
|
|
81
88
|
memvcs/core/llm/__init__.py,sha256=vnjtE9Xlv9a2pZV88DMT9JaINkZ30hC9VLPL5lJRlps,236
|
|
82
89
|
memvcs/core/llm/anthropic_provider.py,sha256=O1eaCb9r464ajLJz-Gy8lGxBie5ojRUZ_5HdgRXO5KY,1540
|
|
83
90
|
memvcs/core/llm/base.py,sha256=qPzg3KPAMeoyWGc_2JoVR4-plpdft5Rc2g9uO-Z4fJQ,623
|
|
@@ -88,6 +95,8 @@ memvcs/core/storage/base.py,sha256=IK4To8Cb-LHv5ltlaQLdB6LE-69euFK3hNqBtMCe7-g,9
|
|
|
88
95
|
memvcs/core/storage/gcs.py,sha256=-cWuGw1jkFh-Xig-Abmwr9HGwjW5lWQJuF2xcAR1l78,10632
|
|
89
96
|
memvcs/core/storage/local.py,sha256=JAik9nta6RMe4mD7aMtgdFi8M4iZCeTqiP8pPisaO6U,6028
|
|
90
97
|
memvcs/core/storage/s3.py,sha256=tY5rfz8FfkRRNaHOPX7Wk6yXdBBBhKV0Ju2qnBtHxeU,13814
|
|
98
|
+
memvcs/health/__init__.py,sha256=YuxF8hVHJHNilAvVa0maptFLBWm4hcBymMjpA2dFJVU,546
|
|
99
|
+
memvcs/health/monitor.py,sha256=2JQqkR6n0e5L-gsU97FEB3rxjrCNAaGRNFpa7LKZtOg,15545
|
|
91
100
|
memvcs/integrations/__init__.py,sha256=hVtJoFaXt6ErAZwctcSBDZLXRHFs1CNgtltIBQiroQ0,103
|
|
92
101
|
memvcs/integrations/mcp_server.py,sha256=PxBYJnbzPs6bcFH6EmH5jQqbu_9Vy5eSAA8ruWTn2Q4,9061
|
|
93
102
|
memvcs/integrations/web_ui/__init__.py,sha256=MQIfgDKDgPctlcTUjwkwueS_MDsDssVRmIUnpECGS0k,51
|
|
@@ -99,8 +108,8 @@ memvcs/retrieval/recaller.py,sha256=8KY-XjMUz5_vcKf46zI64uk1DEM__u7wM92ShukOtsY,
|
|
|
99
108
|
memvcs/retrieval/strategies.py,sha256=26yxQQubQfjxWQXknfVMxuzPHf2EcZxJg_B99BEdl5c,11458
|
|
100
109
|
memvcs/utils/__init__.py,sha256=8psUzz4Ntv2GzbRebkeVsoyC6Ck-FIwi0_lfYdj5oho,185
|
|
101
110
|
memvcs/utils/helpers.py,sha256=37zg_DcQ2y99b9NSLqxFkglHe13rJXKhFDpEbQ7iLhM,4121
|
|
102
|
-
agmem-0.1.
|
|
103
|
-
agmem-0.1.
|
|
104
|
-
agmem-0.1.
|
|
105
|
-
agmem-0.1.
|
|
106
|
-
agmem-0.1.
|
|
111
|
+
agmem-0.2.1.dist-info/METADATA,sha256=6UV86NAOpGnnqpRJJE_9XkU-7j2aoLSIf3TB1oQ3dC0,42320
|
|
112
|
+
agmem-0.2.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
113
|
+
agmem-0.2.1.dist-info/entry_points.txt,sha256=at7eWycgjqOo1wbUMECnXUsNo3gpCkJTU71OzrGLHu0,42
|
|
114
|
+
agmem-0.2.1.dist-info/top_level.txt,sha256=HtMMsKuwLKLOdgF1GxqQztqFM54tTJctVdJuOec6B-4,7
|
|
115
|
+
agmem-0.2.1.dist-info/RECORD,,
|
memvcs/__init__.py
CHANGED
memvcs/cli.py
CHANGED
|
@@ -141,7 +141,7 @@ For more information: https://github.com/vivek-tiwari-vt/agmem
|
|
|
141
141
|
""",
|
|
142
142
|
)
|
|
143
143
|
|
|
144
|
-
parser.add_argument("--version", "-v", action="version", version="%(prog)s 0.1
|
|
144
|
+
parser.add_argument("--version", "-v", action="version", version="%(prog)s 0.2.1")
|
|
145
145
|
|
|
146
146
|
parser.add_argument("--verbose", action="store_true", help="Enable verbose output")
|
|
147
147
|
|
memvcs/commands/daemon.py
CHANGED
|
@@ -227,11 +227,12 @@ class DaemonCommand:
|
|
|
227
227
|
while running:
|
|
228
228
|
time.sleep(1)
|
|
229
229
|
|
|
230
|
-
# Periodic health check (Merkle/signature
|
|
230
|
+
# Periodic health check (Merkle/signature + operational metrics). Alert only; no destructive action.
|
|
231
231
|
if (
|
|
232
232
|
health_check_interval
|
|
233
233
|
and (time.time() - last_health_check) >= health_check_interval
|
|
234
234
|
):
|
|
235
|
+
# Cryptographic integrity check
|
|
235
236
|
try:
|
|
236
237
|
from ..core.crypto_verify import verify_commit, load_public_key
|
|
237
238
|
|
|
@@ -251,6 +252,41 @@ class DaemonCommand:
|
|
|
251
252
|
sys.stderr.write("Run 'agmem fsck' for safe integrity check.\n")
|
|
252
253
|
except Exception:
|
|
253
254
|
pass
|
|
255
|
+
|
|
256
|
+
# Operational health checks (storage, redundancy, stale memory, graph consistency)
|
|
257
|
+
try:
|
|
258
|
+
from ..health.monitor import HealthMonitor
|
|
259
|
+
|
|
260
|
+
health_monitor = HealthMonitor(repo.root)
|
|
261
|
+
report = health_monitor.perform_all_checks()
|
|
262
|
+
|
|
263
|
+
if report.get("warnings"):
|
|
264
|
+
for warning in report["warnings"]:
|
|
265
|
+
sys.stderr.write(f"Health warning: {warning}\n")
|
|
266
|
+
|
|
267
|
+
# Log summary metrics
|
|
268
|
+
if report.get("storage"):
|
|
269
|
+
storage = report["storage"]
|
|
270
|
+
if "total_size_mb" in storage:
|
|
271
|
+
sys.stderr.write(
|
|
272
|
+
f"Storage: {storage['total_size_mb']:.1f}MB "
|
|
273
|
+
f"({storage['packed_objects']} packed objects)\n"
|
|
274
|
+
)
|
|
275
|
+
if report.get("redundancy"):
|
|
276
|
+
red = report["redundancy"]
|
|
277
|
+
if "redundancy_percentage" in red:
|
|
278
|
+
sys.stderr.write(
|
|
279
|
+
f"Redundancy: {red['redundancy_percentage']:.1f}%\n"
|
|
280
|
+
)
|
|
281
|
+
if report.get("stale_memory"):
|
|
282
|
+
stale = report["stale_memory"]
|
|
283
|
+
if "stale_percentage" in stale:
|
|
284
|
+
sys.stderr.write(
|
|
285
|
+
f"Stale memory: {stale['stale_percentage']:.1f}%\n"
|
|
286
|
+
)
|
|
287
|
+
except Exception:
|
|
288
|
+
pass
|
|
289
|
+
|
|
254
290
|
last_health_check = time.time()
|
|
255
291
|
|
|
256
292
|
if handler.pending:
|
memvcs/commands/distill.py
CHANGED
|
@@ -46,6 +46,11 @@ class DistillCommand:
|
|
|
46
46
|
action="store_true",
|
|
47
47
|
help="Use differential privacy (spend epsilon from budget)",
|
|
48
48
|
)
|
|
49
|
+
parser.add_argument(
|
|
50
|
+
"--no-compress",
|
|
51
|
+
action="store_true",
|
|
52
|
+
help="Disable compression pipeline preprocessing",
|
|
53
|
+
)
|
|
49
54
|
|
|
50
55
|
@staticmethod
|
|
51
56
|
def execute(args) -> int:
|
|
@@ -73,6 +78,7 @@ class DistillCommand:
|
|
|
73
78
|
source_dir=args.source,
|
|
74
79
|
target_dir=args.target,
|
|
75
80
|
create_safety_branch=not args.no_branch,
|
|
81
|
+
use_compression_pipeline=not getattr(args, "no_compress", False),
|
|
76
82
|
use_dp=use_dp,
|
|
77
83
|
dp_epsilon=dp_epsilon,
|
|
78
84
|
dp_delta=dp_delta,
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Minimal Federated Coordinator Server for agmem.
|
|
3
|
+
|
|
4
|
+
Implements the coordinator API from docs/FEDERATED.md:
|
|
5
|
+
- POST /push: Accept agent summaries
|
|
6
|
+
- GET /pull: Return merged summaries
|
|
7
|
+
|
|
8
|
+
This is a reference implementation. For production:
|
|
9
|
+
- Add authentication (API keys, OAuth)
|
|
10
|
+
- Use persistent storage (PostgreSQL, Redis)
|
|
11
|
+
- Add rate limiting
|
|
12
|
+
- Enable HTTPS
|
|
13
|
+
- Scale horizontally
|
|
14
|
+
|
|
15
|
+
Install: pip install "agmem[coordinator]"
|
|
16
|
+
Run: uvicorn memvcs.coordinator.server:app --host 0.0.0.0 --port 8000
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from datetime import datetime, timezone
|
|
20
|
+
from typing import Dict, List, Optional, Any
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
import json
|
|
23
|
+
import hashlib
|
|
24
|
+
import re
|
|
25
|
+
|
|
26
|
+
try:
|
|
27
|
+
from fastapi import FastAPI, HTTPException, Request
|
|
28
|
+
from fastapi.responses import JSONResponse
|
|
29
|
+
from pydantic import BaseModel, Field
|
|
30
|
+
|
|
31
|
+
FASTAPI_AVAILABLE = True
|
|
32
|
+
except ImportError:
|
|
33
|
+
FASTAPI_AVAILABLE = False
|
|
34
|
+
|
|
35
|
+
# Stub for when FastAPI not installed
|
|
36
|
+
class BaseModel:
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
def Field(*args, **kwargs):
|
|
40
|
+
return None
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _get_version() -> str:
|
|
44
|
+
"""Get agmem version from pyproject.toml. Falls back to 0.2.1 if not found."""
|
|
45
|
+
try:
|
|
46
|
+
pyproject_path = Path(__file__).parent.parent.parent / "pyproject.toml"
|
|
47
|
+
if pyproject_path.exists():
|
|
48
|
+
content = pyproject_path.read_text()
|
|
49
|
+
match = re.search(r'version\s*=\s*"([^"]+)"', content)
|
|
50
|
+
if match:
|
|
51
|
+
return match.group(1)
|
|
52
|
+
except Exception:
|
|
53
|
+
pass
|
|
54
|
+
return "0.2.1"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# Storage: In-memory for simplicity (use Redis/PostgreSQL for production)
|
|
58
|
+
summaries_store: Dict[str, List[Dict[str, Any]]] = {}
|
|
59
|
+
_version = _get_version()
|
|
60
|
+
metadata_store: Dict[str, Any] = {
|
|
61
|
+
"coordinator_version": _version,
|
|
62
|
+
"started_at": datetime.now(timezone.utc).isoformat(),
|
|
63
|
+
"total_pushes": 0,
|
|
64
|
+
"total_agents": 0,
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class AgentSummary(BaseModel):
|
|
69
|
+
"""Agent summary for federated push."""
|
|
70
|
+
|
|
71
|
+
agent_id: str = Field(..., description="Unique agent identifier")
|
|
72
|
+
timestamp: str = Field(..., description="ISO 8601 timestamp")
|
|
73
|
+
topic_counts: Dict[str, int] = Field(default_factory=dict, description="Topic -> count")
|
|
74
|
+
fact_hashes: List[str] = Field(default_factory=list, description="SHA-256 hashes of facts")
|
|
75
|
+
metadata: Optional[Dict[str, Any]] = Field(default=None, description="Optional metadata")
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class PushRequest(BaseModel):
|
|
79
|
+
"""Request body for /push endpoint."""
|
|
80
|
+
|
|
81
|
+
summary: AgentSummary
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class PullResponse(BaseModel):
|
|
85
|
+
"""Response body for /pull endpoint."""
|
|
86
|
+
|
|
87
|
+
merged_topic_counts: Dict[str, int]
|
|
88
|
+
unique_fact_hashes: List[str]
|
|
89
|
+
contributing_agents: int
|
|
90
|
+
last_updated: str
|
|
91
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
if FASTAPI_AVAILABLE:
|
|
95
|
+
app = FastAPI(
|
|
96
|
+
title="agmem Federated Coordinator",
|
|
97
|
+
description="Minimal coordinator for federated agent memory collaboration",
|
|
98
|
+
version=_version,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
@app.get("/")
|
|
102
|
+
async def root():
|
|
103
|
+
"""Health check and API info."""
|
|
104
|
+
return {
|
|
105
|
+
"service": "agmem-coordinator",
|
|
106
|
+
"version": metadata_store["coordinator_version"],
|
|
107
|
+
"status": "running",
|
|
108
|
+
"endpoints": {
|
|
109
|
+
"push": "POST /push",
|
|
110
|
+
"pull": "GET /pull",
|
|
111
|
+
"health": "GET /health",
|
|
112
|
+
},
|
|
113
|
+
"started_at": metadata_store["started_at"],
|
|
114
|
+
"total_pushes": metadata_store["total_pushes"],
|
|
115
|
+
"total_agents": metadata_store["total_agents"],
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
@app.get("/health")
|
|
119
|
+
async def health():
|
|
120
|
+
"""Health check endpoint."""
|
|
121
|
+
return {
|
|
122
|
+
"status": "healthy",
|
|
123
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
@app.post("/push", response_model=Dict[str, Any])
|
|
127
|
+
async def push(request: PushRequest):
|
|
128
|
+
"""
|
|
129
|
+
Accept agent summary and store it.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
Confirmation with push timestamp
|
|
133
|
+
"""
|
|
134
|
+
summary = request.summary
|
|
135
|
+
|
|
136
|
+
# Validate timestamp
|
|
137
|
+
try:
|
|
138
|
+
datetime.fromisoformat(summary.timestamp.replace("Z", "+00:00"))
|
|
139
|
+
except ValueError:
|
|
140
|
+
raise HTTPException(
|
|
141
|
+
status_code=400, detail="Invalid timestamp format (expected ISO 8601)"
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
# Store summary by agent_id
|
|
145
|
+
if summary.agent_id not in summaries_store:
|
|
146
|
+
summaries_store[summary.agent_id] = []
|
|
147
|
+
metadata_store["total_agents"] += 1
|
|
148
|
+
|
|
149
|
+
summaries_store[summary.agent_id].append(summary.dict())
|
|
150
|
+
metadata_store["total_pushes"] += 1
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
"status": "accepted",
|
|
154
|
+
"agent_id": summary.agent_id,
|
|
155
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
156
|
+
"message": f"Summary from {summary.agent_id} stored successfully",
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
@app.get("/pull", response_model=PullResponse)
|
|
160
|
+
async def pull():
|
|
161
|
+
"""
|
|
162
|
+
Return merged summaries from all agents.
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
Aggregated topic counts, unique fact hashes, contributing agent count
|
|
166
|
+
"""
|
|
167
|
+
if not summaries_store:
|
|
168
|
+
return PullResponse(
|
|
169
|
+
merged_topic_counts={},
|
|
170
|
+
unique_fact_hashes=[],
|
|
171
|
+
contributing_agents=0,
|
|
172
|
+
last_updated=datetime.now(timezone.utc).isoformat(),
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
# Merge topic counts across all agents
|
|
176
|
+
merged_topics: Dict[str, int] = {}
|
|
177
|
+
all_fact_hashes = set()
|
|
178
|
+
latest_timestamp = None
|
|
179
|
+
|
|
180
|
+
for agent_id, summaries in summaries_store.items():
|
|
181
|
+
for summary in summaries:
|
|
182
|
+
# Aggregate topic counts
|
|
183
|
+
for topic, count in summary.get("topic_counts", {}).items():
|
|
184
|
+
merged_topics[topic] = merged_topics.get(topic, 0) + count
|
|
185
|
+
|
|
186
|
+
# Collect unique fact hashes
|
|
187
|
+
for fact_hash in summary.get("fact_hashes", []):
|
|
188
|
+
all_fact_hashes.add(fact_hash)
|
|
189
|
+
|
|
190
|
+
# Track latest update
|
|
191
|
+
ts = summary.get("timestamp")
|
|
192
|
+
if ts:
|
|
193
|
+
if latest_timestamp is None or ts > latest_timestamp:
|
|
194
|
+
latest_timestamp = ts
|
|
195
|
+
|
|
196
|
+
return PullResponse(
|
|
197
|
+
merged_topic_counts=merged_topics,
|
|
198
|
+
unique_fact_hashes=sorted(list(all_fact_hashes)),
|
|
199
|
+
contributing_agents=len(summaries_store),
|
|
200
|
+
last_updated=latest_timestamp or datetime.now(timezone.utc).isoformat(),
|
|
201
|
+
metadata={
|
|
202
|
+
"total_facts": len(all_fact_hashes),
|
|
203
|
+
"total_topics": len(merged_topics),
|
|
204
|
+
},
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
@app.delete("/admin/reset")
|
|
208
|
+
async def admin_reset(request: Request):
|
|
209
|
+
"""
|
|
210
|
+
Admin endpoint to reset all stored data.
|
|
211
|
+
In production, protect this with authentication!
|
|
212
|
+
"""
|
|
213
|
+
summaries_store.clear()
|
|
214
|
+
metadata_store["total_pushes"] = 0
|
|
215
|
+
metadata_store["total_agents"] = 0
|
|
216
|
+
metadata_store["started_at"] = datetime.now(timezone.utc).isoformat()
|
|
217
|
+
|
|
218
|
+
return {
|
|
219
|
+
"status": "reset",
|
|
220
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
else:
|
|
224
|
+
# Stub when FastAPI not available
|
|
225
|
+
app = None
|
|
226
|
+
print("FastAPI not available. Install with: pip install 'agmem[coordinator]'")
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
if __name__ == "__main__":
|
|
230
|
+
if not FASTAPI_AVAILABLE:
|
|
231
|
+
print("Error: FastAPI not installed")
|
|
232
|
+
print("Install with: pip install 'fastapi[all]' uvicorn")
|
|
233
|
+
exit(1)
|
|
234
|
+
|
|
235
|
+
import uvicorn
|
|
236
|
+
|
|
237
|
+
print("Starting agmem Federated Coordinator...")
|
|
238
|
+
print("API docs: http://localhost:8000/docs")
|
|
239
|
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|