dc5dc94d79
Multi-channel retrieval sidecar over Universal Memory Protocol: - 3-channel RRF (UMP FTS5 + Qdrant vector + knowledge graph) - ACT-R re-ranking (Anderson 1983) with access tracking - Co-occurrence graph edges (Phase 6) for dense traversal - Memory lifecycle decay (Phase 4) with per-kind confidence - MCP shim routes recall through sidecar, falls back to canonical UMP Architecture: - src/server.js HTTP sidecar on port 4380 - src/graph.js 2592-node / 111-edge graph from UMP (or +cooccur: 13k+) - src/actr.js A_i = -d*ln(age) + beta*log1p(freq) + epsilon*conf - src/access_log.js per-URN counter + last_accessed_at - src/ump-recall-mcp.js MCP shim (recall via sidecar, others passthrough) Eval results (851-record UMP corpus): - 2ch RRF over baseline: +50pp recall@10 - 3ch RRF (+graph): +60pp, 12 unique wins - ACT-R re-rank: 4/20 #1 changes, 84% top-5 retention Tests: 76/76 passing across graph (27), actr (27), access_log (28), decay (20), mcp-shim (sidecar + fallback). Run with: npm test Inspired by AIAppsAPI/adaptive-recall but built from scratch against existing DNS2 infrastructure (UMP at :4317, Qdrant at :6333, Ollama at :11434). No paid SaaS, MIT-licensed.
54 lines
1.5 KiB
JavaScript
54 lines
1.5 KiB
JavaScript
// Phase 1B entity extractor test suite.
|
|
// Run: node test/test-entities.js
|
|
// Exits 0 on full pass, 1 on any failure.
|
|
//
|
|
// Expected order: first occurrence in the source text (deduped). Matches
|
|
// the task brief.
|
|
|
|
import { extractEntities } from "../src/entities.js";
|
|
|
|
const cases = [
|
|
{
|
|
name: "machine + product + tailscale ip",
|
|
in: "DNS2 runs Triangles daemon on 100.121.150.22",
|
|
want: ["DNS2", "Triangles", "100.121.150.22"],
|
|
},
|
|
{
|
|
name: "PR code + Phase code",
|
|
in: "PR-30 fixed Phase 4 of the plan",
|
|
want: ["PR-30", "Phase 4"],
|
|
},
|
|
{
|
|
name: "explicit arrow relations yield source+target entities",
|
|
in: "DashCaddy → Caddy → nftables",
|
|
want: ["DashCaddy", "Caddy", "nftables"],
|
|
},
|
|
{
|
|
name: "Hermes + krystie (profile) + MCP all-caps token",
|
|
in: "Hermes (krystie profile) uses MCP stdio",
|
|
want: ["Hermes", "krystie", "MCP"],
|
|
},
|
|
];
|
|
|
|
let pass = 0;
|
|
let fail = 0;
|
|
for (const c of cases) {
|
|
const got = extractEntities(c.in);
|
|
const ok = JSON.stringify(got) === JSON.stringify(c.want);
|
|
if (ok) {
|
|
pass++;
|
|
console.log(`PASS ${c.name}`);
|
|
console.log(` in=${JSON.stringify(c.in)}`);
|
|
console.log(` out=${JSON.stringify(got)}`);
|
|
} else {
|
|
fail++;
|
|
console.log(`FAIL ${c.name}`);
|
|
console.log(` in=${JSON.stringify(c.in)}`);
|
|
console.log(` got=${JSON.stringify(got)}`);
|
|
console.log(` want=${JSON.stringify(c.want)}`);
|
|
}
|
|
}
|
|
|
|
console.log(`\n${pass}/${pass + fail} passed`);
|
|
if (fail > 0) process.exit(1);
|