@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.
- package/README.md +3 -3
- package/bin/cli.js +1 -1
- package/bin/commands/config.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/packages/doctor/src/checks/local-memory.js +2 -2
- package/packages/memory/README.md +2 -2
- package/packages/memory/openclaw-plugin/README.md +2 -2
- package/packages/memory/openclaw-plugin/openclaw.plugin.json +1 -1
- package/packages/memory/src/server.js +2 -2
- package/packages/memory-engine-v2/.env.example +30 -0
- package/packages/memory-engine-v2/README.md +125 -0
- package/packages/memory-engine-v2/compat/Dockerfile +11 -0
- package/packages/memory-engine-v2/compat/requirements.txt +6 -0
- package/packages/memory-engine-v2/compat/server.py +1047 -0
- package/packages/memory-engine-v2/docker-compose.aws.yml +78 -0
- package/packages/memory-engine-v2/docker-compose.yml +206 -0
- package/packages/memory-engine-v2/extractor-async/Dockerfile +14 -0
- package/packages/memory-engine-v2/extractor-async/confidence.py +62 -0
- package/packages/memory-engine-v2/extractor-async/noise_filter.py +144 -0
- package/packages/memory-engine-v2/extractor-async/requirements.txt +2 -0
- package/packages/memory-engine-v2/extractor-async/test_confidence.py +76 -0
- package/packages/memory-engine-v2/extractor-async/test_noise_filter.py +177 -0
- package/packages/memory-engine-v2/extractor-async/worker.py +797 -0
- package/packages/memory-engine-v2/extractor-sync/Dockerfile +11 -0
- package/packages/memory-engine-v2/extractor-sync/requirements.txt +4 -0
- package/packages/memory-engine-v2/extractor-sync/server.py +424 -0
- package/packages/memory-engine-v2/org-model/migrations/001_init.sql +390 -0
- package/packages/memory-engine-v2/tests/e2e_smoke.py +356 -0
- package/packages/memory-engine-v2/tests/fixtures/generate_synthetic_corpus.py +758 -0
- package/packages/memory-engine/.env.example +0 -13
- package/packages/memory-engine/MIGRATION.md +0 -219
- package/packages/memory-engine/README.md +0 -145
- package/packages/memory-engine/bench/README.md +0 -99
- package/packages/memory-engine/bench/scorecards-engine/agent-coding__pentatonic-baseline__20260427-142523.json +0 -1115
- package/packages/memory-engine/bench/scorecards-engine/chat-recall__pentatonic-baseline__20260427-142648.json +0 -819
- package/packages/memory-engine/bench/scorecards-engine/circular-economy__pentatonic-baseline__20260427-142757.json +0 -1278
- package/packages/memory-engine/bench/scorecards-engine/customer-support__pentatonic-baseline__20260427-142900.json +0 -1018
- package/packages/memory-engine/bench/scorecards-engine/marketplace-ops__pentatonic-baseline__20260427-142957.json +0 -1038
- package/packages/memory-engine/bench/scorecards-engine/product-catalogue__pentatonic-baseline__20260427-143122.json +0 -961
- package/packages/memory-engine/bench/scorecards-engine-via-docker/agent-coding__pentatonic-memory__20260427-161812.json +0 -1115
- package/packages/memory-engine/bench/scorecards-engine-via-docker/chat-recall__pentatonic-memory__20260427-161701.json +0 -819
- package/packages/memory-engine/bench/scorecards-engine-via-docker/circular-economy__pentatonic-memory__20260427-161713.json +0 -1278
- package/packages/memory-engine/bench/scorecards-engine-via-docker/customer-support__pentatonic-memory__20260427-161723.json +0 -1018
- package/packages/memory-engine/bench/scorecards-engine-via-docker/marketplace-ops__pentatonic-memory__20260427-161732.json +0 -1038
- package/packages/memory-engine/bench/scorecards-engine-via-docker/product-catalogue__pentatonic-memory__20260427-161741.json +0 -937
- package/packages/memory-engine/bench/scorecards-engine-via-l2-7-layer-populated/agent-coding__pentatonic-memory__20260427-184718.json +0 -1115
- package/packages/memory-engine/bench/scorecards-engine-via-l2-7-layer-populated/chat-recall__pentatonic-memory__20260427-184614.json +0 -819
- package/packages/memory-engine/bench/scorecards-engine-via-l2-7-layer-populated/circular-economy__pentatonic-memory__20260427-184809.json +0 -1278
- package/packages/memory-engine/bench/scorecards-engine-via-l2-7-layer-populated/customer-support__pentatonic-memory__20260427-184854.json +0 -1018
- package/packages/memory-engine/bench/scorecards-engine-via-l2-7-layer-populated/marketplace-ops__pentatonic-memory__20260427-184929.json +0 -1038
- package/packages/memory-engine/bench/scorecards-engine-via-l2-7-layer-populated/product-catalogue__pentatonic-memory__20260427-185015.json +0 -961
- package/packages/memory-engine/bench/scorecards-engine-via-l2-empty-layers/agent-coding__pentatonic-memory__20260427-175252.json +0 -1115
- package/packages/memory-engine/bench/scorecards-engine-via-l2-empty-layers/chat-recall__pentatonic-memory__20260427-175312.json +0 -819
- package/packages/memory-engine/bench/scorecards-engine-via-l2-empty-layers/circular-economy__pentatonic-memory__20260427-175335.json +0 -1278
- package/packages/memory-engine/bench/scorecards-engine-via-l2-empty-layers/customer-support__pentatonic-memory__20260427-175355.json +0 -1018
- package/packages/memory-engine/bench/scorecards-engine-via-l2-empty-layers/marketplace-ops__pentatonic-memory__20260427-175413.json +0 -1038
- package/packages/memory-engine/bench/scorecards-engine-via-l2-empty-layers/product-catalogue__pentatonic-memory__20260427-175430.json +0 -883
- package/packages/memory-engine/bench/scorecards-engine-via-shim/agent-coding__pentatonic-memory__20260427-155409.json +0 -1115
- package/packages/memory-engine/bench/scorecards-engine-via-shim/chat-recall__pentatonic-memory__20260427-155421.json +0 -819
- package/packages/memory-engine/bench/scorecards-engine-via-shim/circular-economy__pentatonic-memory__20260427-155433.json +0 -1278
- package/packages/memory-engine/bench/scorecards-engine-via-shim/customer-support__pentatonic-memory__20260427-155443.json +0 -1018
- package/packages/memory-engine/bench/scorecards-engine-via-shim/marketplace-ops__pentatonic-memory__20260427-155453.json +0 -1038
- package/packages/memory-engine/bench/scorecards-engine-via-shim/product-catalogue__pentatonic-memory__20260427-155503.json +0 -937
- package/packages/memory-engine/bench/scorecards-pentatonic-baseline/agent-coding__pentatonic-memory-latest__20260427-145103.json +0 -1115
- package/packages/memory-engine/bench/scorecards-pentatonic-baseline/agent-coding__pentatonic-memory__20260427-144909.json +0 -1115
- package/packages/memory-engine/bench/scorecards-pentatonic-baseline/chat-recall__pentatonic-memory-latest__20260427-145153.json +0 -819
- package/packages/memory-engine/bench/scorecards-pentatonic-baseline/chat-recall__pentatonic-memory__20260427-145120.json +0 -542
- package/packages/memory-engine/bench/scorecards-pentatonic-baseline/circular-economy__pentatonic-memory-latest__20260427-145313.json +0 -1278
- package/packages/memory-engine/bench/scorecards-pentatonic-baseline/circular-economy__pentatonic-memory__20260427-145207.json +0 -894
- package/packages/memory-engine/bench/scorecards-pentatonic-baseline/customer-support__pentatonic-memory-latest__20260427-145412.json +0 -1018
- package/packages/memory-engine/bench/scorecards-pentatonic-baseline/customer-support__pentatonic-memory__20260427-145327.json +0 -680
- package/packages/memory-engine/bench/scorecards-pentatonic-baseline/marketplace-ops__pentatonic-memory-latest__20260427-145517.json +0 -1038
- package/packages/memory-engine/bench/scorecards-pentatonic-baseline/marketplace-ops__pentatonic-memory__20260427-145422.json +0 -693
- package/packages/memory-engine/bench/scorecards-pentatonic-baseline/product-catalogue__pentatonic-memory-latest__20260427-145616.json +0 -961
- package/packages/memory-engine/bench/scorecards-pentatonic-baseline/product-catalogue__pentatonic-memory__20260427-145528.json +0 -727
- package/packages/memory-engine/compat/Dockerfile +0 -22
- package/packages/memory-engine/compat/server.py +0 -1255
- package/packages/memory-engine/docker-compose.test.yml +0 -59
- package/packages/memory-engine/docker-compose.yml +0 -255
- package/packages/memory-engine/engine/README.md +0 -52
- package/packages/memory-engine/engine/l2-hybridrag-proxy.py +0 -1543
- package/packages/memory-engine/engine/l5-comms-layer.py +0 -663
- package/packages/memory-engine/engine/l6-document-store.py +0 -1018
- package/packages/memory-engine/engine/services/_shared/__init__.py +0 -1
- package/packages/memory-engine/engine/services/_shared/embed_provider.py +0 -562
- package/packages/memory-engine/engine/services/l2/Dockerfile +0 -50
- package/packages/memory-engine/engine/services/l2/init_databases.py +0 -81
- package/packages/memory-engine/engine/services/l2/l2-hybridrag-proxy.py +0 -2721
- package/packages/memory-engine/engine/services/l5/Dockerfile +0 -11
- package/packages/memory-engine/engine/services/l5/l5-comms-layer.py +0 -808
- package/packages/memory-engine/engine/services/l6/Dockerfile +0 -30
- package/packages/memory-engine/engine/services/l6/l6-document-store.py +0 -1221
- package/packages/memory-engine/engine/services/nv-embed/Dockerfile +0 -28
- package/packages/memory-engine/engine/services/nv-embed/server.py +0 -152
- package/packages/memory-engine/pme_memory/__init__.py +0 -0
- package/packages/memory-engine/pme_memory/__main__.py +0 -129
- package/packages/memory-engine/pme_memory/artifacts.py +0 -95
- package/packages/memory-engine/pme_memory/embed.py +0 -74
- package/packages/memory-engine/pme_memory/health.py +0 -36
- package/packages/memory-engine/pme_memory/hygiene.py +0 -159
- package/packages/memory-engine/pme_memory/indexer.py +0 -200
- package/packages/memory-engine/pme_memory/needs.py +0 -55
- package/packages/memory-engine/pme_memory/provenance.py +0 -80
- package/packages/memory-engine/pme_memory/scoring.py +0 -168
- package/packages/memory-engine/pme_memory/search.py +0 -52
- package/packages/memory-engine/pme_memory/store.py +0 -86
- package/packages/memory-engine/pme_memory/synthesis.py +0 -114
- package/packages/memory-engine/pyproject.toml +0 -65
- package/packages/memory-engine/scripts/kg-extractor.py +0 -557
- package/packages/memory-engine/scripts/kg-preflexor-v2.py +0 -738
- package/packages/memory-engine/scripts/wipe-legacy-l3-entities.py +0 -128
- package/packages/memory-engine/tests/e2e_arena.sh +0 -259
- package/packages/memory-engine/tests/embed_stub/Dockerfile +0 -13
- package/packages/memory-engine/tests/embed_stub/server.py +0 -80
- package/packages/memory-engine/tests/test_aggregate.py +0 -333
- package/packages/memory-engine/tests/test_api_contract.sh +0 -57
- package/packages/memory-engine/tests/test_arena_safety.py +0 -232
- package/packages/memory-engine/tests/test_channel_stat_reader.py +0 -437
- package/packages/memory-engine/tests/test_channel_stat_rollups.py +0 -308
- package/packages/memory-engine/tests/test_compat_nv_embed_probe.py +0 -48
- package/packages/memory-engine/tests/test_embed_provider.py +0 -693
- package/packages/memory-engine/tests/test_l2_qmd_vec_search.py +0 -280
- package/packages/memory-engine/tests/test_l3_arena_isolation.py +0 -412
- package/packages/memory-engine/tests/test_l6_module_load.py +0 -84
- 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
|