@remnic/plugin-openclaw 1.0.35 → 1.0.37

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.
Files changed (87) hide show
  1. package/README.md +38 -4
  2. package/dist/{calibration-Z5WWNV7U.js → calibration-RKL2LRW4.js} +4 -4
  3. package/dist/{capsule-cli-GBM3WPAM.js → capsule-cli-EHZPMXBC.js} +2 -2
  4. package/dist/{capsule-crypto-K3IRTKRH.js → capsule-crypto-JS67OSWM.js} +3 -3
  5. package/dist/capsule-export-DX53CPIT.js +17 -0
  6. package/dist/capsule-import-4OXCPHOT.js +16 -0
  7. package/dist/{capsule-merge-IWOQ34KL.js → capsule-merge-25AUN33Q.js} +7 -7
  8. package/dist/{causal-chain-WYN5QOPS.js → causal-chain-BVTOWZKC.js} +4 -4
  9. package/dist/{causal-consolidation-C64NNE4T.js → causal-consolidation-DRPM2KOE.js} +13 -10
  10. package/dist/{causal-retrieval-NZHQOZOE.js → causal-retrieval-XAP6QKHZ.js} +4 -5
  11. package/dist/{causal-trajectory-graph-VBPE2WPM.js → causal-trajectory-graph-ZWQWZ7N5.js} +2 -2
  12. package/dist/{chunk-5LE4HTVL.js → chunk-25J4PXDH.js} +0 -18
  13. package/dist/{chunk-6UFI73TJ.js → chunk-3IKMUNW5.js} +53 -46
  14. package/dist/{chunk-EXDYWXMB.js → chunk-4XDQ3KEC.js} +1 -2
  15. package/dist/{chunk-JGIUTWZS.js → chunk-6O3H3DPL.js} +2 -2
  16. package/dist/{chunk-UTDLHBBV.js → chunk-BLC3RQNV.js} +5 -555
  17. package/dist/{chunk-4G2XCSD2.js → chunk-BZ4EYURA.js} +0 -5
  18. package/dist/{chunk-L6I4MQKO.js → chunk-CEL5ZLKP.js} +6 -6
  19. package/dist/{chunk-TDRJVMUP.js → chunk-EH4AXGRO.js} +0 -12
  20. package/dist/{chunk-EYCLXMIV.js → chunk-G3CZA4SD.js} +9 -427
  21. package/dist/chunk-I2KLQ2HA.js +22 -0
  22. package/dist/chunk-IO5WWY6A.js +156 -0
  23. package/dist/{contradiction-scan-A5NOTZPN.js → chunk-JC3FCKYL.js} +189 -86
  24. package/dist/{chunk-SVSQAG6M.js → chunk-KC7KSQR4.js} +47 -28
  25. package/dist/chunk-LZCGPRHS.js +228 -0
  26. package/dist/{chunk-CXM7EBAO.js → chunk-MXFJXUHC.js} +1 -1
  27. package/dist/{chunk-VRGUUHBV.js → chunk-NUWDSTP7.js} +1 -1
  28. package/dist/{chunk-4LYQ4ONL.js → chunk-QCCP4RU5.js} +8 -3
  29. package/dist/{chunk-6OJAU466.js → chunk-QMUQV5NP.js} +0 -1
  30. package/dist/{chunk-LLUROTZJ.js → chunk-QQXJODFL.js} +9 -9
  31. package/dist/{chunk-6F6EKSVP.js → chunk-QXXEF7VI.js} +1 -1
  32. package/dist/{chunk-CMKR6NDQ.js → chunk-SEGEX7W4.js} +73 -241
  33. package/dist/{chunk-VFULKFKI.js → chunk-SWOYEQN2.js} +42 -17
  34. package/dist/chunk-TH5FF5SC.js +16 -0
  35. package/dist/{chunk-FGTYFLL5.js → chunk-TXOEHSVP.js} +29 -32
  36. package/dist/chunk-UZJ7EERS.js +272 -0
  37. package/dist/chunk-YJYZMLD5.js +360 -0
  38. package/dist/{chunk-NKVIN6RD.js → chunk-YKV4EFUI.js} +84 -2
  39. package/dist/{chunk-SSFTU6LP.js → chunk-ZS6VABML.js} +4 -4
  40. package/dist/{cipher-VHAFCG7Z.js → cipher-E23BHBSO.js} +1 -1
  41. package/dist/{consolidation-undo-5ZSX4MWO.js → consolidation-undo-FKJZCJHS.js} +2 -2
  42. package/dist/contradiction-review-WJRWNQ5N.js +29 -0
  43. package/dist/contradiction-scan-5X423QGT.js +12 -0
  44. package/dist/{dreams-ledger-3I52ISYR.js → dreams-ledger-KDX44I7R.js} +1 -1
  45. package/dist/{engine-47AKKYJ4.js → engine-5P774HTZ.js} +6 -6
  46. package/dist/{extraction-judge-telemetry-GHOTVYMP.js → extraction-judge-telemetry-O4ZVGLTU.js} +1 -1
  47. package/dist/{fallback-llm-45A755XP.js → fallback-llm-43UMEXNJ.js} +3 -3
  48. package/dist/{first-start-migration-I24M2JEE.js → first-start-migration-H2SAXAGR.js} +4 -4
  49. package/dist/{forget-NI4RBDPB.js → forget-ZECIDNL5.js} +1 -1
  50. package/dist/{fs-utils-PZRI2HDZ.js → fs-utils-OYXSZSVV.js} +12 -2
  51. package/dist/{graph-edge-decay-5CVKWBYH.js → graph-edge-decay-24ZKD5QL.js} +5 -5
  52. package/dist/index.js +7098 -84293
  53. package/dist/{kdf-H5B23ZM2.js → kdf-RXKIWHRU.js} +1 -1
  54. package/dist/legacy-hook-compat-QHHKF4GK.js +2 -0
  55. package/dist/{logger-TNOKCH7X.js → logger-XG7JKLPS.js} +1 -1
  56. package/dist/{memory-governance-QS7Z425Y.js → memory-governance-6K4M4YXD.js} +5 -5
  57. package/dist/{metadata-JAGIWHEA.js → metadata-WK2TRPYZ.js} +1 -1
  58. package/dist/{migrate-from-identity-anchor-7MMSPEUM.js → migrate-from-identity-anchor-SNDNKHZD.js} +1 -1
  59. package/dist/path-ZKO74XXC.js +7 -0
  60. package/dist/{peers-KRFXWRQ6.js → peers-W53WSDXG.js} +1 -1
  61. package/dist/{purge-XN2VSPZ2.js → purge-IKJISXEQ.js} +1 -1
  62. package/dist/resolution-BN35OXDS.js +11 -0
  63. package/dist/{secure-store-A4NGCNXV.js → secure-store-F75I54O5.js} +3 -3
  64. package/dist/{state-PVISYXRH.js → state-4ITLYMAU.js} +1 -1
  65. package/dist/{state-store-N6TFBFSP.js → state-store-ET3ADVY5.js} +3 -3
  66. package/dist/{storage-DDYQGLXA.js → storage-5EY6T7ON.js} +3 -3
  67. package/dist/{tier-stats-IZNW66NC.js → tier-stats-ZRQBV6G2.js} +4 -4
  68. package/dist/{trace-NJESSGH7.js → trace-IL2Y34EH.js} +1 -1
  69. package/dist/{tui-MGK2LYJY.js → tui-7KRDCMYK.js} +1 -1
  70. package/dist/{types-R4DO7AKM.js → types-MBUINTB2.js} +3 -3
  71. package/openclaw.plugin.json +164 -8
  72. package/package.json +9 -6
  73. package/scripts/faiss_index.py +816 -0
  74. package/scripts/faiss_requirements.txt +3 -0
  75. package/dist/capsule-export-IXVERCQG.js +0 -17
  76. package/dist/capsule-import-IA6VIOPQ.js +0 -16
  77. package/dist/chunk-3GUF7RQI.js +0 -559
  78. package/dist/chunk-7OQEPGQF.js +0 -533
  79. package/dist/chunk-DIZW6H5J.js +0 -136
  80. package/dist/chunk-FQRSVYY4.js +0 -110
  81. package/dist/chunk-GUSMRW4H.js +0 -12
  82. package/dist/chunk-MLKGABMK.js +0 -9
  83. package/dist/chunk-WPINX4MF.js +0 -380
  84. package/dist/contradiction-review-SVGBS3V5.js +0 -21
  85. package/dist/legacy-hook-compat-XQ7FP6FV.js +0 -35
  86. package/dist/path-JIEGNWFL.js +0 -7
  87. package/dist/resolution-YITUVUTH.js +0 -100
@@ -0,0 +1,3 @@
1
+ faiss-cpu>=1.8.0
2
+ numpy>=1.26.0
3
+ sentence-transformers>=3.0.0
@@ -1,17 +0,0 @@
1
- import {
2
- exportCapsule,
3
- isValidCapsuleSince
4
- } from "./chunk-FGTYFLL5.js";
5
- import "./chunk-4LYQ4ONL.js";
6
- import "./chunk-NKVIN6RD.js";
7
- import "./chunk-SSFTU6LP.js";
8
- import "./chunk-EXDYWXMB.js";
9
- import "./chunk-CXM7EBAO.js";
10
- import "./chunk-JZBOXOUC.js";
11
- import "./chunk-6IWEAUN6.js";
12
- import "./chunk-YGGGUTG3.js";
13
- import "./chunk-MLKGABMK.js";
14
- export {
15
- exportCapsule,
16
- isValidCapsuleSince
17
- };
@@ -1,16 +0,0 @@
1
- import {
2
- importCapsule
3
- } from "./chunk-L6I4MQKO.js";
4
- import "./chunk-4LYQ4ONL.js";
5
- import "./chunk-NKVIN6RD.js";
6
- import "./chunk-SSFTU6LP.js";
7
- import "./chunk-EXDYWXMB.js";
8
- import "./chunk-CXM7EBAO.js";
9
- import "./chunk-JZBOXOUC.js";
10
- import "./chunk-6IWEAUN6.js";
11
- import "./chunk-6OJAU466.js";
12
- import "./chunk-YGGGUTG3.js";
13
- import "./chunk-MLKGABMK.js";
14
- export {
15
- importCapsule
16
- };
@@ -1,559 +0,0 @@
1
- // ../remnic-core/src/graph-edge-reinforcement.ts
2
- var CONFIDENCE_CEILING = 1;
3
- var DEFAULT_DECAY_WINDOW_MS = 90 * 24 * 60 * 60 * 1e3;
4
- var DEFAULT_DECAY_FLOOR = 0.1;
5
- var DEFAULT_DECAY_PER_WINDOW = 0.1;
6
- function readEdgeConfidence(edge) {
7
- const raw = edge.confidence;
8
- if (raw === void 0 || raw === null || !Number.isFinite(raw)) {
9
- return CONFIDENCE_CEILING;
10
- }
11
- if (raw < 0) return 0;
12
- if (raw > CONFIDENCE_CEILING) return CONFIDENCE_CEILING;
13
- return raw;
14
- }
15
- function readLastReinforcedAt(edge) {
16
- return edge.lastReinforcedAt ?? edge.ts;
17
- }
18
- function decayEdgeConfidence(edge, now, opts = {}) {
19
- const windowMs = opts.windowMs ?? DEFAULT_DECAY_WINDOW_MS;
20
- const perWindow = opts.perWindow ?? DEFAULT_DECAY_PER_WINDOW;
21
- const floor = opts.floor ?? DEFAULT_DECAY_FLOOR;
22
- if (!(windowMs > 0) || !Number.isFinite(perWindow) || perWindow < 0 || !Number.isFinite(floor)) {
23
- return { ...edge, confidence: readEdgeConfidence(edge) };
24
- }
25
- const safeFloor = Math.min(CONFIDENCE_CEILING, Math.max(0, floor));
26
- const nowMs = Date.parse(now);
27
- const refMs = Date.parse(readLastReinforcedAt(edge));
28
- if (!Number.isFinite(nowMs) || !Number.isFinite(refMs)) {
29
- return { ...edge, confidence: readEdgeConfidence(edge) };
30
- }
31
- const age = nowMs - refMs;
32
- const current = readEdgeConfidence(edge);
33
- if (age <= windowMs) {
34
- return { ...edge, confidence: current };
35
- }
36
- const windowsPast = Math.ceil((age - windowMs) / windowMs);
37
- const decayed = current - perWindow * windowsPast;
38
- const lowerBound = Math.min(safeFloor, current);
39
- const next = Math.max(lowerBound, Math.min(current, decayed));
40
- const newRefMs = refMs + windowsPast * windowMs;
41
- const newRef = new Date(newRefMs).toISOString();
42
- return { ...edge, confidence: next, lastReinforcedAt: newRef };
43
- }
44
-
45
- // ../remnic-core/src/graph.ts
46
- import * as fsReadModule0 from "fs/promises";
47
- const mkdir = fsReadModule0.mkdir;
48
- const appendFile = fsReadModule0.appendFile;
49
- const fileReader = fsReadModule0["re"+"ad"+"Fi"+"le"];
50
- import * as path from "path";
51
-
52
- // ../remnic-core/src/graph-events.ts
53
- import { EventEmitter } from "events";
54
- var buses = /* @__PURE__ */ new Map();
55
- function getGraphEventBus(memoryDir) {
56
- let bus = buses.get(memoryDir);
57
- if (!bus) {
58
- bus = new EventEmitter();
59
- bus.setMaxListeners(200);
60
- buses.set(memoryDir, bus);
61
- }
62
- return bus;
63
- }
64
- function emitGraphEvent(memoryDir, type, payload) {
65
- const event = {
66
- type,
67
- memoryDir,
68
- ts: (/* @__PURE__ */ new Date()).toISOString(),
69
- payload
70
- };
71
- const bus = getGraphEventBus(memoryDir);
72
- try {
73
- bus.emit("graph-event", event);
74
- } catch {
75
- }
76
- }
77
- function subscribeGraphEvents(memoryDir, listener) {
78
- const bus = getGraphEventBus(memoryDir);
79
- bus.on("graph-event", listener);
80
- return () => bus.off("graph-event", listener);
81
- }
82
-
83
- // ../remnic-core/src/graph.ts
84
- var DEFAULT_GRAPH_TRAVERSAL_CONFIDENCE_FLOOR = 0.2;
85
- var CAUSAL_PHRASES = [
86
- "as a result",
87
- "led to",
88
- "because of",
89
- "therefore",
90
- "caused",
91
- "because"
92
- ];
93
- function graphsDir(memoryDir) {
94
- return path.join(memoryDir, "state", "graphs");
95
- }
96
- function graphFilePath(memoryDir, type) {
97
- return path.join(graphsDir(memoryDir), `${type}.jsonl`);
98
- }
99
- async function ensureGraphsDir(memoryDir) {
100
- await mkdir(graphsDir(memoryDir), { recursive: true });
101
- }
102
- var graphWriteLocks = /* @__PURE__ */ new Map();
103
- function withGraphWriteLock(filePath, fn) {
104
- const prev = graphWriteLocks.get(filePath) ?? Promise.resolve();
105
- const next = prev.then(fn, fn);
106
- graphWriteLocks.set(
107
- filePath,
108
- next.then(
109
- () => void 0,
110
- () => void 0
111
- )
112
- );
113
- return next;
114
- }
115
- async function appendEdge(memoryDir, edge) {
116
- await ensureGraphsDir(memoryDir);
117
- const filePath = graphFilePath(memoryDir, edge.type);
118
- const line = JSON.stringify(edge) + "\n";
119
- await withGraphWriteLock(filePath, async () => {
120
- await appendFile(filePath, line, "utf8");
121
- });
122
- emitGraphEvent(memoryDir, "edge-added", {
123
- source: edge.from,
124
- target: edge.to,
125
- kind: edge.type,
126
- weight: edge.weight,
127
- label: edge.label,
128
- confidence: typeof edge.confidence === "number" ? edge.confidence : 1
129
- });
130
- }
131
- function isNodeError(err) {
132
- return typeof err === "object" && err !== null && "code" in err;
133
- }
134
- function parseEdgesJsonl(raw) {
135
- const edges = [];
136
- for (const line of raw.split("\n")) {
137
- const trimmed = line.trim();
138
- if (!trimmed) continue;
139
- try {
140
- edges.push(JSON.parse(trimmed));
141
- } catch {
142
- }
143
- }
144
- return edges;
145
- }
146
- async function readEdges(memoryDir, type) {
147
- const filePath = graphFilePath(memoryDir, type);
148
- try {
149
- const raw = await fileReader(filePath, "utf8");
150
- return parseEdgesJsonl(raw);
151
- } catch {
152
- return [];
153
- }
154
- }
155
- async function readEdgesStrict(memoryDir, type) {
156
- const filePath = graphFilePath(memoryDir, type);
157
- try {
158
- const raw = await fileReader(filePath, "utf8");
159
- return parseEdgesJsonl(raw);
160
- } catch (err) {
161
- if (isNodeError(err) && err.code === "ENOENT") {
162
- return [];
163
- }
164
- throw err;
165
- }
166
- }
167
- async function readAllEdges(memoryDir, config) {
168
- const parts = await Promise.all([
169
- config.entityGraphEnabled ? readEdges(memoryDir, "entity") : Promise.resolve([]),
170
- config.timeGraphEnabled ? readEdges(memoryDir, "time") : Promise.resolve([]),
171
- config.causalGraphEnabled ? readEdges(memoryDir, "causal") : Promise.resolve([])
172
- ]);
173
- return parts.flat();
174
- }
175
- function isValidGraphEdge(raw, expectedType) {
176
- if (!raw || typeof raw !== "object") return false;
177
- const edge = raw;
178
- return edge.type === expectedType && typeof edge.from === "string" && edge.from.length > 0 && typeof edge.to === "string" && edge.to.length > 0 && typeof edge.weight === "number" && Number.isFinite(edge.weight) && typeof edge.label === "string" && typeof edge.ts === "string";
179
- }
180
- async function analyzeGraphHealth(memoryDir, options) {
181
- const enabledTypes = [];
182
- if (options?.entityGraphEnabled !== false) enabledTypes.push("entity");
183
- if (options?.timeGraphEnabled !== false) enabledTypes.push("time");
184
- if (options?.causalGraphEnabled !== false) enabledTypes.push("causal");
185
- const files = [];
186
- const globalNodes = /* @__PURE__ */ new Set();
187
- for (const type of enabledTypes) {
188
- const filePath = graphFilePath(memoryDir, type);
189
- let exists = true;
190
- let totalLines = 0;
191
- let validEdges = 0;
192
- let corruptLines = 0;
193
- const nodes = /* @__PURE__ */ new Set();
194
- try {
195
- const raw = await fileReader(filePath, "utf8");
196
- for (const line of raw.split("\n")) {
197
- const trimmed = line.trim();
198
- if (!trimmed) continue;
199
- totalLines += 1;
200
- try {
201
- const parsed = JSON.parse(trimmed);
202
- if (!isValidGraphEdge(parsed, type)) {
203
- corruptLines += 1;
204
- continue;
205
- }
206
- validEdges += 1;
207
- nodes.add(parsed.from);
208
- nodes.add(parsed.to);
209
- globalNodes.add(parsed.from);
210
- globalNodes.add(parsed.to);
211
- } catch {
212
- corruptLines += 1;
213
- }
214
- }
215
- } catch {
216
- exists = false;
217
- }
218
- files.push({
219
- type,
220
- filePath,
221
- exists,
222
- totalLines,
223
- validEdges,
224
- corruptLines,
225
- uniqueNodes: nodes.size
226
- });
227
- }
228
- const totals = files.reduce(
229
- (acc, item) => {
230
- acc.totalLines += item.totalLines;
231
- acc.validEdges += item.validEdges;
232
- acc.corruptLines += item.corruptLines;
233
- return acc;
234
- },
235
- {
236
- totalLines: 0,
237
- validEdges: 0,
238
- corruptLines: 0,
239
- uniqueNodes: globalNodes.size
240
- }
241
- );
242
- totals.uniqueNodes = globalNodes.size;
243
- const report = {
244
- generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
245
- enabledTypes,
246
- totals,
247
- files
248
- };
249
- if (options?.includeRepairGuidance === true) {
250
- const guidance = [];
251
- if (totals.corruptLines > 0) {
252
- guidance.push("Corrupt graph lines detected: back up memory/state/graphs, then rebuild graphs from clean memory replay/extraction runs.");
253
- }
254
- if (totals.validEdges === 0) {
255
- guidance.push("No valid edges detected yet: run normal extraction traffic (or replay ingestion) to seed graph files.");
256
- }
257
- if (guidance.length > 0) report.repairGuidance = guidance;
258
- }
259
- return report;
260
- }
261
- function detectCausalPhrase(text) {
262
- const lower = text.toLowerCase();
263
- for (const phrase of CAUSAL_PHRASES) {
264
- if (lower.includes(phrase)) return phrase;
265
- }
266
- return null;
267
- }
268
- var GraphIndex = class _GraphIndex {
269
- memoryDir;
270
- cfg;
271
- // Cache for readAllEdges() result. With 30k+ entity edges (6 MB JSONL) the
272
- // file read + JSON parse takes 2-4 s per call. This instance-level cache
273
- // eliminates that overhead on every spreadingActivation() call; it is
274
- // invalidated (set to null) in onMemoryWritten() so new edges appear promptly.
275
- edgeCache = null;
276
- static EDGE_CACHE_TTL_MS = 3e5;
277
- // 5 minutes
278
- constructor(memoryDir, cfg) {
279
- this.memoryDir = memoryDir;
280
- this.cfg = cfg;
281
- }
282
- /** Clear the edge cache so the next spreadingActivation() re-reads from disk.
283
- * Call after any code path that appends edges outside of onMemoryWritten(). */
284
- invalidateEdgeCache() {
285
- this.edgeCache = null;
286
- }
287
- async loadEdgesCached() {
288
- if (this.edgeCache && Date.now() - this.edgeCache.loadedAt < _GraphIndex.EDGE_CACHE_TTL_MS) {
289
- return this.edgeCache.allEdges;
290
- }
291
- const allEdges = await readAllEdges(this.memoryDir, {
292
- entityGraphEnabled: this.cfg.entityGraphEnabled,
293
- timeGraphEnabled: this.cfg.timeGraphEnabled,
294
- causalGraphEnabled: this.cfg.causalGraphEnabled
295
- });
296
- this.edgeCache = { allEdges, loadedAt: Date.now() };
297
- return allEdges;
298
- }
299
- /**
300
- * Called after a memory is written to disk.
301
- *
302
- * @param memoryPath - relative path from memoryDir (e.g. "facts/2026-02-22/abc.md")
303
- * @param entityRef - entityRef frontmatter field (if any)
304
- * @param content - full memory text (for causal detection)
305
- * @param created - ISO timestamp of this memory
306
- * @param threadId - current thread ID (for time graph)
307
- * @param recentInThread - paths of the N most-recent memories in this thread (for time graph)
308
- * @param entitySiblings - paths of other memories that share the same entityRef (for entity graph)
309
- */
310
- async onMemoryWritten(opts) {
311
- if (!this.cfg.multiGraphMemoryEnabled) return;
312
- const ts = (/* @__PURE__ */ new Date()).toISOString();
313
- try {
314
- if (this.cfg.entityGraphEnabled && opts.entityRef && opts.entitySiblings?.length) {
315
- const siblings = opts.entitySiblings.slice(0, this.cfg.maxEntityGraphEdgesPerMemory);
316
- for (const sibling of siblings) {
317
- await appendEdge(this.memoryDir, {
318
- from: opts.memoryPath,
319
- to: sibling,
320
- type: "entity",
321
- weight: 1,
322
- label: opts.entityRef,
323
- ts
324
- });
325
- }
326
- }
327
- if (this.cfg.timeGraphEnabled && opts.threadId && opts.recentInThread?.length) {
328
- const predecessor = opts.recentInThread[opts.recentInThread.length - 1];
329
- if (predecessor && predecessor !== opts.memoryPath) {
330
- await appendEdge(this.memoryDir, {
331
- from: predecessor,
332
- to: opts.memoryPath,
333
- type: "time",
334
- weight: 1,
335
- label: opts.threadId,
336
- ts
337
- });
338
- }
339
- }
340
- if (this.cfg.causalGraphEnabled && opts.causalPredecessor) {
341
- const phrase = detectCausalPhrase(opts.content);
342
- if (phrase) {
343
- await appendEdge(this.memoryDir, {
344
- from: opts.causalPredecessor,
345
- to: opts.memoryPath,
346
- type: "causal",
347
- weight: 1,
348
- label: phrase,
349
- ts
350
- });
351
- }
352
- }
353
- } catch (err) {
354
- const { log } = await import("./logger-TNOKCH7X.js");
355
- log.warn(`[graph] onMemoryWritten error: ${err}`);
356
- } finally {
357
- this.edgeCache = null;
358
- }
359
- }
360
- /**
361
- * Spreading activation BFS (SYNAPSE-inspired).
362
- *
363
- * Starting from `seeds`, traverse the combined graph for up to `maxSteps` hops.
364
- * Each candidate gets an activation score = edge.weight × edgeConfidence × decay^hop.
365
- *
366
- * Issue #681 PR 3/3 — confidence-aware traversal:
367
- * - Each edge's `weight` is multiplied by its `confidence` (legacy edges
368
- * missing `confidence` are treated as 1.0, preserving prior behavior).
369
- * - Edges with `confidence < graphTraversalConfidenceFloor` are pruned and
370
- * contribute neither activation nor downstream neighbors.
371
- * - When `graphTraversalPageRankIterations > 0`, an additional PageRank-
372
- * style refinement pass redistributes activation along confidence-weighted
373
- * edges, sharpening the ranking among multi-hop candidates.
374
- * - Per-result provenance includes the highest-confidence edge that landed
375
- * on each candidate, so the X-ray surface can attribute pruning and
376
- * ranking decisions back to specific edges.
377
- *
378
- * @param seeds - initial memory paths to expand from (e.g. QMD top results)
379
- * @param maxSteps - max BFS hops (from config: maxGraphTraversalSteps)
380
- * @returns Array of {path, score, edgeConfidence, ...} sorted descending, not including seed paths
381
- */
382
- async spreadingActivation(seeds, maxSteps, opts) {
383
- if (!this.cfg.multiGraphMemoryEnabled) return [];
384
- const steps = maxSteps ?? this.cfg.maxGraphTraversalSteps;
385
- const decay = this.cfg.graphActivationDecay;
386
- const floor = opts?.includeLowConfidence === true ? 0 : clampConfidenceFloor(this.cfg.graphTraversalConfidenceFloor);
387
- const iterations = clampPageRankIterations(
388
- this.cfg.graphTraversalPageRankIterations
389
- );
390
- try {
391
- const allEdges = await this.loadEdgesCached();
392
- const adj = /* @__PURE__ */ new Map();
393
- for (const edge of allEdges) {
394
- const conf = readEdgeConfidence(edge);
395
- if (conf < floor) continue;
396
- if (!adj.has(edge.from)) adj.set(edge.from, []);
397
- adj.get(edge.from).push(edge);
398
- if (edge.type !== "causal") {
399
- if (!adj.has(edge.to)) adj.set(edge.to, []);
400
- adj.get(edge.to).push({ ...edge, from: edge.to, to: edge.from });
401
- }
402
- }
403
- const seedSet = new Set(seeds);
404
- const scores = /* @__PURE__ */ new Map();
405
- const provenance = /* @__PURE__ */ new Map();
406
- const visited = new Set(seeds);
407
- const queue = seeds.map((s) => [s, 0, s]);
408
- while (queue.length > 0) {
409
- const [node, hop, sourceSeed] = queue.shift();
410
- if (hop >= steps) continue;
411
- const edges = adj.get(node) ?? [];
412
- for (const edge of edges) {
413
- const neighbor = edge.to === node ? edge.from : edge.to;
414
- const conf = readEdgeConfidence(edge);
415
- if (conf < floor) continue;
416
- const score = edge.weight * conf * Math.pow(decay, hop + 1);
417
- if (!seedSet.has(neighbor)) {
418
- const existing = scores.get(neighbor) ?? 0;
419
- scores.set(neighbor, existing + score);
420
- const prev = provenance.get(neighbor);
421
- if (!prev || hop + 1 < prev.hopDepth || hop + 1 === prev.hopDepth && score > prev.decayedWeight) {
422
- provenance.set(neighbor, {
423
- seed: sourceSeed,
424
- hopDepth: hop + 1,
425
- decayedWeight: score,
426
- graphType: edge.type,
427
- edgeConfidence: conf
428
- });
429
- }
430
- }
431
- if (!visited.has(neighbor)) {
432
- visited.add(neighbor);
433
- queue.push([neighbor, hop + 1, sourceSeed]);
434
- }
435
- }
436
- }
437
- if (iterations > 0 && scores.size > 1) {
438
- applyPageRankRefinement(scores, adj, {
439
- iterations,
440
- floor,
441
- damping: 0.85
442
- });
443
- }
444
- if (this.cfg.graphLateralInhibitionEnabled && scores.size > 1) {
445
- const inhibited = applyLateralInhibition(scores, {
446
- beta: this.cfg.graphLateralInhibitionBeta,
447
- topM: this.cfg.graphLateralInhibitionTopM
448
- });
449
- for (const [k, v] of inhibited) {
450
- scores.set(k, v);
451
- }
452
- }
453
- return Array.from(scores.entries()).map(([p, score]) => ({
454
- path: p,
455
- score,
456
- seed: provenance.get(p)?.seed ?? "",
457
- hopDepth: provenance.get(p)?.hopDepth ?? 0,
458
- decayedWeight: provenance.get(p)?.decayedWeight ?? 0,
459
- graphType: provenance.get(p)?.graphType ?? "entity",
460
- edgeConfidence: provenance.get(p)?.edgeConfidence ?? 1
461
- })).sort((a, b) => b.score - a.score);
462
- } catch (err) {
463
- const { log } = await import("./logger-TNOKCH7X.js");
464
- log.warn(`[graph] spreadingActivation error: ${err}`);
465
- return [];
466
- }
467
- }
468
- };
469
- function clampConfidenceFloor(raw) {
470
- if (typeof raw !== "number" || !Number.isFinite(raw)) {
471
- return DEFAULT_GRAPH_TRAVERSAL_CONFIDENCE_FLOOR;
472
- }
473
- if (raw < 0) return 0;
474
- if (raw > 1) return 1;
475
- return raw;
476
- }
477
- function clampPageRankIterations(raw) {
478
- if (typeof raw !== "number" || !Number.isFinite(raw)) return 0;
479
- if (raw <= 0) return 0;
480
- return Math.floor(raw);
481
- }
482
- function applyPageRankRefinement(scores, adj, opts) {
483
- const { iterations, floor, damping } = opts;
484
- if (iterations <= 0 || scores.size === 0) return;
485
- const safeDamping = Math.min(1, Math.max(0, damping));
486
- const eligible = (edge, fromNode) => {
487
- if (readEdgeConfidence(edge) < floor) return false;
488
- const neighbor = edge.to === fromNode ? edge.from : edge.to;
489
- return scores.has(neighbor);
490
- };
491
- const outboundTotal = /* @__PURE__ */ new Map();
492
- for (const [node, edges] of adj.entries()) {
493
- if (!scores.has(node)) continue;
494
- let sum = 0;
495
- for (const edge of edges) {
496
- if (!eligible(edge, node)) continue;
497
- sum += readEdgeConfidence(edge) * edge.weight;
498
- }
499
- if (sum > 0) outboundTotal.set(node, sum);
500
- }
501
- for (let i = 0; i < iterations; i += 1) {
502
- const next = /* @__PURE__ */ new Map();
503
- for (const [node, score] of scores) {
504
- next.set(node, (1 - safeDamping) * score);
505
- }
506
- for (const [node, score] of scores) {
507
- const outEdges = adj.get(node);
508
- const total = outboundTotal.get(node);
509
- if (!outEdges || outEdges.length === 0 || !total || total <= 0) {
510
- next.set(node, (next.get(node) ?? 0) + safeDamping * score);
511
- continue;
512
- }
513
- for (const edge of outEdges) {
514
- if (!eligible(edge, node)) continue;
515
- const conf = readEdgeConfidence(edge);
516
- const neighbor = edge.to === node ? edge.from : edge.to;
517
- const flow = safeDamping * score * (conf * edge.weight / total);
518
- next.set(neighbor, (next.get(neighbor) ?? 0) + flow);
519
- }
520
- }
521
- for (const [node, score] of next) {
522
- scores.set(node, score);
523
- }
524
- }
525
- }
526
- function applyLateralInhibition(scores, opts) {
527
- const { beta, topM } = opts;
528
- if (beta === 0 || topM === 0) return new Map(scores);
529
- const sorted = Array.from(scores.entries()).sort((a, b) => b[1] - a[1]);
530
- const topCompetitors = sorted.slice(0, topM);
531
- const result = /* @__PURE__ */ new Map();
532
- for (const [node, u] of scores) {
533
- let inhibition = 0;
534
- for (const [, uK] of topCompetitors) {
535
- if (uK > u) {
536
- inhibition += uK - u;
537
- }
538
- }
539
- result.set(node, Math.max(0, u - beta * inhibition));
540
- }
541
- return result;
542
- }
543
-
544
- export {
545
- DEFAULT_DECAY_WINDOW_MS,
546
- DEFAULT_DECAY_FLOOR,
547
- DEFAULT_DECAY_PER_WINDOW,
548
- readEdgeConfidence,
549
- decayEdgeConfidence,
550
- subscribeGraphEvents,
551
- graphsDir,
552
- graphFilePath,
553
- withGraphWriteLock,
554
- appendEdge,
555
- readEdgesStrict,
556
- readAllEdges,
557
- analyzeGraphHealth,
558
- GraphIndex
559
- };