pi-mega-compact 0.13.1 → 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.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-8HRroK9K.js → CacheTab-DPRHjYZ0.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{CacheTab-8HRroK9K.js.map → CacheTab-DPRHjYZ0.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{EventsTab-ncobZw-I.js → EventsTab-CgwYq-Qf.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{EventsTab-ncobZw-I.js.map → EventsTab-CgwYq-Qf.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{HealthTab-C6BI1EZG.js → HealthTab-BgOCjVzR.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{HealthTab-C6BI1EZG.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-B88XTCMk.js → MetricsTab-CcH9fP8P.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MetricsTab-B88XTCMk.js.map → MetricsTab-CcH9fP8P.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{OverviewTab-CGZrSia-.js → OverviewTab-BOs8ZNev.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{OverviewTab-CGZrSia-.js.map → OverviewTab-BOs8ZNev.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{ReposTab-BZo5cNS1.js → ReposTab-B-MfSPvg.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ReposTab-BZo5cNS1.js.map → ReposTab-B-MfSPvg.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SessionsTab-C2RokJcw.js → SessionsTab-BmeN649Q.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SessionsTab-C2RokJcw.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-CewYB2aA.js → TimeSavedCard-DnPg0L0z.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-CewYB2aA.js.map → TimeSavedCard-DnPg0L0z.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TopicsTab-DpVNIuaL.js → TopicsTab-BODHOg_b.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TopicsTab-DpVNIuaL.js.map → TopicsTab-BODHOg_b.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TurnsTab-KeuKKVC9.js → TurnsTab-BK0I7hKr.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TurnsTab-KeuKKVC9.js.map → TurnsTab-BK0I7hKr.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{index-Cucgohga.js → index-mOlljTFI.js} +9 -9
- package/extensions/dashboard-client/dist/assets/index-mOlljTFI.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{useSSE-DJsqdPXC.js → useSSE-BYOtv1-3.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-DJsqdPXC.js.map → useSSE-BYOtv1-3.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +1 -1
- 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 +13 -483
- 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-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/MaintenanceTab-DZi1MnZI.js +0 -2
- package/extensions/dashboard-client/dist/assets/MaintenanceTab-DZi1MnZI.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-CjUa9zzw.js +0 -2
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-CjUa9zzw.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/SetupTab-C_BwmebC.js +0 -2
- package/extensions/dashboard-client/dist/assets/SetupTab-C_BwmebC.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/index-Cucgohga.js.map +0 -1
|
@@ -0,0 +1,79 @@
|
|
|
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, type DedupConfigShape } from "../config/dedup.js";
|
|
17
|
+
import type { EngineMessage } from "../types.js";
|
|
18
|
+
|
|
19
|
+
function mkTmpDir(): string {
|
|
20
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), "mc-dedup-"));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let currentTmpDir: string | undefined;
|
|
24
|
+
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
currentTmpDir = mkTmpDir();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
if (currentTmpDir && fs.existsSync(currentTmpDir)) {
|
|
31
|
+
fs.rmSync(currentTmpDir, { recursive: true, force: true });
|
|
32
|
+
}
|
|
33
|
+
currentTmpDir = undefined;
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
function baseConfig(): DedupConfigShape {
|
|
37
|
+
return loadDedupConfig();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function makeStore(over: Partial<DedupConfigShape> = {}): VectorStore {
|
|
41
|
+
return new VectorStore({
|
|
42
|
+
stateDir: currentTmpDir,
|
|
43
|
+
config: { ...baseConfig(), ...over },
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function makeMsg(role: EngineMessage["role"], text: string): EngineMessage {
|
|
48
|
+
return { role, text };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function buildConversation(n: number, prefix = "turn"): EngineMessage[] {
|
|
52
|
+
const out: EngineMessage[] = [];
|
|
53
|
+
for (let i = 0; i < n; i++) {
|
|
54
|
+
const role = i % 2 === 0 ? "user" : "assistant";
|
|
55
|
+
out.push(
|
|
56
|
+
makeMsg(
|
|
57
|
+
role,
|
|
58
|
+
`${prefix} ${i + 1}: ${role} discusses implementation of feature ${i + 1} in src/module${i + 1}.ts and considers tradeoffs.`,
|
|
59
|
+
),
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function compactFull(
|
|
66
|
+
store: VectorStore,
|
|
67
|
+
sessionId: string,
|
|
68
|
+
messages: EngineMessage[],
|
|
69
|
+
keepFrom?: number,
|
|
70
|
+
): ReturnType<typeof compactSession> {
|
|
71
|
+
return compactSession({ sessionId, messages, keepFrom: keepFrom ?? messages.length }, store);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function okReason(reason: string | undefined, expected: string[]): void {
|
|
75
|
+
assert.ok(
|
|
76
|
+
reason !== undefined && expected.includes(reason),
|
|
77
|
+
`expected dedupReason one of ${expected.join(", ")}, got ${reason}`,
|
|
78
|
+
);
|
|
79
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
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, type DedupConfigShape } from "../config/dedup.js";
|
|
16
|
+
import { defaultEmbedder } from "../embedder.js";
|
|
17
|
+
import { upsertCheckpoint } from "../store/sqlite.js";
|
|
18
|
+
import type { EngineMessage } from "../types.js";
|
|
19
|
+
import type { StoredCheckpoint } from "../store.js";
|
|
20
|
+
|
|
21
|
+
export const baseTmp = mkdtempSync(join(tmpdir(), "mc-e2e-"));
|
|
22
|
+
let counter = 0;
|
|
23
|
+
|
|
24
|
+
export function storeDir(): string {
|
|
25
|
+
return join(baseTmp, `run-${counter++}`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Build an isolated VectorStore with a fresh state dir + optional config overrides. */
|
|
29
|
+
export function store(over: Partial<DedupConfigShape> = {}): VectorStore {
|
|
30
|
+
const dir = storeDir();
|
|
31
|
+
const config: DedupConfigShape = { ...loadDedupConfig(), ...over };
|
|
32
|
+
return new VectorStore({ stateDir: dir, config });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function msg(role: EngineMessage["role"], text: string, toolName?: string, input?: string, output?: string): EngineMessage {
|
|
36
|
+
return toolName
|
|
37
|
+
? { role, text, toolName, input: input ?? text, output: output ?? text }
|
|
38
|
+
: { role, text };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Seed a checkpoint directly into SQLite (bypasses online dedup tiers). */
|
|
42
|
+
export function seedDirect(dir: string, sessionId: string, rows: { id: string; text: string; tok: number; ts?: number }[]): void {
|
|
43
|
+
const e = defaultEmbedder();
|
|
44
|
+
for (const r of rows) {
|
|
45
|
+
const cp: StoredCheckpoint = {
|
|
46
|
+
checkpointId: r.id,
|
|
47
|
+
sessionId,
|
|
48
|
+
summary: r.text,
|
|
49
|
+
keyDecisions: [],
|
|
50
|
+
nextSteps: [],
|
|
51
|
+
filesModified: [],
|
|
52
|
+
tokenEstimate: r.tok,
|
|
53
|
+
regionHash: computeRegionHash(r.text),
|
|
54
|
+
embedding: e.embed(r.text),
|
|
55
|
+
timestamp: r.ts ?? 1,
|
|
56
|
+
};
|
|
57
|
+
upsertCheckpoint(cp, dir);
|
|
58
|
+
}
|
|
59
|
+
}
|
package/src/embedder.ts
CHANGED
|
@@ -18,6 +18,9 @@ export type Vector = number[];
|
|
|
18
18
|
export interface Embedder {
|
|
19
19
|
/** Dimensionality of vectors this embedder produces. */
|
|
20
20
|
readonly dim: number;
|
|
21
|
+
/** Discriminator: "trigram" | "http". Lets callers branch on the embedder
|
|
22
|
+
* backend without instanceof checks (e.g. HyDE is http-only). */
|
|
23
|
+
readonly kind: string;
|
|
21
24
|
embed(text: string): Vector;
|
|
22
25
|
}
|
|
23
26
|
|
|
@@ -65,6 +68,7 @@ function fnv1a(str: string): number {
|
|
|
65
68
|
* from corrupting stored vectors. Set MEGACOMPACT_EMBED_CACHE=0 to disable.
|
|
66
69
|
*/
|
|
67
70
|
export class TrigramEmbedder implements Embedder {
|
|
71
|
+
readonly kind = "trigram";
|
|
68
72
|
readonly dim: number;
|
|
69
73
|
private readonly seed: number;
|
|
70
74
|
/** @type {Map<string, Vector>} */
|
package/src/httpEmbedder.ts
CHANGED
|
@@ -203,6 +203,7 @@ try {
|
|
|
203
203
|
`;
|
|
204
204
|
|
|
205
205
|
export class HttpEmbedder implements Embedder {
|
|
206
|
+
readonly kind = "http";
|
|
206
207
|
private readonly url: string;
|
|
207
208
|
private readonly apiKey?: string;
|
|
208
209
|
private readonly headers: Record<string, string>;
|
|
@@ -219,6 +220,12 @@ export class HttpEmbedder implements Embedder {
|
|
|
219
220
|
return this.resolvedDim;
|
|
220
221
|
}
|
|
221
222
|
|
|
223
|
+
/** Derive the Ollama /api/chat endpoint from the embedding endpoint's origin
|
|
224
|
+
* (same host:port as the BYO embedding server). Used by HyDE (src/hyde.ts). */
|
|
225
|
+
get chatUrl(): string {
|
|
226
|
+
return new URL("/api/chat", this.url).href;
|
|
227
|
+
}
|
|
228
|
+
|
|
222
229
|
embed(text: string): Vector {
|
|
223
230
|
const body = JSON.stringify({ input: [text] });
|
|
224
231
|
const headers: Record<string, string> = {
|
package/src/hyde.ts
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hyde.ts — Hypothetical Document Embeddings for LLM-backed recall (S43 re-plan).
|
|
3
|
+
*
|
|
4
|
+
* When an HttpEmbedder (localhost Ollama) is active and RAG_HYDE_ENABLED, we
|
|
5
|
+
* generate a hypothetical answer to the recall query via the Ollama /api/chat
|
|
6
|
+
* endpoint, embed it, and RRF-fuse the resulting search hits with the raw-query
|
|
7
|
+
* hits. This gives a stronger recall signal than TF-IDF term expansion (S57 B1)
|
|
8
|
+
* when an LLM is available. Non-fatal: any error → returns "" (caller uses raw-only).
|
|
9
|
+
*
|
|
10
|
+
* PREVENT-PI-004: reuses HttpEmbedder's loopback-child-process pattern (spawnSync
|
|
11
|
+
* with its own event loop). The remote opt-in (MEGACOMPACT_ALLOW_REMOTE_EMBEDDER)
|
|
12
|
+
* governs this too — derived chat URL is on the same host as the embedding URL.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { spawnSync } from "node:child_process"; // guardrails-allow PREVENT-PI-004: localhost-only LLM generation — reuses HttpEmbedder's loopback exception; governed by MEGACOMPACT_ALLOW_REMOTE_EMBEDDER
|
|
16
|
+
import type { Embedder } from "./embedder.js";
|
|
17
|
+
import type { SearchHit } from "./vectorStore.js";
|
|
18
|
+
import { reciprocalRankFusion, type RankedItem } from "./queryReformulation/rrf.js";
|
|
19
|
+
import { Logger } from "./log.js";
|
|
20
|
+
|
|
21
|
+
/** Narrow view of an embedder that can produce LLM chat output (HttpEmbedder). */
|
|
22
|
+
interface LlmEmbedder {
|
|
23
|
+
readonly chatUrl: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Inline worker: POSTs to the derived Ollama /api/chat endpoint in a child
|
|
27
|
+
// process (its own event loop, so spawnSync blocks without a fetch deadlock).
|
|
28
|
+
const CHAT_WORKER = String.raw`
|
|
29
|
+
const u = process.env.MC_HYDE_URL, b = process.env.MC_HYDE_BODY;
|
|
30
|
+
try {
|
|
31
|
+
const r = await fetch(u, { method: "POST", headers: { "content-type": "application/json" }, body: b }); // guardrails-allow PREVENT-PI-004: localhost-only /api/chat — same host as BYO embedding endpoint; remote only via MEGACOMPACT_ALLOW_REMOTE_EMBEDDER
|
|
32
|
+
const out = JSON.stringify({ status: r.status, ok: r.ok, text: await r.text() });
|
|
33
|
+
process.stdout.write(out);
|
|
34
|
+
} catch (e) {
|
|
35
|
+
process.stdout.write(JSON.stringify({ error: String(e && e.message ? e.message : e) }));
|
|
36
|
+
}
|
|
37
|
+
`;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Generate a hypothetical answer document for a recall query via the LLM-hosted
|
|
41
|
+
* /api/chat endpoint (HttpEmbedder only). Returns "" when the embedder has no
|
|
42
|
+
* LLM chat surface (TrigramEmbedder) or on ANY error. Non-fatal — the caller
|
|
43
|
+
* falls back to raw-query recall only.
|
|
44
|
+
*/
|
|
45
|
+
/** Best-effort structured failure log. Never throws (PyDE is non-fatal). */
|
|
46
|
+
function logHydeFailure(reason: string): void {
|
|
47
|
+
try {
|
|
48
|
+
new Logger().warn("hyde_failed", { reason });
|
|
49
|
+
} catch {
|
|
50
|
+
/* ignore — logging must never break recall */
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function generateHypotheticalDoc(query: string, embedder: Embedder): string {
|
|
55
|
+
if (embedder.kind !== "http") return ""; // TrigramEmbedder: no LLM surface
|
|
56
|
+
const url = (embedder as Embedder & Partial<LlmEmbedder>).chatUrl;
|
|
57
|
+
if (!url) {
|
|
58
|
+
logHydeFailure("no chatUrl");
|
|
59
|
+
return "";
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const model = process.env.MEGACOMPACT_HYDE_MODEL ?? "llama3.2";
|
|
63
|
+
const content =
|
|
64
|
+
"Answer this question about the codebase concisely (2-3 sentences): " + query;
|
|
65
|
+
const body = JSON.stringify({
|
|
66
|
+
model,
|
|
67
|
+
messages: [{ role: "user", content }],
|
|
68
|
+
stream: false,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
let res;
|
|
72
|
+
try {
|
|
73
|
+
res = spawnSync(process.execPath, ["-e", CHAT_WORKER], { // guardrails-allow PREVENT-PI-004: localhost-only LLM generation — reuses HttpEmbedder's loopback exception; governed by MEGACOMPACT_ALLOW_REMOTE_EMBEDDER
|
|
74
|
+
encoding: "utf8",
|
|
75
|
+
env: { ...process.env, MC_HYDE_URL: url, MC_HYDE_BODY: body },
|
|
76
|
+
timeout: 20000,
|
|
77
|
+
});
|
|
78
|
+
} catch {
|
|
79
|
+
logHydeFailure("spawn-error");
|
|
80
|
+
return "";
|
|
81
|
+
}
|
|
82
|
+
if (
|
|
83
|
+
res.error ||
|
|
84
|
+
typeof res.stdout !== "string" ||
|
|
85
|
+
res.stdout.length === 0 ||
|
|
86
|
+
res.status !== 0
|
|
87
|
+
) {
|
|
88
|
+
logHydeFailure("child-error");
|
|
89
|
+
return "";
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
let parsed: { status?: number; ok?: boolean; text?: unknown; error?: string };
|
|
93
|
+
try {
|
|
94
|
+
parsed = JSON.parse(res.stdout);
|
|
95
|
+
} catch {
|
|
96
|
+
logHydeFailure("non-json");
|
|
97
|
+
return "";
|
|
98
|
+
}
|
|
99
|
+
if (parsed.error || !parsed.ok || (parsed.status ?? 0) >= 400) {
|
|
100
|
+
logHydeFailure("chat-http");
|
|
101
|
+
return "";
|
|
102
|
+
}
|
|
103
|
+
// Ollama /api/chat (stream:false) returns { message: { role, content } }.
|
|
104
|
+
let messageBody: unknown;
|
|
105
|
+
try {
|
|
106
|
+
if (typeof parsed.text === "string") messageBody = JSON.parse(parsed.text);
|
|
107
|
+
else {
|
|
108
|
+
logHydeFailure("empty-body");
|
|
109
|
+
return "";
|
|
110
|
+
}
|
|
111
|
+
} catch {
|
|
112
|
+
logHydeFailure("non-json-body");
|
|
113
|
+
return "";
|
|
114
|
+
}
|
|
115
|
+
if (!messageBody || typeof messageBody !== "object") {
|
|
116
|
+
logHydeFailure("bad-body");
|
|
117
|
+
return "";
|
|
118
|
+
}
|
|
119
|
+
const msg = (messageBody as Record<string, unknown>).message;
|
|
120
|
+
if (!msg || typeof msg !== "object") {
|
|
121
|
+
logHydeFailure("no-message");
|
|
122
|
+
return "";
|
|
123
|
+
}
|
|
124
|
+
const contentOut = (msg as Record<string, unknown>).content;
|
|
125
|
+
if (typeof contentOut !== "string" || contentOut.length === 0) {
|
|
126
|
+
logHydeFailure("empty-content");
|
|
127
|
+
return "";
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return contentOut;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* RRF-fuse two recall hit lists (raw-query and hypothetical-doc) into a single
|
|
135
|
+
* deduplicated ranking, sliced to `limit`. Order is by fused RRF score.
|
|
136
|
+
*/
|
|
137
|
+
export function fuseRecallHits(
|
|
138
|
+
raw: SearchHit[],
|
|
139
|
+
hyde: SearchHit[],
|
|
140
|
+
limit: number,
|
|
141
|
+
): SearchHit[] {
|
|
142
|
+
const byId = new Map<string, SearchHit>();
|
|
143
|
+
const rawRanked: RankedItem[] = raw.map((h, i) => {
|
|
144
|
+
byId.set(h.checkpoint.checkpointId, h);
|
|
145
|
+
return { id: h.checkpoint.checkpointId, rank: i + 1 };
|
|
146
|
+
});
|
|
147
|
+
const hydeRanked: RankedItem[] = hyde.map((h, i) => {
|
|
148
|
+
if (!byId.has(h.checkpoint.checkpointId)) {
|
|
149
|
+
byId.set(h.checkpoint.checkpointId, h);
|
|
150
|
+
}
|
|
151
|
+
return { id: h.checkpoint.checkpointId, rank: i + 1 };
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
const fused = reciprocalRankFusion([rawRanked, hydeRanked]);
|
|
155
|
+
const out: SearchHit[] = [];
|
|
156
|
+
for (const item of fused) {
|
|
157
|
+
const hit = byId.get(item.id);
|
|
158
|
+
if (hit) out.push(hit);
|
|
159
|
+
if (out.length >= limit) break;
|
|
160
|
+
}
|
|
161
|
+
return out;
|
|
162
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* checkpoints.ts — checkpoint node builder (extracted from sources.ts).
|
|
3
|
+
*/
|
|
4
|
+
import type { DatabaseSync } from "node:sqlite";
|
|
5
|
+
import type { MemoryGraphNode, MemoryGraphEdge } from "../../memoryGraph.js";
|
|
6
|
+
import { decodeEmbedding } from "../../store/sqlite/utils.js";
|
|
7
|
+
import { cosineSimilarity } from "../embedding.js";
|
|
8
|
+
import { safeJsonCount } from "./helpers.js";
|
|
9
|
+
|
|
10
|
+
export function buildCheckpointNodes(
|
|
11
|
+
db: DatabaseSync,
|
|
12
|
+
sessionId: string,
|
|
13
|
+
nodes: MemoryGraphNode[],
|
|
14
|
+
edges: MemoryGraphEdge[],
|
|
15
|
+
): void {
|
|
16
|
+
const rows = sessionId
|
|
17
|
+
? (db
|
|
18
|
+
.prepare(
|
|
19
|
+
`SELECT id, session_id, summary, token_estimate, timestamp,
|
|
20
|
+
dedup_status, topic_summary, key_decisions,
|
|
21
|
+
normalized_text, embedding_blob
|
|
22
|
+
FROM context_chunks
|
|
23
|
+
WHERE session_id = ?
|
|
24
|
+
ORDER BY timestamp ASC`,
|
|
25
|
+
)
|
|
26
|
+
.all(sessionId) as Array<Record<string, unknown>>)
|
|
27
|
+
: (db
|
|
28
|
+
.prepare(
|
|
29
|
+
`SELECT id, session_id, summary, token_estimate, timestamp,
|
|
30
|
+
dedup_status, topic_summary, key_decisions,
|
|
31
|
+
normalized_text, embedding_blob
|
|
32
|
+
FROM context_chunks
|
|
33
|
+
ORDER BY timestamp ASC`,
|
|
34
|
+
)
|
|
35
|
+
.all() as Array<Record<string, unknown>>);
|
|
36
|
+
|
|
37
|
+
if (rows.length === 0) return;
|
|
38
|
+
|
|
39
|
+
let prevId: string | null = null;
|
|
40
|
+
for (const row of rows) {
|
|
41
|
+
const id = String(row.id);
|
|
42
|
+
const rowSessionId = sessionId || String(row.session_id ?? "");
|
|
43
|
+
const summary = String(row.summary ?? "");
|
|
44
|
+
const node: MemoryGraphNode = {
|
|
45
|
+
id,
|
|
46
|
+
sessionId: rowSessionId,
|
|
47
|
+
label: id,
|
|
48
|
+
summaryTruncated: summary.length > 200 ? summary.slice(0, 197) + "..." : summary,
|
|
49
|
+
tokenEstimate: Number(row.token_estimate ?? 0),
|
|
50
|
+
timestamp: Number(row.timestamp ?? Date.now()),
|
|
51
|
+
dedupStatus: row.dedup_status ? String(row.dedup_status) : undefined,
|
|
52
|
+
raptorLevel: 0,
|
|
53
|
+
topicSummary: row.topic_summary ? String(row.topic_summary) : undefined,
|
|
54
|
+
decisionCount: row.key_decisions ? safeJsonCount(String(row.key_decisions)) : 0,
|
|
55
|
+
textSnippet: summary.length > 200 ? summary.slice(0, 197) + "..." : summary,
|
|
56
|
+
nodeType: "checkpoint",
|
|
57
|
+
};
|
|
58
|
+
nodes.push(node);
|
|
59
|
+
|
|
60
|
+
if (prevId !== null) {
|
|
61
|
+
edges.push({ source: prevId, target: id, weight: 1.0, type: "temporal" });
|
|
62
|
+
}
|
|
63
|
+
prevId = id;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
addCheckpointSemanticEdges(rows, edges);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function addCheckpointSemanticEdges(
|
|
70
|
+
rows: Array<Record<string, unknown>>,
|
|
71
|
+
edges: MemoryGraphEdge[],
|
|
72
|
+
): void {
|
|
73
|
+
const embeddings: Array<{ id: string; blob: Buffer | null }> = [];
|
|
74
|
+
for (const row of rows) {
|
|
75
|
+
const blob = row.embedding_blob;
|
|
76
|
+
embeddings.push({
|
|
77
|
+
id: String(row.id),
|
|
78
|
+
blob: blob instanceof Buffer ? blob : null,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
for (let i = 0; i < embeddings.length; i++) {
|
|
83
|
+
if (!embeddings[i].blob) continue;
|
|
84
|
+
const a = decodeEmbedding(embeddings[i].blob!);
|
|
85
|
+
for (let j = i + 1; j < embeddings.length; j++) {
|
|
86
|
+
if (!embeddings[j].blob) continue;
|
|
87
|
+
const b = decodeEmbedding(embeddings[j].blob!);
|
|
88
|
+
const sim = cosineSimilarity(a, b);
|
|
89
|
+
if (sim > 0) {
|
|
90
|
+
edges.push({
|
|
91
|
+
source: embeddings[i].id,
|
|
92
|
+
target: embeddings[j].id,
|
|
93
|
+
weight: sim,
|
|
94
|
+
type: "semantic",
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* edges.ts — edge deduplication (extracted from sources.ts).
|
|
3
|
+
*/
|
|
4
|
+
import type { MemoryGraphEdge } from "../../memoryGraph.js";
|
|
5
|
+
|
|
6
|
+
export function deduplicateEdges(edges: MemoryGraphEdge[]): MemoryGraphEdge[] {
|
|
7
|
+
const seen = new Map<string, MemoryGraphEdge>();
|
|
8
|
+
|
|
9
|
+
for (const e of edges) {
|
|
10
|
+
const keyA = `${e.source}|${e.target}`;
|
|
11
|
+
const keyB = `${e.target}|${e.source}`;
|
|
12
|
+
const existing = seen.get(keyA) ?? seen.get(keyB);
|
|
13
|
+
if (existing) {
|
|
14
|
+
if (e.weight > existing.weight) {
|
|
15
|
+
seen.set(keyA, e);
|
|
16
|
+
}
|
|
17
|
+
} else {
|
|
18
|
+
seen.set(keyA, e);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return [...seen.values()];
|
|
23
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* flags.ts — memory-graph feature-flag / env helpers (extracted from sources.ts).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export function flagEnabled(name: string, def: boolean): boolean {
|
|
6
|
+
const v = process.env[name];
|
|
7
|
+
if (v === undefined) return def;
|
|
8
|
+
return v === "true" || v === "1";
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function areTurnsEnabled(): boolean {
|
|
12
|
+
return flagEnabled("MEGACOMPACT_MEMORY_GRAPH_SEED_TURNS", true);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function isTurnContentEnabled(): boolean {
|
|
16
|
+
return flagEnabled("MEGACOMPACT_MEMORY_GRAPH_SEED_TURN_CONTENT", true) &&
|
|
17
|
+
flagEnabled("MEGACOMPACT_DB_MIRROR", false);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function isTurnContentFlaggedOn(): boolean {
|
|
21
|
+
return flagEnabled("MEGACOMPACT_MEMORY_GRAPH_SEED_TURN_CONTENT", true);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function areMemoriesEnabled(): boolean {
|
|
25
|
+
return flagEnabled("MEGACOMPACT_MEMORY_GRAPH_SEED_MEMORIES", true);
|
|
26
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* helpers.ts — shared micro-helpers (extracted from sources.ts).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export function safeJsonCount(raw: string | null | undefined): number {
|
|
6
|
+
if (!raw || typeof raw !== "string") return 0;
|
|
7
|
+
try {
|
|
8
|
+
const arr = JSON.parse(raw);
|
|
9
|
+
return Array.isArray(arr) ? arr.length : 0;
|
|
10
|
+
} catch {
|
|
11
|
+
return 0;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* memories.ts — memory node builder (extracted from sources.ts).
|
|
3
|
+
*/
|
|
4
|
+
import type { DatabaseSync } from "node:sqlite";
|
|
5
|
+
import type { MemoryGraphNode, MemoryGraphEdge } from "../../memoryGraph.js";
|
|
6
|
+
import { getOrComputeEmbedding, cosineSimilarity } from "../embedding.js";
|
|
7
|
+
|
|
8
|
+
export function buildMemoryNodes(
|
|
9
|
+
db: DatabaseSync,
|
|
10
|
+
sessionId: string,
|
|
11
|
+
nodes: MemoryGraphNode[],
|
|
12
|
+
edges: MemoryGraphEdge[],
|
|
13
|
+
): void {
|
|
14
|
+
const existingIds = new Set(nodes.map((n) => n.id));
|
|
15
|
+
const rows = db
|
|
16
|
+
.prepare(
|
|
17
|
+
`SELECT id, content, source_turn, created_at
|
|
18
|
+
FROM memories
|
|
19
|
+
ORDER BY created_at ASC`,
|
|
20
|
+
)
|
|
21
|
+
.all() as Array<Record<string, unknown>>;
|
|
22
|
+
|
|
23
|
+
if (rows.length === 0) return;
|
|
24
|
+
|
|
25
|
+
const memoryNodes: MemoryGraphNode[] = [];
|
|
26
|
+
|
|
27
|
+
for (const row of rows) {
|
|
28
|
+
const id = `mem:${String(row.id)}`;
|
|
29
|
+
if (existingIds.has(id)) continue;
|
|
30
|
+
existingIds.add(id);
|
|
31
|
+
|
|
32
|
+
const content = row.content ? String(row.content) : "";
|
|
33
|
+
const snippet = content.length > 200 ? content.slice(0, 197) + "..." : content;
|
|
34
|
+
|
|
35
|
+
const node: MemoryGraphNode = {
|
|
36
|
+
id,
|
|
37
|
+
sessionId,
|
|
38
|
+
label: `Memory ${String(row.id)}`,
|
|
39
|
+
summaryTruncated: snippet,
|
|
40
|
+
tokenEstimate: content.length,
|
|
41
|
+
timestamp: row.created_at ? Number(row.created_at) : Date.now(),
|
|
42
|
+
dedupStatus: undefined,
|
|
43
|
+
raptorLevel: 0,
|
|
44
|
+
topicSummary: undefined,
|
|
45
|
+
decisionCount: 0,
|
|
46
|
+
textSnippet: snippet,
|
|
47
|
+
nodeType: "memory",
|
|
48
|
+
epochId: undefined,
|
|
49
|
+
};
|
|
50
|
+
memoryNodes.push(node);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (memoryNodes.length > 1) {
|
|
54
|
+
const embeddings = memoryNodes.map((n) => {
|
|
55
|
+
try {
|
|
56
|
+
return { id: n.id, vec: getOrComputeEmbedding(db, n.textSnippet) };
|
|
57
|
+
} catch {
|
|
58
|
+
return { id: n.id, vec: null as number[] | null };
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
for (let i = 0; i < embeddings.length; i++) {
|
|
63
|
+
if (!embeddings[i].vec) continue;
|
|
64
|
+
for (let j = i + 1; j < embeddings.length; j++) {
|
|
65
|
+
if (!embeddings[j].vec) continue;
|
|
66
|
+
const sim = cosineSimilarity(embeddings[i].vec!, embeddings[j].vec!);
|
|
67
|
+
if (sim > 0) {
|
|
68
|
+
edges.push({
|
|
69
|
+
source: embeddings[i].id,
|
|
70
|
+
target: embeddings[j].id,
|
|
71
|
+
weight: sim,
|
|
72
|
+
type: "semantic",
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
crossLinkMemoryToCheckpoints(memoryNodes, nodes, edges);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
nodes.push(...memoryNodes);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function crossLinkMemoryToCheckpoints(
|
|
85
|
+
memoryNodes: MemoryGraphNode[],
|
|
86
|
+
allNodes: MemoryGraphNode[],
|
|
87
|
+
edges: MemoryGraphEdge[],
|
|
88
|
+
): void {
|
|
89
|
+
for (const mn of memoryNodes) {
|
|
90
|
+
let bestNeighbor: { id: string; diff: number } | null = null;
|
|
91
|
+
for (const n of allNodes) {
|
|
92
|
+
if (n.nodeType !== "checkpoint" && n.nodeType !== "turn-content") continue;
|
|
93
|
+
if (n.id === mn.id) continue;
|
|
94
|
+
const diff = Math.abs(mn.timestamp - n.timestamp);
|
|
95
|
+
if (bestNeighbor === null || diff < bestNeighbor.diff) {
|
|
96
|
+
bestNeighbor = { id: n.id, diff };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (bestNeighbor) {
|
|
100
|
+
edges.push({
|
|
101
|
+
source: mn.id,
|
|
102
|
+
target: bestNeighbor.id,
|
|
103
|
+
weight: 0.85,
|
|
104
|
+
type: "semantic",
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* raptor.ts — RAPTOR annotations that enrich checkpoint nodes (extracted from
|
|
3
|
+
* sources.ts).
|
|
4
|
+
*/
|
|
5
|
+
import type { MemoryGraphNode, MemoryGraphEdge } from "../../memoryGraph.js";
|
|
6
|
+
import { listRaptorNodes } from "../../store/sqlite/raptor.js";
|
|
7
|
+
|
|
8
|
+
export function addRaptorAnnotations(
|
|
9
|
+
sessionId: string,
|
|
10
|
+
stateDir: string,
|
|
11
|
+
nodes: MemoryGraphNode[],
|
|
12
|
+
edges: MemoryGraphEdge[],
|
|
13
|
+
): void {
|
|
14
|
+
const raptorNodes = listRaptorNodes(sessionId, stateDir);
|
|
15
|
+
if (!raptorNodes || raptorNodes.length === 0) return;
|
|
16
|
+
|
|
17
|
+
const nodeIndex = new Map<string, number>();
|
|
18
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
19
|
+
nodeIndex.set(nodes[i].id, i);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
for (const rn of raptorNodes) {
|
|
23
|
+
const idx = nodeIndex.get(rn.id);
|
|
24
|
+
if (idx !== undefined) {
|
|
25
|
+
nodes[idx].raptorLevel = rn.level;
|
|
26
|
+
}
|
|
27
|
+
if (!rn.parentId) continue;
|
|
28
|
+
if (nodeIndex.has(rn.id) && nodeIndex.has(rn.parentId)) {
|
|
29
|
+
edges.push({
|
|
30
|
+
source: rn.id,
|
|
31
|
+
target: rn.parentId,
|
|
32
|
+
weight: Math.max(0.1, 1.0 - rn.level * 0.1),
|
|
33
|
+
type: "raptor_parent",
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|