pi-mega-compact 0.16.3 → 0.17.1
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/dist/config/vector-cortex.js +91 -0
- package/dist/dedup/digest.js +30 -0
- package/dist/dedup/l1-lsh-v2.js +60 -0
- package/dist/dedup/l1-lsh.js +52 -0
- package/dist/dedup/l1-minhash-v2.js +193 -0
- package/dist/dedup/l1-minhash.js +91 -0
- package/dist/dedup/l1-verify.js +54 -0
- package/dist/dedup/mmr.js +45 -0
- package/dist/dedup/normalize.js +39 -0
- package/dist/dedup/raptor/buildHistory.js +164 -0
- package/dist/dedup/raptor/guardrails.js +83 -0
- package/dist/dedup/raptor/incremental.js +304 -0
- package/dist/dedup/raptor/index.js +190 -0
- package/dist/dedup/raptor/kmeans.js +152 -0
- package/dist/dedup/raptor/multilevel.js +184 -0
- package/dist/dedup/raptor/retrieval.js +93 -0
- package/dist/dedup/raptor/summarizer.js +86 -0
- package/dist/dedup/raptor/tree.js +202 -0
- package/dist/dedup/topk.js +60 -0
- package/dist/extensions/dashboard-server/api-contracts/endpoints/registry-ext.js +30 -0
- package/dist/extensions/dashboard-server/api-contracts/endpoints/registry.js +4 -14
- package/dist/extensions/dashboard-server/api-contracts/vector-cortex.js +12 -0
- package/dist/extensions/dashboard-server/routes-rag-settings-helpers.js +11 -0
- package/dist/extensions/dashboard-server/routes-vector-cortex.js +292 -0
- package/dist/extensions/dashboard-server/routes.js +1 -0
- package/dist/extensions/dashboard-server/server.js +9 -1
- package/dist/extensions/mega-events/context-handler.js +11 -0
- package/dist/extensions/mega-runtime/vector-cortex-ledger.js +131 -0
- package/dist/extensions/mega-runtime/vector-cortex-safety.js +100 -0
- package/dist/src/config/vector-cortex.js +91 -0
- package/dist/src/config.js +6 -0
- package/dist/src/dedup/l1-lsh-v2.js +60 -0
- package/dist/src/dedup/l1-minhash-v2.js +193 -0
- package/dist/src/dedup/normalize.js +1 -1
- package/dist/src/vector-cortex/conformance/emit.js +46 -0
- package/dist/src/vector-cortex/conformance/manifest.js +235 -0
- package/dist/src/vector-cortex/conformance/runner.js +111 -0
- package/dist/src/vector-cortex/conformance/triadB-reader.js +95 -0
- package/dist/src/vector-cortex/eval/annotations.js +41 -0
- package/dist/src/vector-cortex/eval/metrics.js +86 -0
- package/dist/src/vector-cortex/eval/observer.js +61 -0
- package/dist/src/vector-cortex/eval/persist.js +67 -0
- package/dist/src/vector-cortex/eval/reader.js +29 -0
- package/dist/src/vector-cortex/eval/types.js +33 -0
- package/dist/src/vector-cortex/ledger/adapter.js +55 -0
- package/dist/src/vector-cortex/ledger/compat-journal.js +206 -0
- package/dist/src/vector-cortex/ledger/emit.js +53 -0
- package/dist/src/vector-cortex/ledger/event-codec.js +72 -0
- package/dist/src/vector-cortex/ledger/event-codecB.js +76 -0
- package/dist/src/vector-cortex/ledger/sqlite.js +200 -0
- package/dist/src/vector-cortex/ledger/store.js +184 -0
- package/dist/src/vector-cortex/ledger/types.js +52 -0
- package/dist/src/vector-cortex/ledger/validator.js +117 -0
- package/dist/src/vector-cortex/migrations/effective-cut-v2.js +103 -0
- package/dist/src/vector-cortex/migrations/minhash-v2.js +209 -0
- package/dist/src/vector-cortex/migrations/occurrence-v2.js +139 -0
- package/dist/src/vector-cortex/replay/cut.js +123 -0
- package/dist/src/vector-cortex/replay/emit.js +58 -0
- package/dist/src/vector-cortex/replay/replay.js +260 -0
- package/dist/src/vector-cortex/replay/replayB.js +73 -0
- package/dist/src/vector-cortex/replay/types.js +52 -0
- package/dist/src/vector-cortex/resilience/breaker-core.js +359 -0
- package/dist/src/vector-cortex/resilience/breaker.js +12 -0
- package/dist/src/vector-cortex/resilience/emit.js +56 -0
- package/dist/src/vector-cortex/resilience/spool-core.js +347 -0
- package/dist/src/vector-cortex/resilience/spool.js +12 -0
- package/dist/src/vector-cortex/resilience/types.js +32 -0
- package/dist/vector-cortex/conformance/emit.js +46 -0
- package/dist/vector-cortex/conformance/manifest.js +235 -0
- package/dist/vector-cortex/conformance/runner.js +111 -0
- package/dist/vector-cortex/conformance/triadB-reader.js +95 -0
- package/dist/vector-cortex/eval/annotations.js +41 -0
- package/dist/vector-cortex/eval/metrics.js +86 -0
- package/dist/vector-cortex/eval/observer.js +61 -0
- package/dist/vector-cortex/eval/persist.js +67 -0
- package/dist/vector-cortex/eval/reader.js +29 -0
- package/dist/vector-cortex/eval/types.js +33 -0
- package/dist/vector-cortex/ledger/adapter.js +55 -0
- package/dist/vector-cortex/ledger/compat-journal.js +206 -0
- package/dist/vector-cortex/ledger/emit.js +53 -0
- package/dist/vector-cortex/ledger/event-codec.js +72 -0
- package/dist/vector-cortex/ledger/event-codecB.js +76 -0
- package/dist/vector-cortex/ledger/sqlite.js +200 -0
- package/dist/vector-cortex/ledger/store.js +184 -0
- package/dist/vector-cortex/ledger/types.js +52 -0
- package/dist/vector-cortex/ledger/validator.js +117 -0
- package/dist/vector-cortex/migrations/effective-cut-v2.js +103 -0
- package/dist/vector-cortex/migrations/minhash-v2.js +209 -0
- package/dist/vector-cortex/migrations/occurrence-v2.js +139 -0
- package/dist/vector-cortex/replay/cut.js +123 -0
- package/dist/vector-cortex/replay/emit.js +58 -0
- package/dist/vector-cortex/replay/replay.js +260 -0
- package/dist/vector-cortex/replay/replayB.js +73 -0
- package/dist/vector-cortex/replay/types.js +52 -0
- package/dist/vector-cortex/resilience/breaker-core.js +359 -0
- package/dist/vector-cortex/resilience/breaker.js +12 -0
- package/dist/vector-cortex/resilience/emit.js +56 -0
- package/dist/vector-cortex/resilience/spool-core.js +347 -0
- package/dist/vector-cortex/resilience/spool.js +12 -0
- package/dist/vector-cortex/resilience/types.js +32 -0
- package/extensions/dashboard-client/dist/assets/{AreaChart-Y_X0Bbjd.js → AreaChart-BQXFF7UI.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AreaChart-Y_X0Bbjd.js.map → AreaChart-BQXFF7UI.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{BarChart-B9XDb-Ob.js → BarChart-BVtoz9Eg.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{BarChart-B9XDb-Ob.js.map → BarChart-BVtoz9Eg.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{CacheTab-BUGVb1G1.js → CacheTab-trI2TIGy.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{CacheTab-BUGVb1G1.js.map → CacheTab-trI2TIGy.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{EventsTab-dOqLYTsy.js → EventsTab-CNUbk9__.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{EventsTab-dOqLYTsy.js.map → EventsTab-CNUbk9__.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{HealthTab-c2vezKg1.js → HealthTab-K-bd_CM-.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{HealthTab-c2vezKg1.js.map → HealthTab-K-bd_CM-.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-bQYHIcdx.js → MaintenanceTab-CoEioKzx.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-bQYHIcdx.js.map → MaintenanceTab-CoEioKzx.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-2L8pH6y2.js → MemoryMapTab-CJo24ulv.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-2L8pH6y2.js.map → MemoryMapTab-CJo24ulv.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MetricsTab-CzUx1jpo.js → MetricsTab-DCNlQWWP.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MetricsTab-CzUx1jpo.js.map → MetricsTab-DCNlQWWP.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{OverviewTab-eCNoaclv.js → OverviewTab-CQQlyIQ6.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{OverviewTab-eCNoaclv.js.map → OverviewTab-CQQlyIQ6.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{ReposTab-tb0IW3NF.js → ReposTab-Cqm82_yn.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ReposTab-tb0IW3NF.js.map → ReposTab-Cqm82_yn.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SessionsTab-C-IoLw5h.js → SessionsTab-A8xTAdET.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SessionsTab-C-IoLw5h.js.map → SessionsTab-A8xTAdET.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SetupTab-BvmFi8gf.js → SetupTab-CqaSgaZl.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SetupTab-BvmFi8gf.js.map → SetupTab-CqaSgaZl.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-DBH-cOlA.js → TimeSavedCard-C_f3q8GR.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-DBH-cOlA.js.map → TimeSavedCard-C_f3q8GR.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TurnsTab-DBMgmvnX.js → TurnsTab-BEsafACo.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TurnsTab-DBMgmvnX.js.map → TurnsTab-BEsafACo.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-DD1CMK80.js +2 -0
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-DD1CMK80.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{WikiTab-1LcQrXk3.js → WikiTab-Bf01M2_Z.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{WikiTab-1LcQrXk3.js.map → WikiTab-Bf01M2_Z.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{button-DtEsZTUE.js → button-BEJPTk_E.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{button-DtEsZTUE.js.map → button-BEJPTk_E.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{card-DcfTmw-4.js → card-DK1V382s.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{card-DcfTmw-4.js.map → card-DK1V382s.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-BsIxUDyw.js → generateCategoricalChart-CRtaPphL.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-BsIxUDyw.js.map → generateCategoricalChart-CRtaPphL.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{index-B93cewiX.js → index-CB6BslE4.js} +34 -29
- package/extensions/dashboard-client/dist/assets/index-CB6BslE4.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/index-CfvziyBi.css +1 -0
- package/extensions/dashboard-client/dist/assets/{switch-Bowd7jCD.js → switch-C4FV6B9k.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{switch-Bowd7jCD.js.map → switch-C4FV6B9k.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{toggle-Bo7kJZ4u.js → toggle-GBmeENMd.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{toggle-Bo7kJZ4u.js.map → toggle-GBmeENMd.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{useSSE-zNhb0c3u.js → useSSE-BOKZGSn1.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-zNhb0c3u.js.map → useSSE-BOKZGSn1.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +2 -2
- package/extensions/dashboard-client/src/App.tsx +2 -0
- package/extensions/dashboard-client/src/api/vector-cortex.ts +54 -0
- package/extensions/dashboard-client/src/tabs/VectorCortexTab.tsx +272 -0
- package/extensions/dashboard-client/src/tabs/registry.ts +4 -1
- package/extensions/dashboard-client/src/types/vector-cortex.ts +84 -0
- package/extensions/dashboard-client/tsconfig.json +1 -1
- package/extensions/dashboard-server/api-contracts/endpoints/registry-ext.ts +67 -0
- package/extensions/dashboard-server/api-contracts/endpoints/registry.ts +4 -21
- package/extensions/dashboard-server/api-contracts/index.ts +3 -0
- package/extensions/dashboard-server/api-contracts/vector-cortex.ts +136 -0
- package/extensions/dashboard-server/routes-rag-settings-helpers.ts +41 -0
- package/extensions/dashboard-server/routes-vector-cortex.ts +332 -0
- package/extensions/dashboard-server/routes.ts +6 -0
- package/extensions/dashboard-server/server.ts +8 -0
- package/extensions/mega-events/context-handler.ts +16 -0
- package/extensions/mega-runtime/vector-cortex-ledger.ts +165 -0
- package/extensions/mega-runtime/vector-cortex-safety.ts +181 -0
- package/package.json +2 -1
- package/src/config/vector-cortex.ts +98 -0
- package/src/config.ts +28 -0
- package/src/dedup/l1-lsh-v2.ts +78 -0
- package/src/dedup/l1-minhash-v2.ts +221 -0
- package/src/dedup/normalize.ts +1 -1
- package/src/store/sqlite/game-scores.ts +2 -1
- package/src/vector-cortex/conformance/emit.ts +56 -0
- package/src/vector-cortex/conformance/manifest.ts +298 -0
- package/src/vector-cortex/conformance/runner.ts +165 -0
- package/src/vector-cortex/conformance/triadB-reader.ts +110 -0
- package/src/vector-cortex/eval/annotations.ts +70 -0
- package/src/vector-cortex/eval/metrics.ts +113 -0
- package/src/vector-cortex/eval/observer.ts +86 -0
- package/src/vector-cortex/eval/persist.ts +73 -0
- package/src/vector-cortex/eval/reader.ts +45 -0
- package/src/vector-cortex/eval/types.ts +89 -0
- package/src/vector-cortex/ledger/adapter.ts +71 -0
- package/src/vector-cortex/ledger/compat-journal.ts +234 -0
- package/src/vector-cortex/ledger/emit.ts +86 -0
- package/src/vector-cortex/ledger/event-codec.ts +79 -0
- package/src/vector-cortex/ledger/event-codecB.ts +87 -0
- package/src/vector-cortex/ledger/sqlite.ts +265 -0
- package/src/vector-cortex/ledger/store.ts +380 -0
- package/src/vector-cortex/ledger/types.ts +141 -0
- package/src/vector-cortex/ledger/validator.ts +124 -0
- package/src/vector-cortex/migrations/effective-cut-v2.ts +149 -0
- package/src/vector-cortex/migrations/minhash-v2.ts +263 -0
- package/src/vector-cortex/migrations/occurrence-v2.ts +192 -0
- package/src/vector-cortex/replay/cut.ts +169 -0
- package/src/vector-cortex/replay/emit.ts +89 -0
- package/src/vector-cortex/replay/replay.ts +308 -0
- package/src/vector-cortex/replay/replayB.ts +97 -0
- package/src/vector-cortex/replay/types.ts +145 -0
- package/src/vector-cortex/resilience/breaker-core.ts +444 -0
- package/src/vector-cortex/resilience/breaker.ts +22 -0
- package/src/vector-cortex/resilience/emit.ts +99 -0
- package/src/vector-cortex/resilience/spool-core.ts +411 -0
- package/src/vector-cortex/resilience/spool.ts +22 -0
- package/src/vector-cortex/resilience/types.ts +158 -0
- package/extensions/dashboard-client/dist/assets/index-B93cewiX.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/index-C_tCbOI0.css +0 -1
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* summarizer.ts — per-cluster summary for the RAPTOR tree (Sprint 13, Phase 6).
|
|
3
|
+
*
|
|
4
|
+
* Default: pure extractive (deterministic, zero network, zero model) reusing
|
|
5
|
+
* extractive.ts. Optional: a LOCAL Ollama model (llama3.2:3b by default) when
|
|
6
|
+
* MEGACOMPACT_RAPTOR_MODEL is set — localhost only, same PREVENT-PI-004
|
|
7
|
+
* exception class as HttpEmbedder/the dashboard. No remote API is ever called.
|
|
8
|
+
*
|
|
9
|
+
* The summarizer returns structured text + a token estimate. Faithfulness is
|
|
10
|
+
* enforced downstream by guardrails.ts — this module only produces candidates.
|
|
11
|
+
*/
|
|
12
|
+
import { extractiveSummarize } from "../../extractive.js";
|
|
13
|
+
import { estimateBlockTokens } from "../../tokens.js";
|
|
14
|
+
import { spawnSync } from "node:child_process"; // guardrails-allow PREVENT-PI-004: localhost-only user-spawned Ollama server (BYO local model, never remote)
|
|
15
|
+
/** The local Ollama endpoint (loopback). Read lazily so tests can avoid it. */
|
|
16
|
+
function ollamaEndpoint() {
|
|
17
|
+
const model = process.env.MEGACOMPACT_RAPTOR_MODEL;
|
|
18
|
+
if (!model)
|
|
19
|
+
return null;
|
|
20
|
+
const base = process.env.MEGACOMPACT_RAPTOR_URL ?? "http://127.0.0.1:11434"; // guardrails-allow PREVENT-PI-004: loopback-only Ollama endpoint for local RAPTOR summarization
|
|
21
|
+
// Guard: only loopback is permitted (remote Ollama would violate PREVENT-PI-004).
|
|
22
|
+
if (!/^https?:\/\/(localhost|127\.0\.0\.1)([:/]|$)/.test(base)) {
|
|
23
|
+
throw new Error(`MEGACOMPACT_RAPTOR_URL must be localhost/127.0.0.1 (got ${base}). ` +
|
|
24
|
+
`Remote Ollama is not allowed (PREVENT-PI-004).`);
|
|
25
|
+
}
|
|
26
|
+
return { url: `${base}/api/generate`, model };
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Extractive summarization of a cluster's source messages. Deterministic and
|
|
30
|
+
* fully local — the on-by-default path.
|
|
31
|
+
*/
|
|
32
|
+
export function extractiveClusterSummary(messages) {
|
|
33
|
+
const s = extractiveSummarize(messages);
|
|
34
|
+
return { summary: s.topicSummary, tokenEstimate: s.tokenEstimate };
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Build a summary for one cluster of source messages.
|
|
38
|
+
*
|
|
39
|
+
* Uses local Ollama when MEGACOMPACT_RAPTOR_MODEL is set (localhost-only);
|
|
40
|
+
* otherwise falls back to deterministic extractive. The `fetch` is a localhost
|
|
41
|
+
* call inside the PREVENT-PI-004 exception — annotated accordingly.
|
|
42
|
+
*/
|
|
43
|
+
export function summarizeCluster(messages) {
|
|
44
|
+
const ollama = ollamaEndpoint();
|
|
45
|
+
if (!ollama)
|
|
46
|
+
return extractiveClusterSummary(messages);
|
|
47
|
+
return ollamaSummarize(messages, ollama);
|
|
48
|
+
}
|
|
49
|
+
function ollamaSummarize(messages, ollama) {
|
|
50
|
+
// The fetch below is localhost-only (loopback Ollama) — the PREVENT-PI-004
|
|
51
|
+
// sanctioned local-model exceptions (same class as /dashboard, HttpEmbedder).
|
|
52
|
+
const prompt = messages.map((m) => `${m.role}: ${m.text}`).join("\n");
|
|
53
|
+
// Synchronous bridge: spawnSync an inline worker so the call blocks without
|
|
54
|
+
// deadlocking fetch (mirrors HttpEmbedder — Atomics.wait on main thread would
|
|
55
|
+
// hang). A blocked main thread cannot pump the socket.
|
|
56
|
+
const WORKER = String.raw `
|
|
57
|
+
const url = process.env.R_URL, model = process.env.R_MODEL, prompt = process.env.R_PROMPT;
|
|
58
|
+
try {
|
|
59
|
+
const r = await fetch(url, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ model, prompt, stream: false }) }); // guardrails-allow PREVENT-PI-004: localhost-only user-spawned Ollama server (BYO local model, never remote)
|
|
60
|
+
const j = await r.json();
|
|
61
|
+
process.stdout.write(JSON.stringify({ ok: r.ok, text: j.response || "" }));
|
|
62
|
+
} catch (e) {
|
|
63
|
+
process.stdout.write(JSON.stringify({ ok: false, error: String(e && e.message ? e.message : e) }));
|
|
64
|
+
}
|
|
65
|
+
`;
|
|
66
|
+
const res = spawnSync(process.execPath, ["-e", WORKER], {
|
|
67
|
+
encoding: "utf8",
|
|
68
|
+
timeout: 30_000,
|
|
69
|
+
env: { ...process.env, R_URL: ollama.url, R_MODEL: ollama.model, R_PROMPT: prompt },
|
|
70
|
+
});
|
|
71
|
+
let parsed = { ok: false, error: "no response" };
|
|
72
|
+
if (typeof res.stdout === "string" && res.stdout.length > 0) {
|
|
73
|
+
try {
|
|
74
|
+
parsed = JSON.parse(res.stdout);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
parsed = { ok: false, error: "bad json" };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (!parsed.ok || !parsed.text) {
|
|
81
|
+
// Ollama unavailable → deterministic extractive fallback (never fail the build).
|
|
82
|
+
return extractiveClusterSummary(messages);
|
|
83
|
+
}
|
|
84
|
+
const summary = parsed.text.trim();
|
|
85
|
+
return { summary, tokenEstimate: estimateBlockTokens(summary) };
|
|
86
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tree.ts — RAPTOR hierarchical summary-tree builder (Sprint 13, Phase 6).
|
|
3
|
+
*
|
|
4
|
+
* Builds a multi-level tree of summary nodes over leaf chunks: leaves are the
|
|
5
|
+
* original regions; each higher level summarizes clusters of the level below
|
|
6
|
+
* until a single root remains. QA ops: a wall-clock budget guard — on exhaustion
|
|
7
|
+
* we build an extractive fallback root. <10 leaves → a single summary node.
|
|
8
|
+
*
|
|
9
|
+
* Node model (kept simple + flat): every RaptorNode stores the LIST OF LEAF IDS
|
|
10
|
+
* it ultimately covers in `children` (not a mix of node/leaf ids). So the node
|
|
11
|
+
* map holds ONLY internal summary nodes — never per-leaf wrappers — which is
|
|
12
|
+
* what makes RAPTOR consolidate (nodes.size << leaves) and makes retrieval's
|
|
13
|
+
* leaf walk trivial.
|
|
14
|
+
*
|
|
15
|
+
* PREVENT-PI-004: no network here. summarizeCluster() may call a localhost
|
|
16
|
+
* Ollama (annotated in summarizer.ts); extractive is the default.
|
|
17
|
+
*/
|
|
18
|
+
import { kmeanspp, meanVector } from "./kmeans.js";
|
|
19
|
+
import { summarizeCluster } from "./summarizer.js";
|
|
20
|
+
import { applyHallucinationGuardrails, sourceTokenSet } from "./guardrails.js";
|
|
21
|
+
const DEFAULT_BUDGET_MS = 5000;
|
|
22
|
+
const DEFAULT_CLUSTERS = 5;
|
|
23
|
+
function defaultNextId(level, index) {
|
|
24
|
+
return `r${level}_${index}`;
|
|
25
|
+
}
|
|
26
|
+
function summarizeInto(item, centroid, embedder, consistencyThreshold) {
|
|
27
|
+
let summary = summarizeCluster(item.messages);
|
|
28
|
+
const guard = applyHallucinationGuardrails({
|
|
29
|
+
summary: summary.summary,
|
|
30
|
+
sources: item.sources,
|
|
31
|
+
centroid,
|
|
32
|
+
embedder,
|
|
33
|
+
sourceTokens: sourceTokenSet(item.sources),
|
|
34
|
+
consistencyThreshold,
|
|
35
|
+
});
|
|
36
|
+
if (guard.marker === "extractive_fallback") {
|
|
37
|
+
summary = summarizeCluster(item.messages); // deterministic extractive text
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
summary: summary.summary,
|
|
41
|
+
tokenEstimate: summary.tokenEstimate,
|
|
42
|
+
qualityMarker: guard.marker === "extractive_fallback" ? "low" : guard.marker,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Build a RAPTOR tree from leaf chunks. Synchronous; guarded by an elapsed-time
|
|
47
|
+
* budget. Returns a tree whose `nodes` map holds ONLY internal summary nodes.
|
|
48
|
+
*/
|
|
49
|
+
export function buildRaptorTree(leaves, opts) {
|
|
50
|
+
const embedder = opts.embedder;
|
|
51
|
+
const budgetMs = opts.budgetMs ?? DEFAULT_BUDGET_MS;
|
|
52
|
+
const clustersPerLevel = opts.clustersPerLevel ?? DEFAULT_CLUSTERS;
|
|
53
|
+
const nextId = opts.nextId ?? defaultNextId;
|
|
54
|
+
const now = opts.now ?? (() => Date.now());
|
|
55
|
+
const start = now();
|
|
56
|
+
const within = () => now() - start <= budgetMs;
|
|
57
|
+
const nodes = new Map();
|
|
58
|
+
// <10 leaves → single summary root (no hierarchy needed).
|
|
59
|
+
if (leaves.length < 10) {
|
|
60
|
+
const item = {
|
|
61
|
+
id: "root",
|
|
62
|
+
parentId: null,
|
|
63
|
+
embedding: meanVector(leaves.map((l) => l.embedding)),
|
|
64
|
+
leafIds: leaves.map((l) => l.id),
|
|
65
|
+
messages: leaves.flatMap((l) => l.messages),
|
|
66
|
+
sources: leaves.map((l) => l.sourceText),
|
|
67
|
+
};
|
|
68
|
+
const centroid = item.embedding;
|
|
69
|
+
const { summary, tokenEstimate, qualityMarker } = summarizeInto(item, centroid, embedder, opts.consistencyThreshold);
|
|
70
|
+
const rootId = nextId(0, 0);
|
|
71
|
+
nodes.set(rootId, {
|
|
72
|
+
id: rootId,
|
|
73
|
+
level: 0,
|
|
74
|
+
parentId: null,
|
|
75
|
+
children: item.leafIds,
|
|
76
|
+
summary,
|
|
77
|
+
embedding: centroid,
|
|
78
|
+
qualityMarker,
|
|
79
|
+
tokenEstimate,
|
|
80
|
+
});
|
|
81
|
+
return { nodes, rootId, levels: 1, timedOut: false };
|
|
82
|
+
}
|
|
83
|
+
let currentLevel = leaves.map((l) => ({
|
|
84
|
+
id: l.id,
|
|
85
|
+
parentId: null,
|
|
86
|
+
embedding: l.embedding,
|
|
87
|
+
leafIds: [l.id],
|
|
88
|
+
messages: l.messages,
|
|
89
|
+
sources: [l.sourceText],
|
|
90
|
+
}));
|
|
91
|
+
let level = 0;
|
|
92
|
+
while (currentLevel.length > 1) {
|
|
93
|
+
if (!within())
|
|
94
|
+
return extractiveFallbackRoot(leaves, nodes, nextId);
|
|
95
|
+
// Once we're down to a handful of items, collapse them all into one root.
|
|
96
|
+
// (k === currentLevel.length would make every item its own singleton
|
|
97
|
+
// cluster and never shrink — an infinite loop until the budget blows.)
|
|
98
|
+
if (currentLevel.length <= clustersPerLevel) {
|
|
99
|
+
const merged = {
|
|
100
|
+
id: "merge",
|
|
101
|
+
parentId: null,
|
|
102
|
+
embedding: meanVector(currentLevel.map((c) => c.embedding)),
|
|
103
|
+
leafIds: currentLevel.flatMap((c) => c.leafIds),
|
|
104
|
+
messages: currentLevel.flatMap((c) => c.messages),
|
|
105
|
+
sources: currentLevel.flatMap((c) => c.sources),
|
|
106
|
+
};
|
|
107
|
+
const centroid = merged.embedding;
|
|
108
|
+
const { summary, tokenEstimate, qualityMarker } = summarizeInto(merged, centroid, embedder, opts.consistencyThreshold);
|
|
109
|
+
const rootId = nextId(level + 1, 0);
|
|
110
|
+
nodes.set(rootId, {
|
|
111
|
+
id: rootId,
|
|
112
|
+
level: level + 1,
|
|
113
|
+
parentId: null,
|
|
114
|
+
children: merged.leafIds,
|
|
115
|
+
summary,
|
|
116
|
+
embedding: centroid,
|
|
117
|
+
qualityMarker,
|
|
118
|
+
tokenEstimate,
|
|
119
|
+
});
|
|
120
|
+
// Populate parentId for the internal nodes being merged into this root.
|
|
121
|
+
// currentLevel items with ids in `nodes` are internal summary nodes (level
|
|
122
|
+
// >= 1); raw leaf ids are not in `nodes` and are correctly skipped.
|
|
123
|
+
for (const c of currentLevel) {
|
|
124
|
+
const child = nodes.get(c.id);
|
|
125
|
+
if (child && child.id !== rootId && child.parentId === null) {
|
|
126
|
+
child.parentId = rootId;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return { nodes, rootId, levels: level + 2, timedOut: false };
|
|
130
|
+
}
|
|
131
|
+
const k = Math.max(1, Math.min(clustersPerLevel, currentLevel.length));
|
|
132
|
+
const clustered = kmeanspp(currentLevel.map((c) => c.embedding), k, { seed: 0x1234 + level });
|
|
133
|
+
const groups = Array.from({ length: clustered.k }, () => []);
|
|
134
|
+
clustered.assignments.forEach((c, i) => groups[c].push(currentLevel[i]));
|
|
135
|
+
const nextLevel = [];
|
|
136
|
+
for (let g = 0; g < groups.length; g++) {
|
|
137
|
+
const group = groups[g];
|
|
138
|
+
if (group.length === 0)
|
|
139
|
+
continue;
|
|
140
|
+
const merged = {
|
|
141
|
+
id: nextId(level + 1, g),
|
|
142
|
+
parentId: null,
|
|
143
|
+
embedding: clustered.centroids[g],
|
|
144
|
+
leafIds: group.flatMap((c) => c.leafIds),
|
|
145
|
+
messages: group.flatMap((c) => c.messages),
|
|
146
|
+
sources: group.flatMap((c) => c.sources),
|
|
147
|
+
};
|
|
148
|
+
const { summary, tokenEstimate, qualityMarker } = summarizeInto(merged, merged.embedding, embedder, opts.consistencyThreshold);
|
|
149
|
+
nodes.set(merged.id, {
|
|
150
|
+
id: merged.id,
|
|
151
|
+
level: level + 1,
|
|
152
|
+
parentId: null,
|
|
153
|
+
children: merged.leafIds,
|
|
154
|
+
summary,
|
|
155
|
+
embedding: merged.embedding,
|
|
156
|
+
qualityMarker,
|
|
157
|
+
tokenEstimate,
|
|
158
|
+
});
|
|
159
|
+
// Populate parentId for the internal nodes being absorbed into this
|
|
160
|
+
// parent summary. Group members with ids in `nodes` are internal summary
|
|
161
|
+
// nodes (level >= 1); raw leaf ids are not in `nodes` (per-leaf wrappers
|
|
162
|
+
// are intentionally absent) and are correctly skipped — leaf→summary
|
|
163
|
+
// walks go through the parent's `children` list instead.
|
|
164
|
+
for (const c of group) {
|
|
165
|
+
const child = nodes.get(c.id);
|
|
166
|
+
if (child && child.id !== merged.id) {
|
|
167
|
+
child.parentId = merged.id;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
nextLevel.push(merged);
|
|
171
|
+
}
|
|
172
|
+
currentLevel = nextLevel;
|
|
173
|
+
level++;
|
|
174
|
+
}
|
|
175
|
+
const root = currentLevel[0];
|
|
176
|
+
const rootId = root ? root.id : null;
|
|
177
|
+
return {
|
|
178
|
+
nodes,
|
|
179
|
+
rootId,
|
|
180
|
+
levels: level + 1,
|
|
181
|
+
timedOut: false,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Budget-exceeded fallback: build a single deterministic extractive root over
|
|
186
|
+
* all leaves and mark it low quality. Keeps a valid (if shallow) tree.
|
|
187
|
+
*/
|
|
188
|
+
function extractiveFallbackRoot(leaves, nodes, nextId) {
|
|
189
|
+
const summary = summarizeCluster(leaves.flatMap((l) => l.messages));
|
|
190
|
+
const rootId = nextId(99, 0);
|
|
191
|
+
nodes.set(rootId, {
|
|
192
|
+
id: rootId,
|
|
193
|
+
level: 99,
|
|
194
|
+
parentId: null,
|
|
195
|
+
children: leaves.map((l) => l.id),
|
|
196
|
+
summary: summary.summary,
|
|
197
|
+
embedding: meanVector(leaves.map((l) => l.embedding)),
|
|
198
|
+
qualityMarker: "low",
|
|
199
|
+
tokenEstimate: summary.tokenEstimate,
|
|
200
|
+
});
|
|
201
|
+
return { nodes, rootId, levels: 100, timedOut: true };
|
|
202
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* topk.ts — min-heap based top-K selection (Sprint 12, QA #4).
|
|
3
|
+
*
|
|
4
|
+
* Replaces the O(N log N) full `.sort()` in search() with an O(N log k) heap,
|
|
5
|
+
* which matters once a session holds thousands of checkpoints. Generic over any
|
|
6
|
+
* scored item with a numeric `score`.
|
|
7
|
+
*
|
|
8
|
+
* Pure, no deps, no network (PREVENT-PI-004).
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Return the `k` highest-scoring items (stable insertion order on ties).
|
|
12
|
+
* O(N log k) — a bounded min-heap of size k.
|
|
13
|
+
*/
|
|
14
|
+
export function topK(items, k) {
|
|
15
|
+
if (k <= 0)
|
|
16
|
+
return [];
|
|
17
|
+
if (items.length <= k)
|
|
18
|
+
return [...items].sort((a, b) => b.score - a.score);
|
|
19
|
+
// Min-heap of the current top-k, stored as a flat array of Scored<T>.
|
|
20
|
+
const heap = [];
|
|
21
|
+
const push = (e) => {
|
|
22
|
+
heap.push(e);
|
|
23
|
+
let i = heap.length - 1;
|
|
24
|
+
while (i > 0) {
|
|
25
|
+
const parent = (i - 1) >> 1;
|
|
26
|
+
if (heap[parent].score <= heap[i].score)
|
|
27
|
+
break;
|
|
28
|
+
[heap[parent], heap[i]] = [heap[i], heap[parent]];
|
|
29
|
+
i = parent;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
const siftDown = (start) => {
|
|
33
|
+
let i = start;
|
|
34
|
+
for (;;) {
|
|
35
|
+
const l = 2 * i + 1;
|
|
36
|
+
const r = 2 * i + 2;
|
|
37
|
+
let smallest = i;
|
|
38
|
+
if (l < heap.length && heap[l].score < heap[smallest].score)
|
|
39
|
+
smallest = l;
|
|
40
|
+
if (r < heap.length && heap[r].score < heap[smallest].score)
|
|
41
|
+
smallest = r;
|
|
42
|
+
if (smallest === i)
|
|
43
|
+
break;
|
|
44
|
+
[heap[smallest], heap[i]] = [heap[i], heap[smallest]];
|
|
45
|
+
i = smallest;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
for (const it of items) {
|
|
49
|
+
if (heap.length < k) {
|
|
50
|
+
push(it);
|
|
51
|
+
}
|
|
52
|
+
else if (it.score > heap[0].score) {
|
|
53
|
+
// Replace the current minimum with this better-scoring item, then sift
|
|
54
|
+
// it down to restore the min-heap invariant.
|
|
55
|
+
heap[0] = it;
|
|
56
|
+
siftDown(0);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return heap.sort((a, b) => b.score - a.score);
|
|
60
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** Additive endpoint entries spread into the ENDPOINTS registry. */
|
|
2
|
+
export const EXTRA_ENDPOINTS = {
|
|
3
|
+
// ─── Per-model compaction thresholds (S52 / v0.16.1) ───────────────
|
|
4
|
+
/** GET /api/model-thresholds — List known models + their thresholds. */
|
|
5
|
+
modelThresholds: {
|
|
6
|
+
method: "GET",
|
|
7
|
+
path: "/api/model-thresholds",
|
|
8
|
+
description: "Every known model (from model_snapshots) with its per-model threshold override (or defaults).",
|
|
9
|
+
},
|
|
10
|
+
// ─── RAG Metrics (Sprint H2) ──────────────────────────────────────
|
|
11
|
+
/** GET /api/rag-metrics — HyDE + recall-quality telemetry aggregates. */
|
|
12
|
+
ragMetrics: {
|
|
13
|
+
method: "GET",
|
|
14
|
+
path: "/api/rag-metrics",
|
|
15
|
+
description: "HyDE invocation + recall-quality telemetry: flags, totals, recent turns, and daily series.",
|
|
16
|
+
},
|
|
17
|
+
// ─── Vector Cortex (VC0A) ────────────────────────────────────────
|
|
18
|
+
/** GET /api/vector-cortex/evaluation — reader-only eval aggregate (VC0A). */
|
|
19
|
+
vectorCortexEvaluation: {
|
|
20
|
+
method: "GET",
|
|
21
|
+
path: "/api/vector-cortex/evaluation",
|
|
22
|
+
description: "Reader-only vector-cortex evaluation summary: latency histogram + per-mode sample counts (never payloads).",
|
|
23
|
+
},
|
|
24
|
+
/** GET /api/vector-cortex/ledger — reader-only occurrence ledger view (VC1B). */
|
|
25
|
+
vectorCortexLedger: {
|
|
26
|
+
method: "GET",
|
|
27
|
+
path: "/api/vector-cortex/ledger",
|
|
28
|
+
description: "Reader-only occurrence-ledger identity view: seq/eventId/kind/digest + high-water (never source payloads).",
|
|
29
|
+
},
|
|
30
|
+
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { EXTRA_ENDPOINTS } from "./registry-ext.js";
|
|
1
2
|
// ─── ENDPOINTS Registry ─────────────────────────────────────────────────────
|
|
2
3
|
/**
|
|
3
4
|
* Central registry of all 14 dashboard API endpoints. Each entry is an
|
|
@@ -290,18 +291,7 @@ export const ENDPOINTS = {
|
|
|
290
291
|
path: "/api/rag-settings",
|
|
291
292
|
description: "Update RAG feature flag states by writing _DISABLED env vars to .mega-compact.env.",
|
|
292
293
|
},
|
|
293
|
-
// ───
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
method: "GET",
|
|
297
|
-
path: "/api/rag-metrics",
|
|
298
|
-
description: "HyDE invocation + recall-quality telemetry: flags, totals, recent turns, and daily series.",
|
|
299
|
-
},
|
|
300
|
-
// ─── Per-model compaction thresholds (S52 / v0.16.1) ───────────────
|
|
301
|
-
/** GET /api/model-thresholds — List known models + their thresholds. */
|
|
302
|
-
modelThresholds: {
|
|
303
|
-
method: "GET",
|
|
304
|
-
path: "/api/model-thresholds",
|
|
305
|
-
description: "Every known model (from model_snapshots) with its per-model threshold override (or defaults).",
|
|
306
|
-
},
|
|
294
|
+
// ─── Additive groups (rag-metrics, thresholds, vector-cortex) live in
|
|
295
|
+
// ─── registry-ext.ts so this registry stays under the 500-line limit.
|
|
296
|
+
...EXTRA_ENDPOINTS,
|
|
307
297
|
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* api-contracts/vector-cortex.ts — vector-cortex dashboard API contracts.
|
|
3
|
+
*
|
|
4
|
+
* Owned by the vector-cortex sprints. VC0A ships only the reader-only aggregate
|
|
5
|
+
* `GET /api/vector-cortex/evaluation`. VC0C adds the breaker health endpoint
|
|
6
|
+
* and reset mutation into this SAME file — keep entries small and additive so
|
|
7
|
+
* the file stays within extension limits (400 soft / 500 hard).
|
|
8
|
+
*
|
|
9
|
+
* PREVENT-PI-004: type definitions only, no network code.
|
|
10
|
+
* PREVENT-011: no `any` type.
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
@@ -129,6 +129,17 @@ export const SETTINGS = [
|
|
|
129
129
|
num("MEGACOMPACT_EMBED_CACHE", "Embed Cache Size", "Embedding cache entries (0 = disabled)", 256, 0, 10000),
|
|
130
130
|
],
|
|
131
131
|
},
|
|
132
|
+
{
|
|
133
|
+
name: "Vector Cortex",
|
|
134
|
+
settings: [
|
|
135
|
+
boolDirect("MEGACOMPACT_VC0A", "VC0A Baseline Observability", "Structured evaluation observer (MetricEventV1 + latency histogram). OFF = mode C, byte-identical to predecessor.", true),
|
|
136
|
+
boolDirect("MEGACOMPACT_VC0B", "VC0B Replay Correctness", "ReplayCutV2 effective-cut (min of boundary-safe/commit/capture high-water + pair retreat + anchor floor) and M3 effective-cut-v2 migration. OFF = legacy capped replay, byte-identical.", true),
|
|
137
|
+
boolDirect("MEGACOMPACT_VC1A", "VC1A Canonical Byte Events", "EventV2 byte-authority ledger codec (original bytes + SHA-256, strict UTF-8, derived NFC) and canonical validator (EVT_DIGEST_MISMATCH / EVT_UTF8_TAG_INVALID / EVT_DUPLICATE_ID). OFF = mode C, transcript codec unchanged, byte-identical.", true),
|
|
138
|
+
boolDirect("MEGACOMPACT_VC1B", "VC1B Occurrence Ledger + Tool Identity", "Neutral occurrence ledger (LedgerReader/Writer/Admin + CompatJournalV1): per-session monotonic seq, tool result references one earlier call, uniqueness by (eventId,digest) only, and the M2 copy-validate-switch downgrade journal. OFF = mode C, ledger unwritten, byte-identical.", true),
|
|
139
|
+
boolDirect("MEGACOMPACT_VC0C", "VC0C Live Safety Envelope", "TriadResult/Breaker live circuit breaker (60s window, 20 attempts, 30s cooldown, 3 probes, 5min healthy residence) + durable spool before provider invocation; manual reset clears cooldown but never evidence. OFF = mode C, unchanged transcript, byte-identical.", true),
|
|
140
|
+
boolDirect("MEGACOMPACT_VC1C", "VC1C Cross-Language Conformance v2", "FixtureManifestV2 canonical manifest validator + DowngradeReport deterministic downgrade export + MinHashV2 exact big-integer signatures and the M4 copy/validate/switch minhash-v2 migration (seed table frozen, cross-language byte-exact). OFF = mode C, v1 sync dedup scan unchanged, byte-identical.", true),
|
|
141
|
+
],
|
|
142
|
+
},
|
|
132
143
|
{
|
|
133
144
|
name: "Cost API",
|
|
134
145
|
settings: [
|