@pentatonic-ai/ai-agent-sdk 0.9.6 → 0.10.0

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 (127) hide show
  1. package/README.md +3 -3
  2. package/bin/cli.js +1 -1
  3. package/bin/commands/config.js +1 -1
  4. package/dist/index.cjs +1 -1
  5. package/dist/index.js +1 -1
  6. package/package.json +2 -2
  7. package/packages/doctor/src/checks/local-memory.js +2 -2
  8. package/packages/memory/README.md +2 -2
  9. package/packages/memory/openclaw-plugin/README.md +2 -2
  10. package/packages/memory/openclaw-plugin/openclaw.plugin.json +1 -1
  11. package/packages/memory/src/server.js +2 -2
  12. package/packages/memory-engine-v2/.env.example +30 -0
  13. package/packages/memory-engine-v2/README.md +125 -0
  14. package/packages/memory-engine-v2/compat/Dockerfile +11 -0
  15. package/packages/memory-engine-v2/compat/requirements.txt +6 -0
  16. package/packages/memory-engine-v2/compat/server.py +1047 -0
  17. package/packages/memory-engine-v2/docker-compose.aws.yml +78 -0
  18. package/packages/memory-engine-v2/docker-compose.yml +206 -0
  19. package/packages/memory-engine-v2/extractor-async/Dockerfile +14 -0
  20. package/packages/memory-engine-v2/extractor-async/confidence.py +62 -0
  21. package/packages/memory-engine-v2/extractor-async/noise_filter.py +144 -0
  22. package/packages/memory-engine-v2/extractor-async/requirements.txt +2 -0
  23. package/packages/memory-engine-v2/extractor-async/test_confidence.py +76 -0
  24. package/packages/memory-engine-v2/extractor-async/test_noise_filter.py +177 -0
  25. package/packages/memory-engine-v2/extractor-async/worker.py +797 -0
  26. package/packages/memory-engine-v2/extractor-sync/Dockerfile +11 -0
  27. package/packages/memory-engine-v2/extractor-sync/requirements.txt +4 -0
  28. package/packages/memory-engine-v2/extractor-sync/server.py +424 -0
  29. package/packages/memory-engine-v2/org-model/migrations/001_init.sql +390 -0
  30. package/packages/memory-engine-v2/tests/e2e_smoke.py +356 -0
  31. package/packages/memory-engine-v2/tests/fixtures/generate_synthetic_corpus.py +758 -0
  32. package/packages/memory-engine/.env.example +0 -13
  33. package/packages/memory-engine/MIGRATION.md +0 -219
  34. package/packages/memory-engine/README.md +0 -145
  35. package/packages/memory-engine/bench/README.md +0 -99
  36. package/packages/memory-engine/bench/scorecards-engine/agent-coding__pentatonic-baseline__20260427-142523.json +0 -1115
  37. package/packages/memory-engine/bench/scorecards-engine/chat-recall__pentatonic-baseline__20260427-142648.json +0 -819
  38. package/packages/memory-engine/bench/scorecards-engine/circular-economy__pentatonic-baseline__20260427-142757.json +0 -1278
  39. package/packages/memory-engine/bench/scorecards-engine/customer-support__pentatonic-baseline__20260427-142900.json +0 -1018
  40. package/packages/memory-engine/bench/scorecards-engine/marketplace-ops__pentatonic-baseline__20260427-142957.json +0 -1038
  41. package/packages/memory-engine/bench/scorecards-engine/product-catalogue__pentatonic-baseline__20260427-143122.json +0 -961
  42. package/packages/memory-engine/bench/scorecards-engine-via-docker/agent-coding__pentatonic-memory__20260427-161812.json +0 -1115
  43. package/packages/memory-engine/bench/scorecards-engine-via-docker/chat-recall__pentatonic-memory__20260427-161701.json +0 -819
  44. package/packages/memory-engine/bench/scorecards-engine-via-docker/circular-economy__pentatonic-memory__20260427-161713.json +0 -1278
  45. package/packages/memory-engine/bench/scorecards-engine-via-docker/customer-support__pentatonic-memory__20260427-161723.json +0 -1018
  46. package/packages/memory-engine/bench/scorecards-engine-via-docker/marketplace-ops__pentatonic-memory__20260427-161732.json +0 -1038
  47. package/packages/memory-engine/bench/scorecards-engine-via-docker/product-catalogue__pentatonic-memory__20260427-161741.json +0 -937
  48. package/packages/memory-engine/bench/scorecards-engine-via-l2-7-layer-populated/agent-coding__pentatonic-memory__20260427-184718.json +0 -1115
  49. package/packages/memory-engine/bench/scorecards-engine-via-l2-7-layer-populated/chat-recall__pentatonic-memory__20260427-184614.json +0 -819
  50. package/packages/memory-engine/bench/scorecards-engine-via-l2-7-layer-populated/circular-economy__pentatonic-memory__20260427-184809.json +0 -1278
  51. package/packages/memory-engine/bench/scorecards-engine-via-l2-7-layer-populated/customer-support__pentatonic-memory__20260427-184854.json +0 -1018
  52. package/packages/memory-engine/bench/scorecards-engine-via-l2-7-layer-populated/marketplace-ops__pentatonic-memory__20260427-184929.json +0 -1038
  53. package/packages/memory-engine/bench/scorecards-engine-via-l2-7-layer-populated/product-catalogue__pentatonic-memory__20260427-185015.json +0 -961
  54. package/packages/memory-engine/bench/scorecards-engine-via-l2-empty-layers/agent-coding__pentatonic-memory__20260427-175252.json +0 -1115
  55. package/packages/memory-engine/bench/scorecards-engine-via-l2-empty-layers/chat-recall__pentatonic-memory__20260427-175312.json +0 -819
  56. package/packages/memory-engine/bench/scorecards-engine-via-l2-empty-layers/circular-economy__pentatonic-memory__20260427-175335.json +0 -1278
  57. package/packages/memory-engine/bench/scorecards-engine-via-l2-empty-layers/customer-support__pentatonic-memory__20260427-175355.json +0 -1018
  58. package/packages/memory-engine/bench/scorecards-engine-via-l2-empty-layers/marketplace-ops__pentatonic-memory__20260427-175413.json +0 -1038
  59. package/packages/memory-engine/bench/scorecards-engine-via-l2-empty-layers/product-catalogue__pentatonic-memory__20260427-175430.json +0 -883
  60. package/packages/memory-engine/bench/scorecards-engine-via-shim/agent-coding__pentatonic-memory__20260427-155409.json +0 -1115
  61. package/packages/memory-engine/bench/scorecards-engine-via-shim/chat-recall__pentatonic-memory__20260427-155421.json +0 -819
  62. package/packages/memory-engine/bench/scorecards-engine-via-shim/circular-economy__pentatonic-memory__20260427-155433.json +0 -1278
  63. package/packages/memory-engine/bench/scorecards-engine-via-shim/customer-support__pentatonic-memory__20260427-155443.json +0 -1018
  64. package/packages/memory-engine/bench/scorecards-engine-via-shim/marketplace-ops__pentatonic-memory__20260427-155453.json +0 -1038
  65. package/packages/memory-engine/bench/scorecards-engine-via-shim/product-catalogue__pentatonic-memory__20260427-155503.json +0 -937
  66. package/packages/memory-engine/bench/scorecards-pentatonic-baseline/agent-coding__pentatonic-memory-latest__20260427-145103.json +0 -1115
  67. package/packages/memory-engine/bench/scorecards-pentatonic-baseline/agent-coding__pentatonic-memory__20260427-144909.json +0 -1115
  68. package/packages/memory-engine/bench/scorecards-pentatonic-baseline/chat-recall__pentatonic-memory-latest__20260427-145153.json +0 -819
  69. package/packages/memory-engine/bench/scorecards-pentatonic-baseline/chat-recall__pentatonic-memory__20260427-145120.json +0 -542
  70. package/packages/memory-engine/bench/scorecards-pentatonic-baseline/circular-economy__pentatonic-memory-latest__20260427-145313.json +0 -1278
  71. package/packages/memory-engine/bench/scorecards-pentatonic-baseline/circular-economy__pentatonic-memory__20260427-145207.json +0 -894
  72. package/packages/memory-engine/bench/scorecards-pentatonic-baseline/customer-support__pentatonic-memory-latest__20260427-145412.json +0 -1018
  73. package/packages/memory-engine/bench/scorecards-pentatonic-baseline/customer-support__pentatonic-memory__20260427-145327.json +0 -680
  74. package/packages/memory-engine/bench/scorecards-pentatonic-baseline/marketplace-ops__pentatonic-memory-latest__20260427-145517.json +0 -1038
  75. package/packages/memory-engine/bench/scorecards-pentatonic-baseline/marketplace-ops__pentatonic-memory__20260427-145422.json +0 -693
  76. package/packages/memory-engine/bench/scorecards-pentatonic-baseline/product-catalogue__pentatonic-memory-latest__20260427-145616.json +0 -961
  77. package/packages/memory-engine/bench/scorecards-pentatonic-baseline/product-catalogue__pentatonic-memory__20260427-145528.json +0 -727
  78. package/packages/memory-engine/compat/Dockerfile +0 -22
  79. package/packages/memory-engine/compat/server.py +0 -1255
  80. package/packages/memory-engine/docker-compose.test.yml +0 -59
  81. package/packages/memory-engine/docker-compose.yml +0 -255
  82. package/packages/memory-engine/engine/README.md +0 -52
  83. package/packages/memory-engine/engine/l2-hybridrag-proxy.py +0 -1543
  84. package/packages/memory-engine/engine/l5-comms-layer.py +0 -663
  85. package/packages/memory-engine/engine/l6-document-store.py +0 -1018
  86. package/packages/memory-engine/engine/services/_shared/__init__.py +0 -1
  87. package/packages/memory-engine/engine/services/_shared/embed_provider.py +0 -562
  88. package/packages/memory-engine/engine/services/l2/Dockerfile +0 -50
  89. package/packages/memory-engine/engine/services/l2/init_databases.py +0 -81
  90. package/packages/memory-engine/engine/services/l2/l2-hybridrag-proxy.py +0 -2721
  91. package/packages/memory-engine/engine/services/l5/Dockerfile +0 -11
  92. package/packages/memory-engine/engine/services/l5/l5-comms-layer.py +0 -808
  93. package/packages/memory-engine/engine/services/l6/Dockerfile +0 -30
  94. package/packages/memory-engine/engine/services/l6/l6-document-store.py +0 -1221
  95. package/packages/memory-engine/engine/services/nv-embed/Dockerfile +0 -28
  96. package/packages/memory-engine/engine/services/nv-embed/server.py +0 -152
  97. package/packages/memory-engine/pme_memory/__init__.py +0 -0
  98. package/packages/memory-engine/pme_memory/__main__.py +0 -129
  99. package/packages/memory-engine/pme_memory/artifacts.py +0 -95
  100. package/packages/memory-engine/pme_memory/embed.py +0 -74
  101. package/packages/memory-engine/pme_memory/health.py +0 -36
  102. package/packages/memory-engine/pme_memory/hygiene.py +0 -159
  103. package/packages/memory-engine/pme_memory/indexer.py +0 -200
  104. package/packages/memory-engine/pme_memory/needs.py +0 -55
  105. package/packages/memory-engine/pme_memory/provenance.py +0 -80
  106. package/packages/memory-engine/pme_memory/scoring.py +0 -168
  107. package/packages/memory-engine/pme_memory/search.py +0 -52
  108. package/packages/memory-engine/pme_memory/store.py +0 -86
  109. package/packages/memory-engine/pme_memory/synthesis.py +0 -114
  110. package/packages/memory-engine/pyproject.toml +0 -65
  111. package/packages/memory-engine/scripts/kg-extractor.py +0 -557
  112. package/packages/memory-engine/scripts/kg-preflexor-v2.py +0 -738
  113. package/packages/memory-engine/scripts/wipe-legacy-l3-entities.py +0 -128
  114. package/packages/memory-engine/tests/e2e_arena.sh +0 -259
  115. package/packages/memory-engine/tests/embed_stub/Dockerfile +0 -13
  116. package/packages/memory-engine/tests/embed_stub/server.py +0 -80
  117. package/packages/memory-engine/tests/test_aggregate.py +0 -333
  118. package/packages/memory-engine/tests/test_api_contract.sh +0 -57
  119. package/packages/memory-engine/tests/test_arena_safety.py +0 -232
  120. package/packages/memory-engine/tests/test_channel_stat_reader.py +0 -437
  121. package/packages/memory-engine/tests/test_channel_stat_rollups.py +0 -308
  122. package/packages/memory-engine/tests/test_compat_nv_embed_probe.py +0 -48
  123. package/packages/memory-engine/tests/test_embed_provider.py +0 -693
  124. package/packages/memory-engine/tests/test_l2_qmd_vec_search.py +0 -280
  125. package/packages/memory-engine/tests/test_l3_arena_isolation.py +0 -412
  126. package/packages/memory-engine/tests/test_l6_module_load.py +0 -84
  127. package/packages/memory-engine/tests/test_people_list_reader.py +0 -432
@@ -1,13 +0,0 @@
1
- # pentatonic-memory-engine — environment overrides
2
-
3
- # Compat shim port (matches pentatonic-memory v0.5 default)
4
- PME_PORT=8099
5
-
6
- # Client tenant scoping
7
- CLIENT_ID=default
8
-
9
- # Neo4j auth (L3 KG)
10
- NEO4J_AUTH=neo4j/local-dev-pw
11
-
12
- # NV-Embed model (auto-downloaded from Hugging Face on first run)
13
- NV_EMBED_MODEL=nvidia/NV-Embed-v2
@@ -1,219 +0,0 @@
1
- # Wire format & migration
2
-
3
- `pentatonic-memory-engine` is a drop-in replacement for `pentatonic-memory` v0.5.x.
4
- Same HTTP API, same request/response shapes — your existing SDK client code
5
- keeps working. This doc covers:
6
-
7
- 1. **Wire format** — what every endpoint accepts and returns
8
- 2. **What changed vs v0.5.x** — new endpoints + small additive fields
9
- 3. **Operational notes** — per-layer health, deep healthchecks, env vars
10
-
11
- ---
12
-
13
- ## Wire format
14
-
15
- All endpoints accept and return JSON. Base URL is the compat-shim host
16
- (default `http://localhost:8099`).
17
-
18
- ### `POST /store`
19
-
20
- Write a memory.
21
-
22
- ```json
23
- {
24
- "content": "User prefers dark mode",
25
- "metadata": {
26
- "arena": "my-app", // tenant-scoping key. Defaults to "default".
27
- "kind": "note", // optional; opaque, surfaced on read
28
- "source_file": "config.md", // optional; routed to L1/L6 paths
29
- "contact_email": "...", // optional; triggers L3 Person extraction
30
- "contact_name": "...", // optional; same
31
- "channel": "email", // optional; tags ChannelStat denormalisation
32
- "direction": "inbound" // optional; same
33
- },
34
- "client_id": "my-app" // optional; alternative to metadata.arena
35
- }
36
- ```
37
-
38
- Response:
39
-
40
- ```json
41
- {
42
- "id": "cc830b145b1e36514f73fd508aac885a",
43
- "content": "User prefers dark mode",
44
- "layerId": "ml_my-app_episodic",
45
- "engine": {
46
- "l0": 1, "l4_qmd": 1, "l4": 1, "l5": 1, "l6": 1,
47
- "l3_chunks": 0, "l3_entities": 0 // non-zero when metadata.contact_* present
48
- }
49
- }
50
- ```
51
-
52
- ### `POST /store-batch`
53
-
54
- Same body as `/store` but `content` is replaced with `records: [{content, metadata}, ...]`.
55
- 30–50× faster than calling `/store` per record because L2 issues one
56
- batched `/v1/embeddings` call instead of one per record.
57
-
58
- ### `POST /search`
59
-
60
- Hybrid search across all 7 layers, RRF-fused.
61
-
62
- ```json
63
- {
64
- "query": "dark mode preferences",
65
- "limit": 10, // default 16
66
- "min_score": 0.3, // default 0; filter low-similarity hits
67
- "client_id": "my-app", // tenant scope
68
- "user_id": "alice@example.com", // optional; spans clientId AND clientId:user_id arenas
69
- "method": "hybrid" // hybrid (default) | vector | bm25
70
- }
71
- ```
72
-
73
- Response:
74
-
75
- ```json
76
- {
77
- "results": [
78
- {
79
- "id": "cc830b145b1e36514f73fd508aac885a.md",
80
- "content": "User prefers dark mode",
81
- "metadata": { "arena": "my-app", "kind": "note", ... },
82
- "similarity": 0.87,
83
- "layer_id": "ml_my-app_episodic",
84
- "source": "cc830b145b1e36514f73fd508aac885a.md",
85
- "engine_layer": "" // which layer produced this hit (l0/l3/l4/l5/l6)
86
- }
87
- ]
88
- }
89
- ```
90
-
91
- ### `POST /forget`
92
-
93
- Delete memories matching a filter. Two modes:
94
-
95
- - **Per-arena delete**: `{"arena": "my-app"}` removes everything tagged with
96
- that arena across L0/L4/L5/L6 + L3 chunks + L3 Entity nodes.
97
- - **Global wipe**: `{"confirm": "GLOBAL_WIPE"}` (literal string, no arena) wipes
98
- every layer for every tenant. Intended for dev resets only.
99
-
100
- Returns counts deleted per layer.
101
-
102
- ### `GET /health`
103
-
104
- Shallow health. Returns 200 even when `status: "degraded"` — the body's
105
- `status` is the verdict.
106
-
107
- ```json
108
- {
109
- "status": "ok",
110
- "version": "0.1.0",
111
- "engine": "pentatonic-memory-engine",
112
- "layers": {
113
- "l0": "ok", "l1": "ok", "l2": "ok", "l3": "ok",
114
- "l4": "ok", "l5": "ok", "l6": "ok", "nv_embed": "ok"
115
- },
116
- "memories": {
117
- "l0_bm25_chunks": 233142,
118
- "l4_vectors": 64212,
119
- "l5_chats_chunks": 109671,
120
- "l6_vector_chunks": 68220,
121
- "l6_fts_chunks": 39703
122
- }
123
- }
124
- ```
125
-
126
- Layer values are either `"ok"`, `"degraded"`, `"http <code>"`, or
127
- `"unreachable: <reason>"`. The aggregate `status` is `degraded` if any
128
- single layer is non-ok and `down` if ≥3 are non-ok.
129
-
130
- The `memories` field is a per-layer chunk-count dict (since v0.8.4 — previously
131
- a single int that only reported L6's count and misled operators about real
132
- corpus size).
133
-
134
- ### `GET /health/deep` (since v0.8.4)
135
-
136
- Synthetic round-trip per layer: embed a sentinel → write to layer → search
137
- for it → assert hit. Slower (~1–2s); intended for ops/cron, not for compose
138
- healthchecks.
139
-
140
- ```json
141
- {
142
- "status": "ok",
143
- "ok": true,
144
- "layers": {
145
- "l4": {"status": "ok", "ok": true, "embed_ms": 12.6, "write_ms": 2.2,
146
- "search_ms": 0.0, "hit": true, "total_ms": 17.1},
147
- "l5": {"status": "ok", "ok": true,
148
- "collections": {"chats": true, "emails": true, "contacts": true, "memory": true},
149
- "embed_ms": 9.4, "write_ms": 7.6, "search_ms": 1.6, "hit": true},
150
- "l6": {"status": "ok", "ok": true, "embed_ms": 11.3, "write_ms": 635.1,
151
- "search_ms": 59.5, "hit": true, "reranker": "ok"}
152
- }
153
- }
154
- ```
155
-
156
- Sentinel rows are stored under arena `__healthcheck__` with a fixed id, so
157
- the probe pollutes the corpus by at most one row per layer (upserts, never
158
- accumulates).
159
-
160
- ### `POST /aggregate` (since v0.8.x)
161
-
162
- Typed-Person aggregation over the L3 graph. Counts `(:Person)-[:COMMUNICATED]->(:Chunk)`
163
- edges by `group_by` keys. See `packages/memory-engine/compat/server.py` for
164
- the full schema — used today by the relationships UI in the TES module.
165
-
166
- ---
167
-
168
- ## What changed vs `pentatonic-memory` v0.5.x
169
-
170
- | | v0.5.x | This package |
171
- |---|---|---|
172
- | Storage | Single Postgres + pgvector + HNSW | 7-layer fusion (SQLite FTS, Neo4j, sqlite-vec, Milvus, Milvus+rerank) |
173
- | Embedding | One model, one dim, ingest-time | Per-layer configurable; provider-aware (`L*_EMBED_PROVIDER`) |
174
- | Endpoints added | — | `/store-batch`, `/forget`, `/health/deep`, `/aggregate` |
175
- | `/health` body | `{status, layers}` only | + `version`, `engine`, `nv_embed` layer, per-layer `memories` dict |
176
- | `/store` engine fields | absent | `engine: { l0, l3_chunks, l3_entities, l4, l5, l6 }` per-layer write counts |
177
- | Backwards-incompat changes | — | **None.** All v0.5 client code keeps working. |
178
-
179
- The engine container's compat shim (`compat/server.py`) is the API surface;
180
- the layer services behind it can be replaced or scaled independently
181
- without changing client code.
182
-
183
- ---
184
-
185
- ## Operational notes
186
-
187
- ### Provider-aware embedding (since v0.8.0)
188
-
189
- Each layer service picks an embedding provider via `L*_EMBED_PROVIDER`:
190
-
191
- - `openai` (default) — Bearer auth, `/v1/embeddings` path, OpenAI-shaped body
192
- - `pentatonic-gateway` — X-API-Key auth, `/v1/embed` path
193
- - `cohere` — `{texts, input_type}` body shape
194
-
195
- A 401 from the configured provider auto-detects against the other built-ins
196
- (opt out per layer with `L*_EMBED_AUTODETECT=false`). See
197
- `engine/services/_shared/embed_provider.py` for the dispatch table.
198
-
199
- ### L2 concurrency (since v0.8.4)
200
-
201
- L2 hybridrag-proxy is async throughout — `AsyncGraphDatabase` for Neo4j,
202
- `httpx.AsyncClient` for L4/L5/L6 fan-out, `asyncio.to_thread` for sqlite +
203
- PyTorch reranker. Fan-out across layers runs concurrently via
204
- `asyncio.gather`. Under sustained ingest, `/health` and `/search` no
205
- longer compete for a saturated threadpool.
206
-
207
- ### L5 collection bootstrap (since v0.8.4)
208
-
209
- L5's serve() ensures all four collections (`chats`, `emails`, `contacts`,
210
- `memory`) exist at startup. Previously only `chats` was bootstrapped and
211
- writes to the others would 500.
212
-
213
- ### Health check semantics
214
-
215
- - `compose` healthcheck and `engine-runner.sh` deploy gate use `/health` —
216
- it's fast (<50ms) and returns HTTP 200 regardless of body status.
217
- - Operators/cron should use `/health/deep` for real functional validation.
218
- - A `compose` healthcheck on `/health/deep` would burn embedding budget
219
- every 10s — avoid.
@@ -1,145 +0,0 @@
1
- # pentatonic-memory-engine
2
-
3
- **Drop-in replacement for `pentatonic-memory` v0.5.x with a 7-layer retrieval stack underneath.**
4
-
5
- | Configuration | Mean accuracy* | p50 latency |
6
- |---|---|---|
7
- | pentatonic-memory v0.5.6 (current OSS) | 17.6% | 33ms |
8
- | pentatonic-memory v0.4.7 (legacy OSS) | 38.8% | 27ms |
9
- | **pentatonic-memory-engine — fast path** (L6-only via docker, default config) | **84.6%** | **110ms** |
10
- | **pentatonic-memory-engine — max accuracy** (full 7-layer L2 fusion) | **85.7%** | **1241ms** |
11
- | langmem (in-process) | 83.0% | 121ms |
12
- | cognee | 82.1% | 192ms |
13
- | single-store baseline | 79.3% | 110ms |
14
-
15
- \* Mean over 6 commerce-domain benches (agent-coding, chat-recall, circular-economy, customer-support, marketplace-ops, product-catalogue) using substring grading. Full reports under `bench/`.
16
-
17
- **Two configurations, same package.** The fast path (L6-only) is the default and ships at #1 on accuracy among real OSS memory stacks. The max-accuracy 7-layer mode adds Knowledge-Graph entity matching + L0 BM25 + L4 vec fusion via the L2 orchestrator — buys you +1.1pp at 11× latency. Pick per workload (live agent loop → fast path; offline batch / accuracy-graded eval → 7-layer).
18
-
19
- ---
20
-
21
- ## What this is
22
-
23
- A self-contained docker-compose package that exposes the **same HTTP API as `pentatonic-memory`** (`/store`, `/search`, `/health`), plus two regression-fix endpoints (`/store-batch`, `/forget`) — but routes every call through a 7-layer hybrid retrieval engine instead of the single Postgres + pgvector store.
24
-
25
- Same client code. Same SDK. ~5x better accuracy on retrieval-style benchmarks.
26
-
27
- ## Why does the existing OSS underperform?
28
-
29
- Detailed analysis in `docs/why-v05-underperforms.md`. Short version:
30
-
31
- - Single vector store (pgvector), single embedding per row → diluted vectors on long content
32
- - `atomBoost: +0.15` makes LLM-paraphrased atoms outrank source verbatim → substring grading fails
33
- - HyDE generated at ingest time (60s LLM call per /store), not at query time
34
- - pgvector HNSW broken at >2000 dims → 4096d NV-Embed falls back to sequential scan
35
- - No reranker, no graph traversal, no multi-store fusion
36
-
37
- ## Architecture (7-layer)
38
-
39
- The engine is the same `sequential-hybridrag-7-layer` stack the L2 proxy reports in its health endpoint.
40
-
41
- ```
42
- ┌──────────────────┐
43
- │ L0 BM25 (FTS) │
44
- ├──────────────────┤
45
- │ L1 Core files │
46
- POST /store ┌──────────────┐ ├──────────────────┤
47
- POST /search │ compat shim │ │ L2 HybridRAG │
48
- client (any) ───► POST /forget ──► (FastAPI) │──►│ orchestrator│
49
- POST /store-batch└──────────────┘ ├──────────────────┤
50
- GET /health │ L3 Knowledge │
51
- │ Graph (KG) │
52
- ├──────────────────┤
53
- │ L4 sqlite-vec │
54
- ├──────────────────┤
55
- │ L5 Milvus comms │
56
- ├──────────────────┤
57
- │ L6 Document │
58
- │ Store + │
59
- │ reranker │
60
- └─────────┬────────┘
61
-
62
- ┌────────────────┴───────┐
63
- │ NV-Embed-v2 │
64
- │ Cross-encoder reranker │
65
- └─────────────────────────┘
66
- ```
67
-
68
- Each layer indexes the same content differently. Search runs all seven in parallel and fuses results via Reciprocal Rank Fusion (RRF). Different query types win on different layers — agent-coding queries land on L0 BM25, chat-recall on L5, multi-hop entity questions on L3, conversational context on L1.
69
-
70
- **Layer cheat-sheet:**
71
-
72
- | # | Layer | Purpose | Backing tech |
73
- |---|---|---|---|
74
- | L0 | BM25 | Lexical / keyword recall | SQLite FTS5 |
75
- | L1 | Core files | Always-loaded high-priority text (system manuals, key docs) | flat markdown read by L2 |
76
- | L2 | HybridRAG orchestrator | Fan-out + RRF fusion across all layers | Python FastAPI |
77
- | L3 | Knowledge Graph | Entity-aware retrieval, multi-hop relationships | Neo4j (OSS) |
78
- | L4 | Vector index | High-recall semantic search | sqlite-vec |
79
- | L5 | Comms / multi-collection vectors | Chat / email / contact / memory namespaces | Milvus (Lite by default; standalone via compose) |
80
- | L6 | Document store | Per-arena docs + cross-encoder reranker | sqlite + Milvus + MiniLM |
81
-
82
- ## Quick start
83
-
84
- ```bash
85
- git clone <this-repo>
86
- cd pentatonic-memory-engine
87
- cp .env.example .env # set NEO4J_AUTH, etc.
88
- docker compose up -d
89
- ```
90
-
91
- Wait ~30s for layers to come up. Verify:
92
-
93
- ```bash
94
- curl http://localhost:8099/health
95
- # → {
96
- # "status": "ok",
97
- # "version": "0.1.0",
98
- # "engine": "pentatonic-memory-engine",
99
- # "layers": {"l0":"ok","l1":"ok","l2":"ok","l3":"ok","l4":"ok","l5":"ok","l6":"ok","nv_embed":"ok"},
100
- # "memories": {
101
- # "l0_bm25_chunks": N, "l4_vectors": N,
102
- # "l5_chats_chunks": N, "l6_vector_chunks": N, "l6_fts_chunks": N
103
- # }
104
- # }
105
-
106
- # Or run real functional round-trips per layer (slower; ~1–2s):
107
- curl http://localhost:8099/health/deep
108
- ```
109
-
110
- Now point your existing `pentatonic-memory` SDK client at `http://localhost:8099` — no code change.
111
-
112
- ### Picking a mode
113
-
114
- Both modes share the same `docker compose up -d` and the same HTTP API. Switch via one env var on the `compat` container:
115
-
116
- ```bash
117
- # Fast path — L6-only, 84.6% / 110ms p50 (default)
118
- BYPASS_L2_PROXY=1 docker compose up -d compat
119
-
120
- # Max accuracy — full 7-layer L2 fusion, 85.7% / 1241ms p50
121
- BYPASS_L2_PROXY=0 docker compose up -d compat
122
- ```
123
-
124
- | Mode | Mean acc | p50 | When to use |
125
- |---|---|---|---|
126
- | L6-only (default) | 84.6% | 110ms | Live agent calls, latency-sensitive paths |
127
- | 7-layer fusion | 85.7% | 1241ms | Offline batch retrieval, accuracy-graded eval, multi-hop entity queries |
128
-
129
- Both modes populate all 7 layers on `/store-batch` (since v0.2). The mode flag only changes which layers the **search** path queries.
130
-
131
- ## API compatibility
132
-
133
- | Endpoint | v0.5 | This package | Notes |
134
- |---|---|---|---|
135
- | `POST /store` | ✅ | ✅ | Same request/response shape |
136
- | `POST /search` | ✅ | ✅ | Same request/response shape; ?mode=vector/text both supported |
137
- | `GET /health` | ✅ | ✅ | Returns aggregate health across all 7 layers + nv-embed reachability + per-layer `memories` counts |
138
- | `GET /health/deep` | ❌ | ✅ | NEW (v0.8.4): synthetic embed → write → search round-trip per layer. Slower (~1–2s); for ops/monitoring on demand. |
139
- | `POST /store-batch` | ❌ | ✅ | Batch-ingest N records in one HTTP call (30-50× faster) |
140
- | `POST /forget` | ❌ (regression) | ✅ | Restored from v0.4.x; supports `metadata_contains` filter |
141
- | `POST /aggregate` | ❌ | ✅ | NEW (v0.8.x): typed-Person aggregation over the L3 graph — counts COMMUNICATED edges per channel via the ChannelStat denormalisation |
142
-
143
- Migration: see [`MIGRATION.md`](MIGRATION.md) for the wire-format walkthrough.
144
-
145
-
@@ -1,99 +0,0 @@
1
- # Benchmark Results
2
-
3
- All runs were conducted on **DGX Spark GB10** (10-core ARM CPU, 128GB unified memory, NVIDIA GB10 SoC) on **2026-04-27**.
4
-
5
- ## Summary
6
-
7
- | Stack | Mean accuracy | Mean p50 latency | Coverage |
8
- |---|---|---|---|
9
- | **pentatonic-memory-engine — 7-layer fusion** | **85.7%** | 1241ms | 6/6 |
10
- | **pentatonic-memory-engine — L6-only fast path** | **84.6%** | 110ms | 6/6 |
11
- | pentatonic-memory v0.4.7 (current canonical OSS) | 38.8% | 27ms | 6/6 |
12
- | pentatonic-memory v0.5.6 (latest OSS) | 17.6% | 33ms | 6/6 |
13
-
14
- Both pentatonic-memory baselines were freshly purged before the run (no stale data pollution). Both modes of `pentatonic-memory-engine` ship in the same docker-compose package — one env var (`BYPASS_L2_PROXY`) toggles between fast path and 7-layer fusion.
15
-
16
- ## Per-bench breakdown
17
-
18
- | Bench | 7-layer | L6-only | v0.4.7 | v0.5.6 |
19
- |---|---|---|---|---|
20
- | agent-coding | 100.0% (22/22) | 100.0% (22/22) | 63.6% (14/22) | 9.1% (2/22) |
21
- | chat-recall | 100.0% (16/16) | 100.0% (16/16) | 12.5% (2/16) | 0.0% (0/16) |
22
- | circular-economy | 76.0% (19/25) | 80.0% (20/25) | 40.0% (10/25) | 32.0% (8/25) |
23
- | customer-support | 75.0% (15/20) | 70.0% (14/20) | 25.0% (5/20) | 5.0% (1/20) |
24
- | marketplace-ops | 80.0% (16/20) | 80.0% (16/20) | 25.0% (5/20) | 15.0% (3/20) |
25
- | product-catalogue | 83.3% (15/18) | 77.8% (14/18) | 66.7% (12/18) | 44.4% (8/18) |
26
- | **MEAN** | **85.7%** | **84.6%** | **38.8%** | **17.6%** |
27
-
28
- ### When does 7-layer fusion help?
29
-
30
- Layer-by-layer effect over L6-only:
31
-
32
- - **+5.6pp on product-catalogue** — KG entity matching pulls related SKUs / materials in one hop; L0 BM25 catches part numbers that vector search alone misses.
33
- - **+5.0pp on customer-support** — Multi-hop entity resolution (customer → order → policy) lifts retrieval where pure semantic search loses the relationship.
34
- - **Tied on agent-coding, chat-recall, marketplace-ops** — L6 already saturated (100%, 100%, 80%); extra layers add nothing.
35
- - **−4.0pp on circular-economy** — Extra layers add noise on this sustainability corpus; L6's reranker alone is the better signal.
36
-
37
- Net: +1.1pp accuracy at 11× latency cost. Use 7-layer for accuracy-graded eval and offline batch retrieval; stay on L6-only for live agent calls.
38
-
39
- ## Bench corpora
40
-
41
- The 6 benches use commerce-domain corpora that overlap Pentatonic's actual product space:
42
-
43
- - `agent-coding` — 22 questions over 22 docs (TES + agent SDK source/docs)
44
- - `chat-recall` — 16 questions over a 16-turn chat transcript
45
- - `circular-economy` — 25 questions over 25 sustainability docs
46
- - `customer-support` — 20 questions over a 20-doc support knowledge base
47
- - `marketplace-ops` — 20 questions over 20 marketplace listings
48
- - `product-catalogue` — 18 questions over an 18-SKU product catalogue
49
-
50
- All grading uses **substring match**: a hit is correct if the retrieved text contains the literal answer string. This is the strictest grading mode and the closest analogue to "did the SDK return a chunk that actually answers the question."
51
-
52
- ## Reproduce
53
-
54
- ```bash
55
- # Bring up the engine
56
- cd pentatonic-memory-engine && docker compose up -d
57
-
58
- # Wait for healthy
59
- until curl -sf http://localhost:8099/health | grep -q '"status":"ok"'; do sleep 2; done
60
-
61
- # Set up the bench harness
62
- cd ~/pentatonic-memory-bench
63
- pip install -e .
64
-
65
- # Run the L6-only fast path (default)
66
- PENTATONIC_MEMORY_URL=http://localhost:8099 \
67
- python -m pentatonic_bench.cli run -b chat-recall -s pentatonic-memory -k 3
68
-
69
- # Run the 7-layer fusion (toggle BYPASS_L2_PROXY=0 + restart compat)
70
- BYPASS_L2_PROXY=0 docker compose up -d --force-recreate compat
71
- PENTATONIC_MEMORY_URL=http://localhost:8099 \
72
- python -m pentatonic_bench.cli run -b chat-recall -s pentatonic-memory -k 3
73
- ```
74
-
75
- ## Comparison to other open-source memory stacks
76
-
77
- | Stack | Mean acc | Mean p50 | Notes |
78
- |---|---|---|---|
79
- | 🥇 **pentatonic-memory-engine — 7-layer** | **85.7%** | **1241ms** | This package, full L2 fusion |
80
- | 🥈 **pentatonic-memory-engine — L6-only** | **84.6%** | **110ms** | This package, fast path |
81
- | 🥉 langmem | 83.0% | 121ms | LangChain's in-process memory; no HTTP/embedding overhead |
82
- | cognee | 82.1% | 192ms | Graph + vector hybrid, KG-first |
83
- | single-store baseline | 79.3% | 110ms | Single vector store + sentence-transformers |
84
- | llamaindex | 79.3% | 203ms | LlamaIndex with default config |
85
- | bm25-baseline | 75.9% | 0ms | Pure SQLite FTS5, no embeddings |
86
- | pentatonic-memory v0.4.7 | 38.8% | 27ms | Current canonical OSS |
87
- | graphiti | 30.1% | 156ms | Graph-only, no vector |
88
- | pentatonic-memory v0.5.6 | 17.6% | 33ms | Latest OSS |
89
-
90
- Engine beats every other OSS memory stack on accuracy in both modes. The L6-only fast path matches langmem's latency profile while delivering +1.6pp accuracy. The 7-layer mode is the genuine #1 on accuracy across all benchmarked stacks.
91
-
92
- ## Raw scorecards
93
-
94
- - `scorecards-engine-via-docker/` — 6 JSON scorecards, L6-only fast path (84.6% mean / 110ms p50)
95
- - `scorecards-engine-via-l2-7-layer-populated/` — 6 JSON scorecards, full 7-layer fusion (85.7% mean / 1241ms p50)
96
- - `scorecards-engine-via-l2-empty-layers/` — earlier experiment, 7-layer with empty L0/L4-qmd/L3 (82.1%, rolled back; superseded by populated 7-layer)
97
- - `scorecards-engine-via-shim/` — earlier experiment, shim-direct ingestion path
98
- - `scorecards-engine/` — initial bench (1183ms, before L6-only optimisation)
99
- - `scorecards-pentatonic-baseline/` — 12 JSON scorecards (6 per stack) for the v0.4.7 and v0.5.6 baselines