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
|
@@ -1,59 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* sqlite-store.ts — SqliteTurnStore: the reference implementation.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Thin delegate shell: each method body lives as a free function in ./sqlite-store/*
|
|
5
|
+
* (read.ts / write.ts / admin.ts) operating on an internal ctx ({db, stateDir,
|
|
6
|
+
* opts}); this class wires those to the contract. The public API surface —
|
|
7
|
+
* SqliteTurnStore implements TurnStore, all methods, asReader/asWriter/asAdmin,
|
|
8
|
+
* close — is unchanged for existing callers.
|
|
9
|
+
*
|
|
10
|
+
* Private schema (SQL lives in the impl files + connection.ts, not in types.ts).
|
|
6
11
|
* Append-only: no UPDATE on turns/turn_recall after INSERT (only in migration).
|
|
7
12
|
*
|
|
8
13
|
* PREVENT-PI-004: node:sqlite in-process only.
|
|
9
14
|
* PREVENT-002: all queries use bound parameters.
|
|
10
15
|
* PREVENT-001: safeJson not needed — no JSON columns in turns.db.
|
|
11
16
|
*/
|
|
12
|
-
import { randomBytes } from "node:crypto";
|
|
13
|
-
import { statSync } from "node:fs";
|
|
14
|
-
import { join } from "node:path";
|
|
15
17
|
import { openTurnDb, closeTurnDb } from "./connection.js";
|
|
16
|
-
import
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return `conv_${randomBytes(8).toString("hex")}`;
|
|
20
|
-
}
|
|
21
|
-
function normalizeSessionId(sid) {
|
|
22
|
-
// Matches the existing normalizeSessionId in src/store.ts
|
|
23
|
-
return sid.replace(/-.*$/, "");
|
|
24
|
-
}
|
|
25
|
-
function rowToEntry(r) {
|
|
26
|
-
return {
|
|
27
|
-
conversationId: r.conversation_id,
|
|
28
|
-
sessionId: r.session_id,
|
|
29
|
-
turnIndex: r.turn_index,
|
|
30
|
-
role: r.role,
|
|
31
|
-
endedAt: r.ended_at,
|
|
32
|
-
ctxTokens: r.ctx_tokens ?? undefined,
|
|
33
|
-
ctxPercent: r.ctx_percent ?? undefined,
|
|
34
|
-
pressureBand: r.pressure_band ?? undefined,
|
|
35
|
-
model: r.model ?? undefined,
|
|
36
|
-
epochId: r.epoch_id ?? undefined,
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
function rowToRecall(r) {
|
|
40
|
-
return {
|
|
41
|
-
turnId: String(r.turn_id),
|
|
42
|
-
checkpointId: r.checkpoint_id,
|
|
43
|
-
score: r.score,
|
|
44
|
-
source: r.source,
|
|
45
|
-
raptorLevel: r.raptor_level ?? undefined,
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
function rowToFork(r) {
|
|
49
|
-
return {
|
|
50
|
-
parentConversationId: r.parent_conversation_id,
|
|
51
|
-
childConversationId: r.child_conversation_id,
|
|
52
|
-
forkTurnIndex: r.fork_turn_index,
|
|
53
|
-
createdAt: r.created_at,
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
// ─── SqliteTurnStore ──────────────────────────────────────────────
|
|
18
|
+
import * as read from "./sqlite-store/read.js";
|
|
19
|
+
import * as write from "./sqlite-store/write.js";
|
|
20
|
+
import * as admin from "./sqlite-store/admin.js";
|
|
57
21
|
export class SqliteTurnStore {
|
|
58
22
|
db;
|
|
59
23
|
stateDir;
|
|
@@ -66,353 +30,65 @@ export class SqliteTurnStore {
|
|
|
66
30
|
inMemory: options.inMemory,
|
|
67
31
|
});
|
|
68
32
|
}
|
|
33
|
+
ctx() {
|
|
34
|
+
return { db: this.db, stateDir: this.stateDir, opts: this.opts };
|
|
35
|
+
}
|
|
69
36
|
// ── TurnReader ──────────────────────────────────────────────
|
|
70
37
|
query(filter) {
|
|
71
|
-
|
|
72
|
-
const params = [];
|
|
73
|
-
if (filter.conversationId !== undefined) {
|
|
74
|
-
clauses.push("conversation_id = ?");
|
|
75
|
-
params.push(filter.conversationId);
|
|
76
|
-
}
|
|
77
|
-
if (filter.sessionId !== undefined) {
|
|
78
|
-
clauses.push("session_id = ?");
|
|
79
|
-
params.push(normalizeSessionId(filter.sessionId));
|
|
80
|
-
}
|
|
81
|
-
if (filter.sinceMs !== undefined) {
|
|
82
|
-
clauses.push("ended_at >= ?");
|
|
83
|
-
params.push(filter.sinceMs);
|
|
84
|
-
}
|
|
85
|
-
if (filter.untilMs !== undefined) {
|
|
86
|
-
clauses.push("ended_at <= ?");
|
|
87
|
-
params.push(filter.untilMs);
|
|
88
|
-
}
|
|
89
|
-
if (filter.pressureBand !== undefined) {
|
|
90
|
-
clauses.push("pressure_band = ?");
|
|
91
|
-
params.push(filter.pressureBand);
|
|
92
|
-
}
|
|
93
|
-
const where = clauses.length > 0 ? `WHERE ${clauses.join(" AND ")}` : "";
|
|
94
|
-
const limit = filter.limit ?? 1000;
|
|
95
|
-
const offset = filter.offset ?? 0;
|
|
96
|
-
const rows = this.db
|
|
97
|
-
.prepare(`SELECT * FROM turns ${where} ORDER BY ended_at ASC LIMIT ? OFFSET ?`)
|
|
98
|
-
.all(...params, limit, offset);
|
|
99
|
-
return rows.map(rowToEntry);
|
|
38
|
+
return read.query(this.ctx(), filter);
|
|
100
39
|
}
|
|
101
40
|
getTurn(turnId) {
|
|
102
|
-
|
|
103
|
-
.prepare("SELECT * FROM turns WHERE id = ?")
|
|
104
|
-
.get(Number(turnId));
|
|
105
|
-
return row ? rowToEntry(row) : undefined;
|
|
41
|
+
return read.getTurn(this.ctx(), turnId);
|
|
106
42
|
}
|
|
107
43
|
getTurnByIndex(conversationId, turnIndex) {
|
|
108
|
-
|
|
109
|
-
.prepare("SELECT * FROM turns WHERE conversation_id = ? AND turn_index = ?")
|
|
110
|
-
.get(conversationId, turnIndex);
|
|
111
|
-
return row ? rowToEntry(row) : undefined;
|
|
44
|
+
return read.getTurnByIndex(this.ctx(), conversationId, turnIndex);
|
|
112
45
|
}
|
|
113
46
|
listRecall(turnId) {
|
|
114
|
-
|
|
115
|
-
.prepare("SELECT * FROM turn_recall WHERE turn_id = ? ORDER BY score DESC")
|
|
116
|
-
.all(Number(turnId));
|
|
117
|
-
return rows.map(rowToRecall);
|
|
47
|
+
return read.listRecall(this.ctx(), turnId);
|
|
118
48
|
}
|
|
119
49
|
listRecallByIndex(conversationId, turnIndex) {
|
|
120
|
-
|
|
121
|
-
.prepare("SELECT id FROM turns WHERE conversation_id = ? AND turn_index = ?")
|
|
122
|
-
.get(conversationId, turnIndex);
|
|
123
|
-
if (!row)
|
|
124
|
-
return [];
|
|
125
|
-
return this.listRecall(String(row.id));
|
|
50
|
+
return read.listRecallByIndex(this.ctx(), conversationId, turnIndex);
|
|
126
51
|
}
|
|
127
52
|
listForks(conversationId) {
|
|
128
|
-
|
|
129
|
-
.prepare("SELECT * FROM conversation_forks WHERE parent_conversation_id = ? ORDER BY created_at ASC")
|
|
130
|
-
.all(conversationId);
|
|
131
|
-
return rows.map(rowToFork);
|
|
53
|
+
return read.listForks(this.ctx(), conversationId);
|
|
132
54
|
}
|
|
133
55
|
countTurns(conversationId) {
|
|
134
|
-
|
|
135
|
-
.prepare("SELECT COUNT(*) as cnt FROM turns WHERE conversation_id = ?")
|
|
136
|
-
.get(conversationId);
|
|
137
|
-
return row.cnt;
|
|
56
|
+
return read.countTurns(this.ctx(), conversationId);
|
|
138
57
|
}
|
|
139
58
|
conversationStats(conversationId) {
|
|
140
|
-
|
|
141
|
-
.prepare("SELECT ended_at, ctx_percent, pressure_band FROM turns WHERE conversation_id = ? ORDER BY ended_at ASC")
|
|
142
|
-
.all(conversationId);
|
|
143
|
-
if (rows.length === 0) {
|
|
144
|
-
return {
|
|
145
|
-
turnCount: 0,
|
|
146
|
-
firstTurnAt: 0,
|
|
147
|
-
lastTurnAt: 0,
|
|
148
|
-
avgCtxPercent: 0,
|
|
149
|
-
pressureBands: {},
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
let ctxSum = 0;
|
|
153
|
-
let ctxCount = 0;
|
|
154
|
-
const bands = {};
|
|
155
|
-
for (const r of rows) {
|
|
156
|
-
if (r.ctx_percent !== null) {
|
|
157
|
-
ctxSum += r.ctx_percent;
|
|
158
|
-
ctxCount++;
|
|
159
|
-
}
|
|
160
|
-
const band = r.pressure_band;
|
|
161
|
-
if (band)
|
|
162
|
-
bands[band] = (bands[band] ?? 0) + 1;
|
|
163
|
-
}
|
|
164
|
-
return {
|
|
165
|
-
turnCount: rows.length,
|
|
166
|
-
firstTurnAt: rows[0].ended_at,
|
|
167
|
-
lastTurnAt: rows[rows.length - 1].ended_at,
|
|
168
|
-
avgCtxPercent: ctxCount > 0 ? ctxSum / ctxCount : 0,
|
|
169
|
-
pressureBands: bands,
|
|
170
|
-
};
|
|
59
|
+
return read.conversationStats(this.ctx(), conversationId);
|
|
171
60
|
}
|
|
172
61
|
// ── TurnWriter ──────────────────────────────────────────────
|
|
173
62
|
appendTurn(entry) {
|
|
174
|
-
|
|
175
|
-
this.persistSessionConv(sid, entry.conversationId);
|
|
176
|
-
try {
|
|
177
|
-
this.db
|
|
178
|
-
.prepare(`INSERT INTO turns (conversation_id, session_id, turn_index, role, ended_at,
|
|
179
|
-
ctx_tokens, ctx_percent, pressure_band, model, epoch_id)
|
|
180
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
181
|
-
.run(entry.conversationId, sid, entry.turnIndex, entry.role, entry.endedAt, entry.ctxTokens ?? null, entry.ctxPercent ?? null, entry.pressureBand ?? null, entry.model ?? null, entry.epochId ?? null);
|
|
182
|
-
}
|
|
183
|
-
catch (e) {
|
|
184
|
-
if (e instanceof Error &&
|
|
185
|
-
e.message.includes("UNIQUE constraint") &&
|
|
186
|
-
e.code === "ERR_SQLITE_ERROR") {
|
|
187
|
-
throw new DuplicateTurnError(entry.conversationId, entry.turnIndex);
|
|
188
|
-
}
|
|
189
|
-
throw e;
|
|
190
|
-
}
|
|
191
|
-
const row = this.db
|
|
192
|
-
.prepare("SELECT id FROM turns WHERE conversation_id = ? AND turn_index = ?")
|
|
193
|
-
.get(entry.conversationId, entry.turnIndex);
|
|
194
|
-
return String(row.id);
|
|
195
|
-
}
|
|
196
|
-
/** Persist the session → conversation mapping when a turn is written. */
|
|
197
|
-
persistSessionConv(sid, conversationId) {
|
|
198
|
-
this.db
|
|
199
|
-
.prepare("INSERT OR IGNORE INTO session_conversations (session_id, conversation_id) VALUES (?, ?)")
|
|
200
|
-
.run(sid, conversationId);
|
|
63
|
+
return write.appendTurn(this.ctx(), entry);
|
|
201
64
|
}
|
|
202
65
|
appendRecall(entry) {
|
|
203
|
-
this.
|
|
204
|
-
.prepare(`INSERT OR IGNORE INTO turn_recall (turn_id, checkpoint_id, score, source, raptor_level)
|
|
205
|
-
VALUES (?, ?, ?, ?, ?)`)
|
|
206
|
-
.run(Number(entry.turnId), entry.checkpointId, entry.score, entry.source, entry.raptorLevel ?? null);
|
|
66
|
+
write.appendRecall(this.ctx(), entry);
|
|
207
67
|
}
|
|
208
68
|
ensureConversationId(sessionId) {
|
|
209
|
-
|
|
210
|
-
// Check session_conversations table first (persistent mapping)
|
|
211
|
-
const row = this.db
|
|
212
|
-
.prepare("SELECT conversation_id FROM session_conversations WHERE session_id = ?")
|
|
213
|
-
.get(sid);
|
|
214
|
-
if (row)
|
|
215
|
-
return row.conversation_id;
|
|
216
|
-
// Check if any turn exists for this session (fallback)
|
|
217
|
-
const turnRow = this.db
|
|
218
|
-
.prepare("SELECT conversation_id FROM turns WHERE session_id = ? ORDER BY ended_at DESC LIMIT 1")
|
|
219
|
-
.get(sid);
|
|
220
|
-
if (turnRow) {
|
|
221
|
-
// Persist the mapping so future calls are consistent
|
|
222
|
-
this.db
|
|
223
|
-
.prepare("INSERT OR IGNORE INTO session_conversations (session_id, conversation_id) VALUES (?, ?)")
|
|
224
|
-
.run(sid, turnRow.conversation_id);
|
|
225
|
-
return turnRow.conversation_id;
|
|
226
|
-
}
|
|
227
|
-
// No turns yet — generate and persist a new conversation id
|
|
228
|
-
const convId = newConversationId();
|
|
229
|
-
this.db
|
|
230
|
-
.prepare("INSERT OR IGNORE INTO session_conversations (session_id, conversation_id) VALUES (?, ?)")
|
|
231
|
-
.run(sid, convId);
|
|
232
|
-
return convId;
|
|
69
|
+
return write.ensureConversationId(this.ctx(), sessionId);
|
|
233
70
|
}
|
|
234
71
|
forkConversation(parentId, forkTurnIndex) {
|
|
235
|
-
|
|
236
|
-
const now = Date.now();
|
|
237
|
-
// 1. Record the fork lineage
|
|
238
|
-
this.db
|
|
239
|
-
.prepare(`INSERT INTO conversation_forks (parent_conversation_id, child_conversation_id, fork_turn_index, created_at)
|
|
240
|
-
VALUES (?, ?, ?, ?)`)
|
|
241
|
-
.run(parentId, childId, forkTurnIndex, now);
|
|
242
|
-
// 2. Find the parent's turn at forkTurnIndex
|
|
243
|
-
const parentTurn = this.db
|
|
244
|
-
.prepare("SELECT id FROM turns WHERE conversation_id = ? AND turn_index = ?")
|
|
245
|
-
.get(parentId, forkTurnIndex);
|
|
246
|
-
if (!parentTurn)
|
|
247
|
-
return childId; // no parent turn at that index — nothing to seed
|
|
248
|
-
// 3. Create a seed turn in the child conversation (turnIndex 0, role system)
|
|
249
|
-
this.db
|
|
250
|
-
.prepare(`INSERT INTO turns (conversation_id, session_id, turn_index, role, ended_at)
|
|
251
|
-
VALUES (?, ?, 0, 'system', ?)`)
|
|
252
|
-
.run(childId, `fork_${childId}`, now);
|
|
253
|
-
const childTurnRow = this.db
|
|
254
|
-
.prepare("SELECT id FROM turns WHERE conversation_id = ? AND turn_index = 0")
|
|
255
|
-
.get(childId);
|
|
256
|
-
if (!childTurnRow)
|
|
257
|
-
return childId;
|
|
258
|
-
// 4. Copy the parent's recall entries into the child's seed turn
|
|
259
|
-
const parentRecall = this.db
|
|
260
|
-
.prepare("SELECT checkpoint_id, score, source, raptor_level FROM turn_recall WHERE turn_id = ?")
|
|
261
|
-
.all(parentTurn.id);
|
|
262
|
-
const insertRecall = this.db.prepare(`INSERT OR IGNORE INTO turn_recall (turn_id, checkpoint_id, score, source, raptor_level)
|
|
263
|
-
VALUES (?, ?, ?, ?, ?)`);
|
|
264
|
-
for (const r of parentRecall) {
|
|
265
|
-
insertRecall.run(childTurnRow.id, r.checkpoint_id, r.score, r.source, r.raptor_level ?? null);
|
|
266
|
-
}
|
|
267
|
-
return childId;
|
|
72
|
+
return write.forkConversation(this.ctx(), parentId, forkTurnIndex);
|
|
268
73
|
}
|
|
269
74
|
// ── TurnAdmin ───────────────────────────────────────────────
|
|
270
75
|
prune(policy) {
|
|
271
|
-
|
|
272
|
-
const cutoff = Date.now() - policy.maxTurnAgeMs;
|
|
273
|
-
// Find conversations with turns to potentially prune
|
|
274
|
-
const convRows = this.db
|
|
275
|
-
.prepare("SELECT DISTINCT conversation_id FROM turns")
|
|
276
|
-
.all();
|
|
277
|
-
let turnsRemoved = 0;
|
|
278
|
-
let recallRemoved = 0;
|
|
279
|
-
for (const { conversation_id } of convRows) {
|
|
280
|
-
// Count total turns in this conversation
|
|
281
|
-
const total = this.db
|
|
282
|
-
.prepare("SELECT COUNT(*) as cnt FROM turns WHERE conversation_id = ?")
|
|
283
|
-
.get(conversation_id);
|
|
284
|
-
// Keep at least keepMinPerConversation — delete only the oldest
|
|
285
|
-
const canDelete = Math.max(0, total.cnt - policy.keepMinPerConversation);
|
|
286
|
-
if (canDelete === 0)
|
|
287
|
-
continue;
|
|
288
|
-
// Find old turns to delete
|
|
289
|
-
const oldTurns = this.db
|
|
290
|
-
.prepare(`SELECT id FROM turns WHERE conversation_id = ? AND ended_at < ?
|
|
291
|
-
ORDER BY ended_at ASC LIMIT ?`)
|
|
292
|
-
.all(conversation_id, cutoff, canDelete);
|
|
293
|
-
if (oldTurns.length === 0)
|
|
294
|
-
continue;
|
|
295
|
-
const ids = oldTurns.map((t) => t.id);
|
|
296
|
-
const placeholders = ids.map(() => "?").join(",");
|
|
297
|
-
// Delete recall for those turns
|
|
298
|
-
const delRecall = this.db
|
|
299
|
-
.prepare(`DELETE FROM turn_recall WHERE turn_id IN (${placeholders})`)
|
|
300
|
-
.run(...ids);
|
|
301
|
-
recallRemoved += Number(delRecall.changes);
|
|
302
|
-
// Delete the turns
|
|
303
|
-
const delTurns = this.db
|
|
304
|
-
.prepare(`DELETE FROM turns WHERE id IN (${placeholders})`)
|
|
305
|
-
.run(...ids);
|
|
306
|
-
turnsRemoved += Number(delTurns.changes);
|
|
307
|
-
}
|
|
308
|
-
// Count preserved branches
|
|
309
|
-
const branchesPreserved = this.db
|
|
310
|
-
.prepare("SELECT COUNT(*) as cnt FROM conversation_forks")
|
|
311
|
-
.get().cnt;
|
|
312
|
-
if (policy.vacuumAfterPrune && (turnsRemoved > 0 || recallRemoved > 0)) {
|
|
313
|
-
this.vacuum();
|
|
314
|
-
}
|
|
315
|
-
const afterSize = this.dbSizeBytes();
|
|
316
|
-
return {
|
|
317
|
-
turnsRemoved,
|
|
318
|
-
recallRemoved,
|
|
319
|
-
branchesPreserved,
|
|
320
|
-
freedBytes: Math.max(0, beforeSize - afterSize),
|
|
321
|
-
};
|
|
76
|
+
return admin.prune(this.ctx(), policy);
|
|
322
77
|
}
|
|
323
78
|
vacuum() {
|
|
324
|
-
this.
|
|
79
|
+
admin.vacuum(this.ctx());
|
|
325
80
|
}
|
|
326
81
|
checkpoint() {
|
|
327
|
-
|
|
328
|
-
const turnRows = this.db
|
|
329
|
-
.prepare("SELECT * FROM turns ORDER BY ended_at ASC")
|
|
330
|
-
.all();
|
|
331
|
-
const turns = turnRows.map(rowToEntry);
|
|
332
|
-
// Build mapping: row_id → 1-based position in turns array
|
|
333
|
-
const rowIdToPos = new Map();
|
|
334
|
-
for (let i = 0; i < turnRows.length; i++) {
|
|
335
|
-
rowIdToPos.set(turnRows[i].id, i + 1);
|
|
336
|
-
}
|
|
337
|
-
const recallRows = this.db
|
|
338
|
-
.prepare("SELECT * FROM turn_recall ORDER BY turn_id ASC")
|
|
339
|
-
.all();
|
|
340
|
-
// Replace recall's turnId with the 1-based position of the referenced turn
|
|
341
|
-
// in the turns array. This makes the TurnId stable across restore.
|
|
342
|
-
const recall = recallRows.map((r) => {
|
|
343
|
-
const originalTurnId = r.turn_id;
|
|
344
|
-
const stableTurnId = rowIdToPos.get(originalTurnId) ?? originalTurnId;
|
|
345
|
-
return {
|
|
346
|
-
turnId: String(stableTurnId),
|
|
347
|
-
checkpointId: r.checkpoint_id,
|
|
348
|
-
score: r.score,
|
|
349
|
-
source: r.source,
|
|
350
|
-
raptorLevel: r.raptor_level ?? undefined,
|
|
351
|
-
};
|
|
352
|
-
});
|
|
353
|
-
const forks = this.db
|
|
354
|
-
.prepare("SELECT * FROM conversation_forks ORDER BY created_at ASC")
|
|
355
|
-
.all().map(rowToFork);
|
|
356
|
-
return {
|
|
357
|
-
version: 1,
|
|
358
|
-
exportedAt: Date.now(),
|
|
359
|
-
turns,
|
|
360
|
-
recall,
|
|
361
|
-
forks,
|
|
362
|
-
};
|
|
82
|
+
return admin.checkpoint(this.ctx());
|
|
363
83
|
}
|
|
364
84
|
restore(from) {
|
|
365
|
-
this.
|
|
366
|
-
const insertTurn = this.db.prepare(`INSERT INTO turns (conversation_id, session_id, turn_index, role, ended_at,
|
|
367
|
-
ctx_tokens, ctx_percent, pressure_band, model, epoch_id)
|
|
368
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
369
|
-
const insertRecall = this.db.prepare(`INSERT INTO turn_recall (turn_id, checkpoint_id, score, source, raptor_level)
|
|
370
|
-
VALUES (?, ?, ?, ?, ?)`);
|
|
371
|
-
const insertFork = this.db.prepare(`INSERT INTO conversation_forks (parent_conversation_id, child_conversation_id, fork_turn_index, created_at)
|
|
372
|
-
VALUES (?, ?, ?, ?)`);
|
|
373
|
-
this.db.exec("BEGIN TRANSACTION");
|
|
374
|
-
try {
|
|
375
|
-
// Map: 1-based position → new auto-increment row ID
|
|
376
|
-
const posToNewId = new Map();
|
|
377
|
-
for (let i = 0; i < from.turns.length; i++) {
|
|
378
|
-
const t = from.turns[i];
|
|
379
|
-
insertTurn.run(t.conversationId, normalizeSessionId(t.sessionId), t.turnIndex, t.role, t.endedAt, t.ctxTokens ?? null, t.ctxPercent ?? null, t.pressureBand ?? null, t.model ?? null, t.epochId ?? null);
|
|
380
|
-
const row = this.db
|
|
381
|
-
.prepare("SELECT id FROM turns WHERE conversation_id = ? AND turn_index = ?")
|
|
382
|
-
.get(t.conversationId, t.turnIndex);
|
|
383
|
-
if (row)
|
|
384
|
-
posToNewId.set(i + 1, row.id);
|
|
385
|
-
}
|
|
386
|
-
// Recall's turnId is now the 1-based position from checkpoint().
|
|
387
|
-
// Map it to the new row ID.
|
|
388
|
-
for (const r of from.recall) {
|
|
389
|
-
const targetTurnId = posToNewId.get(Number(r.turnId)) ?? Number(r.turnId);
|
|
390
|
-
insertRecall.run(targetTurnId, r.checkpointId, r.score, r.source, r.raptorLevel ?? null);
|
|
391
|
-
}
|
|
392
|
-
for (const f of from.forks) {
|
|
393
|
-
insertFork.run(f.parentConversationId, f.childConversationId, f.forkTurnIndex, f.createdAt);
|
|
394
|
-
}
|
|
395
|
-
this.db.exec("COMMIT");
|
|
396
|
-
}
|
|
397
|
-
catch (err) {
|
|
398
|
-
this.db.exec("ROLLBACK");
|
|
399
|
-
throw err;
|
|
400
|
-
}
|
|
85
|
+
admin.restore(this.ctx(), from);
|
|
401
86
|
}
|
|
402
87
|
clear() {
|
|
403
|
-
this.
|
|
404
|
-
this.db.exec("DELETE FROM conversation_forks");
|
|
405
|
-
this.db.exec("DELETE FROM turns");
|
|
406
|
-
this.db.exec("DELETE FROM session_conversations");
|
|
407
|
-
// Reset autoincrement
|
|
408
|
-
this.db.exec("DELETE FROM sqlite_sequence WHERE name IN ('turns','turn_recall','conversation_forks')");
|
|
88
|
+
admin.clear(this.ctx());
|
|
409
89
|
}
|
|
410
90
|
stampTurnsEpoch(sessionId, epochId) {
|
|
411
|
-
|
|
412
|
-
const res = this.db
|
|
413
|
-
.prepare("UPDATE turns SET epoch_id = ? WHERE session_id = ? AND epoch_id IS NULL")
|
|
414
|
-
.run(epochId, sid);
|
|
415
|
-
return Number(res.changes ?? 0);
|
|
91
|
+
return admin.stampTurnsEpoch(this.ctx(), sessionId, epochId);
|
|
416
92
|
}
|
|
417
93
|
// ── Capability gating ───────────────────────────────────────
|
|
418
94
|
asReader() {
|
|
@@ -451,16 +127,4 @@ export class SqliteTurnStore {
|
|
|
451
127
|
inMemory: this.opts.inMemory,
|
|
452
128
|
});
|
|
453
129
|
}
|
|
454
|
-
// ── Private helpers ─────────────────────────────────────────
|
|
455
|
-
dbSizeBytes() {
|
|
456
|
-
if (this.opts.inMemory)
|
|
457
|
-
return 0;
|
|
458
|
-
try {
|
|
459
|
-
const path = this.opts.dbPath ?? join(this.stateDir, "turns.db");
|
|
460
|
-
return statSync(path).size;
|
|
461
|
-
}
|
|
462
|
-
catch {
|
|
463
|
-
return 0;
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
130
|
}
|