pi-mega-compact 0.11.7 → 0.11.8
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/routes-memory-map.js +8 -15
- package/dist/extensions/mega-commands.js +65 -5
- package/dist/extensions/mega-config.js +6 -0
- package/dist/extensions/mega-events/context-handler.js +65 -0
- package/dist/src/config/turns.js +2 -1
- package/dist/src/memoryGraph/embedding.js +50 -0
- package/dist/src/memoryGraph/gates.js +379 -0
- package/dist/src/memoryGraph/sources.js +390 -0
- package/dist/src/memoryGraph.js +133 -259
- package/dist/src/store/sqlite/embedding-cache.js +71 -0
- package/dist/src/store/sqlite.js +1 -0
- package/dist/src/topics/cluster.js +10 -2
- package/extensions/dashboard-client/dist/assets/{AchievementTiles-DR9cLGDL.js → AchievementTiles-BESF1HT1.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AchievementTiles-DR9cLGDL.js.map → AchievementTiles-BESF1HT1.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{AchievementsTab-svNUgJ1e.js → AchievementsTab-8RzNnz8u.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AchievementsTab-svNUgJ1e.js.map → AchievementsTab-8RzNnz8u.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{CacheTab-ASwhOMjR.js → CacheTab-CUIiUgh3.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{CacheTab-ASwhOMjR.js.map → CacheTab-CUIiUgh3.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{ConfigTab-CmmWheuW.js → ConfigTab-D85fB9HP.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ConfigTab-CmmWheuW.js.map → ConfigTab-D85fB9HP.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{EventsTab-CFE7jLsa.js → EventsTab-TCLR81G5.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{EventsTab-CFE7jLsa.js.map → EventsTab-TCLR81G5.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{GameTab-CJAX_th_.js → GameTab-BqneNRYH.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{GameTab-CJAX_th_.js.map → GameTab-BqneNRYH.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-P4SUsvMf.js → MaintenanceTab-LblMg3NB.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-P4SUsvMf.js.map → MaintenanceTab-LblMg3NB.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-CpjMQwRr.js +2 -0
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-CpjMQwRr.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{MetricsTab-CHQscixy.js → MetricsTab-LxNtNzLQ.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MetricsTab-CHQscixy.js.map → MetricsTab-LxNtNzLQ.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{OverviewTab-DBs4DJdd.js → OverviewTab-BXKUZbT6.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{OverviewTab-DBs4DJdd.js.map → OverviewTab-BXKUZbT6.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{ReposTab-DeFz76L5.js → ReposTab-DTooKeAi.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ReposTab-DeFz76L5.js.map → ReposTab-DTooKeAi.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SessionsTab-BWNsj1OB.js → SessionsTab-Devulgm9.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SessionsTab-BWNsj1OB.js.map → SessionsTab-Devulgm9.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SetupTab-uS6A0xmw.js → SetupTab-By9eqUoE.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SetupTab-uS6A0xmw.js.map → SetupTab-By9eqUoE.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-CiqCOQuL.js → TimeSavedCard-z4M8TDLm.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-CiqCOQuL.js.map → TimeSavedCard-z4M8TDLm.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/TopicsTab-bCGZSfLN.js +2 -0
- package/extensions/dashboard-client/dist/assets/TopicsTab-bCGZSfLN.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{TurnsTab-CVz4f4-o.js → TurnsTab-m_XzE0H4.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TurnsTab-CVz4f4-o.js.map → TurnsTab-m_XzE0H4.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{index-DrktNOoT.js → index-PRkilPXw.js} +3 -3
- package/extensions/dashboard-client/dist/assets/{index-DrktNOoT.js.map → index-PRkilPXw.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{useSSE-Bf5LOLSi.js → useSSE-CGzgc2IK.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-Bf5LOLSi.js.map → useSSE-CGzgc2IK.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +1 -1
- package/extensions/dashboard-client/src/memory-map-layout.ts +161 -0
- package/extensions/dashboard-client/src/memory-map-shapes.tsx +126 -0
- package/extensions/dashboard-client/src/tabs/MemoryMapTab.tsx +201 -165
- package/extensions/dashboard-client/src/tabs/ReposTab.tsx +21 -0
- package/extensions/dashboard-client/src/tabs/TopicsTab.tsx +1 -1
- package/extensions/dashboard-server/api-contracts/index.ts +2 -1
- package/extensions/dashboard-server/api-contracts/memory-map.ts +14 -6
- package/extensions/dashboard-server/routes-memory-map.ts +21 -29
- package/extensions/mega-commands.ts +63 -6
- package/extensions/mega-config.ts +18 -0
- package/extensions/mega-events/context-handler.ts +80 -0
- package/package.json +1 -1
- package/src/config/turns.ts +5 -2
- package/src/memoryGraph/embedding.ts +63 -0
- package/src/memoryGraph/gates.ts +451 -0
- package/src/memoryGraph/sources.ts +484 -0
- package/src/memoryGraph.ts +188 -350
- package/src/store/sqlite/embedding-cache.ts +81 -0
- package/src/store/sqlite.ts +1 -0
- package/src/topics/cluster.ts +11 -1
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-BBiH76eF.js +0 -2
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-BBiH76eF.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/TopicsTab-BWWQxltv.js +0 -2
- package/extensions/dashboard-client/dist/assets/TopicsTab-BWWQxltv.js.map +0 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* routes-memory-map.ts — GET /api/memory-map route handler (S46).
|
|
2
|
+
* routes-memory-map.ts — GET /api/memory-map route handler (S46/D3).
|
|
3
3
|
*
|
|
4
4
|
* Builds a memory graph from the local SQLite store and returns it as JSON.
|
|
5
|
+
* D3: surfaces nodeType on each node and the GraphValidationReport.
|
|
5
6
|
* Uses an inline require to the pi-agnostic src/memoryGraph.ts builder.
|
|
6
7
|
*/
|
|
7
8
|
import { createRequire } from "node:module";
|
|
@@ -16,19 +17,8 @@ export function handleMemoryMap(req, res, ctx) {
|
|
|
16
17
|
return false;
|
|
17
18
|
// guardrails-allow PREVENT-PI-004: local loopback-only dashboard server — reads the local SQLite store for graph data.
|
|
18
19
|
const { buildMemoryGraph } = _req("../../src/memoryGraph.js");
|
|
19
|
-
const sessionId = typeof parsed.query.sessionId === "string" ? parsed.query.sessionId :
|
|
20
|
-
const
|
|
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
|
-
});
|
|
20
|
+
const sessionId = typeof parsed.query.sessionId === "string" ? parsed.query.sessionId : "";
|
|
21
|
+
const graph = buildMemoryGraph(sessionId, ctx.stateDir);
|
|
32
22
|
const nodes = graph.nodes.map((n) => ({
|
|
33
23
|
id: n.id,
|
|
34
24
|
sessionId: n.sessionId,
|
|
@@ -41,9 +31,12 @@ export function handleMemoryMap(req, res, ctx) {
|
|
|
41
31
|
topicSummary: n.topicSummary,
|
|
42
32
|
decisionCount: n.decisionCount,
|
|
43
33
|
textSnippet: n.textSnippet,
|
|
34
|
+
// D3: pass through nodeType for UI node-shape encoding
|
|
35
|
+
nodeType: n.nodeType,
|
|
44
36
|
}));
|
|
45
37
|
const edges = graph.edges;
|
|
46
|
-
|
|
38
|
+
// D3: surface the validation report (optional in the response type for backward compat)
|
|
39
|
+
const response = { nodes, edges, metadata: graph.metadata, validation: graph.validation };
|
|
47
40
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
48
41
|
res.end(JSON.stringify(response));
|
|
49
42
|
return true;
|
|
@@ -9,12 +9,12 @@ import { sessionEntryToContextMessages } from "@earendil-works/pi-coding-agent";
|
|
|
9
9
|
import { normalizeSessionId } from "../src/store.js";
|
|
10
10
|
import { listCheckpoints, latestModelSnapshot, countInjectedGlobal, listRepoRegistry } from "../src/store/sqlite.js";
|
|
11
11
|
import { decompressSmart } from "../src/store/compression.js";
|
|
12
|
-
import { loadMetrics, fpRate, p95, defaultMetricsPath } from "../src/monitoring.js";
|
|
12
|
+
import { loadMetrics, fpRate, p95, defaultMetricsPath, defaultEventsPath } from "../src/monitoring.js";
|
|
13
13
|
import { C, recentUserQuery } from "./mega-runtime.js";
|
|
14
14
|
import { runCompact, doRecall, doRecallAsync } from "./mega-pipeline.js";
|
|
15
15
|
import { vectorStats, vectorRepoStats, vectorDataInvariant } from "../src/vectorStore.js";
|
|
16
16
|
import { spawnSync } from "node:child_process"; // guardrails-allow PREVENT-PI-004: local subprocess detection only (no network)
|
|
17
|
-
import { mkdirSync, writeFileSync } from "node:fs";
|
|
17
|
+
import { mkdirSync, writeFileSync, existsSync, readFileSync } from "node:fs";
|
|
18
18
|
import path from "node:path";
|
|
19
19
|
import os from "node:os";
|
|
20
20
|
import { createRequire } from "node:module";
|
|
@@ -260,6 +260,58 @@ export function registerCommands(pi, runtime, config) {
|
|
|
260
260
|
`• data safety — every compressed region is kept verbatim; nothing is permanently deleted. /mega-restore brings any of it back.`);
|
|
261
261
|
},
|
|
262
262
|
});
|
|
263
|
+
/**
|
|
264
|
+
* Try to peek at recent events.log and mega-compact.log for low recall quality signals.
|
|
265
|
+
* Best-effort, non-fatal — returns true if a low-quality signal was found.
|
|
266
|
+
*/
|
|
267
|
+
/**
|
|
268
|
+
* Try to peek at recent events.log and mega-compact.log for low recall quality signals.
|
|
269
|
+
* Best-effort, non-fatal — returns true if a low-quality signal was found.
|
|
270
|
+
*/
|
|
271
|
+
function checkRecallQuality(stateDir) {
|
|
272
|
+
const eventPaths = [
|
|
273
|
+
defaultEventsPath(stateDir),
|
|
274
|
+
path.join(stateDir, "mega-compact.log"),
|
|
275
|
+
];
|
|
276
|
+
for (const fp of eventPaths) {
|
|
277
|
+
try {
|
|
278
|
+
if (!existsSync(fp))
|
|
279
|
+
continue;
|
|
280
|
+
const buf = readFileSync(fp, { encoding: "utf-8" });
|
|
281
|
+
// Only scan last 64 KiB of the file
|
|
282
|
+
const tail = buf.length > 65536 ? buf.slice(buf.length - 65536) : buf;
|
|
283
|
+
const lines = tail.split("\n").filter(Boolean);
|
|
284
|
+
for (const line of lines) {
|
|
285
|
+
try {
|
|
286
|
+
// guardrails-allow PREVENT-001: JSON.parse with null check
|
|
287
|
+
const parsed = JSON.parse(line);
|
|
288
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
289
|
+
continue;
|
|
290
|
+
// Check for recall_metrics_low_quality event (latest format)
|
|
291
|
+
if (parsed.event === "recall_metrics_low_quality" && parsed.score !== undefined) {
|
|
292
|
+
if (typeof parsed.score === "number" && parsed.score < 0.4)
|
|
293
|
+
return true;
|
|
294
|
+
}
|
|
295
|
+
// Check for recall_metrics with low relevanceScore
|
|
296
|
+
if (parsed.event === "recall_metrics" && parsed.relevanceScore !== undefined) {
|
|
297
|
+
if (typeof parsed.relevanceScore === "number" && parsed.relevanceScore < 0.4)
|
|
298
|
+
return true;
|
|
299
|
+
}
|
|
300
|
+
// Check for RecallQualityEvent format from monitoring.ts
|
|
301
|
+
if (parsed.score !== undefined && typeof parsed.score === "number" && parsed.score < 0.4)
|
|
302
|
+
return true;
|
|
303
|
+
}
|
|
304
|
+
catch {
|
|
305
|
+
// skip unparseable lines
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
catch {
|
|
310
|
+
// non-fatal: skip if can't read
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
263
315
|
pi.registerCommand("mega-setup", {
|
|
264
316
|
description: "Local embedding setup wizard — detect available embedders and configure mega-compact.",
|
|
265
317
|
handler: async (_args, ctx) => {
|
|
@@ -335,6 +387,10 @@ export function registerCommands(pi, runtime, config) {
|
|
|
335
387
|
catch {
|
|
336
388
|
// require error
|
|
337
389
|
}
|
|
390
|
+
// --- 2.5 Quality check ---
|
|
391
|
+
// Scan recent events for low recall quality (best-effort, non-fatal)
|
|
392
|
+
const stateDir = process.env["MEGACOMPACT_STATE_DIR"] ?? path.join(os.homedir(), ".pi", "mega-compact");
|
|
393
|
+
const lowRecallQuality = checkRecallQuality(stateDir);
|
|
338
394
|
const choices = [];
|
|
339
395
|
if (ollamaDetected && ollamaRunning) {
|
|
340
396
|
const model = ollamaModels.find((m) => m.includes("nomic-embed") ||
|
|
@@ -370,6 +426,9 @@ export function registerCommands(pi, runtime, config) {
|
|
|
370
426
|
});
|
|
371
427
|
// --- 4. Prompt user ---
|
|
372
428
|
log(`Current embedder: ${currentEmbedder}`);
|
|
429
|
+
if (lowRecallQuality) {
|
|
430
|
+
log("Tap: recent recall quality is low. Consider switching to Ollama or llama.cpp for better results.");
|
|
431
|
+
}
|
|
373
432
|
let selected = "trigram";
|
|
374
433
|
if (choices.length > 1) {
|
|
375
434
|
try {
|
|
@@ -403,7 +462,6 @@ export function registerCommands(pi, runtime, config) {
|
|
|
403
462
|
];
|
|
404
463
|
const envContent = lines.join("\n") + "\n";
|
|
405
464
|
// Write .mega-compact.env to state dir
|
|
406
|
-
const stateDir = process.env["MEGACOMPACT_STATE_DIR"] ?? path.join(os.homedir(), ".pi", "mega-compact");
|
|
407
465
|
try {
|
|
408
466
|
mkdirSync(stateDir, { recursive: true });
|
|
409
467
|
writeFileSync(path.join(stateDir, ".mega-compact.env"), envContent, "utf-8");
|
|
@@ -421,7 +479,6 @@ export function registerCommands(pi, runtime, config) {
|
|
|
421
479
|
`export MEGACOMPACT_EMBEDDING_URL="${url}"`,
|
|
422
480
|
];
|
|
423
481
|
const envContent = lines.join("\n") + "\n";
|
|
424
|
-
const stateDir = process.env["MEGACOMPACT_STATE_DIR"] ?? path.join(os.homedir(), ".pi", "mega-compact");
|
|
425
482
|
try {
|
|
426
483
|
mkdirSync(stateDir, { recursive: true });
|
|
427
484
|
writeFileSync(path.join(stateDir, ".mega-compact.env"), envContent, "utf-8");
|
|
@@ -435,7 +492,10 @@ export function registerCommands(pi, runtime, config) {
|
|
|
435
492
|
log("ONNX Runtime configuration is experimental.\n\nSet MEGACOMPACT_EMBEDDING_URL to your local ONNX server URL, or see docs for manual setup.\nKeeping TrigramEmbedder for now.");
|
|
436
493
|
}
|
|
437
494
|
else {
|
|
438
|
-
|
|
495
|
+
const qualityTip = lowRecallQuality
|
|
496
|
+
? " Recent recall quality is low — consider running /mega-setup again to switch to Ollama or llama.cpp for better results."
|
|
497
|
+
: "";
|
|
498
|
+
log(`Keeping TrigramEmbedder (default). No configuration needed.${qualityTip}`);
|
|
439
499
|
}
|
|
440
500
|
}
|
|
441
501
|
catch (e) {
|
|
@@ -173,6 +173,12 @@ export function loadConfig() {
|
|
|
173
173
|
ragTieredRouter: envBool("MEGACOMPACT_TIERED_ROUTER", false),
|
|
174
174
|
ragRecallMetrics: envBool("MEGACOMPACT_RECALL_METRICS", false),
|
|
175
175
|
ragMemoryGraph: envBool("MEGACOMPACT_MEMORY_GRAPH", false),
|
|
176
|
+
wikiSeedFromTurns: envBool("MEGACOMPACT_WIKI_SEED_FROM_TURNS", true),
|
|
177
|
+
memoryGraphSeedTurns: envBool("MEGACOMPACT_MEMORY_GRAPH_SEED_TURNS", true),
|
|
178
|
+
memoryGraphSeedTurnContent: envBool("MEGACOMPACT_MEMORY_GRAPH_SEED_TURN_CONTENT", true),
|
|
179
|
+
memoryGraphSeedMemories: envBool("MEGACOMPACT_MEMORY_GRAPH_SEED_MEMORIES", true),
|
|
180
|
+
memoryGraphCrossTypeThreshold: envFlag("MEGACOMPACT_MEMORY_GRAPH_CROSS_TYPE_THRESHOLD", 0.85),
|
|
181
|
+
memoryGraphWithinTypeThreshold: envFlag("MEGACOMPACT_MEMORY_GRAPH_WITHIN_TYPE_THRESHOLD", 0.7),
|
|
176
182
|
// D.1: env-overridable recompact delta (minimum context growth % before
|
|
177
183
|
// re-compacting instead of replaying the cached live trim). Default 50.
|
|
178
184
|
recompactPctDelta: envFlag("MEGACOMPACT_RECOMPACT_PCT_DELTA", 50),
|
|
@@ -7,6 +7,7 @@ import { stampTurnsEpochFor } from "../mega-turn-store.js";
|
|
|
7
7
|
import { TurnsConfig } from "../../src/config/turns.js";
|
|
8
8
|
import { openTurnStore } from "../../src/store/turns/connection.js";
|
|
9
9
|
import { buildTopicModel, createTopicStore, bumpWikiCompactCounter, } from "../../src/topics/index.js";
|
|
10
|
+
import { TrigramEmbedder } from "../../src/embedder.js";
|
|
10
11
|
import { computeLiveTrimCut, liveTrimSummaryMessage } from "../mega-trim.js";
|
|
11
12
|
import { pressureFromPct, pressureRatio, } from "../mega-config.js";
|
|
12
13
|
import { appendMirrorMessages } from "./mirror-append.js";
|
|
@@ -250,6 +251,70 @@ export function registerContextHandler(pi, runtime, config) {
|
|
|
250
251
|
error: String(wikiErr),
|
|
251
252
|
});
|
|
252
253
|
}
|
|
254
|
+
// D1: seed the topic model from raw_transcript when context_chunks is
|
|
255
|
+
// thin (pre-compaction). Gated on WIKI_SEED_FROM_TURNS; non-fatal.
|
|
256
|
+
// Seeds buildTopicModel with on-the-fly trigram embeddings from
|
|
257
|
+
// recent raw_transcript rows for the current session.
|
|
258
|
+
try {
|
|
259
|
+
if (config.autoWikiEnabled &&
|
|
260
|
+
config.turnsDbEnabled &&
|
|
261
|
+
TurnsConfig.WIKI_SEED_FROM_TURNS) {
|
|
262
|
+
const floor = 50;
|
|
263
|
+
const countRow = db
|
|
264
|
+
.prepare(`SELECT COUNT(*) AS cnt FROM context_chunks WHERE session_id = ?`)
|
|
265
|
+
.get(runtime.rt.sessionId);
|
|
266
|
+
const chunkCount = countRow?.cnt ?? 0;
|
|
267
|
+
if (chunkCount < floor) {
|
|
268
|
+
const transcriptRows = db
|
|
269
|
+
.prepare(`SELECT DISTINCT content_bytes
|
|
270
|
+
FROM raw_transcript
|
|
271
|
+
WHERE session_id = ?
|
|
272
|
+
AND length(content_bytes) > 10
|
|
273
|
+
ORDER BY seq ASC
|
|
274
|
+
LIMIT 200`)
|
|
275
|
+
.all(runtime.rt.sessionId);
|
|
276
|
+
if (transcriptRows.length > 0) {
|
|
277
|
+
const embedder = new TrigramEmbedder();
|
|
278
|
+
const seedChunks = [];
|
|
279
|
+
for (let i = 0; i < transcriptRows.length; i++) {
|
|
280
|
+
const text = transcriptRows[i].content_bytes.trim();
|
|
281
|
+
if (text.length === 0)
|
|
282
|
+
continue;
|
|
283
|
+
const vec = embedder.embed(text);
|
|
284
|
+
seedChunks.push({
|
|
285
|
+
chunkId: `seed_transcript_${i}`,
|
|
286
|
+
sessionId: runtime.rt.sessionId,
|
|
287
|
+
vec,
|
|
288
|
+
text,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
if (seedChunks.length > 0) {
|
|
292
|
+
const model = buildTopicModel(db, {
|
|
293
|
+
kRange: [
|
|
294
|
+
TurnsConfig.WIKI_K_MIN,
|
|
295
|
+
TurnsConfig.WIKI_K_MAX,
|
|
296
|
+
],
|
|
297
|
+
labelTopTerms: TurnsConfig.WIKI_LABEL_TOP_TERMS,
|
|
298
|
+
restarts: 5,
|
|
299
|
+
seed: 0x9e3779b9,
|
|
300
|
+
}, seedChunks);
|
|
301
|
+
createTopicStore(runtime.currentStateDir).replaceTopicModel(model);
|
|
302
|
+
runtime.logger.info("wiki_seed", {
|
|
303
|
+
clusterCount: model.k,
|
|
304
|
+
sourceChunks: seedChunks.length,
|
|
305
|
+
totalChunks: model.totalChunks,
|
|
306
|
+
method: "kmeans+tfidf",
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
catch (seedErr) {
|
|
314
|
+
runtime.logger.warn("wiki_seed_failed", {
|
|
315
|
+
error: String(seedErr),
|
|
316
|
+
});
|
|
317
|
+
}
|
|
253
318
|
// S27 Task 6: Fire-and-forget dedup pipeline.
|
|
254
319
|
// Deduplicates raw_transcript rows for the compacted range.
|
|
255
320
|
try {
|
package/dist/src/config/turns.js
CHANGED
|
@@ -42,7 +42,8 @@ export function loadTurnsConfig() {
|
|
|
42
42
|
WIKI_K_MIN: kMin,
|
|
43
43
|
WIKI_K_MAX: kMax,
|
|
44
44
|
WIKI_LABEL_TOP_TERMS: envNum("MEGACOMPACT_WIKI_LABEL_TOP_TERMS", 5),
|
|
45
|
-
WIKI_REBUILD_EVERY_N_COMPACTS: envNum("MEGACOMPACT_WIKI_REBUILD_EVERY",
|
|
45
|
+
WIKI_REBUILD_EVERY_N_COMPACTS: envNum("MEGACOMPACT_WIKI_REBUILD_EVERY", 3),
|
|
46
|
+
WIKI_SEED_FROM_TURNS: envBool("MEGACOMPACT_WIKI_SEED_FROM_TURNS", true),
|
|
46
47
|
};
|
|
47
48
|
}
|
|
48
49
|
export const TurnsConfig = loadTurnsConfig();
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { TrigramEmbedder } from "../embedder.js";
|
|
2
|
+
let _trigramEmbedder = null;
|
|
3
|
+
function lazyEmbedder() {
|
|
4
|
+
if (!_trigramEmbedder) {
|
|
5
|
+
_trigramEmbedder = new TrigramEmbedder();
|
|
6
|
+
}
|
|
7
|
+
return _trigramEmbedder;
|
|
8
|
+
}
|
|
9
|
+
function simpleHash(s) {
|
|
10
|
+
let h = 0x811c9dc5;
|
|
11
|
+
for (let i = 0; i < s.length; i++) {
|
|
12
|
+
h ^= s.charCodeAt(i);
|
|
13
|
+
h = Math.imul(h, 0x01000193);
|
|
14
|
+
}
|
|
15
|
+
return h.toString(36);
|
|
16
|
+
}
|
|
17
|
+
/** Compute or retrieve a cached embedding vector for a text string.
|
|
18
|
+
* Uses the embedding_cache table (created by the A2 migration) for
|
|
19
|
+
* persistence. Falls back to uncached TrigramEmbedder on table error. */
|
|
20
|
+
export function getOrComputeEmbedding(db, content) {
|
|
21
|
+
try {
|
|
22
|
+
const hash = simpleHash(content);
|
|
23
|
+
const cached = db
|
|
24
|
+
.prepare("SELECT embedding FROM embedding_cache WHERE content_hash = ?")
|
|
25
|
+
.get(hash);
|
|
26
|
+
if (cached && typeof cached.embedding === "string") {
|
|
27
|
+
return JSON.parse(cached.embedding);
|
|
28
|
+
}
|
|
29
|
+
const vec = lazyEmbedder().embed(content);
|
|
30
|
+
db.prepare("INSERT OR REPLACE INTO embedding_cache (content_hash, content, embedding) VALUES (?, ?, ?)").run(hash, content, JSON.stringify(vec));
|
|
31
|
+
return vec;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return lazyEmbedder().embed(content);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/** Cosine similarity between two equal-length vectors. */
|
|
38
|
+
export function cosineSimilarity(a, b) {
|
|
39
|
+
let dot = 0;
|
|
40
|
+
let na = 0;
|
|
41
|
+
let nb = 0;
|
|
42
|
+
const len = Math.min(a.length, b.length);
|
|
43
|
+
for (let i = 0; i < len; i++) {
|
|
44
|
+
dot += a[i] * b[i];
|
|
45
|
+
na += a[i] * a[i];
|
|
46
|
+
nb += b[i] * b[i];
|
|
47
|
+
}
|
|
48
|
+
const denom = Math.sqrt(na) * Math.sqrt(nb);
|
|
49
|
+
return denom > 0 ? dot / denom : 0;
|
|
50
|
+
}
|