pi-mega-compact 0.11.7 → 0.11.9
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/gather-debug-keys.js +18 -0
- package/dist/extensions/dashboard-server/gather-debug.js +129 -0
- package/dist/extensions/dashboard-server/routes-maintenance.js +6 -0
- package/dist/extensions/dashboard-server/routes-memory-map.js +8 -15
- package/dist/extensions/mega-commands.js +65 -5
- package/dist/extensions/mega-config.js +7 -0
- package/dist/extensions/mega-events/agent-handlers.js +74 -5
- package/dist/extensions/mega-events/context-handler.js +132 -3
- package/dist/extensions/mega-runtime/snapshot.js +1 -1
- package/dist/extensions/mega-trim.js +10 -0
- package/dist/src/config/turns.js +2 -1
- package/dist/src/memoryGraph/embedding.js +50 -0
- package/dist/src/memoryGraph/gates.js +379 -0
- package/dist/src/memoryGraph/sources.js +390 -0
- package/dist/src/memoryGraph.js +133 -259
- package/dist/src/store/sqlite/embedding-cache.js +71 -0
- package/dist/src/store/sqlite.js +1 -0
- package/dist/src/topics/cluster.js +10 -2
- package/extensions/dashboard-client/dist/assets/{AchievementTiles-DR9cLGDL.js → AchievementTiles-DFitrb4Y.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AchievementTiles-DR9cLGDL.js.map → AchievementTiles-DFitrb4Y.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{AchievementsTab-svNUgJ1e.js → AchievementsTab-PJrmq8pa.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AchievementsTab-svNUgJ1e.js.map → AchievementsTab-PJrmq8pa.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/CacheTab-C1WE7dEx.js +2 -0
- package/extensions/dashboard-client/dist/assets/CacheTab-C1WE7dEx.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{ConfigTab-CmmWheuW.js → ConfigTab-Dx-RpO8C.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ConfigTab-CmmWheuW.js.map → ConfigTab-Dx-RpO8C.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{EventsTab-CFE7jLsa.js → EventsTab-C63BEWEs.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{EventsTab-CFE7jLsa.js.map → EventsTab-C63BEWEs.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{GameTab-CJAX_th_.js → GameTab-DHpJE6km.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{GameTab-CJAX_th_.js.map → GameTab-DHpJE6km.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/MaintenanceTab-BSv0GfBb.js +2 -0
- package/extensions/dashboard-client/dist/assets/MaintenanceTab-BSv0GfBb.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-Cg1fgEx_.js +2 -0
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-Cg1fgEx_.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{MetricsTab-CHQscixy.js → MetricsTab-DCahxNOQ.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MetricsTab-CHQscixy.js.map → MetricsTab-DCahxNOQ.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{OverviewTab-DBs4DJdd.js → OverviewTab-RYvO1SZL.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{OverviewTab-DBs4DJdd.js.map → OverviewTab-RYvO1SZL.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{ReposTab-DeFz76L5.js → ReposTab-BDGr_UXb.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ReposTab-DeFz76L5.js.map → ReposTab-BDGr_UXb.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SessionsTab-BWNsj1OB.js → SessionsTab-ByrTnHaB.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SessionsTab-BWNsj1OB.js.map → SessionsTab-ByrTnHaB.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SetupTab-uS6A0xmw.js → SetupTab-CELafKis.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SetupTab-uS6A0xmw.js.map → SetupTab-CELafKis.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-CiqCOQuL.js → TimeSavedCard-BLWtmfr_.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-CiqCOQuL.js.map → TimeSavedCard-BLWtmfr_.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/TopicsTab-8Fsh_Igx.js +2 -0
- package/extensions/dashboard-client/dist/assets/TopicsTab-8Fsh_Igx.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{TurnsTab-CVz4f4-o.js → TurnsTab-D7mgXDe2.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TurnsTab-CVz4f4-o.js.map → TurnsTab-D7mgXDe2.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{index-DrktNOoT.js → index-h3jgEs6G.js} +10 -10
- package/extensions/dashboard-client/dist/assets/{index-DrktNOoT.js.map → index-h3jgEs6G.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{useSSE-Bf5LOLSi.js → useSSE-C5lmipBF.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-Bf5LOLSi.js.map → useSSE-C5lmipBF.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +1 -1
- package/extensions/dashboard-client/src/api/client.ts +5 -0
- package/extensions/dashboard-client/src/memory-map-layout.ts +161 -0
- package/extensions/dashboard-client/src/memory-map-shapes.tsx +126 -0
- package/extensions/dashboard-client/src/tabs/CacheTab.tsx +29 -2
- package/extensions/dashboard-client/src/tabs/MaintenanceTab.tsx +101 -0
- package/extensions/dashboard-client/src/tabs/MemoryMapTab.tsx +201 -165
- package/extensions/dashboard-client/src/tabs/ReposTab.tsx +21 -0
- package/extensions/dashboard-client/src/tabs/TopicsTab.tsx +1 -1
- package/extensions/dashboard-server/api-contracts/index.ts +3 -1
- package/extensions/dashboard-server/api-contracts/maintenance.ts +13 -0
- package/extensions/dashboard-server/api-contracts/memory-map.ts +14 -6
- package/extensions/dashboard-server/gather-debug-keys.ts +18 -0
- package/extensions/dashboard-server/gather-debug.ts +136 -0
- package/extensions/dashboard-server/routes-maintenance.ts +7 -0
- package/extensions/dashboard-server/routes-memory-map.ts +21 -29
- package/extensions/mega-commands.ts +63 -6
- package/extensions/mega-config.ts +22 -0
- package/extensions/mega-events/agent-handlers.ts +88 -5
- package/extensions/mega-events/context-handler.ts +152 -3
- package/extensions/mega-runtime/snapshot.ts +1 -1
- package/extensions/mega-trim.ts +15 -0
- package/package.json +1 -1
- package/src/config/turns.ts +5 -2
- package/src/memoryGraph/embedding.ts +63 -0
- package/src/memoryGraph/gates.ts +451 -0
- package/src/memoryGraph/sources.ts +484 -0
- package/src/memoryGraph.ts +188 -350
- package/src/store/sqlite/embedding-cache.ts +81 -0
- package/src/store/sqlite.ts +1 -0
- package/src/topics/cluster.ts +11 -1
- package/extensions/dashboard-client/dist/assets/CacheTab-ASwhOMjR.js +0 -2
- package/extensions/dashboard-client/dist/assets/CacheTab-ASwhOMjR.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/MaintenanceTab-P4SUsvMf.js +0 -2
- package/extensions/dashboard-client/dist/assets/MaintenanceTab-P4SUsvMf.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-BBiH76eF.js +0 -2
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-BBiH76eF.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/TopicsTab-BWWQxltv.js +0 -2
- package/extensions/dashboard-client/dist/assets/TopicsTab-BWWQxltv.js.map +0 -1
package/src/memoryGraph.ts
CHANGED
|
@@ -1,438 +1,276 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* memoryGraph.ts — S46 visual memory map: build a graph of graphs.
|
|
2
|
+
* memoryGraph.ts — S46/D3 visual memory map: build a graph of graphs.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Delegated-shell pattern: implementation lives in memoryGraph/gates.ts,
|
|
5
|
+
* memoryGraph/sources.ts, and memoryGraph/embedding.ts. This file owns
|
|
6
|
+
* the public types, the entry point (buildMemoryGraph), and exports.
|
|
7
7
|
*
|
|
8
8
|
* pi-agnostic (no pi runtime types). Zero network calls (PREVENT-PI-004).
|
|
9
|
-
* Synchronous read-only interface
|
|
9
|
+
* Synchronous read-only interface -- non-fatal on store errors.
|
|
10
10
|
*
|
|
11
11
|
* Re-exports the public types as both MemoryGraph* and shorter aliases
|
|
12
12
|
* (GraphNode, GraphEdge, GraphMetadata) so dashboard api-contracts can import
|
|
13
13
|
* from the canonical source.
|
|
14
14
|
*/
|
|
15
|
-
import { getStateDir
|
|
16
|
-
import { openStore
|
|
17
|
-
import {
|
|
15
|
+
import { getStateDir } from "./store.js";
|
|
16
|
+
import { openStore } from "./store/sqlite/utils.js";
|
|
17
|
+
import type { DatabaseSync } from "node:sqlite";
|
|
18
18
|
import { Logger } from "./log.js";
|
|
19
|
+
import { runValidationPipeline } from "./memoryGraph/gates.js";
|
|
20
|
+
import {
|
|
21
|
+
buildCheckpointNodes,
|
|
22
|
+
buildTurnNodes,
|
|
23
|
+
buildTurnContentNodes,
|
|
24
|
+
buildMemoryNodes,
|
|
25
|
+
addRaptorAnnotations,
|
|
26
|
+
deduplicateEdges,
|
|
27
|
+
areTurnsEnabled,
|
|
28
|
+
isTurnContentEnabled,
|
|
29
|
+
isTurnContentFlaggedOn,
|
|
30
|
+
areMemoriesEnabled,
|
|
31
|
+
} from "./memoryGraph/sources.js";
|
|
19
32
|
const log = new Logger();
|
|
20
33
|
|
|
21
34
|
// ---------------------------------------------------------------------------
|
|
22
35
|
// Types
|
|
23
|
-
//
|
|
36
|
+
// ------
|
|
24
37
|
|
|
25
|
-
/** A node in the memory graph
|
|
26
|
-
* RAPTOR level information if it participates in a RAPTOR tree). */
|
|
38
|
+
/** A single node in the memory graph. */
|
|
27
39
|
export interface MemoryGraphNode {
|
|
28
40
|
id: string;
|
|
29
41
|
sessionId: string;
|
|
30
42
|
label: string;
|
|
31
43
|
summaryTruncated: string;
|
|
32
44
|
tokenEstimate: number;
|
|
33
|
-
/** Unix-epoch ms (from checkpoint timestamp or created_at). */
|
|
34
45
|
timestamp: number;
|
|
35
46
|
dedupStatus: string | undefined;
|
|
36
|
-
/** 0 = no RAPTOR parent; 1+ = RAPTOR cluster level. */
|
|
37
47
|
raptorLevel: number;
|
|
38
48
|
topicSummary: string | undefined;
|
|
39
49
|
decisionCount: number;
|
|
40
|
-
/** First ~200 chars of the checkpoint summary/text for inline preview. */
|
|
41
50
|
textSnippet: string;
|
|
51
|
+
/** D3: node type discriminator for validation and UI styling. */
|
|
52
|
+
nodeType: "checkpoint" | "turn" | "turn-content" | "memory";
|
|
53
|
+
/** D3: if this turn node has an associated checkpoint epoch. */
|
|
54
|
+
epochId?: string;
|
|
42
55
|
}
|
|
43
56
|
|
|
44
|
-
/**
|
|
45
|
-
export type MemoryGraphEdgeType = "temporal" | "semantic" | "raptor_parent";
|
|
46
|
-
|
|
57
|
+
/** A directed edge between two graph nodes. */
|
|
47
58
|
export interface MemoryGraphEdge {
|
|
48
59
|
source: string;
|
|
49
60
|
target: string;
|
|
50
61
|
weight: number;
|
|
51
|
-
type:
|
|
62
|
+
type: "temporal" | "semantic" | "raptor_parent";
|
|
52
63
|
}
|
|
53
64
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
65
|
+
/** D3: validation report baked into every graph. */
|
|
66
|
+
export interface GraphValidationReport {
|
|
67
|
+
gatesRun: number;
|
|
68
|
+
gatesPassed: number;
|
|
69
|
+
dropped: { nodes: number; edges: number };
|
|
70
|
+
warnings: Array<{ gate: string; code: string; count: number }>;
|
|
71
|
+
sources: {
|
|
72
|
+
checkpoint: number;
|
|
73
|
+
turn: number;
|
|
74
|
+
turnContent: number;
|
|
75
|
+
memory: number;
|
|
76
|
+
};
|
|
62
77
|
builtAt: number;
|
|
63
78
|
}
|
|
64
79
|
|
|
65
|
-
/** The
|
|
80
|
+
/** The full graph structure returned to consumers. */
|
|
66
81
|
export interface MemoryGraph {
|
|
67
82
|
nodes: MemoryGraphNode[];
|
|
68
83
|
edges: MemoryGraphEdge[];
|
|
69
|
-
metadata:
|
|
84
|
+
metadata: {
|
|
85
|
+
totalNodes: number;
|
|
86
|
+
totalEdges: number;
|
|
87
|
+
avgWeight: number;
|
|
88
|
+
nodeTypeBreakdown: Record<string, number>;
|
|
89
|
+
edgeTypeBreakdown: Record<string, number>;
|
|
90
|
+
};
|
|
91
|
+
/** D3: validation report from the 9-gate pipeline. */
|
|
92
|
+
validation: GraphValidationReport;
|
|
70
93
|
}
|
|
71
94
|
|
|
72
95
|
// ---------------------------------------------------------------------------
|
|
73
|
-
// Short aliases
|
|
96
|
+
// Short aliases (dashboard api-contracts import these)
|
|
74
97
|
// ---------------------------------------------------------------------------
|
|
75
98
|
|
|
76
99
|
export type GraphNode = MemoryGraphNode;
|
|
77
100
|
export type GraphEdge = MemoryGraphEdge;
|
|
78
|
-
export type GraphMetadata =
|
|
79
|
-
|
|
80
|
-
/** Options to configure graph construction. */
|
|
81
|
-
export interface MemoryGraphOptions {
|
|
82
|
-
/** Similarity threshold for semantic edges (cosine). Default 0.7. */
|
|
83
|
-
similarityThreshold?: number;
|
|
84
|
-
/** Maximum number of semantic edges per node (avoids dense clique). Default 4. */
|
|
85
|
-
maxEdgesPerNode?: number;
|
|
86
|
-
/** Optional session filter — undefined = all sessions. */
|
|
87
|
-
sessionId?: string;
|
|
88
|
-
/** State directory (defaults to getStateDir()). */
|
|
89
|
-
stateDir?: string;
|
|
90
|
-
/** Include RAPTOR parent–child edges when available. Default true. */
|
|
91
|
-
includeRaptorEdges?: boolean;
|
|
92
|
-
/** Include temporal adjacency edges (consecutive checkpoints in same session). Default true. */
|
|
93
|
-
includeTemporalEdges?: boolean;
|
|
94
|
-
}
|
|
101
|
+
export type GraphMetadata = MemoryGraph["metadata"];
|
|
95
102
|
|
|
96
103
|
// ---------------------------------------------------------------------------
|
|
97
|
-
//
|
|
98
|
-
// ---------------------------------------------------------------------------
|
|
99
|
-
|
|
100
|
-
const DEFAULT_SIMILARITY_THRESHOLD = 0.7;
|
|
101
|
-
const DEFAULT_MAX_EDGES_PER_NODE = 4;
|
|
102
|
-
|
|
103
|
-
// ---------------------------------------------------------------------------
|
|
104
|
-
// Public API
|
|
104
|
+
// Public entry point
|
|
105
105
|
// ---------------------------------------------------------------------------
|
|
106
106
|
|
|
107
107
|
/**
|
|
108
|
-
* Build a memory graph from
|
|
108
|
+
* Build a memory graph from three sources (checkpoints / turns / memories)
|
|
109
|
+
* wired through a 9-gate validation pipeline.
|
|
109
110
|
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
* Returns a MemoryGraph or an empty graph on failure (non-fatal).
|
|
111
|
+
* Returns an empty graph (byte-identical pre-change for checkpoint-only) when
|
|
112
|
+
* no sources are available.
|
|
113
113
|
*/
|
|
114
|
-
export function buildMemoryGraph(
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
// Temporal edges: consecutive checkpoints within the same session
|
|
132
|
-
if (includeTemporalEdges) {
|
|
133
|
-
edges.push(...buildTemporalEdges(nodes));
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Semantic edges: cosine similarity above threshold
|
|
137
|
-
edges.push(...buildSemanticEdges(nodes, nodeIndex, similarityThreshold, maxEdgesPerNode));
|
|
138
|
-
|
|
139
|
-
// RAPTOR parent–child edges
|
|
140
|
-
if (includeRaptorEdges) {
|
|
141
|
-
edges.push(...buildRaptorEdges(nodes, sessionId, stateDir, nodeIndex));
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Deduplicate edges (keep highest weight for each source-target pair)
|
|
145
|
-
const dedupedEdges = deduplicateEdges(edges);
|
|
146
|
-
|
|
147
|
-
// Count sessions
|
|
148
|
-
const sessionSet = new Set<string>();
|
|
149
|
-
for (const n of nodes) {
|
|
150
|
-
sessionSet.add(n.sessionId);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const meta: MemoryGraphMetadata = {
|
|
154
|
-
sessionCount: sessionSet.size,
|
|
155
|
-
totalCheckpoints: nodes.length,
|
|
156
|
-
totalEdges: dedupedEdges.length,
|
|
157
|
-
semanticEdgeCount: dedupedEdges.filter((e) => e.type === "semantic").length,
|
|
158
|
-
temporalEdgeCount: dedupedEdges.filter((e) => e.type === "temporal").length,
|
|
159
|
-
raptorEdgeCount: dedupedEdges.filter((e) => e.type === "raptor_parent").length,
|
|
160
|
-
similarityThresholdUsed: similarityThreshold,
|
|
161
|
-
builtAt,
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
return { nodes, edges: dedupedEdges, metadata: meta };
|
|
165
|
-
} catch (err) {
|
|
166
|
-
log.warn("buildMemoryGraph failed", { error: String(err) });
|
|
167
|
-
return {
|
|
168
|
-
nodes: [],
|
|
169
|
-
edges: [],
|
|
170
|
-
metadata: {
|
|
171
|
-
sessionCount: 0,
|
|
172
|
-
totalCheckpoints: 0,
|
|
173
|
-
totalEdges: 0,
|
|
174
|
-
semanticEdgeCount: 0,
|
|
175
|
-
temporalEdgeCount: 0,
|
|
176
|
-
raptorEdgeCount: 0,
|
|
177
|
-
similarityThresholdUsed: similarityThreshold,
|
|
178
|
-
builtAt,
|
|
179
|
-
},
|
|
180
|
-
};
|
|
114
|
+
export function buildMemoryGraph(
|
|
115
|
+
sessionId: string,
|
|
116
|
+
stateDir: string = getStateDir(),
|
|
117
|
+
): MemoryGraph {
|
|
118
|
+
const { nodes, edges } = buildUnvalidatedGraph(sessionId, stateDir);
|
|
119
|
+
|
|
120
|
+
// Gate pipeline -- filters, deduplicates, and validates
|
|
121
|
+
const { ws, stats } = runValidationPipeline({ nodes, edges });
|
|
122
|
+
|
|
123
|
+
const nodeTypeBreakdown: Record<string, number> = {};
|
|
124
|
+
const edgeTypeBreakdown: Record<string, number> = {};
|
|
125
|
+
for (const n of ws.nodes) {
|
|
126
|
+
nodeTypeBreakdown[n.nodeType] = (nodeTypeBreakdown[n.nodeType] ?? 0) + 1;
|
|
127
|
+
}
|
|
128
|
+
for (const e of ws.edges) {
|
|
129
|
+
edgeTypeBreakdown[e.type] = (edgeTypeBreakdown[e.type] ?? 0) + 1;
|
|
181
130
|
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// ---------------------------------------------------------------------------
|
|
185
|
-
// Node loading
|
|
186
|
-
// ---------------------------------------------------------------------------
|
|
187
|
-
|
|
188
|
-
function loadNodes(sessionId: string | undefined, stateDir: string): MemoryGraphNode[] {
|
|
189
|
-
const db = openStore(stateDir);
|
|
190
|
-
|
|
191
|
-
const sql = sessionId
|
|
192
|
-
? "SELECT * FROM context_chunks WHERE session_id = ? ORDER BY id ASC"
|
|
193
|
-
: "SELECT * FROM context_chunks ORDER BY session_id, id ASC";
|
|
194
|
-
|
|
195
|
-
const rows = sessionId
|
|
196
|
-
? (db.prepare(sql).all(normalizeSessionId(sessionId)) as any[])
|
|
197
|
-
: (db.prepare(sql).all() as any[]);
|
|
198
131
|
|
|
199
|
-
|
|
200
|
-
|
|
132
|
+
const avgWeight =
|
|
133
|
+
ws.edges.length > 0
|
|
134
|
+
? ws.edges.reduce((s, e) => s + e.weight, 0) / ws.edges.length
|
|
135
|
+
: 0;
|
|
136
|
+
|
|
137
|
+
const sources = countSourcesByType(ws.nodes);
|
|
138
|
+
|
|
139
|
+
const validation: GraphValidationReport = {
|
|
140
|
+
gatesRun: stats.gatesRun.length,
|
|
141
|
+
gatesPassed: stats.gatesPassed.length,
|
|
142
|
+
dropped: stats.dropped,
|
|
143
|
+
warnings: stats.warnings.map((w) => ({
|
|
144
|
+
gate: w.gate,
|
|
145
|
+
code: w.code,
|
|
146
|
+
count: w.count,
|
|
147
|
+
})),
|
|
148
|
+
sources,
|
|
149
|
+
builtAt: Date.now(),
|
|
150
|
+
};
|
|
201
151
|
|
|
202
|
-
function rowToGraphNode(row: any): MemoryGraphNode {
|
|
203
|
-
const summary = row.summary ?? "";
|
|
204
152
|
return {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
? safeJsonCount(row.key_decisions)
|
|
216
|
-
: 0,
|
|
217
|
-
textSnippet: summary.length > 200 ? summary.slice(0, 197) + "..." : summary,
|
|
153
|
+
nodes: ws.nodes,
|
|
154
|
+
edges: ws.edges,
|
|
155
|
+
metadata: {
|
|
156
|
+
totalNodes: ws.nodes.length,
|
|
157
|
+
totalEdges: ws.edges.length,
|
|
158
|
+
avgWeight,
|
|
159
|
+
nodeTypeBreakdown,
|
|
160
|
+
edgeTypeBreakdown,
|
|
161
|
+
},
|
|
162
|
+
validation,
|
|
218
163
|
};
|
|
219
164
|
}
|
|
220
165
|
|
|
221
|
-
/** Parse a JSON array stored in a text column and return its length. */
|
|
222
|
-
function safeJsonCount(raw: string | null | undefined): number {
|
|
223
|
-
if (!raw) return 0;
|
|
224
|
-
try {
|
|
225
|
-
const arr = JSON.parse(raw);
|
|
226
|
-
return Array.isArray(arr) ? arr.length : 0;
|
|
227
|
-
} catch {
|
|
228
|
-
return 0;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
166
|
// ---------------------------------------------------------------------------
|
|
233
|
-
//
|
|
167
|
+
// Source orchestrator
|
|
234
168
|
// ---------------------------------------------------------------------------
|
|
235
169
|
|
|
236
|
-
function
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
// ---------------------------------------------------------------------------
|
|
243
|
-
// Edges: temporal
|
|
244
|
-
// ---------------------------------------------------------------------------
|
|
245
|
-
|
|
246
|
-
function buildTemporalEdges(nodes: MemoryGraphNode[]): MemoryGraphEdge[] {
|
|
170
|
+
function buildUnvalidatedGraph(
|
|
171
|
+
sessionId: string,
|
|
172
|
+
stateDir: string,
|
|
173
|
+
): { nodes: MemoryGraphNode[]; edges: MemoryGraphEdge[] } {
|
|
174
|
+
const nodes: MemoryGraphNode[] = [];
|
|
247
175
|
const edges: MemoryGraphEdge[] = [];
|
|
248
|
-
if (nodes.length < 2) return edges;
|
|
249
176
|
|
|
250
|
-
let
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
target: cur.id,
|
|
257
|
-
weight: 1.0,
|
|
258
|
-
type: "temporal",
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
prev = cur;
|
|
262
|
-
}
|
|
263
|
-
return edges;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
// ---------------------------------------------------------------------------
|
|
267
|
-
// Edges: semantic (cosine similarity)
|
|
268
|
-
// ---------------------------------------------------------------------------
|
|
269
|
-
|
|
270
|
-
function buildSemanticEdges(
|
|
271
|
-
nodes: MemoryGraphNode[],
|
|
272
|
-
_nodeIndex: Map<string, number>,
|
|
273
|
-
threshold: number,
|
|
274
|
-
maxPerNode: number,
|
|
275
|
-
): MemoryGraphEdge[] {
|
|
276
|
-
if (nodes.length < 2) return [];
|
|
277
|
-
const db = openStore();
|
|
278
|
-
|
|
279
|
-
// Retrieve embeddings from DB for each node
|
|
280
|
-
const embeddings = new Map<string, number[]>();
|
|
281
|
-
const placeholders = nodes.map(() => "?").join(",");
|
|
282
|
-
const ids = nodes.map((n) => n.id);
|
|
283
|
-
const rows = db
|
|
284
|
-
.prepare(`SELECT id, embedding_blob FROM context_chunks WHERE id IN (${placeholders})`)
|
|
285
|
-
.all(...ids) as unknown as Array<{ id: string; embedding_blob: Uint8Array | null }>;
|
|
286
|
-
|
|
287
|
-
for (const row of rows) {
|
|
288
|
-
const emb = decodeEmbedding(row.embedding_blob as Uint8Array | null | undefined);
|
|
289
|
-
if (emb.length > 0) {
|
|
290
|
-
embeddings.set(row.id, emb);
|
|
291
|
-
}
|
|
177
|
+
let db: DatabaseSync;
|
|
178
|
+
try {
|
|
179
|
+
db = openStore(stateDir);
|
|
180
|
+
} catch {
|
|
181
|
+
log.warn("graph_source_unavailable", { detail: "Cannot open store" });
|
|
182
|
+
return { nodes: [], edges: [] };
|
|
292
183
|
}
|
|
293
184
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
const bEmb = embeddings.get(other.id);
|
|
308
|
-
if (!bEmb) continue;
|
|
309
|
-
|
|
310
|
-
const sim = cosineSimilarity(aEmb, bEmb);
|
|
311
|
-
if (sim >= threshold) {
|
|
312
|
-
candidates.push({ target: other.id, weight: sim });
|
|
185
|
+
try {
|
|
186
|
+
// Source: checkpoints (always on)
|
|
187
|
+
buildCheckpointNodes(db, sessionId, nodes, edges);
|
|
188
|
+
|
|
189
|
+
// Source A: turns (structural, metadata-only)
|
|
190
|
+
if (areTurnsEnabled()) {
|
|
191
|
+
try {
|
|
192
|
+
buildTurnNodes(db, sessionId, nodes, edges);
|
|
193
|
+
} catch (err) {
|
|
194
|
+
log.warn("graph_source_unavailable", {
|
|
195
|
+
source: "turns",
|
|
196
|
+
detail: String(err),
|
|
197
|
+
});
|
|
313
198
|
}
|
|
314
199
|
}
|
|
315
200
|
|
|
316
|
-
//
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
201
|
+
// Source B: turn content (raw_transcript join, embedding-based)
|
|
202
|
+
if (isTurnContentEnabled()) {
|
|
203
|
+
try {
|
|
204
|
+
buildTurnContentNodes(db, sessionId, nodes, edges);
|
|
205
|
+
} catch (err) {
|
|
206
|
+
log.warn("graph_source_unavailable", {
|
|
207
|
+
source: "turn-content",
|
|
208
|
+
detail: String(err),
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
} else if (isTurnContentFlaggedOn() && !isTurnContentEnabled()) {
|
|
212
|
+
log.warn("graph_source_unavailable", {
|
|
213
|
+
source: "turn-content",
|
|
214
|
+
detail: "dbMirror is OFF -- no raw_transcript available",
|
|
325
215
|
});
|
|
326
216
|
}
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
return edges;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
// ---------------------------------------------------------------------------
|
|
333
|
-
// Edges: RAPTOR parent–child
|
|
334
|
-
// ---------------------------------------------------------------------------
|
|
335
|
-
|
|
336
|
-
function buildRaptorEdges(
|
|
337
|
-
nodes: MemoryGraphNode[],
|
|
338
|
-
sessionId: string | undefined,
|
|
339
|
-
stateDir: string,
|
|
340
|
-
nodeIndex: Map<string, number>,
|
|
341
|
-
): MemoryGraphEdge[] {
|
|
342
|
-
const edges: MemoryGraphEdge[] = [];
|
|
343
217
|
|
|
344
|
-
|
|
345
|
-
if (
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
for (const row of sessionRows) {
|
|
354
|
-
enrichRaptorForSession(row.session_id as string, stateDir, nodeIndex, nodes, edges);
|
|
218
|
+
// Source C: memories
|
|
219
|
+
if (areMemoriesEnabled()) {
|
|
220
|
+
try {
|
|
221
|
+
buildMemoryNodes(db, sessionId, nodes, edges);
|
|
222
|
+
} catch (err) {
|
|
223
|
+
log.warn("graph_source_unavailable", {
|
|
224
|
+
source: "memories",
|
|
225
|
+
detail: String(err),
|
|
226
|
+
});
|
|
355
227
|
}
|
|
356
228
|
}
|
|
357
|
-
} catch (err) {
|
|
358
|
-
log.warn("RAPTOR edge build failed (non-fatal)", { error: String(err) });
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
return edges;
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
function enrichRaptorForSession(
|
|
365
|
-
sessId: string,
|
|
366
|
-
stateDir: string,
|
|
367
|
-
nodeIndex: Map<string, number>,
|
|
368
|
-
nodes: MemoryGraphNode[],
|
|
369
|
-
edges: MemoryGraphEdge[],
|
|
370
|
-
): void {
|
|
371
|
-
const raptorNodes = listRaptorNodes(sessId, stateDir);
|
|
372
|
-
|
|
373
|
-
for (const rn of raptorNodes) {
|
|
374
|
-
const idx = nodeIndex.get(rn.id);
|
|
375
|
-
if (idx !== undefined) {
|
|
376
|
-
// Annotate the graph node with the RAPTOR level
|
|
377
|
-
nodes[idx].raptorLevel = rn.level;
|
|
378
|
-
}
|
|
379
229
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
target: rn.parentId,
|
|
386
|
-
weight: Math.max(0.1, 1.0 - rn.level * 0.1), // higher levels = weaker link
|
|
387
|
-
type: "raptor_parent",
|
|
388
|
-
});
|
|
230
|
+
// RAPTOR annotations on checkpoint nodes
|
|
231
|
+
try {
|
|
232
|
+
addRaptorAnnotations(sessionId, stateDir, nodes, edges);
|
|
233
|
+
} catch {
|
|
234
|
+
// non-fatal
|
|
389
235
|
}
|
|
236
|
+
} finally {
|
|
237
|
+
// DatabaseSync has no close in Node 22 -- leave GC to clean up
|
|
390
238
|
}
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
// ---------------------------------------------------------------------------
|
|
394
|
-
// Edge deduplication
|
|
395
|
-
// ---------------------------------------------------------------------------
|
|
396
|
-
|
|
397
|
-
function deduplicateEdges(edges: MemoryGraphEdge[]): MemoryGraphEdge[] {
|
|
398
|
-
const seen = new Map<string, MemoryGraphEdge>();
|
|
399
239
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
if (!existing) {
|
|
406
|
-
seen.set(keyA, e);
|
|
407
|
-
} else if (e.weight > existing.weight) {
|
|
408
|
-
// Replace with higher-weight edge
|
|
409
|
-
seen.delete(keyA);
|
|
410
|
-
seen.delete(keyB);
|
|
411
|
-
seen.set(keyA, e);
|
|
412
|
-
}
|
|
413
|
-
}
|
|
240
|
+
// Pre-gate edge deduplication
|
|
241
|
+
const deduped = deduplicateEdges(edges);
|
|
242
|
+
edges.length = 0;
|
|
243
|
+
edges.push(...deduped);
|
|
414
244
|
|
|
415
|
-
return
|
|
245
|
+
return { nodes, edges };
|
|
416
246
|
}
|
|
417
247
|
|
|
418
248
|
// ---------------------------------------------------------------------------
|
|
419
|
-
//
|
|
249
|
+
// Helpers
|
|
420
250
|
// ---------------------------------------------------------------------------
|
|
421
251
|
|
|
422
|
-
function
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
let
|
|
427
|
-
let
|
|
428
|
-
let
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
252
|
+
function countSourcesByType(
|
|
253
|
+
nodes: MemoryGraphNode[],
|
|
254
|
+
): GraphValidationReport["sources"] {
|
|
255
|
+
let checkpoint = 0;
|
|
256
|
+
let turn = 0;
|
|
257
|
+
let turnContent = 0;
|
|
258
|
+
let memory = 0;
|
|
259
|
+
for (const n of nodes) {
|
|
260
|
+
switch (n.nodeType) {
|
|
261
|
+
case "checkpoint":
|
|
262
|
+
checkpoint++;
|
|
263
|
+
break;
|
|
264
|
+
case "turn":
|
|
265
|
+
turn++;
|
|
266
|
+
break;
|
|
267
|
+
case "turn-content":
|
|
268
|
+
turnContent++;
|
|
269
|
+
break;
|
|
270
|
+
case "memory":
|
|
271
|
+
memory++;
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
434
274
|
}
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
return denom === 0 ? 0 : dot / denom;
|
|
438
|
-
}
|
|
275
|
+
return { checkpoint, turn, turnContent, memory };
|
|
276
|
+
}
|