@remnic/plugin-openclaw 1.0.34 → 1.0.36
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/README.md +59 -10
- package/dist/{calibration-JD4AU7FB.js → calibration-RKL2LRW4.js} +4 -4
- package/dist/{capsule-cli-GBM3WPAM.js → capsule-cli-EHZPMXBC.js} +2 -2
- package/dist/{capsule-crypto-K3IRTKRH.js → capsule-crypto-JS67OSWM.js} +3 -3
- package/dist/capsule-export-YPDWRB3C.js +17 -0
- package/dist/capsule-import-SWPOFG6F.js +16 -0
- package/dist/{capsule-merge-IWOQ34KL.js → capsule-merge-YXAF7ZJW.js} +7 -7
- package/dist/{causal-chain-WYN5QOPS.js → causal-chain-BVTOWZKC.js} +4 -4
- package/dist/{causal-consolidation-DSLFN64P.js → causal-consolidation-DRPM2KOE.js} +13 -10
- package/dist/{causal-retrieval-NZHQOZOE.js → causal-retrieval-XAP6QKHZ.js} +4 -5
- package/dist/{causal-trajectory-graph-VBPE2WPM.js → causal-trajectory-graph-ZWQWZ7N5.js} +2 -2
- package/dist/{chunk-5LE4HTVL.js → chunk-25J4PXDH.js} +0 -18
- package/dist/{chunk-FGTYFLL5.js → chunk-3IHGISUN.js} +29 -32
- package/dist/{chunk-6UFI73TJ.js → chunk-3IKMUNW5.js} +53 -46
- package/dist/{chunk-EXDYWXMB.js → chunk-4XDQ3KEC.js} +1 -2
- package/dist/{chunk-4UA6KMRO.js → chunk-6O3H3DPL.js} +2 -2
- package/dist/{chunk-7NMHI4IC.js → chunk-BLC3RQNV.js} +5 -555
- package/dist/{chunk-4G2XCSD2.js → chunk-BZ4EYURA.js} +0 -5
- package/dist/{chunk-4LYQ4ONL.js → chunk-E4RM7637.js} +1 -1
- package/dist/{chunk-TDRJVMUP.js → chunk-EH4AXGRO.js} +0 -12
- package/dist/{chunk-ZXLYEVOP.js → chunk-G3CZA4SD.js} +60 -362
- package/dist/chunk-I2KLQ2HA.js +22 -0
- package/dist/chunk-IO5WWY6A.js +156 -0
- package/dist/{contradiction-scan-U3QKHWQN.js → chunk-JC3FCKYL.js} +191 -87
- package/dist/{chunk-SVSQAG6M.js → chunk-KC7KSQR4.js} +47 -28
- package/dist/chunk-LZCGPRHS.js +228 -0
- package/dist/{chunk-CXM7EBAO.js → chunk-MXFJXUHC.js} +1 -1
- package/dist/{chunk-L6I4MQKO.js → chunk-NNAN63QK.js} +6 -6
- package/dist/{chunk-VRGUUHBV.js → chunk-NUWDSTP7.js} +1 -1
- package/dist/{chunk-6OJAU466.js → chunk-QMUQV5NP.js} +0 -1
- package/dist/{chunk-LLUROTZJ.js → chunk-QQXJODFL.js} +9 -9
- package/dist/{chunk-6F6EKSVP.js → chunk-QXXEF7VI.js} +1 -1
- package/dist/{chunk-NDZNURDM.js → chunk-SEGEX7W4.js} +73 -241
- package/dist/{chunk-7NUFIRM3.js → chunk-SWOYEQN2.js} +97 -21
- package/dist/chunk-TH5FF5SC.js +16 -0
- package/dist/chunk-UZJ7EERS.js +272 -0
- package/dist/chunk-YJYZMLD5.js +360 -0
- package/dist/{chunk-NKVIN6RD.js → chunk-YKV4EFUI.js} +84 -2
- package/dist/{chunk-SSFTU6LP.js → chunk-ZS6VABML.js} +4 -4
- package/dist/{cipher-VHAFCG7Z.js → cipher-E23BHBSO.js} +1 -1
- package/dist/{consolidation-undo-5ZSX4MWO.js → consolidation-undo-FKJZCJHS.js} +2 -2
- package/dist/contradiction-review-WJRWNQ5N.js +29 -0
- package/dist/contradiction-scan-5X423QGT.js +12 -0
- package/dist/{dreams-ledger-3I52ISYR.js → dreams-ledger-KDX44I7R.js} +1 -1
- package/dist/{engine-57HLTQBN.js → engine-5P774HTZ.js} +6 -6
- package/dist/{extraction-judge-telemetry-GHOTVYMP.js → extraction-judge-telemetry-O4ZVGLTU.js} +1 -1
- package/dist/{fallback-llm-33SPYXQY.js → fallback-llm-43UMEXNJ.js} +3 -3
- package/dist/{first-start-migration-I24M2JEE.js → first-start-migration-H2SAXAGR.js} +4 -4
- package/dist/{forget-NI4RBDPB.js → forget-ZECIDNL5.js} +1 -1
- package/dist/{fs-utils-PZRI2HDZ.js → fs-utils-OYXSZSVV.js} +12 -2
- package/dist/{graph-edge-decay-5CVKWBYH.js → graph-edge-decay-24ZKD5QL.js} +5 -5
- package/dist/index.js +7187 -71983
- package/dist/{kdf-H5B23ZM2.js → kdf-RXKIWHRU.js} +1 -1
- package/dist/legacy-hook-compat-QHHKF4GK.js +2 -0
- package/dist/{logger-TNOKCH7X.js → logger-XG7JKLPS.js} +1 -1
- package/dist/{memory-governance-FEQCA35V.js → memory-governance-6K4M4YXD.js} +5 -5
- package/dist/{metadata-JAGIWHEA.js → metadata-WK2TRPYZ.js} +1 -1
- package/dist/{migrate-from-identity-anchor-7MMSPEUM.js → migrate-from-identity-anchor-SNDNKHZD.js} +1 -1
- package/dist/path-ZKO74XXC.js +7 -0
- package/dist/{peers-KRFXWRQ6.js → peers-W53WSDXG.js} +1 -1
- package/dist/{purge-XN2VSPZ2.js → purge-IKJISXEQ.js} +1 -1
- package/dist/resolution-BN35OXDS.js +11 -0
- package/dist/{secure-store-A4NGCNXV.js → secure-store-F75I54O5.js} +3 -3
- package/dist/{state-PVISYXRH.js → state-4ITLYMAU.js} +1 -1
- package/dist/{state-store-N6TFBFSP.js → state-store-ET3ADVY5.js} +3 -3
- package/dist/{storage-R3V6ZFQT.js → storage-5EY6T7ON.js} +3 -3
- package/dist/{tier-stats-IZNW66NC.js → tier-stats-ZRQBV6G2.js} +4 -4
- package/dist/{trace-NJESSGH7.js → trace-IL2Y34EH.js} +1 -1
- package/dist/{tui-MGK2LYJY.js → tui-7KRDCMYK.js} +1 -1
- package/dist/{types-R4DO7AKM.js → types-7L34HYDW.js} +3 -3
- package/openclaw.plugin.json +153 -20
- package/package.json +18 -9
- package/scripts/faiss_index.py +756 -0
- package/scripts/faiss_requirements.txt +3 -0
- package/dist/capsule-export-IXVERCQG.js +0 -17
- package/dist/capsule-import-IA6VIOPQ.js +0 -16
- package/dist/chunk-3GUF7RQI.js +0 -559
- package/dist/chunk-7OQEPGQF.js +0 -533
- package/dist/chunk-DIZW6H5J.js +0 -136
- package/dist/chunk-FQRSVYY4.js +0 -110
- package/dist/chunk-GUSMRW4H.js +0 -12
- package/dist/chunk-MLKGABMK.js +0 -9
- package/dist/chunk-WPINX4MF.js +0 -380
- package/dist/contradiction-review-SVGBS3V5.js +0 -21
- package/dist/legacy-hook-compat-XQ7FP6FV.js +0 -35
- package/dist/path-JIEGNWFL.js +0 -7
- package/dist/resolution-YITUVUTH.js +0 -100
|
@@ -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
|
-
};
|
package/dist/chunk-3GUF7RQI.js
DELETED
|
@@ -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
|
-
};
|