pi-mega-compact 0.11.5 → 0.11.6
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/extensions/dashboard-server/api-contracts/cache-stripes.js +8 -0
- package/dist/extensions/dashboard-server/api-contracts/endpoints.js +13 -0
- package/dist/extensions/dashboard-server/api-contracts/memory-map.js +1 -0
- package/dist/extensions/dashboard-server/routes-cache.js +28 -0
- package/dist/extensions/dashboard-server/routes-game.js +3 -0
- package/dist/extensions/dashboard-server/routes-memory-map.js +50 -0
- package/dist/extensions/dashboard-server/routes-setup.js +105 -0
- package/dist/extensions/dashboard-server/routes.js +3 -1
- package/dist/extensions/dashboard-server/server.js +7 -1
- package/dist/extensions/mega-compact.js +5 -0
- package/dist/extensions/mega-config.js +5 -0
- package/dist/extensions/mega-events/context-handler.js +10 -2
- package/dist/extensions/mega-events/perf-handler.js +83 -1
- package/dist/extensions/mega-events/separated-prompt.js +248 -0
- package/dist/extensions/mega-runtime/env-loader.js +56 -0
- package/dist/extensions/mega-runtime/reset-runtime.js +1 -0
- package/dist/extensions/mega-runtime/runtime-snapshot.js +1 -0
- package/dist/extensions/mega-runtime/runtime.js +1 -0
- package/dist/extensions/mega-runtime/snapshot.js +1 -0
- package/dist/extensions/mega-runtime/widget.js +5 -0
- package/dist/src/cache-stripe-impl.js +288 -0
- package/dist/src/cache-stripe.js +11 -0
- package/dist/src/config/stopwords.js +24 -0
- package/dist/src/config.js +17 -0
- package/dist/src/memoryGraph.js +299 -0
- package/dist/src/monitoring.js +13 -0
- package/dist/src/queryExpansion.js +163 -0
- package/dist/src/queryReformulation/cache.js +123 -0
- package/dist/src/queryReformulation/rrf.js +29 -0
- package/dist/src/queryReformulation/tfidf.js +61 -0
- package/dist/src/queryReformulation/vagueness.js +33 -0
- package/dist/src/queryReformulation.js +225 -0
- package/dist/src/recallMetrics.js +258 -0
- package/dist/src/store/sqlite/cache-stripes.js +133 -0
- package/dist/src/store/sqlite/fts5-search.js +68 -0
- package/dist/src/store/sqlite/perf-samples.js +1 -0
- package/dist/src/store/sqlite/schema.js +60 -1
- package/dist/src/store/sqlite.js +1 -0
- package/dist/src/store/vectorIndex.js +29 -5
- package/dist/src/tiered-router/types.js +18 -0
- package/dist/src/tieredRouter.js +421 -0
- package/dist/src/vectorStore.js +8 -6
- package/extensions/dashboard-client/dist/assets/{AchievementTiles-BoL7qBOJ.js → AchievementTiles-DR9cLGDL.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AchievementTiles-BoL7qBOJ.js.map → AchievementTiles-DR9cLGDL.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{AchievementsTab-BFDE3HYc.js → AchievementsTab-svNUgJ1e.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AchievementsTab-BFDE3HYc.js.map → AchievementsTab-svNUgJ1e.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/CacheTab-ASwhOMjR.js +2 -0
- package/extensions/dashboard-client/dist/assets/CacheTab-ASwhOMjR.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{ConfigTab-DDFE-ckA.js → ConfigTab-CmmWheuW.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ConfigTab-DDFE-ckA.js.map → ConfigTab-CmmWheuW.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{EventsTab-B6UxZ7PM.js → EventsTab-CFE7jLsa.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{EventsTab-B6UxZ7PM.js.map → EventsTab-CFE7jLsa.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/GameTab-CJAX_th_.js +2 -0
- package/extensions/dashboard-client/dist/assets/{GameTab-DehUX-KE.js.map → GameTab-CJAX_th_.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-0GWRt4wn.js → MaintenanceTab-P4SUsvMf.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-0GWRt4wn.js.map → MaintenanceTab-P4SUsvMf.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-BBiH76eF.js +2 -0
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-BBiH76eF.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{MetricsTab-C3rwMVsN.js → MetricsTab-CHQscixy.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MetricsTab-C3rwMVsN.js.map → MetricsTab-CHQscixy.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{OverviewTab-39O9_x5j.js → OverviewTab-DBs4DJdd.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{OverviewTab-39O9_x5j.js.map → OverviewTab-DBs4DJdd.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{ReposTab-Cfj6Q5sH.js → ReposTab-DeFz76L5.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ReposTab-Cfj6Q5sH.js.map → ReposTab-DeFz76L5.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SessionsTab-DXDTCi3r.js → SessionsTab-BWNsj1OB.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SessionsTab-DXDTCi3r.js.map → SessionsTab-BWNsj1OB.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/SetupTab-uS6A0xmw.js +2 -0
- package/extensions/dashboard-client/dist/assets/SetupTab-uS6A0xmw.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-Cw1dJ4e9.js → TimeSavedCard-CiqCOQuL.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-Cw1dJ4e9.js.map → TimeSavedCard-CiqCOQuL.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TopicsTab-BAw972BV.js → TopicsTab-BWWQxltv.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TopicsTab-BAw972BV.js.map → TopicsTab-BWWQxltv.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TurnsTab-Cf5mGIdl.js → TurnsTab-CVz4f4-o.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TurnsTab-Cf5mGIdl.js.map → TurnsTab-CVz4f4-o.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/index-CUNn22iV.css +1 -0
- package/extensions/dashboard-client/dist/assets/{index-4gQ7auad.js → index-DrktNOoT.js} +11 -11
- package/extensions/dashboard-client/dist/assets/index-DrktNOoT.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{useSSE-DNgMuyP6.js → useSSE-Bf5LOLSi.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-DNgMuyP6.js.map → useSSE-Bf5LOLSi.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +2 -2
- package/extensions/dashboard-client/src/App.tsx +24 -8
- package/extensions/dashboard-client/src/api/client.ts +15 -0
- package/extensions/dashboard-client/src/components/CacheHitRateTrendCard.tsx +100 -0
- package/extensions/dashboard-client/src/components/StripeDistributionCard.tsx +110 -0
- package/extensions/dashboard-client/src/components/TabBar.tsx +49 -4
- package/extensions/dashboard-client/src/main.tsx +1 -0
- package/extensions/dashboard-client/src/styles/base.css +30 -0
- package/extensions/dashboard-client/src/styles/cache.css +167 -0
- package/extensions/dashboard-client/src/tabs/CacheTab.tsx +75 -13
- package/extensions/dashboard-client/src/tabs/MemoryMapTab.tsx +440 -0
- package/extensions/dashboard-client/src/tabs/SetupTab.tsx +65 -2
- package/extensions/dashboard-server/api-contracts/cache-stripes.ts +49 -0
- package/extensions/dashboard-server/api-contracts/endpoints.ts +31 -1
- package/extensions/dashboard-server/api-contracts/index.ts +16 -1
- package/extensions/dashboard-server/api-contracts/memory-map.ts +50 -0
- package/extensions/dashboard-server/api-contracts/setup.ts +22 -0
- package/extensions/dashboard-server/routes-cache.ts +36 -1
- package/extensions/dashboard-server/routes-game.ts +3 -0
- package/extensions/dashboard-server/routes-memory-map.ts +105 -0
- package/extensions/dashboard-server/routes-setup.ts +112 -0
- package/extensions/dashboard-server/routes.ts +3 -1
- package/extensions/dashboard-server/server.ts +6 -0
- package/extensions/mega-compact.ts +5 -0
- package/extensions/mega-config.ts +17 -0
- package/extensions/mega-events/context-handler.ts +10 -2
- package/extensions/mega-events/perf-handler.ts +111 -1
- package/extensions/mega-events/separated-prompt.ts +329 -0
- package/extensions/mega-runtime/env-loader.ts +55 -0
- package/extensions/mega-runtime/helpers.ts +2 -0
- package/extensions/mega-runtime/reset-runtime.ts +1 -0
- package/extensions/mega-runtime/runtime-snapshot.ts +1 -0
- package/extensions/mega-runtime/runtime.ts +1 -0
- package/extensions/mega-runtime/snapshot.ts +6 -0
- package/extensions/mega-runtime/widget-types.ts +3 -0
- package/extensions/mega-runtime/widget.ts +5 -0
- package/package.json +1 -1
- package/src/cache-stripe-impl.ts +385 -0
- package/src/cache-stripe.ts +18 -0
- package/src/config/stopwords.ts +25 -0
- package/src/config.ts +26 -0
- package/src/memoryGraph.ts +438 -0
- package/src/monitoring.ts +35 -0
- package/src/queryExpansion.ts +206 -0
- package/src/queryReformulation/cache.ts +169 -0
- package/src/queryReformulation/rrf.ts +51 -0
- package/src/queryReformulation/tfidf.ts +79 -0
- package/src/queryReformulation/vagueness.ts +38 -0
- package/src/queryReformulation.ts +355 -0
- package/src/recallMetrics.ts +388 -0
- package/src/store/sqlite/cache-stripes.ts +196 -0
- package/src/store/sqlite/fts5-search.ts +90 -0
- package/src/store/sqlite/perf-samples.ts +3 -1
- package/src/store/sqlite/schema.ts +60 -1
- package/src/store/sqlite.ts +1 -0
- package/src/store/vectorIndex.ts +38 -7
- package/src/tiered-router/types.ts +64 -0
- package/src/tieredRouter.ts +489 -0
- package/src/vectorStore.ts +9 -5
- package/extensions/dashboard-client/dist/assets/CacheTab-eKVc-NV1.js +0 -2
- package/extensions/dashboard-client/dist/assets/CacheTab-eKVc-NV1.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/GameTab-DehUX-KE.js +0 -2
- package/extensions/dashboard-client/dist/assets/SetupTab-mMlfunJa.js +0 -2
- package/extensions/dashboard-client/dist/assets/SetupTab-mMlfunJa.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/index-4gQ7auad.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/index-BEdKlpAB.css +0 -1
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* api-contracts/cache-stripes.ts — Cache stripe API contract (A3, PLAN_V2 Phase 4).
|
|
3
|
+
*
|
|
4
|
+
* Response shape for GET /api/cache-stripes: per-stripe distribution counts,
|
|
5
|
+
* average stability, and a top-level health score. Loopback-only data;
|
|
6
|
+
* zero network (PREVENT-PI-004).
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
@@ -196,6 +196,13 @@ export const ENDPOINTS = {
|
|
|
196
196
|
path: "/api/provider-cache",
|
|
197
197
|
description: "Lifetime provider prompt cache hit-rate aggregates + dollar savings estimate.",
|
|
198
198
|
},
|
|
199
|
+
// ─── A3 Cache Stripes (PLAN_V2 Phase 4) ───────────────────────────
|
|
200
|
+
/** GET /api/cache-stripes — Per-stripe distribution + health score. */
|
|
201
|
+
cacheStripes: {
|
|
202
|
+
method: "GET",
|
|
203
|
+
path: "/api/cache-stripes",
|
|
204
|
+
description: "Per-stripe distribution counts, average stability scores, and composite cache health.",
|
|
205
|
+
},
|
|
199
206
|
// ─── Memory Effectiveness (S53B) ───────────────────────────────────────
|
|
200
207
|
/** GET /api/memory-status — Memory store aggregate statistics. */
|
|
201
208
|
memoryStatus: {
|
|
@@ -215,4 +222,10 @@ export const ENDPOINTS = {
|
|
|
215
222
|
path: "/api/setup-detect",
|
|
216
223
|
description: "Best-effort detection of local embedder backends (ollama, llama.cpp, ONNX) available on the machine.",
|
|
217
224
|
},
|
|
225
|
+
/** POST /api/setup-configure — Write embedder config to .mega-compact.env. */
|
|
226
|
+
setupConfigure: {
|
|
227
|
+
method: "POST",
|
|
228
|
+
path: "/api/setup-configure",
|
|
229
|
+
description: "Write the chosen embedder configuration to .mega-compact.env (loaded at next startup). Returns whether a restart is required.",
|
|
230
|
+
},
|
|
218
231
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -138,3 +138,31 @@ export function handleProviderCache(req, res, ctx) {
|
|
|
138
138
|
return false;
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
|
+
// ---------------------------------------------------------------------------
|
|
142
|
+
// handleCacheStripes — "GET /api/cache-stripes"
|
|
143
|
+
// ---------------------------------------------------------------------------
|
|
144
|
+
export function handleCacheStripes(req, res, ctx) {
|
|
145
|
+
if (!req.url?.startsWith("/api/cache-stripes"))
|
|
146
|
+
return false;
|
|
147
|
+
if (req.method !== "GET") {
|
|
148
|
+
res.writeHead(405, { "Content-Type": "application/json" });
|
|
149
|
+
res.end(JSON.stringify({ error: "method_not_allowed" }));
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
const stateDir = ctx.stateDir;
|
|
154
|
+
const pfReq = createRequire(import.meta.url);
|
|
155
|
+
const { readCacheStripes } = pfReq("../../src/store/sqlite/cache-stripes.js");
|
|
156
|
+
const result = readCacheStripes(stateDir);
|
|
157
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
158
|
+
res.end(JSON.stringify(result));
|
|
159
|
+
}
|
|
160
|
+
catch (e) {
|
|
161
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
162
|
+
res.end(JSON.stringify({
|
|
163
|
+
error: "cache_stripes_unavailable",
|
|
164
|
+
detail: String(e),
|
|
165
|
+
}));
|
|
166
|
+
}
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
@@ -256,6 +256,9 @@ export function handlePerf(req, res, ctx) {
|
|
|
256
256
|
avg: avg(get("cache_hit_pct")),
|
|
257
257
|
latest: latest(get("cache_hit_pct")),
|
|
258
258
|
n: get("cache_hit_pct").length,
|
|
259
|
+
samples: rows
|
|
260
|
+
.filter((r) => r.kind === "cache_hit_pct")
|
|
261
|
+
.map((r) => ({ pct: r.value, ts: r.ts })),
|
|
259
262
|
},
|
|
260
263
|
db_recompute_ms: {
|
|
261
264
|
p50: pct(get("db_recompute_ms"), 50),
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* routes-memory-map.ts — GET /api/memory-map route handler (S46).
|
|
3
|
+
*
|
|
4
|
+
* Builds a memory graph from the local SQLite store and returns it as JSON.
|
|
5
|
+
* Uses an inline require to the pi-agnostic src/memoryGraph.ts builder.
|
|
6
|
+
*/
|
|
7
|
+
import { createRequire } from "node:module";
|
|
8
|
+
import { parse as parseUrl } from "node:url";
|
|
9
|
+
const _req = createRequire(import.meta.url);
|
|
10
|
+
// guardrails-allow PREVENT-PI-004: localhost-only dashboard API endpoint that reads from the local SQLite store — zero remote network calls.
|
|
11
|
+
export function handleMemoryMap(req, res, ctx) {
|
|
12
|
+
if (req.method !== "GET")
|
|
13
|
+
return false;
|
|
14
|
+
const parsed = parseUrl(req.url ?? "", true);
|
|
15
|
+
if (parsed.pathname !== "/api/memory-map")
|
|
16
|
+
return false;
|
|
17
|
+
// guardrails-allow PREVENT-PI-004: local loopback-only dashboard server — reads the local SQLite store for graph data.
|
|
18
|
+
const { buildMemoryGraph } = _req("../../src/memoryGraph.js");
|
|
19
|
+
const sessionId = typeof parsed.query.sessionId === "string" ? parsed.query.sessionId : undefined;
|
|
20
|
+
const threshold = typeof parsed.query.threshold === "string" ? Number.parseFloat(parsed.query.threshold) : undefined;
|
|
21
|
+
const maxEdges = typeof parsed.query.maxEdgesPerNode === "string" ? Number.parseInt(parsed.query.maxEdgesPerNode, 10) : undefined;
|
|
22
|
+
const raptorEdges = parsed.query.includeRaptorEdges === "false" ? false : true;
|
|
23
|
+
const temporalEdges = parsed.query.includeTemporalEdges === "false" ? false : true;
|
|
24
|
+
const graph = buildMemoryGraph({
|
|
25
|
+
sessionId,
|
|
26
|
+
similarityThreshold: threshold,
|
|
27
|
+
maxEdgesPerNode: maxEdges,
|
|
28
|
+
stateDir: ctx.stateDir,
|
|
29
|
+
includeRaptorEdges: raptorEdges,
|
|
30
|
+
includeTemporalEdges: temporalEdges,
|
|
31
|
+
});
|
|
32
|
+
const nodes = graph.nodes.map((n) => ({
|
|
33
|
+
id: n.id,
|
|
34
|
+
sessionId: n.sessionId,
|
|
35
|
+
label: n.label,
|
|
36
|
+
summaryTruncated: n.summaryTruncated,
|
|
37
|
+
tokenEstimate: n.tokenEstimate,
|
|
38
|
+
timestamp: n.timestamp,
|
|
39
|
+
dedupStatus: n.dedupStatus,
|
|
40
|
+
raptorLevel: n.raptorLevel,
|
|
41
|
+
topicSummary: n.topicSummary,
|
|
42
|
+
decisionCount: n.decisionCount,
|
|
43
|
+
textSnippet: n.textSnippet,
|
|
44
|
+
}));
|
|
45
|
+
const edges = graph.edges;
|
|
46
|
+
const response = { nodes, edges, metadata: graph.metadata };
|
|
47
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
48
|
+
res.end(JSON.stringify(response));
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { spawnSync } from "node:child_process"; // guardrails-allow PREVENT-PI-004: local subprocess detection only
|
|
12
12
|
import { createRequire } from "node:module";
|
|
13
|
+
import { writeFileSync, mkdirSync } from "node:fs";
|
|
14
|
+
import { join } from "node:path";
|
|
13
15
|
// ---------------------------------------------------------------------------
|
|
14
16
|
// handleSetupStatus — "/api/setup-status"
|
|
15
17
|
// ---------------------------------------------------------------------------
|
|
@@ -160,3 +162,106 @@ export function handleSetupDetect(req, res, _ctx) {
|
|
|
160
162
|
res.end(JSON.stringify(body));
|
|
161
163
|
return true;
|
|
162
164
|
}
|
|
165
|
+
// ---------------------------------------------------------------------------
|
|
166
|
+
// handleSetupConfigure — POST "/api/setup-configure"
|
|
167
|
+
// ---------------------------------------------------------------------------
|
|
168
|
+
const OLLAMA_DEFAULT_URL = "http://localhost:11434/api/embeddings"; // guardrails-allow PREVENT-PI-004: localhost-only config string, not a runtime fetch
|
|
169
|
+
const LLAMA_DEFAULT_URL = "http://localhost:8080/v1/embeddings"; // guardrails-allow PREVENT-PI-004: localhost-only config string, not a runtime fetch
|
|
170
|
+
function readJsonBody(req, cb) {
|
|
171
|
+
let body = "";
|
|
172
|
+
let tooBig = false;
|
|
173
|
+
req.on("data", (chunk) => {
|
|
174
|
+
if (body.length > 65536) {
|
|
175
|
+
tooBig = true;
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
body += chunk.toString();
|
|
179
|
+
});
|
|
180
|
+
req.on("end", () => {
|
|
181
|
+
if (tooBig)
|
|
182
|
+
return cb({ ok: false, error: "body_too_large" });
|
|
183
|
+
try {
|
|
184
|
+
const v = body ? JSON.parse(body) : {}; // PREVENT-001: parsed value type-checked below
|
|
185
|
+
if (typeof v !== "object" || v === null || Array.isArray(v)) {
|
|
186
|
+
return cb({ ok: false, error: "invalid_object" });
|
|
187
|
+
}
|
|
188
|
+
cb({ ok: true, value: v });
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
cb({ ok: false, error: "invalid_json" });
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
req.on("error", () => cb({ ok: false, error: "read_error" }));
|
|
195
|
+
}
|
|
196
|
+
export function handleSetupConfigure(req, res, ctx) {
|
|
197
|
+
if (req.url !== "/api/setup-configure")
|
|
198
|
+
return false;
|
|
199
|
+
if (req.method !== "POST") {
|
|
200
|
+
// guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
|
|
201
|
+
res.writeHead(405, { "Content-Type": "application/json" });
|
|
202
|
+
res.end(JSON.stringify({ error: "method_not_allowed" }));
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
readJsonBody(req, (parsed) => {
|
|
206
|
+
if (!parsed.ok) {
|
|
207
|
+
// guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
|
|
208
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
209
|
+
res.end(JSON.stringify({ error: parsed.error }));
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const body = parsed.value;
|
|
213
|
+
const embedder = body.embedder;
|
|
214
|
+
if (embedder !== "ollama" && embedder !== "llama" && embedder !== "trigram") {
|
|
215
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
216
|
+
res.end(JSON.stringify({ error: "invalid_embedder" }));
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const url = body.url;
|
|
220
|
+
let resolvedUrl;
|
|
221
|
+
if (embedder === "ollama")
|
|
222
|
+
resolvedUrl = typeof url === "string" && url ? url : OLLAMA_DEFAULT_URL;
|
|
223
|
+
else if (embedder === "llama")
|
|
224
|
+
resolvedUrl = typeof url === "string" && url ? url : LLAMA_DEFAULT_URL;
|
|
225
|
+
else
|
|
226
|
+
resolvedUrl = null;
|
|
227
|
+
// Write .mega-compact.env to the state dir (loaded by env-loader at next startup).
|
|
228
|
+
const stateDir = ctx.stateDir;
|
|
229
|
+
const envPath = join(stateDir, ".mega-compact.env");
|
|
230
|
+
const lines = [
|
|
231
|
+
"# Mega-Compact Embedder Configuration",
|
|
232
|
+
`# Configured via dashboard Setup tab at ${new Date().toISOString()}`,
|
|
233
|
+
];
|
|
234
|
+
if (resolvedUrl) {
|
|
235
|
+
lines.push(`export MEGACOMPACT_EMBEDDING_URL="${resolvedUrl}"`);
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
lines.push("# trigram: built-in embedder, no URL needed");
|
|
239
|
+
lines.push("# unset MEGACOMPACT_EMBEDDING_URL (commented to override any shell-set value)");
|
|
240
|
+
lines.push("# export MEGACOMPACT_EMBEDDING_URL=");
|
|
241
|
+
}
|
|
242
|
+
lines.push("");
|
|
243
|
+
try {
|
|
244
|
+
mkdirSync(stateDir, { recursive: true });
|
|
245
|
+
writeFileSync(envPath, lines.join("\n"), "utf-8");
|
|
246
|
+
}
|
|
247
|
+
catch (e) {
|
|
248
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
249
|
+
res.end(JSON.stringify({ error: `write_failed: ${e instanceof Error ? e.message : String(e)}` }));
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
// Detect if the new config matches what's already active (no restart needed).
|
|
253
|
+
const currentUrl = process.env["MEGACOMPACT_EMBEDDING_URL"];
|
|
254
|
+
const alreadyActive = (resolvedUrl === null && !currentUrl) || (resolvedUrl !== null && currentUrl === resolvedUrl);
|
|
255
|
+
const resp = {
|
|
256
|
+
embedder,
|
|
257
|
+
url: resolvedUrl,
|
|
258
|
+
envPath,
|
|
259
|
+
restartRequired: !alreadyActive,
|
|
260
|
+
alreadyActive,
|
|
261
|
+
};
|
|
262
|
+
// guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
|
|
263
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
264
|
+
res.end(JSON.stringify(resp));
|
|
265
|
+
});
|
|
266
|
+
return true;
|
|
267
|
+
}
|
|
@@ -13,4 +13,6 @@ export { handleTurns } from "./routes-turns.js";
|
|
|
13
13
|
export { handleMaintenance } from "./routes-maintenance.js";
|
|
14
14
|
export { handleProviderCache } from "./routes-cache.js";
|
|
15
15
|
export { handleMemoryStatus } from "./routes-memory.js";
|
|
16
|
-
export { handleSetupStatus, handleSetupDetect } from "./routes-setup.js";
|
|
16
|
+
export { handleSetupStatus, handleSetupDetect, handleSetupConfigure } from "./routes-setup.js";
|
|
17
|
+
export { handleMemoryMap } from "./routes-memory-map.js";
|
|
18
|
+
export { handleCacheStripes } from "./routes-cache.js";
|
|
@@ -12,7 +12,7 @@ import { join, dirname } from "node:path";
|
|
|
12
12
|
import { fileURLToPath } from "node:url";
|
|
13
13
|
import { createRequire } from "node:module";
|
|
14
14
|
import { log, setLogPath, setDashboardServerVersion } from "./state.js";
|
|
15
|
-
import { buildRouteContext, handleIndex, handleRepoIndex, handleEvents, handleGameState, handleGameScores, handlePerf, handleAchievements, handleSessions, handleTopics, handleTurns, handleMaintenance, handleProviderCache, handleMemoryStatus, handleSetupStatus, handleSetupDetect, handleStatic, } from "./routes.js";
|
|
15
|
+
import { buildRouteContext, handleIndex, handleRepoIndex, handleEvents, handleGameState, handleGameScores, handlePerf, handleAchievements, handleSessions, handleTopics, handleTurns, handleMaintenance, handleProviderCache, handleCacheStripes, handleMemoryStatus, handleSetupStatus, handleSetupDetect, handleSetupConfigure, handleMemoryMap, handleStatic, } from "./routes.js";
|
|
16
16
|
export async function launchDashboardServer(stateDir) {
|
|
17
17
|
// Our own package version — exposed at /api/version so the launcher can
|
|
18
18
|
// detect a stale server (started by an older build) and replace it on
|
|
@@ -197,10 +197,16 @@ export async function launchDashboardServer(stateDir) {
|
|
|
197
197
|
return;
|
|
198
198
|
if (handleMemoryStatus(req, res, ctx))
|
|
199
199
|
return;
|
|
200
|
+
if (handleCacheStripes(req, res, ctx))
|
|
201
|
+
return;
|
|
200
202
|
if (handleSetupStatus(req, res, ctx))
|
|
201
203
|
return;
|
|
202
204
|
if (handleSetupDetect(req, res, ctx))
|
|
203
205
|
return;
|
|
206
|
+
if (handleSetupConfigure(req, res, ctx))
|
|
207
|
+
return;
|
|
208
|
+
if (handleMemoryMap(req, res, ctx))
|
|
209
|
+
return;
|
|
204
210
|
handleStatic(req, res, ctx);
|
|
205
211
|
});
|
|
206
212
|
// Bind base + range are env-configurable so tests can use a private,
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
import { closeVectorIndex } from "../src/store/vectorIndex.js";
|
|
29
29
|
import { closeMemoryIndex } from "../src/store/memoryIndex.js";
|
|
30
30
|
import { loadConfig } from "./mega-config.js";
|
|
31
|
+
import { loadMegaEnv } from "./mega-runtime/env-loader.js";
|
|
31
32
|
import { MegaRuntime } from "./mega-runtime.js";
|
|
32
33
|
import { registerEventHandlers } from "./mega-events.js";
|
|
33
34
|
import { registerCommands } from "./mega-commands.js";
|
|
@@ -38,6 +39,10 @@ import { registerGameCommands } from "./mega-game-cmds.js";
|
|
|
38
39
|
import { registerMetricsCommands } from "./mega-metrics-cmds.js";
|
|
39
40
|
import { registerTopicsCommands } from "./mega-topics-cmds.js";
|
|
40
41
|
export default function (pi) {
|
|
42
|
+
// Load .mega-compact.env (written by /mega-setup + dashboard Setup tab) BEFORE
|
|
43
|
+
// config resolution so the wizard's choices take effect. Shell env wins over
|
|
44
|
+
// the file (see env-loader.ts). Non-fatal: missing/malformed file is a no-op.
|
|
45
|
+
loadMegaEnv(loadConfig().stateDir);
|
|
41
46
|
const config = loadConfig();
|
|
42
47
|
// S38.9: preflight env validation — check for obviously invalid values at startup.
|
|
43
48
|
// Non-fatal: log warnings and fall back to defaults.
|
|
@@ -167,7 +167,12 @@ export function loadConfig() {
|
|
|
167
167
|
recallMaxTokens: envFlag("MEGACOMPACT_RECALL_MAX_TOKENS", 1500),
|
|
168
168
|
windowDedupe: envBool("MEGACOMPACT_WINDOW_DEDUPE", true),
|
|
169
169
|
recallTailInject: envBool("MEGACOMPACT_RECALL_TAIL_INJECT", true),
|
|
170
|
+
messageSeparation: envBool("MEGACOMPACT_MESSAGE_SEPARATION", false),
|
|
170
171
|
tuiWidget: envBool("MEGACOMPACT_TUI_WIDGET", true),
|
|
172
|
+
ragQueryReformulation: envBool("MEGACOMPACT_QUERY_REFORMULATION", false),
|
|
173
|
+
ragTieredRouter: envBool("MEGACOMPACT_TIERED_ROUTER", false),
|
|
174
|
+
ragRecallMetrics: envBool("MEGACOMPACT_RECALL_METRICS", false),
|
|
175
|
+
ragMemoryGraph: envBool("MEGACOMPACT_MEMORY_GRAPH", false),
|
|
171
176
|
// D.1: env-overridable recompact delta (minimum context growth % before
|
|
172
177
|
// re-compacting instead of replaying the cached live trim). Default 50.
|
|
173
178
|
recompactPctDelta: envFlag("MEGACOMPACT_RECOMPACT_PCT_DELTA", 50),
|
|
@@ -11,6 +11,7 @@ import { computeLiveTrimCut, liveTrimSummaryMessage } from "../mega-trim.js";
|
|
|
11
11
|
import { pressureFromPct, pressureRatio, } from "../mega-config.js";
|
|
12
12
|
import { appendMirrorMessages } from "./mirror-append.js";
|
|
13
13
|
import { stagedForTail, withRecallTail } from "./recall-tail.js";
|
|
14
|
+
import { buildSeparatedPrompt } from "./separated-prompt.js";
|
|
14
15
|
/** Register the context event handler (live-trim auto-trigger). */
|
|
15
16
|
export function registerContextHandler(pi, runtime, config) {
|
|
16
17
|
// ---- Auto-trigger: live trim (compact and continue) + native durable ----
|
|
@@ -38,9 +39,16 @@ export function registerContextHandler(pi, runtime, config) {
|
|
|
38
39
|
// REAL transcript before any view is built, so the injected tail never
|
|
39
40
|
// reaches raw_transcript (PREVENT-PI: append-only, view-only).
|
|
40
41
|
const tailResult = (msgs) => {
|
|
41
|
-
|
|
42
|
+
const base = msgs ?? messages;
|
|
43
|
+
if (!stagedForTail(runtime, config) && !config.messageSeparation)
|
|
42
44
|
return undefined;
|
|
43
|
-
|
|
45
|
+
let result = stagedForTail(runtime, config)
|
|
46
|
+
? withRecallTail(base, runtime, config)
|
|
47
|
+
: base;
|
|
48
|
+
if (config.messageSeparation) {
|
|
49
|
+
result = buildSeparatedPrompt(result);
|
|
50
|
+
}
|
|
51
|
+
return { messages: result };
|
|
44
52
|
};
|
|
45
53
|
// Always track context for the dashboard/widget, even when auto is off.
|
|
46
54
|
// (v0.8 regression: !config.auto gate sat above this, leaving ctx stats
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { recordPerfSample } from "../../src/store/sqlite.js";
|
|
1
|
+
import { recordPerfSample, readPerfSamples, } from "../../src/store/sqlite.js";
|
|
2
2
|
import { classifyPrefixBreak } from "../../src/prefix-break.js";
|
|
3
3
|
/** Narrow a turn_end message to its usage block when it is an assistant msg. */
|
|
4
4
|
function usageOf(msg) {
|
|
@@ -14,6 +14,9 @@ function usageOf(msg) {
|
|
|
14
14
|
* classifyPrefixBreak with the three candidate event timestamps from the
|
|
15
15
|
* runtime and records a `prefix_break` sample. Best-effort + non-fatal.
|
|
16
16
|
*
|
|
17
|
+
* Also evaluates rolling cache health and emits a degradation event when the
|
|
18
|
+
* composite score falls below 0.6 (A3, PLAN_V2 Phase 4).
|
|
19
|
+
*
|
|
17
20
|
* PREVENT-PI-004: guardrails-allow PREVENT-PI-004: local SQLite write only.
|
|
18
21
|
* PREVENT-002: SQL is fully parameterized via recordPerfSample.
|
|
19
22
|
*/
|
|
@@ -34,11 +37,90 @@ function tryRecordPrefixBreak(stateDir, prevHitPct, currHitPct, breakAt, runtime
|
|
|
34
37
|
currHitPct,
|
|
35
38
|
breakAt,
|
|
36
39
|
}); // guardrails-allow PREVENT-PI-004: local SQLite write (loopback perf instrumentation)
|
|
40
|
+
// A3: compute rolling cache health score and emit alert on degradation.
|
|
41
|
+
tryComputeCacheHealth(stateDir, currHitPct, runtime);
|
|
37
42
|
}
|
|
38
43
|
catch {
|
|
39
44
|
/* non-fatal: prefix-break detection never blocks the agent loop */
|
|
40
45
|
}
|
|
41
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Compute a rolling cache health score and emit a dashboard event when it
|
|
49
|
+
* falls below the degradation threshold (0.6 / "yellow").
|
|
50
|
+
*
|
|
51
|
+
* The score is a weighted composite of:
|
|
52
|
+
* - hitRateScore (0-1): recent cache_hit_pct sample average / 100
|
|
53
|
+
* - stabilityScore (0-1): 1 - recent prefix_break count / maxExpectedBreaks
|
|
54
|
+
* - churnScore (0-1): 1 - stripe re-assignment rate (derived from prefix_break classifications)
|
|
55
|
+
*
|
|
56
|
+
* Weights: hit rate 50%, prefix stability 30%, churn 20%.
|
|
57
|
+
*
|
|
58
|
+
* PREVENT-PI-004: guardrails-allow PREVENT-PI-004: local SQLite read, no network.
|
|
59
|
+
* PREVENT-001: readPerfSamples returns empty array when no data; handled.
|
|
60
|
+
* PREVENT-011: no `any` — all arrays are typed PerfSampleRow[].
|
|
61
|
+
*/
|
|
62
|
+
function tryComputeCacheHealth(stateDir, currHitPct, runtime) {
|
|
63
|
+
try {
|
|
64
|
+
const now = Date.now();
|
|
65
|
+
const windowMs = 300_000; // 5-minute lookback
|
|
66
|
+
const sinceTs = now - windowMs;
|
|
67
|
+
// Read recent cache_hit_pct and prefix_break samples.
|
|
68
|
+
const hitSamples = readPerfSamples(stateDir, sinceTs, "cache_hit_pct");
|
|
69
|
+
const breakSamples = readPerfSamples(stateDir, sinceTs, "prefix_break");
|
|
70
|
+
// hitRateScore: average of recent cache hit percentages / 100.
|
|
71
|
+
let hitRateAvg = currHitPct;
|
|
72
|
+
if (hitSamples.length > 0) {
|
|
73
|
+
const sum = hitSamples.reduce((a, r) => a + r.value, 0);
|
|
74
|
+
hitRateAvg = sum / hitSamples.length;
|
|
75
|
+
}
|
|
76
|
+
const hitRateScore = Math.max(0, Math.min(1, hitRateAvg / 100));
|
|
77
|
+
// stabilityScore: penalize for frequent prefix breaks.
|
|
78
|
+
// Assume at most 2 breaks in 5min is tolerable.
|
|
79
|
+
const maxExpectedBreaks = 2;
|
|
80
|
+
const stabilityScore = Math.max(0, 1 - breakSamples.length / maxExpectedBreaks);
|
|
81
|
+
// churnScore: if recent breaks have varied causes, penalize.
|
|
82
|
+
const causeVariety = new Set(breakSamples.map((r) => {
|
|
83
|
+
const m = typeof r.meta === "string" ? JSON.parse(r.meta) : null;
|
|
84
|
+
return typeof m?.cause === "string" ? m.cause : "other";
|
|
85
|
+
}));
|
|
86
|
+
const churnPenalty = Math.min(1, causeVariety.size / 4); // 4 possible causes
|
|
87
|
+
const churnScore = 1 - churnPenalty;
|
|
88
|
+
// Composite: hitRate dominates.
|
|
89
|
+
const composite = hitRateScore * 0.5 + stabilityScore * 0.3 + churnScore * 0.2;
|
|
90
|
+
// Emit degradation event when score < 0.6.
|
|
91
|
+
if (composite < 0.6) {
|
|
92
|
+
const prevScore = runtime.rt._lastCacheHealthScore ?? 1;
|
|
93
|
+
runtime.rt._lastCacheHealthScore = composite;
|
|
94
|
+
recordPerfSample(stateDir, "cache_health", composite, {
|
|
95
|
+
hitRateScore: Math.round(hitRateScore * 1000) / 1000,
|
|
96
|
+
stabilityScore: Math.round(stabilityScore * 1000) / 1000,
|
|
97
|
+
churnScore: Math.round(churnScore * 1000) / 1000,
|
|
98
|
+
breakCount: breakSamples.length,
|
|
99
|
+
hitSampleCount: hitSamples.length,
|
|
100
|
+
currHitPct,
|
|
101
|
+
trend: composite < prevScore ? "falling" : "stable",
|
|
102
|
+
}); // guardrails-allow PREVENT-PI-004: local SQLite write (loopback dashboard event)
|
|
103
|
+
// Structured log line for the host to pick up.
|
|
104
|
+
const level = composite < 0.4 ? "error" : "warn";
|
|
105
|
+
// eslint-disable-next-line no-console
|
|
106
|
+
console.log(JSON.stringify({
|
|
107
|
+
ts: now,
|
|
108
|
+
event: `cache_health_${level}`,
|
|
109
|
+
composite: Math.round(composite * 1000) / 1000,
|
|
110
|
+
hitRateAvg: Math.round(hitRateAvg * 10) / 10,
|
|
111
|
+
breakCount: breakSamples.length,
|
|
112
|
+
trend: composite < prevScore ? "falling" : "stable",
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
// Still healthy — just update the stored score.
|
|
117
|
+
runtime.rt._lastCacheHealthScore = composite;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
/* non-fatal: cache health computation never blocks */
|
|
122
|
+
}
|
|
123
|
+
}
|
|
42
124
|
/** Register perf instrumentation handlers + start the 5s cpu/mem interval. */
|
|
43
125
|
export function registerPerfHandler(pi, runtime) {
|
|
44
126
|
// turn_start: record the wall-clock start of the turn. Using Date.now() (not
|