@pentatonic-ai/ai-agent-sdk 0.6.0 → 0.7.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 +170 -69
- package/bin/__tests__/callback-server.test.js +4 -1
- package/bin/cli.js +41 -164
- package/bin/commands/config.js +251 -0
- package/package.json +2 -1
- package/packages/doctor/__tests__/detect.test.js +2 -6
- package/packages/doctor/src/checks/local-memory.js +164 -196
- package/packages/doctor/src/detect.js +11 -3
- package/packages/memory/src/corpus/adapters.js +104 -0
- package/packages/memory/src/corpus/cli.js +72 -7
- package/packages/memory/src/corpus/index.js +1 -1
- package/packages/memory-engine/.env.example +13 -0
- package/packages/memory-engine/README.md +131 -0
- package/packages/memory-engine/bench/README.md +99 -0
- package/packages/memory-engine/bench/scorecards-engine/agent-coding__pentatonic-baseline__20260427-142523.json +1115 -0
- package/packages/memory-engine/bench/scorecards-engine/chat-recall__pentatonic-baseline__20260427-142648.json +819 -0
- package/packages/memory-engine/bench/scorecards-engine/circular-economy__pentatonic-baseline__20260427-142757.json +1278 -0
- package/packages/memory-engine/bench/scorecards-engine/customer-support__pentatonic-baseline__20260427-142900.json +1018 -0
- package/packages/memory-engine/bench/scorecards-engine/marketplace-ops__pentatonic-baseline__20260427-142957.json +1038 -0
- package/packages/memory-engine/bench/scorecards-engine/product-catalogue__pentatonic-baseline__20260427-143122.json +961 -0
- package/packages/memory-engine/bench/scorecards-engine-via-docker/agent-coding__pentatonic-memory__20260427-161812.json +1115 -0
- package/packages/memory-engine/bench/scorecards-engine-via-docker/chat-recall__pentatonic-memory__20260427-161701.json +819 -0
- package/packages/memory-engine/bench/scorecards-engine-via-docker/circular-economy__pentatonic-memory__20260427-161713.json +1278 -0
- package/packages/memory-engine/bench/scorecards-engine-via-docker/customer-support__pentatonic-memory__20260427-161723.json +1018 -0
- package/packages/memory-engine/bench/scorecards-engine-via-docker/marketplace-ops__pentatonic-memory__20260427-161732.json +1038 -0
- package/packages/memory-engine/bench/scorecards-engine-via-docker/product-catalogue__pentatonic-memory__20260427-161741.json +937 -0
- package/packages/memory-engine/bench/scorecards-engine-via-l2-7-layer-populated/agent-coding__pentatonic-memory__20260427-184718.json +1115 -0
- package/packages/memory-engine/bench/scorecards-engine-via-l2-7-layer-populated/chat-recall__pentatonic-memory__20260427-184614.json +819 -0
- package/packages/memory-engine/bench/scorecards-engine-via-l2-7-layer-populated/circular-economy__pentatonic-memory__20260427-184809.json +1278 -0
- package/packages/memory-engine/bench/scorecards-engine-via-l2-7-layer-populated/customer-support__pentatonic-memory__20260427-184854.json +1018 -0
- package/packages/memory-engine/bench/scorecards-engine-via-l2-7-layer-populated/marketplace-ops__pentatonic-memory__20260427-184929.json +1038 -0
- package/packages/memory-engine/bench/scorecards-engine-via-l2-7-layer-populated/product-catalogue__pentatonic-memory__20260427-185015.json +961 -0
- package/packages/memory-engine/bench/scorecards-engine-via-l2-empty-layers/agent-coding__pentatonic-memory__20260427-175252.json +1115 -0
- package/packages/memory-engine/bench/scorecards-engine-via-l2-empty-layers/chat-recall__pentatonic-memory__20260427-175312.json +819 -0
- package/packages/memory-engine/bench/scorecards-engine-via-l2-empty-layers/circular-economy__pentatonic-memory__20260427-175335.json +1278 -0
- package/packages/memory-engine/bench/scorecards-engine-via-l2-empty-layers/customer-support__pentatonic-memory__20260427-175355.json +1018 -0
- package/packages/memory-engine/bench/scorecards-engine-via-l2-empty-layers/marketplace-ops__pentatonic-memory__20260427-175413.json +1038 -0
- package/packages/memory-engine/bench/scorecards-engine-via-l2-empty-layers/product-catalogue__pentatonic-memory__20260427-175430.json +883 -0
- package/packages/memory-engine/bench/scorecards-engine-via-shim/agent-coding__pentatonic-memory__20260427-155409.json +1115 -0
- package/packages/memory-engine/bench/scorecards-engine-via-shim/chat-recall__pentatonic-memory__20260427-155421.json +819 -0
- package/packages/memory-engine/bench/scorecards-engine-via-shim/circular-economy__pentatonic-memory__20260427-155433.json +1278 -0
- package/packages/memory-engine/bench/scorecards-engine-via-shim/customer-support__pentatonic-memory__20260427-155443.json +1018 -0
- package/packages/memory-engine/bench/scorecards-engine-via-shim/marketplace-ops__pentatonic-memory__20260427-155453.json +1038 -0
- package/packages/memory-engine/bench/scorecards-engine-via-shim/product-catalogue__pentatonic-memory__20260427-155503.json +937 -0
- package/packages/memory-engine/bench/scorecards-pentatonic-baseline/agent-coding__pentatonic-memory-latest__20260427-145103.json +1115 -0
- package/packages/memory-engine/bench/scorecards-pentatonic-baseline/agent-coding__pentatonic-memory__20260427-144909.json +1115 -0
- package/packages/memory-engine/bench/scorecards-pentatonic-baseline/chat-recall__pentatonic-memory-latest__20260427-145153.json +819 -0
- package/packages/memory-engine/bench/scorecards-pentatonic-baseline/chat-recall__pentatonic-memory__20260427-145120.json +542 -0
- package/packages/memory-engine/bench/scorecards-pentatonic-baseline/circular-economy__pentatonic-memory-latest__20260427-145313.json +1278 -0
- package/packages/memory-engine/bench/scorecards-pentatonic-baseline/circular-economy__pentatonic-memory__20260427-145207.json +894 -0
- package/packages/memory-engine/bench/scorecards-pentatonic-baseline/customer-support__pentatonic-memory-latest__20260427-145412.json +1018 -0
- package/packages/memory-engine/bench/scorecards-pentatonic-baseline/customer-support__pentatonic-memory__20260427-145327.json +680 -0
- package/packages/memory-engine/bench/scorecards-pentatonic-baseline/marketplace-ops__pentatonic-memory-latest__20260427-145517.json +1038 -0
- package/packages/memory-engine/bench/scorecards-pentatonic-baseline/marketplace-ops__pentatonic-memory__20260427-145422.json +693 -0
- package/packages/memory-engine/bench/scorecards-pentatonic-baseline/product-catalogue__pentatonic-memory-latest__20260427-145616.json +961 -0
- package/packages/memory-engine/bench/scorecards-pentatonic-baseline/product-catalogue__pentatonic-memory__20260427-145528.json +727 -0
- package/packages/memory-engine/compat/Dockerfile +11 -0
- package/packages/memory-engine/compat/server.py +680 -0
- package/packages/memory-engine/docker-compose.yml +243 -0
- package/packages/memory-engine/docs/MIGRATION.md +178 -0
- package/packages/memory-engine/docs/RUNBOOK-AWS.md +375 -0
- package/packages/memory-engine/docs/why-v05-underperforms.md +138 -0
- package/packages/memory-engine/engine/README.md +52 -0
- package/packages/memory-engine/engine/l2-hybridrag-proxy.py +1543 -0
- package/packages/memory-engine/engine/l5-comms-layer.py +663 -0
- package/packages/memory-engine/engine/l6-document-store.py +1018 -0
- package/packages/memory-engine/engine/services/l2/Dockerfile +41 -0
- package/packages/memory-engine/engine/services/l2/init_databases.py +81 -0
- package/packages/memory-engine/engine/services/l2/l2-hybridrag-proxy.py +1543 -0
- package/packages/memory-engine/engine/services/l4/Dockerfile +15 -0
- package/packages/memory-engine/engine/services/l4/server.py +235 -0
- package/packages/memory-engine/engine/services/l5/Dockerfile +9 -0
- package/packages/memory-engine/engine/services/l5/l5-comms-layer.py +678 -0
- package/packages/memory-engine/engine/services/l6/Dockerfile +11 -0
- package/packages/memory-engine/engine/services/l6/l6-document-store.py +1016 -0
- package/packages/memory-engine/engine/services/nv-embed/Dockerfile +28 -0
- package/packages/memory-engine/engine/services/nv-embed/server.py +152 -0
- package/packages/memory-engine/pme_memory/__init__.py +0 -0
- package/packages/memory-engine/pme_memory/__main__.py +129 -0
- package/packages/memory-engine/pme_memory/artifacts.py +95 -0
- package/packages/memory-engine/pme_memory/embed.py +74 -0
- package/packages/memory-engine/pme_memory/health.py +36 -0
- package/packages/memory-engine/pme_memory/hygiene.py +159 -0
- package/packages/memory-engine/pme_memory/indexer.py +200 -0
- package/packages/memory-engine/pme_memory/needs.py +55 -0
- package/packages/memory-engine/pme_memory/provenance.py +80 -0
- package/packages/memory-engine/pme_memory/scoring.py +168 -0
- package/packages/memory-engine/pme_memory/search.py +52 -0
- package/packages/memory-engine/pme_memory/store.py +86 -0
- package/packages/memory-engine/pme_memory/synthesis.py +114 -0
- package/packages/memory-engine/pyproject.toml +65 -0
- package/packages/memory-engine/scripts/kg-extractor.py +557 -0
- package/packages/memory-engine/scripts/kg-preflexor-v2.py +738 -0
- package/packages/memory-engine/tests/test_api_contract.sh +57 -0
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* formatting.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { resolve
|
|
9
|
+
import { resolve } from "node:path";
|
|
10
10
|
import { existsSync, readFileSync } from "node:fs";
|
|
11
11
|
import { promises as fsp } from "node:fs";
|
|
12
12
|
import { execFileSync } from "node:child_process";
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
ingestPaths,
|
|
20
20
|
estimateCorpus,
|
|
21
21
|
hostedAdapter,
|
|
22
|
+
engineAdapter,
|
|
22
23
|
loadState,
|
|
23
24
|
saveState,
|
|
24
25
|
defaultStatePath,
|
|
@@ -64,16 +65,80 @@ function resolveTenant() {
|
|
|
64
65
|
return null;
|
|
65
66
|
}
|
|
66
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Read the Claude Code plugin config (tes-memory.local.md) to discover
|
|
70
|
+
* which memory backend the user has configured. Single source of truth
|
|
71
|
+
* for `tes ingest` so it routes the same way the plugin's hooks do.
|
|
72
|
+
*
|
|
73
|
+
* Returns: { mode: "local"|"hosted", memory_url?, tes_endpoint?, … } or null.
|
|
74
|
+
*/
|
|
75
|
+
function readPluginConfig() {
|
|
76
|
+
const candidates = [
|
|
77
|
+
process.env.CLAUDE_CONFIG_DIR,
|
|
78
|
+
join(homedir(), ".claude-pentatonic"),
|
|
79
|
+
join(homedir(), ".claude"),
|
|
80
|
+
].filter(Boolean);
|
|
81
|
+
for (const dir of candidates) {
|
|
82
|
+
const p = join(dir, "tes-memory.local.md");
|
|
83
|
+
if (!existsSync(p)) continue;
|
|
84
|
+
try {
|
|
85
|
+
const content = readFileSync(p, "utf-8");
|
|
86
|
+
const m = content.match(/^---\n([\s\S]*?)\n---/);
|
|
87
|
+
if (!m) continue;
|
|
88
|
+
const out = { _path: p };
|
|
89
|
+
for (const line of m[1].split("\n")) {
|
|
90
|
+
const kv = line.match(/^(\w+):\s*(.+)$/);
|
|
91
|
+
if (kv) out[kv[1]] = kv[2].trim();
|
|
92
|
+
}
|
|
93
|
+
return out;
|
|
94
|
+
} catch {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
|
|
67
101
|
function buildAdapterOrFail() {
|
|
102
|
+
// 1. Env-var override (CI / scripts / explicit). Highest precedence.
|
|
103
|
+
const envEngineUrl =
|
|
104
|
+
process.env.MEMORY_ENGINE_URL || process.env.PENTATONIC_ENGINE_URL || null;
|
|
105
|
+
if (envEngineUrl) {
|
|
106
|
+
const arena =
|
|
107
|
+
process.env.MEMORY_ARENA ||
|
|
108
|
+
process.env.PENTATONIC_CLIENT_ID ||
|
|
109
|
+
process.env.TES_CLIENT_ID ||
|
|
110
|
+
"default";
|
|
111
|
+
return {
|
|
112
|
+
tenant: { source: "env-engine", engineUrl: envEngineUrl, arena },
|
|
113
|
+
adapter: engineAdapter({
|
|
114
|
+
engineUrl: envEngineUrl,
|
|
115
|
+
arena,
|
|
116
|
+
apiKey: process.env.MEMORY_ENGINE_API_KEY || null,
|
|
117
|
+
}),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// 2. Plugin config — same source of truth as the Claude Code hooks.
|
|
122
|
+
const pluginConfig = readPluginConfig();
|
|
123
|
+
if (pluginConfig?.mode === "local" && pluginConfig.memory_url) {
|
|
124
|
+
const arena = pluginConfig.client_id || "default";
|
|
125
|
+
return {
|
|
126
|
+
tenant: { source: `plugin-config (${pluginConfig._path})`, engineUrl: pluginConfig.memory_url, arena },
|
|
127
|
+
adapter: engineAdapter({ engineUrl: pluginConfig.memory_url, arena }),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// 3. Hosted/TES path: env vars + ~/.config/tes/credentials.json.
|
|
68
132
|
const tenant = resolveTenant();
|
|
69
133
|
if (!tenant) {
|
|
70
134
|
process.stderr.write(
|
|
71
|
-
"Error:
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"
|
|
135
|
+
"Error: no memory backend configured.\n\n" +
|
|
136
|
+
" Configure with one of:\n" +
|
|
137
|
+
" npx @pentatonic-ai/ai-agent-sdk config local # local engine\n" +
|
|
138
|
+
" npx @pentatonic-ai/ai-agent-sdk login # hosted TES\n\n" +
|
|
139
|
+
" Or set env vars directly:\n" +
|
|
140
|
+
" MEMORY_ENGINE_URL=http://localhost:8099\n" +
|
|
141
|
+
" TES_ENDPOINT=… TES_CLIENT_ID=… TES_API_KEY=…\n"
|
|
77
142
|
);
|
|
78
143
|
return null;
|
|
79
144
|
}
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
export { discover, isPathEligible } from "./discover.js";
|
|
28
28
|
export { chunkFile } from "./chunkers.js";
|
|
29
29
|
export { ingestCorpus, syncCorpus, ingestPaths } from "./ingest.js";
|
|
30
|
-
export { localAdapter, hostedAdapter } from "./adapters.js";
|
|
30
|
+
export { localAdapter, hostedAdapter, engineAdapter } from "./adapters.js";
|
|
31
31
|
export {
|
|
32
32
|
loadState,
|
|
33
33
|
saveState,
|
|
@@ -0,0 +1,13 @@
|
|
|
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
|
|
@@ -0,0 +1,131 @@
|
|
|
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 Qdrant 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 | Qdrant |
|
|
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
|
+
# → {"status":"ok","layers":{"l0":"ok","l1":"ok","l2":"ok","l3":"ok","l4":"ok","l5":"ok","l6":"ok"},"engine":"pentatonic-memory-engine"}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Now point your existing `pentatonic-memory` SDK client at `http://localhost:8099` — no code change.
|
|
99
|
+
|
|
100
|
+
### Picking a mode
|
|
101
|
+
|
|
102
|
+
Both modes share the same `docker compose up -d` and the same HTTP API. Switch via one env var on the `compat` container:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# Fast path — L6-only, 84.6% / 110ms p50 (default)
|
|
106
|
+
BYPASS_L2_PROXY=1 docker compose up -d compat
|
|
107
|
+
|
|
108
|
+
# Max accuracy — full 7-layer L2 fusion, 85.7% / 1241ms p50
|
|
109
|
+
BYPASS_L2_PROXY=0 docker compose up -d compat
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
| Mode | Mean acc | p50 | When to use |
|
|
113
|
+
|---|---|---|---|
|
|
114
|
+
| L6-only (default) | 84.6% | 110ms | Live agent calls, latency-sensitive paths |
|
|
115
|
+
| 7-layer fusion | 85.7% | 1241ms | Offline batch retrieval, accuracy-graded eval, multi-hop entity queries |
|
|
116
|
+
|
|
117
|
+
Both modes populate all 7 layers on `/store-batch` (since v0.2). The mode flag only changes which layers the **search** path queries.
|
|
118
|
+
|
|
119
|
+
## API compatibility
|
|
120
|
+
|
|
121
|
+
| Endpoint | v0.5 | This package | Notes |
|
|
122
|
+
|---|---|---|---|
|
|
123
|
+
| `POST /store` | ✅ | ✅ | Same request/response shape |
|
|
124
|
+
| `POST /search` | ✅ | ✅ | Same request/response shape; ?mode=vector/text both supported |
|
|
125
|
+
| `GET /health` | ✅ | ✅ | Returns aggregate health across all 7 layers |
|
|
126
|
+
| `POST /store-batch` | ❌ | ✅ | New: batch-ingest N records in one HTTP call (30-50× faster) |
|
|
127
|
+
| `POST /forget` | ❌ (regression) | ✅ | Restored from v0.4.x; supports `metadata_contains` filter |
|
|
128
|
+
|
|
129
|
+
Migration: see `docs/MIGRATION.md`.
|
|
130
|
+
|
|
131
|
+
|
|
@@ -0,0 +1,99 @@
|
|
|
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
|