pi-mega-compact 0.13.0 → 0.13.2
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/embedder-health.js +11 -0
- package/dist/extensions/dashboard-server/api-contracts/endpoints/registry.js +225 -0
- package/dist/extensions/dashboard-server/api-contracts/endpoints/types.js +1 -0
- package/dist/extensions/dashboard-server/api-contracts/endpoints.js +5 -224
- package/dist/extensions/dashboard-server/api-contracts/raptor.js +8 -0
- package/dist/extensions/dashboard-server/api-contracts.test/_helpers.js +32 -0
- package/dist/extensions/dashboard-server/routes-cache.test/_helpers.js +48 -0
- package/dist/extensions/dashboard-server/routes-embedder-health.js +67 -0
- package/dist/extensions/dashboard-server/routes-raptor.js +88 -0
- package/dist/extensions/dashboard-server/routes-setup.js +1 -1
- package/dist/extensions/dashboard-server/routes.js +2 -0
- package/dist/extensions/dashboard-server/server.js +5 -1
- package/dist/extensions/mega-cache-replay.test/_helpers.js +175 -0
- package/dist/extensions/mega-commands/dataCommands.js +151 -0
- package/dist/extensions/mega-commands/helpers.js +61 -0
- package/dist/extensions/mega-commands/historyCommands.js +97 -0
- package/dist/extensions/mega-commands/setupCommand.js +200 -0
- package/dist/extensions/mega-commands.js +14 -499
- package/dist/extensions/mega-compact-s38.test/_helpers.js +194 -0
- package/dist/extensions/mega-compact.js +12 -2
- package/dist/extensions/mega-compact.test/_helpers.js +225 -0
- package/dist/extensions/mega-events/agent-handlers/agentEndHandler.js +211 -0
- package/dist/extensions/mega-events/agent-handlers/turnEndHandler/cacheStripe.js +49 -0
- package/dist/extensions/mega-events/agent-handlers/turnEndHandler/contextHealth.js +33 -0
- package/dist/extensions/mega-events/agent-handlers/turnEndHandler/errorRetry.js +387 -0
- package/dist/extensions/mega-events/agent-handlers/turnEndHandler/event.js +7 -0
- package/dist/extensions/mega-events/agent-handlers/turnEndHandler/gameScoring.js +55 -0
- package/dist/extensions/mega-events/agent-handlers/turnEndHandler/lengthStop.js +12 -0
- package/dist/extensions/mega-events/agent-handlers/turnEndHandler/memoryReview.js +22 -0
- package/dist/extensions/mega-events/agent-handlers/turnEndHandler/recordTurnRow.js +38 -0
- package/dist/extensions/mega-events/agent-handlers/turnEndHandler.js +36 -0
- package/dist/extensions/mega-events/agent-handlers.js +4 -799
- package/dist/extensions/mega-events/context-handler/afterCompact.js +163 -0
- package/dist/extensions/mega-events/context-handler/messageText.js +12 -0
- package/dist/extensions/mega-events/context-handler/tailResult.js +46 -0
- package/dist/extensions/mega-events/context-handler.js +11 -198
- package/dist/extensions/mega-events/separated-prompt.test/_helpers.js +25 -0
- package/dist/src/config.js +2 -0
- package/dist/src/dedup-engine.test/_helpers.js +55 -0
- package/dist/src/e2e.test/_helpers.js +52 -0
- package/dist/src/embedder.js +1 -0
- package/dist/src/httpEmbedder.js +6 -0
- package/dist/src/hyde.js +146 -0
- package/dist/src/importance.test/_helpers.js +5 -0
- package/dist/src/memoryGraph/sources/checkpoints.js +78 -0
- package/dist/src/memoryGraph/sources/edges.js +17 -0
- package/dist/src/memoryGraph/sources/flags.js +22 -0
- package/dist/src/memoryGraph/sources/helpers.js +14 -0
- package/dist/src/memoryGraph/sources/memories.js +88 -0
- package/dist/src/memoryGraph/sources/raptor.js +26 -0
- package/dist/src/memoryGraph/sources/turns.js +176 -0
- package/dist/src/memoryGraph/sources.js +15 -441
- package/dist/src/memoryGraph-gates.test/_helpers.js +120 -0
- package/dist/src/ratio.bench.test/_helpers.js +198 -0
- package/dist/src/recall/async.js +112 -0
- package/dist/src/recall/format.js +149 -0
- package/dist/src/recall/memory.js +62 -0
- package/dist/src/recall/reformulate.js +82 -0
- package/dist/src/recall/sync.js +169 -0
- package/dist/src/recall/types.js +1 -0
- package/dist/src/recall.js +13 -530
- package/dist/src/store/sqlite/schema/core.js +232 -0
- package/dist/src/store/sqlite/schema/game.js +65 -0
- package/dist/src/store/sqlite/schema/plan-v2.js +107 -0
- package/dist/src/store/sqlite/schema/turns.js +59 -0
- package/dist/src/store/sqlite/schema.js +8 -441
- package/dist/src/store/turns/contract-compliance.test/_helpers.js +21 -0
- package/dist/src/store/turns/sqlite-store/admin.js +171 -0
- package/dist/src/store/turns/sqlite-store/ctx.js +1 -0
- package/dist/src/store/turns/sqlite-store/read.js +111 -0
- package/dist/src/store/turns/sqlite-store/rows.js +42 -0
- package/dist/src/store/turns/sqlite-store/write.js +102 -0
- package/dist/src/store/turns/sqlite-store.js +31 -367
- package/dist/src/vectorStore/class.js +356 -0
- package/dist/src/vectorStore/hash.js +10 -0
- package/dist/src/vectorStore/types.js +2 -0
- package/dist/src/vectorStore.js +8 -359
- package/dist/src/vectorStore.test/_helpers.js +17 -0
- package/extensions/dashboard-client/dist/assets/{CacheTab-BZNnKhh5.js → CacheTab-DPRHjYZ0.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{CacheTab-BZNnKhh5.js.map → CacheTab-DPRHjYZ0.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{EventsTab-CzF5L42U.js → EventsTab-CgwYq-Qf.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{EventsTab-CzF5L42U.js.map → EventsTab-CgwYq-Qf.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{HealthTab-BLpidMrX.js → HealthTab-BgOCjVzR.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{HealthTab-BLpidMrX.js.map → HealthTab-BgOCjVzR.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/MaintenanceTab-Yw1yFpsy.js +2 -0
- package/extensions/dashboard-client/dist/assets/MaintenanceTab-Yw1yFpsy.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-yHUX7Yzi.js +2 -0
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-yHUX7Yzi.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{MetricsTab-B0PCysqs.js → MetricsTab-CcH9fP8P.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MetricsTab-B0PCysqs.js.map → MetricsTab-CcH9fP8P.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{OverviewTab-DsOhqFu4.js → OverviewTab-BOs8ZNev.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{OverviewTab-DsOhqFu4.js.map → OverviewTab-BOs8ZNev.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{ReposTab-B3YKYuOf.js → ReposTab-B-MfSPvg.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ReposTab-B3YKYuOf.js.map → ReposTab-B-MfSPvg.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SessionsTab-B96FWcrC.js → SessionsTab-BmeN649Q.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SessionsTab-B96FWcrC.js.map → SessionsTab-BmeN649Q.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/SetupTab-nOknoph5.js +2 -0
- package/extensions/dashboard-client/dist/assets/SetupTab-nOknoph5.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-BfkUVTvA.js → TimeSavedCard-DnPg0L0z.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-BfkUVTvA.js.map → TimeSavedCard-DnPg0L0z.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TopicsTab-DLRsZmXJ.js → TopicsTab-BODHOg_b.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TopicsTab-DLRsZmXJ.js.map → TopicsTab-BODHOg_b.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TurnsTab-DKGU2Bf6.js → TurnsTab-BK0I7hKr.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TurnsTab-DKGU2Bf6.js.map → TurnsTab-BK0I7hKr.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{index-D-lPLRWB.js → index-mOlljTFI.js} +10 -10
- package/extensions/dashboard-client/dist/assets/index-mOlljTFI.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{useSSE-ClbbcgIp.js → useSSE-BYOtv1-3.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-ClbbcgIp.js.map → useSSE-BYOtv1-3.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +1 -1
- package/extensions/dashboard-client/src/App.tsx +0 -4
- package/extensions/dashboard-client/src/api/client.ts +16 -0
- package/extensions/dashboard-client/src/tabs/MaintenanceTab/ActionsCard.tsx +178 -0
- package/extensions/dashboard-client/src/tabs/MaintenanceTab/DbStatsCard.tsx +140 -0
- package/extensions/dashboard-client/src/tabs/MaintenanceTab/DebugBundleCard.tsx +109 -0
- package/extensions/dashboard-client/src/tabs/MaintenanceTab/HealthMitigationCard.tsx +98 -0
- package/extensions/dashboard-client/src/tabs/MaintenanceTab/SchemaHealthCard.tsx +108 -0
- package/extensions/dashboard-client/src/tabs/MaintenanceTab.tsx +12 -598
- package/extensions/dashboard-client/src/tabs/MemoryMapTab/MemoryMapView.tsx +476 -0
- package/extensions/dashboard-client/src/tabs/MemoryMapTab/RaptorTreeView.tsx +163 -0
- package/extensions/dashboard-client/src/tabs/MemoryMapTab.tsx +56 -466
- package/extensions/dashboard-client/src/tabs/SetupTab/EmbedderHealthCard.tsx +109 -0
- package/extensions/dashboard-client/src/tabs/SetupTab/EmbedderSetup.tsx +468 -0
- package/extensions/dashboard-client/src/tabs/SetupTab.tsx +23 -484
- package/extensions/dashboard-server/api-contracts/embedder-health.ts +32 -0
- package/extensions/dashboard-server/api-contracts/endpoints/registry.ts +360 -0
- package/extensions/dashboard-server/api-contracts/endpoints/types.ts +350 -0
- package/extensions/dashboard-server/api-contracts/endpoints.ts +27 -648
- package/extensions/dashboard-server/api-contracts/index.ts +6 -0
- package/extensions/dashboard-server/api-contracts/raptor.ts +49 -0
- package/extensions/dashboard-server/api-contracts.test/_helpers.ts +47 -0
- package/extensions/dashboard-server/routes-cache.test/_helpers.ts +94 -0
- package/extensions/dashboard-server/routes-embedder-health.ts +77 -0
- package/extensions/dashboard-server/routes-raptor.ts +128 -0
- package/extensions/dashboard-server/routes-setup.ts +1 -1
- package/extensions/dashboard-server/routes.ts +2 -0
- package/extensions/dashboard-server/server.ts +4 -0
- package/extensions/mega-cache-replay.test/_helpers.ts +188 -0
- package/extensions/mega-commands/dataCommands.ts +169 -0
- package/extensions/mega-commands/helpers.ts +62 -0
- package/extensions/mega-commands/historyCommands.ts +117 -0
- package/extensions/mega-commands/setupCommand.ts +235 -0
- package/extensions/mega-commands.ts +25 -538
- package/extensions/mega-compact-s38.test/_helpers.ts +201 -0
- package/extensions/mega-compact.test/_helpers.ts +237 -0
- package/extensions/mega-compact.ts +12 -2
- package/extensions/mega-events/agent-handlers/agentEndHandler.ts +238 -0
- package/extensions/mega-events/agent-handlers/turnEndHandler/cacheStripe.ts +74 -0
- package/extensions/mega-events/agent-handlers/turnEndHandler/contextHealth.ts +50 -0
- package/extensions/mega-events/agent-handlers/turnEndHandler/errorRetry.ts +421 -0
- package/extensions/mega-events/agent-handlers/turnEndHandler/event.ts +16 -0
- package/extensions/mega-events/agent-handlers/turnEndHandler/gameScoring.ts +73 -0
- package/extensions/mega-events/agent-handlers/turnEndHandler/lengthStop.ts +29 -0
- package/extensions/mega-events/agent-handlers/turnEndHandler/memoryReview.ts +42 -0
- package/extensions/mega-events/agent-handlers/turnEndHandler/recordTurnRow.ts +61 -0
- package/extensions/mega-events/agent-handlers/turnEndHandler.ts +64 -0
- package/extensions/mega-events/agent-handlers.ts +15 -861
- package/extensions/mega-events/context-handler/afterCompact.ts +213 -0
- package/extensions/mega-events/context-handler/messageText.ts +20 -0
- package/extensions/mega-events/context-handler/tailResult.ts +63 -0
- package/extensions/mega-events/context-handler.ts +17 -235
- package/extensions/mega-events/separated-prompt.test/_helpers.ts +35 -0
- package/package.json +1 -1
- package/src/config.ts +4 -0
- package/src/dedup-engine.test/_helpers.ts +79 -0
- package/src/e2e.test/_helpers.ts +59 -0
- package/src/embedder.ts +4 -0
- package/src/httpEmbedder.ts +7 -0
- package/src/hyde.ts +162 -0
- package/src/importance.test/_helpers.ts +5 -0
- package/src/memoryGraph/sources/checkpoints.ts +99 -0
- package/src/memoryGraph/sources/edges.ts +23 -0
- package/src/memoryGraph/sources/flags.ts +26 -0
- package/src/memoryGraph/sources/helpers.ts +13 -0
- package/src/memoryGraph/sources/memories.ts +108 -0
- package/src/memoryGraph/sources/raptor.ts +37 -0
- package/src/memoryGraph/sources/turns.ts +226 -0
- package/src/memoryGraph/sources.ts +19 -544
- package/src/memoryGraph-gates.test/_helpers.ts +164 -0
- package/src/ratio.bench.test/_helpers.ts +268 -0
- package/src/recall/async.ts +142 -0
- package/src/recall/format.ts +173 -0
- package/src/recall/memory.ts +90 -0
- package/src/recall/reformulate.ts +111 -0
- package/src/recall/sync.ts +196 -0
- package/src/recall/types.ts +63 -0
- package/src/recall.ts +25 -712
- package/src/store/sqlite/schema/core.ts +233 -0
- package/src/store/sqlite/schema/game.ts +66 -0
- package/src/store/sqlite/schema/plan-v2.ts +108 -0
- package/src/store/sqlite/schema/turns.ts +60 -0
- package/src/store/sqlite/schema.ts +13 -441
- package/src/store/turns/contract-compliance.test/_helpers.ts +38 -0
- package/src/store/turns/sqlite-store/admin.ts +249 -0
- package/src/store/turns/sqlite-store/ctx.ts +14 -0
- package/src/store/turns/sqlite-store/read.ts +174 -0
- package/src/store/turns/sqlite-store/rows.ts +55 -0
- package/src/store/turns/sqlite-store/write.ts +193 -0
- package/src/store/turns/sqlite-store.ts +33 -514
- package/src/vectorStore/class.ts +433 -0
- package/src/vectorStore/hash.ts +11 -0
- package/src/vectorStore/types.ts +58 -0
- package/src/vectorStore.test/_helpers.ts +20 -0
- package/src/vectorStore.ts +13 -489
- package/extensions/dashboard-client/dist/assets/ConfigTab-DG0WkuuG.js +0 -2
- package/extensions/dashboard-client/dist/assets/ConfigTab-DG0WkuuG.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/MaintenanceTab-BQF7W7xX.js +0 -2
- package/extensions/dashboard-client/dist/assets/MaintenanceTab-BQF7W7xX.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-CPtHLv0A.js +0 -2
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-CPtHLv0A.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/SetupTab-hbzQ_NZv.js +0 -2
- package/extensions/dashboard-client/dist/assets/SetupTab-hbzQ_NZv.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/index-D-lPLRWB.js.map +0 -1
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* context-handler/afterCompact.ts — post-compaction DB persistence + maintenance.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from context-handler.ts (delegate-shell split). Runs after a live
|
|
5
|
+
* compaction: writes the checkpoint_epoch row (deterministic nonce), stamps turn
|
|
6
|
+
* epochs, rebuilds the auto-categorizing wiki, seeds the topic model from
|
|
7
|
+
* raw_transcript, and fire-and-forgets the dedup pipeline. All best-effort +
|
|
8
|
+
* non-fatal — a failure never breaks the agent loop.
|
|
9
|
+
*/
|
|
10
|
+
import { openStore, writeCheckpointEpoch, } from "../../../src/store/sqlite.js";
|
|
11
|
+
import { epochIdFor } from "../../../src/mirror/epoch.js";
|
|
12
|
+
import { stampTurnsEpochFor } from "../../mega-turn-store.js";
|
|
13
|
+
import { TurnsConfig } from "../../../src/config/turns.js";
|
|
14
|
+
import { openTurnStore } from "../../../src/store/turns/connection.js";
|
|
15
|
+
import { buildTopicModel, createTopicStore, bumpWikiCompactCounter, } from "../../../src/topics/index.js";
|
|
16
|
+
import { TrigramEmbedder } from "../../../src/embedder.js";
|
|
17
|
+
/**
|
|
18
|
+
* Persist the checkpoint_epoch, stamp turns, rebuild the auto-wiki, seed the
|
|
19
|
+
* topic model, and dedup — gated on dbMirror. Non-fatal end-to-end.
|
|
20
|
+
*/
|
|
21
|
+
export async function persistEpochAndMaintain(runtime, config, ran) {
|
|
22
|
+
// S27 DB-mirror: write checkpoint_epoch with deterministic nonce.
|
|
23
|
+
// This makes the cache key stable across identical compactions.
|
|
24
|
+
if (config.dbMirror) {
|
|
25
|
+
try {
|
|
26
|
+
const db = openStore(runtime.currentStateDir);
|
|
27
|
+
const cpId = ran.result.checkpointId ?? `epoch-${Date.now()}`;
|
|
28
|
+
const epoch = {
|
|
29
|
+
epochId: epochIdFor(cpId),
|
|
30
|
+
sessionId: runtime.rt.sessionId,
|
|
31
|
+
startedSeq: 0,
|
|
32
|
+
committedSeq: ran.result.compactedFrom,
|
|
33
|
+
checkpointId: cpId,
|
|
34
|
+
cutIndex: ran.result.compactedFrom,
|
|
35
|
+
summaryMessageText: ran.result.summary,
|
|
36
|
+
createdAt: Date.now(),
|
|
37
|
+
};
|
|
38
|
+
writeCheckpointEpoch(db, epoch);
|
|
39
|
+
// S50B: link this session's turns to the epoch that just compacted
|
|
40
|
+
// them (compression-by-conversation-epoch metrics). Isolated-store
|
|
41
|
+
// only; best-effort + non-fatal.
|
|
42
|
+
try {
|
|
43
|
+
stampTurnsEpochFor(config, runtime.rt.sessionId, epoch.epochId, runtime.currentStateDir);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
/* non-fatal: epoch stamping never breaks compaction */
|
|
47
|
+
}
|
|
48
|
+
// S51B: auto-categorizing wiki rebuild — every Nth compaction, derived
|
|
49
|
+
// from real context_chunks embeddings. Isolated-store only, gated on
|
|
50
|
+
// AUTO_WIKI_ENABLED; best-effort + non-fatal (never breaks compaction).
|
|
51
|
+
// Fire regardless of dbMirror — context_chunks is the isolated store.
|
|
52
|
+
// Uses the already-open db when inside the dbMirror block; opens its own
|
|
53
|
+
// connection otherwise.
|
|
54
|
+
// from real context_chunks embeddings. Isolated-store only, gated on
|
|
55
|
+
// AUTO_WIKI_ENABLED; best-effort + non-fatal (never breaks compaction).
|
|
56
|
+
try {
|
|
57
|
+
if (config.autoWikiEnabled && config.turnsDbEnabled) {
|
|
58
|
+
const every = Math.max(1, TurnsConfig.WIKI_REBUILD_EVERY_N_COMPACTS);
|
|
59
|
+
const tdb = openTurnStore(runtime.currentStateDir);
|
|
60
|
+
const n = bumpWikiCompactCounter(tdb);
|
|
61
|
+
if (n % every === 0) {
|
|
62
|
+
const model = buildTopicModel(db, {
|
|
63
|
+
kRange: [TurnsConfig.WIKI_K_MIN, TurnsConfig.WIKI_K_MAX],
|
|
64
|
+
labelTopTerms: TurnsConfig.WIKI_LABEL_TOP_TERMS,
|
|
65
|
+
restarts: 5,
|
|
66
|
+
seed: 0x9e3779b9,
|
|
67
|
+
});
|
|
68
|
+
createTopicStore(runtime.currentStateDir).replaceTopicModel(model);
|
|
69
|
+
runtime.logger.info("wiki_rebuild", {
|
|
70
|
+
clusterCount: model.k,
|
|
71
|
+
totalChunks: model.totalChunks,
|
|
72
|
+
method: "kmeans+tfidf",
|
|
73
|
+
criterion: model.criterion,
|
|
74
|
+
silhouetteScore: model.silhouetteScore,
|
|
75
|
+
uncalibrated: false,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch (wikiErr) {
|
|
81
|
+
runtime.logger.warn("wiki_rebuild_failed", {
|
|
82
|
+
error: String(wikiErr),
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
// D1: seed the topic model from raw_transcript when context_chunks is
|
|
86
|
+
// thin (pre-compaction). Gated on WIKI_SEED_FROM_TURNS; non-fatal.
|
|
87
|
+
// Seeds buildTopicModel with on-the-fly trigram embeddings from
|
|
88
|
+
// recent raw_transcript rows for the current session.
|
|
89
|
+
try {
|
|
90
|
+
if (config.autoWikiEnabled &&
|
|
91
|
+
config.turnsDbEnabled &&
|
|
92
|
+
TurnsConfig.WIKI_SEED_FROM_TURNS) {
|
|
93
|
+
const floor = 50;
|
|
94
|
+
const countRow = db
|
|
95
|
+
.prepare(`SELECT COUNT(*) AS cnt FROM context_chunks WHERE session_id = ?`)
|
|
96
|
+
.get(runtime.rt.sessionId);
|
|
97
|
+
const chunkCount = countRow?.cnt ?? 0;
|
|
98
|
+
if (chunkCount < floor) {
|
|
99
|
+
const transcriptRows = db
|
|
100
|
+
.prepare(`SELECT DISTINCT content_bytes
|
|
101
|
+
FROM raw_transcript
|
|
102
|
+
WHERE session_id = ?
|
|
103
|
+
AND length(content_bytes) > 10
|
|
104
|
+
ORDER BY seq ASC
|
|
105
|
+
LIMIT 200`)
|
|
106
|
+
.all(runtime.rt.sessionId);
|
|
107
|
+
if (transcriptRows.length > 0) {
|
|
108
|
+
const embedder = new TrigramEmbedder();
|
|
109
|
+
const seedChunks = [];
|
|
110
|
+
for (let i = 0; i < transcriptRows.length; i++) {
|
|
111
|
+
const text = transcriptRows[i].content_bytes.trim();
|
|
112
|
+
if (text.length === 0)
|
|
113
|
+
continue;
|
|
114
|
+
const vec = embedder.embed(text);
|
|
115
|
+
seedChunks.push({
|
|
116
|
+
chunkId: `seed_transcript_${i}`,
|
|
117
|
+
sessionId: runtime.rt.sessionId,
|
|
118
|
+
vec,
|
|
119
|
+
text,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
if (seedChunks.length > 0) {
|
|
123
|
+
const model = buildTopicModel(db, {
|
|
124
|
+
kRange: [
|
|
125
|
+
TurnsConfig.WIKI_K_MIN,
|
|
126
|
+
TurnsConfig.WIKI_K_MAX,
|
|
127
|
+
],
|
|
128
|
+
labelTopTerms: TurnsConfig.WIKI_LABEL_TOP_TERMS,
|
|
129
|
+
restarts: 5,
|
|
130
|
+
seed: 0x9e3779b9,
|
|
131
|
+
}, seedChunks);
|
|
132
|
+
createTopicStore(runtime.currentStateDir).replaceTopicModel(model);
|
|
133
|
+
runtime.logger.info("wiki_seed", {
|
|
134
|
+
clusterCount: model.k,
|
|
135
|
+
sourceChunks: seedChunks.length,
|
|
136
|
+
totalChunks: model.totalChunks,
|
|
137
|
+
method: "kmeans+tfidf",
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
catch (seedErr) {
|
|
145
|
+
runtime.logger.warn("wiki_seed_failed", {
|
|
146
|
+
error: String(seedErr),
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
// S27 Task 6: Fire-and-forget dedup pipeline.
|
|
150
|
+
// Deduplicates raw_transcript rows for the compacted range.
|
|
151
|
+
try {
|
|
152
|
+
const { dedupTranscript } = await import("../../../src/mirror/dedup.js");
|
|
153
|
+
dedupTranscript(db, runtime.rt.sessionId, 0, ran.result.compactedFrom);
|
|
154
|
+
}
|
|
155
|
+
catch (_dedupErr) {
|
|
156
|
+
// Fire-and-forget: dedup failure is non-fatal
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
catch (e) {
|
|
160
|
+
runtime.logger.warn("db-mirror-epoch-fail", { error: String(e) });
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Best-effort text extraction from an AgentMessage for analytics/logging. */
|
|
2
|
+
export function messageContentText(m) {
|
|
3
|
+
const c = m.content;
|
|
4
|
+
if (typeof c === "string")
|
|
5
|
+
return c;
|
|
6
|
+
if (Array.isArray(c)) {
|
|
7
|
+
return c
|
|
8
|
+
.map((b) => (b && typeof b === "object" && "text" in b ? String(b.text ?? "") : ""))
|
|
9
|
+
.join(" ");
|
|
10
|
+
}
|
|
11
|
+
return "";
|
|
12
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { stagedForTail, withRecallTail } from "../recall-tail.js";
|
|
2
|
+
import { buildSeparatedPrompt, buildCacheOptimizedPrompt } from "../separated-prompt.js";
|
|
3
|
+
import { messageContentText } from "./messageText.js";
|
|
4
|
+
/**
|
|
5
|
+
* Build the tail injection closure. Returns undefined when nothing is staged
|
|
6
|
+
* (or the flags are OFF) so the caller falls through to its normal return.
|
|
7
|
+
*/
|
|
8
|
+
export function buildTailResult(runtime, config, messages) {
|
|
9
|
+
// S53: helper to inject the staged recall/memory block as a user-role
|
|
10
|
+
// tail message at any view-return point. Returns undefined when nothing
|
|
11
|
+
// is staged (or the flag is OFF) so the caller falls through to its
|
|
12
|
+
// normal return. The F3 mirror append (above the gates) runs on the
|
|
13
|
+
// REAL transcript before any view is built, so the injected tail never
|
|
14
|
+
// reaches raw_transcript (PREVENT-PI: append-only, view-only).
|
|
15
|
+
const tailResult = (msgs) => {
|
|
16
|
+
const base = msgs ?? messages;
|
|
17
|
+
if (!stagedForTail(runtime, config) && !config.messageSeparation && !config.cacheStriping)
|
|
18
|
+
return undefined;
|
|
19
|
+
let result = stagedForTail(runtime, config)
|
|
20
|
+
? withRecallTail(base, runtime, config)
|
|
21
|
+
: base;
|
|
22
|
+
if (config.cacheStriping) {
|
|
23
|
+
result = buildCacheOptimizedPrompt(result);
|
|
24
|
+
}
|
|
25
|
+
else if (config.messageSeparation) {
|
|
26
|
+
result = buildSeparatedPrompt(result);
|
|
27
|
+
}
|
|
28
|
+
// P2.5: log prefix stability (fire-and-forget, non-fatal).
|
|
29
|
+
// tailResult is sync, so use .then().catch() on the dynamic import.
|
|
30
|
+
if (result.length > 1) {
|
|
31
|
+
import("../../../src/cache-stripe-impl.js").then(({ computeStabilityScore }) => {
|
|
32
|
+
const stableScore = computeStabilityScore({ content: messageContentText(result[0] ?? result[0]), chunkId: "prefix", accessCount: 0, lastAccessedAt: 0 }, result.slice(0, 2).map((m) => ({ content: messageContentText(m), chunkId: "prefix", accessCount: 0, lastAccessedAt: 0 })));
|
|
33
|
+
runtime.logger.info("prefix_stability", {
|
|
34
|
+
stableScore: Number.isFinite(stableScore) ? stableScore : 0,
|
|
35
|
+
prefixMessages: result.length,
|
|
36
|
+
separation: config.messageSeparation ? "v2" : "off",
|
|
37
|
+
striping: config.cacheStriping ? "v3" : "off",
|
|
38
|
+
});
|
|
39
|
+
}).catch(() => {
|
|
40
|
+
// Non-fatal: stability logging is best-effort.
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
return { messages: result };
|
|
44
|
+
};
|
|
45
|
+
return tailResult;
|
|
46
|
+
}
|
|
@@ -1,32 +1,14 @@
|
|
|
1
|
-
import { openStore,
|
|
2
|
-
import { epochIdFor } from "../../src/mirror/epoch.js";
|
|
1
|
+
import { openStore, } from "../../src/store/sqlite.js";
|
|
3
2
|
import { autoCompactCheck } from "../../src/compact.js";
|
|
4
3
|
import { estimateSessionTokens } from "../../src/tokens.js";
|
|
5
4
|
import { runCompact, piCompactWouldNoop } from "../mega-pipeline.js";
|
|
6
|
-
import { stampTurnsEpochFor } from "../mega-turn-store.js";
|
|
7
|
-
import { TurnsConfig } from "../../src/config/turns.js";
|
|
8
|
-
import { openTurnStore } from "../../src/store/turns/connection.js";
|
|
9
|
-
import { buildTopicModel, createTopicStore, bumpWikiCompactCounter, } from "../../src/topics/index.js";
|
|
10
|
-
import { TrigramEmbedder } from "../../src/embedder.js";
|
|
11
|
-
import { computeLiveTrimCut, liveTrimSummaryMessage } from "../mega-trim.js";
|
|
12
5
|
import { pressureFromPct, pressureRatio, } from "../mega-config.js";
|
|
13
6
|
import { appendMirrorMessages } from "./mirror-append.js";
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
function messageContentText(m) {
|
|
20
|
-
const c = m.content;
|
|
21
|
-
if (typeof c === "string")
|
|
22
|
-
return c;
|
|
23
|
-
if (Array.isArray(c)) {
|
|
24
|
-
return c
|
|
25
|
-
.map((b) => (b && typeof b === "object" && "text" in b ? String(b.text ?? "") : ""))
|
|
26
|
-
.join(" ");
|
|
27
|
-
}
|
|
28
|
-
return "";
|
|
29
|
-
}
|
|
7
|
+
import { epochIdFor } from "../../src/mirror/epoch.js";
|
|
8
|
+
import { computeLiveTrimCut, liveTrimSummaryMessage } from "../mega-trim.js";
|
|
9
|
+
import { messageContentText } from "./context-handler/messageText.js";
|
|
10
|
+
import { buildTailResult } from "./context-handler/tailResult.js";
|
|
11
|
+
import { persistEpochAndMaintain } from "./context-handler/afterCompact.js";
|
|
30
12
|
/** Register the context event handler (live-trim auto-trigger). */
|
|
31
13
|
export function registerContextHandler(pi, runtime, config) {
|
|
32
14
|
// ---- Auto-trigger: live trim (compact and continue) + native durable ----
|
|
@@ -50,39 +32,8 @@ export function registerContextHandler(pi, runtime, config) {
|
|
|
50
32
|
// S53: helper to inject the staged recall/memory block as a user-role
|
|
51
33
|
// tail message at any view-return point. Returns undefined when nothing
|
|
52
34
|
// is staged (or the flag is OFF) so the caller falls through to its
|
|
53
|
-
// normal return.
|
|
54
|
-
|
|
55
|
-
// reaches raw_transcript (PREVENT-PI: append-only, view-only).
|
|
56
|
-
const tailResult = (msgs) => {
|
|
57
|
-
const base = msgs ?? messages;
|
|
58
|
-
if (!stagedForTail(runtime, config) && !config.messageSeparation && !config.cacheStriping)
|
|
59
|
-
return undefined;
|
|
60
|
-
let result = stagedForTail(runtime, config)
|
|
61
|
-
? withRecallTail(base, runtime, config)
|
|
62
|
-
: base;
|
|
63
|
-
if (config.cacheStriping) {
|
|
64
|
-
result = buildCacheOptimizedPrompt(result);
|
|
65
|
-
}
|
|
66
|
-
else if (config.messageSeparation) {
|
|
67
|
-
result = buildSeparatedPrompt(result);
|
|
68
|
-
}
|
|
69
|
-
// P2.5: log prefix stability (fire-and-forget, non-fatal).
|
|
70
|
-
// tailResult is sync, so use .then().catch() on the dynamic import.
|
|
71
|
-
if (result.length > 1) {
|
|
72
|
-
import("../../src/cache-stripe-impl.js").then(({ computeStabilityScore }) => {
|
|
73
|
-
const stableScore = computeStabilityScore({ content: messageContentText(result[0] ?? result[0]), chunkId: "prefix", accessCount: 0, lastAccessedAt: 0 }, result.slice(0, 2).map((m) => ({ content: messageContentText(m), chunkId: "prefix", accessCount: 0, lastAccessedAt: 0 })));
|
|
74
|
-
runtime.logger.info("prefix_stability", {
|
|
75
|
-
stableScore: Number.isFinite(stableScore) ? stableScore : 0,
|
|
76
|
-
prefixMessages: result.length,
|
|
77
|
-
separation: config.messageSeparation ? "v2" : "off",
|
|
78
|
-
striping: config.cacheStriping ? "v3" : "off",
|
|
79
|
-
});
|
|
80
|
-
}).catch(() => {
|
|
81
|
-
// Non-fatal: stability logging is best-effort.
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
return { messages: result };
|
|
85
|
-
};
|
|
35
|
+
// normal return.
|
|
36
|
+
const tailResult = buildTailResult(runtime, config, messages);
|
|
86
37
|
// Always track context for the dashboard/widget, even when auto is off.
|
|
87
38
|
// (v0.8 regression: !config.auto gate sat above this, leaving ctx stats
|
|
88
39
|
// null -> widget '?% / ?/?' when auto disabled. Track first, THEN gate.)
|
|
@@ -249,147 +200,9 @@ export function registerContextHandler(pi, runtime, config) {
|
|
|
249
200
|
}
|
|
250
201
|
return tailResult() ?? undefined;
|
|
251
202
|
}
|
|
252
|
-
// S27 DB-mirror: write checkpoint_epoch
|
|
253
|
-
//
|
|
254
|
-
|
|
255
|
-
try {
|
|
256
|
-
const db = openStore(runtime.currentStateDir);
|
|
257
|
-
const cpId = ran.result.checkpointId ?? `epoch-${Date.now()}`;
|
|
258
|
-
const epoch = {
|
|
259
|
-
epochId: epochIdFor(cpId),
|
|
260
|
-
sessionId: runtime.rt.sessionId,
|
|
261
|
-
startedSeq: 0,
|
|
262
|
-
committedSeq: ran.result.compactedFrom,
|
|
263
|
-
checkpointId: cpId,
|
|
264
|
-
cutIndex: ran.result.compactedFrom,
|
|
265
|
-
summaryMessageText: ran.result.summary,
|
|
266
|
-
createdAt: Date.now(),
|
|
267
|
-
};
|
|
268
|
-
writeCheckpointEpoch(db, epoch);
|
|
269
|
-
// S50B: link this session's turns to the epoch that just compacted
|
|
270
|
-
// them (compression-by-conversation-epoch metrics). Isolated-store
|
|
271
|
-
// only; best-effort + non-fatal.
|
|
272
|
-
try {
|
|
273
|
-
stampTurnsEpochFor(config, runtime.rt.sessionId, epoch.epochId, runtime.currentStateDir);
|
|
274
|
-
}
|
|
275
|
-
catch {
|
|
276
|
-
/* non-fatal: epoch stamping never breaks compaction */
|
|
277
|
-
}
|
|
278
|
-
// S51B: auto-categorizing wiki rebuild — every Nth compaction, derived
|
|
279
|
-
// from real context_chunks embeddings. Isolated-store only, gated on
|
|
280
|
-
// AUTO_WIKI_ENABLED; best-effort + non-fatal (never breaks compaction).
|
|
281
|
-
// Fire regardless of dbMirror — context_chunks is the isolated store.
|
|
282
|
-
// Uses the already-open db when inside the dbMirror block; opens its own
|
|
283
|
-
// connection otherwise.
|
|
284
|
-
// from real context_chunks embeddings. Isolated-store only, gated on
|
|
285
|
-
// AUTO_WIKI_ENABLED; best-effort + non-fatal (never breaks compaction).
|
|
286
|
-
try {
|
|
287
|
-
if (config.autoWikiEnabled && config.turnsDbEnabled) {
|
|
288
|
-
const every = Math.max(1, TurnsConfig.WIKI_REBUILD_EVERY_N_COMPACTS);
|
|
289
|
-
const tdb = openTurnStore(runtime.currentStateDir);
|
|
290
|
-
const n = bumpWikiCompactCounter(tdb);
|
|
291
|
-
if (n % every === 0) {
|
|
292
|
-
const model = buildTopicModel(db, {
|
|
293
|
-
kRange: [TurnsConfig.WIKI_K_MIN, TurnsConfig.WIKI_K_MAX],
|
|
294
|
-
labelTopTerms: TurnsConfig.WIKI_LABEL_TOP_TERMS,
|
|
295
|
-
restarts: 5,
|
|
296
|
-
seed: 0x9e3779b9,
|
|
297
|
-
});
|
|
298
|
-
createTopicStore(runtime.currentStateDir).replaceTopicModel(model);
|
|
299
|
-
runtime.logger.info("wiki_rebuild", {
|
|
300
|
-
clusterCount: model.k,
|
|
301
|
-
totalChunks: model.totalChunks,
|
|
302
|
-
method: "kmeans+tfidf",
|
|
303
|
-
criterion: model.criterion,
|
|
304
|
-
silhouetteScore: model.silhouetteScore,
|
|
305
|
-
uncalibrated: false,
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
catch (wikiErr) {
|
|
311
|
-
runtime.logger.warn("wiki_rebuild_failed", {
|
|
312
|
-
error: String(wikiErr),
|
|
313
|
-
});
|
|
314
|
-
}
|
|
315
|
-
// D1: seed the topic model from raw_transcript when context_chunks is
|
|
316
|
-
// thin (pre-compaction). Gated on WIKI_SEED_FROM_TURNS; non-fatal.
|
|
317
|
-
// Seeds buildTopicModel with on-the-fly trigram embeddings from
|
|
318
|
-
// recent raw_transcript rows for the current session.
|
|
319
|
-
try {
|
|
320
|
-
if (config.autoWikiEnabled &&
|
|
321
|
-
config.turnsDbEnabled &&
|
|
322
|
-
TurnsConfig.WIKI_SEED_FROM_TURNS) {
|
|
323
|
-
const floor = 50;
|
|
324
|
-
const countRow = db
|
|
325
|
-
.prepare(`SELECT COUNT(*) AS cnt FROM context_chunks WHERE session_id = ?`)
|
|
326
|
-
.get(runtime.rt.sessionId);
|
|
327
|
-
const chunkCount = countRow?.cnt ?? 0;
|
|
328
|
-
if (chunkCount < floor) {
|
|
329
|
-
const transcriptRows = db
|
|
330
|
-
.prepare(`SELECT DISTINCT content_bytes
|
|
331
|
-
FROM raw_transcript
|
|
332
|
-
WHERE session_id = ?
|
|
333
|
-
AND length(content_bytes) > 10
|
|
334
|
-
ORDER BY seq ASC
|
|
335
|
-
LIMIT 200`)
|
|
336
|
-
.all(runtime.rt.sessionId);
|
|
337
|
-
if (transcriptRows.length > 0) {
|
|
338
|
-
const embedder = new TrigramEmbedder();
|
|
339
|
-
const seedChunks = [];
|
|
340
|
-
for (let i = 0; i < transcriptRows.length; i++) {
|
|
341
|
-
const text = transcriptRows[i].content_bytes.trim();
|
|
342
|
-
if (text.length === 0)
|
|
343
|
-
continue;
|
|
344
|
-
const vec = embedder.embed(text);
|
|
345
|
-
seedChunks.push({
|
|
346
|
-
chunkId: `seed_transcript_${i}`,
|
|
347
|
-
sessionId: runtime.rt.sessionId,
|
|
348
|
-
vec,
|
|
349
|
-
text,
|
|
350
|
-
});
|
|
351
|
-
}
|
|
352
|
-
if (seedChunks.length > 0) {
|
|
353
|
-
const model = buildTopicModel(db, {
|
|
354
|
-
kRange: [
|
|
355
|
-
TurnsConfig.WIKI_K_MIN,
|
|
356
|
-
TurnsConfig.WIKI_K_MAX,
|
|
357
|
-
],
|
|
358
|
-
labelTopTerms: TurnsConfig.WIKI_LABEL_TOP_TERMS,
|
|
359
|
-
restarts: 5,
|
|
360
|
-
seed: 0x9e3779b9,
|
|
361
|
-
}, seedChunks);
|
|
362
|
-
createTopicStore(runtime.currentStateDir).replaceTopicModel(model);
|
|
363
|
-
runtime.logger.info("wiki_seed", {
|
|
364
|
-
clusterCount: model.k,
|
|
365
|
-
sourceChunks: seedChunks.length,
|
|
366
|
-
totalChunks: model.totalChunks,
|
|
367
|
-
method: "kmeans+tfidf",
|
|
368
|
-
});
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
catch (seedErr) {
|
|
375
|
-
runtime.logger.warn("wiki_seed_failed", {
|
|
376
|
-
error: String(seedErr),
|
|
377
|
-
});
|
|
378
|
-
}
|
|
379
|
-
// S27 Task 6: Fire-and-forget dedup pipeline.
|
|
380
|
-
// Deduplicates raw_transcript rows for the compacted range.
|
|
381
|
-
try {
|
|
382
|
-
const { dedupTranscript } = await import("../../src/mirror/dedup.js");
|
|
383
|
-
dedupTranscript(db, runtime.rt.sessionId, 0, ran.result.compactedFrom);
|
|
384
|
-
}
|
|
385
|
-
catch (_dedupErr) {
|
|
386
|
-
// Fire-and-forget: dedup failure is non-fatal
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
catch (e) {
|
|
390
|
-
runtime.logger.warn("db-mirror-epoch-fail", { error: String(e) });
|
|
391
|
-
}
|
|
392
|
-
}
|
|
203
|
+
// S27 DB-mirror: write checkpoint_epoch + stamp turn epochs + auto-wiki +
|
|
204
|
+
// topic seed + fire-and-forget dedup. Best-effort + non-fatal.
|
|
205
|
+
await persistEpochAndMaintain(runtime, config, ran);
|
|
393
206
|
// LEGACY path (rollback): v0.4.28 ctx.compact() + the no-op gate. The
|
|
394
207
|
// manual compact path aborts the in-flight turn — only used behind the flag.
|
|
395
208
|
// Read live from env (in addition to the load-time config) so the flag can be
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helpers for the separated-prompt.test split files.
|
|
3
|
+
* Extracted from extensions/mega-events/separated-prompt.test.ts.
|
|
4
|
+
*/
|
|
5
|
+
import { mkdtempSync } from "node:fs";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { tmpdir } from "node:os";
|
|
8
|
+
import { DatabaseSync } from "node:sqlite";
|
|
9
|
+
import { initSchema } from "../../../src/store/sqlite/schema.js";
|
|
10
|
+
export function asR(arr) {
|
|
11
|
+
return arr;
|
|
12
|
+
}
|
|
13
|
+
/** Create a temp DB with schema initialized, returns db + dir. */
|
|
14
|
+
export function createTestDb() {
|
|
15
|
+
const dir = mkdtempSync(join(tmpdir(), "separated-prompt-test-"));
|
|
16
|
+
const db = new DatabaseSync(join(dir, "sqlite.db"));
|
|
17
|
+
db.exec("PRAGMA journal_mode=WAL");
|
|
18
|
+
db.exec("PRAGMA foreign_keys=ON");
|
|
19
|
+
initSchema(db);
|
|
20
|
+
return { db, dir };
|
|
21
|
+
}
|
|
22
|
+
/** Helper: create an AgentMessage-like object. */
|
|
23
|
+
export function msg(role, content, extra) {
|
|
24
|
+
return { role, content, ...extra };
|
|
25
|
+
}
|
package/dist/src/config.js
CHANGED
|
@@ -98,3 +98,5 @@ export const RAG_TIERED_ROUTER = () => ragFlag("MEGACOMPACT_TIERED_ROUTER");
|
|
|
98
98
|
export const RAG_RECALL_METRICS = () => ragFlag("MEGACOMPACT_RECALL_METRICS");
|
|
99
99
|
/** B4: Memory graph traversal (dashboard-oriented). */
|
|
100
100
|
export const RAG_MEMORY_GRAPH = () => ragFlag("MEGACOMPACT_MEMORY_GRAPH");
|
|
101
|
+
/** B5: HyDE — generate a hypothetical answer doc via LLM (HttpEmbedder only). Default OFF. */
|
|
102
|
+
export const RAG_HYDE_ENABLED = () => ragFlag("MEGACOMPACT_HYDE_ENABLED");
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared test fixtures/harness for the dedup-engine split test files.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from dedup-engine.test.ts: tmp-dir lifecycle (beforeEach/afterEach),
|
|
5
|
+
* store construction, message builders, and the compact + okReason helpers.
|
|
6
|
+
* `currentTmpDir` is module-scoped per test-file subprocess (the runner isolates
|
|
7
|
+
* each file in its own node --test process), so tests never collide.
|
|
8
|
+
*/
|
|
9
|
+
import { beforeEach, afterEach } from "node:test";
|
|
10
|
+
import assert from "node:assert/strict";
|
|
11
|
+
import fs from "fs";
|
|
12
|
+
import path from "path";
|
|
13
|
+
import os from "os";
|
|
14
|
+
import { compactSession } from "../engine.js";
|
|
15
|
+
import { VectorStore } from "../vectorStore.js";
|
|
16
|
+
import { loadDedupConfig } from "../config/dedup.js";
|
|
17
|
+
function mkTmpDir() {
|
|
18
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), "mc-dedup-"));
|
|
19
|
+
}
|
|
20
|
+
let currentTmpDir;
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
currentTmpDir = mkTmpDir();
|
|
23
|
+
});
|
|
24
|
+
afterEach(() => {
|
|
25
|
+
if (currentTmpDir && fs.existsSync(currentTmpDir)) {
|
|
26
|
+
fs.rmSync(currentTmpDir, { recursive: true, force: true });
|
|
27
|
+
}
|
|
28
|
+
currentTmpDir = undefined;
|
|
29
|
+
});
|
|
30
|
+
function baseConfig() {
|
|
31
|
+
return loadDedupConfig();
|
|
32
|
+
}
|
|
33
|
+
export function makeStore(over = {}) {
|
|
34
|
+
return new VectorStore({
|
|
35
|
+
stateDir: currentTmpDir,
|
|
36
|
+
config: { ...baseConfig(), ...over },
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
export function makeMsg(role, text) {
|
|
40
|
+
return { role, text };
|
|
41
|
+
}
|
|
42
|
+
export function buildConversation(n, prefix = "turn") {
|
|
43
|
+
const out = [];
|
|
44
|
+
for (let i = 0; i < n; i++) {
|
|
45
|
+
const role = i % 2 === 0 ? "user" : "assistant";
|
|
46
|
+
out.push(makeMsg(role, `${prefix} ${i + 1}: ${role} discusses implementation of feature ${i + 1} in src/module${i + 1}.ts and considers tradeoffs.`));
|
|
47
|
+
}
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
export function compactFull(store, sessionId, messages, keepFrom) {
|
|
51
|
+
return compactSession({ sessionId, messages, keepFrom: keepFrom ?? messages.length }, store);
|
|
52
|
+
}
|
|
53
|
+
export function okReason(reason, expected) {
|
|
54
|
+
assert.ok(reason !== undefined && expected.includes(reason), `expected dedupReason one of ${expected.join(", ")}, got ${reason}`);
|
|
55
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helpers for the src/e2e.test split files.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from the top of src/e2e.test.ts: isolated temp-store management,
|
|
5
|
+
* the config-overridable VectorStore factory (store), the message builder
|
|
6
|
+
* (msg), and the direct SQLite seeder (seedDirect) that bypasses online dedup.
|
|
7
|
+
*
|
|
8
|
+
* Relative paths are one directory deeper than the original file, hence
|
|
9
|
+
* `../vectorStore.js` etc.
|
|
10
|
+
*/
|
|
11
|
+
import { mkdtempSync } from "node:fs";
|
|
12
|
+
import { tmpdir } from "node:os";
|
|
13
|
+
import { join } from "node:path";
|
|
14
|
+
import { VectorStore, computeRegionHash } from "../vectorStore.js";
|
|
15
|
+
import { loadDedupConfig } from "../config/dedup.js";
|
|
16
|
+
import { defaultEmbedder } from "../embedder.js";
|
|
17
|
+
import { upsertCheckpoint } from "../store/sqlite.js";
|
|
18
|
+
export const baseTmp = mkdtempSync(join(tmpdir(), "mc-e2e-"));
|
|
19
|
+
let counter = 0;
|
|
20
|
+
export function storeDir() {
|
|
21
|
+
return join(baseTmp, `run-${counter++}`);
|
|
22
|
+
}
|
|
23
|
+
/** Build an isolated VectorStore with a fresh state dir + optional config overrides. */
|
|
24
|
+
export function store(over = {}) {
|
|
25
|
+
const dir = storeDir();
|
|
26
|
+
const config = { ...loadDedupConfig(), ...over };
|
|
27
|
+
return new VectorStore({ stateDir: dir, config });
|
|
28
|
+
}
|
|
29
|
+
export function msg(role, text, toolName, input, output) {
|
|
30
|
+
return toolName
|
|
31
|
+
? { role, text, toolName, input: input ?? text, output: output ?? text }
|
|
32
|
+
: { role, text };
|
|
33
|
+
}
|
|
34
|
+
/** Seed a checkpoint directly into SQLite (bypasses online dedup tiers). */
|
|
35
|
+
export function seedDirect(dir, sessionId, rows) {
|
|
36
|
+
const e = defaultEmbedder();
|
|
37
|
+
for (const r of rows) {
|
|
38
|
+
const cp = {
|
|
39
|
+
checkpointId: r.id,
|
|
40
|
+
sessionId,
|
|
41
|
+
summary: r.text,
|
|
42
|
+
keyDecisions: [],
|
|
43
|
+
nextSteps: [],
|
|
44
|
+
filesModified: [],
|
|
45
|
+
tokenEstimate: r.tok,
|
|
46
|
+
regionHash: computeRegionHash(r.text),
|
|
47
|
+
embedding: e.embed(r.text),
|
|
48
|
+
timestamp: r.ts ?? 1,
|
|
49
|
+
};
|
|
50
|
+
upsertCheckpoint(cp, dir);
|
|
51
|
+
}
|
|
52
|
+
}
|
package/dist/src/embedder.js
CHANGED
package/dist/src/httpEmbedder.js
CHANGED
|
@@ -190,6 +190,7 @@ try {
|
|
|
190
190
|
}
|
|
191
191
|
`;
|
|
192
192
|
export class HttpEmbedder {
|
|
193
|
+
kind = "http";
|
|
193
194
|
url;
|
|
194
195
|
apiKey;
|
|
195
196
|
headers;
|
|
@@ -203,6 +204,11 @@ export class HttpEmbedder {
|
|
|
203
204
|
get dim() {
|
|
204
205
|
return this.resolvedDim;
|
|
205
206
|
}
|
|
207
|
+
/** Derive the Ollama /api/chat endpoint from the embedding endpoint's origin
|
|
208
|
+
* (same host:port as the BYO embedding server). Used by HyDE (src/hyde.ts). */
|
|
209
|
+
get chatUrl() {
|
|
210
|
+
return new URL("/api/chat", this.url).href;
|
|
211
|
+
}
|
|
206
212
|
embed(text) {
|
|
207
213
|
const body = JSON.stringify({ input: [text] });
|
|
208
214
|
const headers = {
|