@remnic/plugin-openclaw 1.0.6 → 1.0.8
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 +36 -0
- package/dist/{calibration-3JHF25QT.js → calibration-BAC7KNKR.js} +2 -1
- package/dist/{causal-consolidation-EBLROS42.js → causal-consolidation-33R5JTPX.js} +7 -5
- package/dist/chunk-3A5ELHTT.js +61 -0
- package/dist/chunk-5ZW5XJQ6.js +125 -0
- package/dist/chunk-6OJAU466.js +148 -0
- package/dist/{chunk-QHMR3D7U.js → chunk-BQLPVRIU.js} +109 -2
- package/dist/chunk-DIZW6H5J.js +136 -0
- package/dist/{chunk-KPMXWORS.js → chunk-JJSNPSCD.js} +608 -354
- package/dist/{chunk-3SA5F4WT.js → chunk-NXLHSCLU.js} +125 -69
- package/dist/{chunk-GUKYM4XZ.js → chunk-PFH73PN6.js} +3 -3
- package/dist/consolidation-undo-5ZSX4MWO.js +426 -0
- package/dist/contradiction-review-SVGBS3V5.js +21 -0
- package/dist/contradiction-scan-U3QKHWQN.js +412 -0
- package/dist/{engine-BU6GNUJ5.js → engine-M5G6ZJU7.js} +3 -2
- package/dist/extraction-judge-telemetry-GHOTVYMP.js +14 -0
- package/dist/{fallback-llm-HJRCHKSA.js → fallback-llm-QEAPMDW7.js} +2 -1
- package/dist/index.js +6467 -1285
- package/dist/resolution-YITUVUTH.js +100 -0
- package/dist/{storage-BA6OBLMK.js → storage-DM4ZGOCN.js} +2 -1
- package/openclaw.plugin.json +280 -9
- package/package.json +2 -2
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
import {
|
|
2
|
+
computePairId,
|
|
3
|
+
isCoolingDown,
|
|
4
|
+
listPairs,
|
|
5
|
+
writePairs
|
|
6
|
+
} from "./chunk-DIZW6H5J.js";
|
|
7
|
+
import {
|
|
8
|
+
extractJsonCandidates
|
|
9
|
+
} from "./chunk-3A5ELHTT.js";
|
|
10
|
+
import {
|
|
11
|
+
log
|
|
12
|
+
} from "./chunk-UFU5GGGA.js";
|
|
13
|
+
import "./chunk-MLKGABMK.js";
|
|
14
|
+
|
|
15
|
+
// ../remnic-core/src/contradiction/contradiction-judge.ts
|
|
16
|
+
import { createHash } from "crypto";
|
|
17
|
+
var CONTRADICTION_JUDGE_PROMPT = `You are a memory contradiction classifier. You will receive pairs of stored memories and must classify their semantic relationship.
|
|
18
|
+
|
|
19
|
+
For each pair, respond with a JSON array where each element has:
|
|
20
|
+
- "pairKey": the pairKey provided in the input
|
|
21
|
+
- "verdict": one of "contradicts", "independent", "duplicates", "needs-user"
|
|
22
|
+
- "rationale": one sentence explaining why
|
|
23
|
+
- "confidence": number between 0 and 1
|
|
24
|
+
|
|
25
|
+
VERDICT DEFINITIONS:
|
|
26
|
+
- "contradicts": The two memories make claims that cannot both be true. One must be wrong or outdated.
|
|
27
|
+
- "duplicates": The two memories convey essentially the same information (near-paraphrase).
|
|
28
|
+
- "independent": The memories are topically similar but do not conflict or duplicate.
|
|
29
|
+
- "needs-user": Cannot determine with sufficient confidence; requires human review.
|
|
30
|
+
|
|
31
|
+
IMPORTANT:
|
|
32
|
+
- Be conservative. When in doubt, prefer "needs-user" over a wrong classification.
|
|
33
|
+
- Two memories about the same entity/topic are NOT necessarily contradictory.
|
|
34
|
+
- Temporal changes ("Joshua uses pnpm" vs "Joshua switched to npm") ARE contradictions.
|
|
35
|
+
- Different aspects of the same entity ("Joshua uses pnpm" vs "Joshua works on Remnic") are "independent".`;
|
|
36
|
+
var defaultVerdictCache = /* @__PURE__ */ new Map();
|
|
37
|
+
var CACHE_MAX = 1e4;
|
|
38
|
+
function pairKey(idA, idB) {
|
|
39
|
+
const sorted = [idA, idB].sort();
|
|
40
|
+
return `${sorted[0]}:${sorted[1]}`;
|
|
41
|
+
}
|
|
42
|
+
function contentHash(a) {
|
|
43
|
+
const sides = [
|
|
44
|
+
[a.textA.trim(), (a.categoryA ?? "").trim()].join("|"),
|
|
45
|
+
[a.textB.trim(), (a.categoryB ?? "").trim()].join("|")
|
|
46
|
+
].sort();
|
|
47
|
+
const normalized = sides.join("|||");
|
|
48
|
+
return createHash("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
49
|
+
}
|
|
50
|
+
async function judgeContradictionPairs(pairs, config, localLlm, fallbackLlm, cache) {
|
|
51
|
+
const startTime = Date.now();
|
|
52
|
+
const results = /* @__PURE__ */ new Map();
|
|
53
|
+
const activeCache = cache ?? defaultVerdictCache;
|
|
54
|
+
let cached = 0;
|
|
55
|
+
let judged = 0;
|
|
56
|
+
const toJudge = [];
|
|
57
|
+
for (const pair of pairs) {
|
|
58
|
+
const key = pairKey(pair.memoryIdA, pair.memoryIdB);
|
|
59
|
+
const hash = contentHash(pair);
|
|
60
|
+
const cachedResult = activeCache.get(hash);
|
|
61
|
+
if (cachedResult) {
|
|
62
|
+
results.set(key, { ...cachedResult, memoryIdA: pair.memoryIdA, memoryIdB: pair.memoryIdB });
|
|
63
|
+
cached++;
|
|
64
|
+
} else {
|
|
65
|
+
toJudge.push(pair);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (toJudge.length === 0) {
|
|
69
|
+
return { results, cached, judged, elapsed: Date.now() - startTime };
|
|
70
|
+
}
|
|
71
|
+
const pairDescriptions = toJudge.map((p, i) => {
|
|
72
|
+
const pk = pairKey(p.memoryIdA, p.memoryIdB);
|
|
73
|
+
const catA = p.categoryA ? ` [${p.categoryA}]` : "";
|
|
74
|
+
const catB = p.categoryB ? ` [${p.categoryB}]` : "";
|
|
75
|
+
return `Pair ${i + 1} (pairKey: "${pk}"):${catA} "${p.textA}"${catB} "${p.textB}"`;
|
|
76
|
+
});
|
|
77
|
+
const userMessage = `Classify these ${toJudge.length} memory pair(s):
|
|
78
|
+
|
|
79
|
+
${pairDescriptions.join("\n\n")}`;
|
|
80
|
+
let llmResponse = null;
|
|
81
|
+
if (localLlm) {
|
|
82
|
+
try {
|
|
83
|
+
llmResponse = await callLlm(localLlm, config, userMessage);
|
|
84
|
+
} catch (err) {
|
|
85
|
+
log.warn("[contradiction-judge] local LLM call failed: %s", err instanceof Error ? err.message : err);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (!llmResponse && fallbackLlm) {
|
|
89
|
+
try {
|
|
90
|
+
llmResponse = await callLlm(fallbackLlm, config, userMessage);
|
|
91
|
+
} catch (err) {
|
|
92
|
+
log.warn("[contradiction-judge] fallback LLM call failed: %s", err instanceof Error ? err.message : err);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (llmResponse) {
|
|
96
|
+
const candidates = extractJsonCandidates(llmResponse);
|
|
97
|
+
const parsed = parseJudgeResponse(candidates, toJudge);
|
|
98
|
+
for (const result of parsed) {
|
|
99
|
+
const key = pairKey(result.memoryIdA, result.memoryIdB);
|
|
100
|
+
results.set(key, result);
|
|
101
|
+
const input = toJudge.find(
|
|
102
|
+
(p) => pairKey(p.memoryIdA, p.memoryIdB) === key
|
|
103
|
+
);
|
|
104
|
+
if (input) {
|
|
105
|
+
const hash = contentHash(input);
|
|
106
|
+
if (activeCache.size >= CACHE_MAX) {
|
|
107
|
+
const firstKey = activeCache.keys().next().value;
|
|
108
|
+
if (firstKey !== void 0) activeCache.delete(firstKey);
|
|
109
|
+
}
|
|
110
|
+
activeCache.set(hash, result);
|
|
111
|
+
}
|
|
112
|
+
judged++;
|
|
113
|
+
}
|
|
114
|
+
} else {
|
|
115
|
+
for (const pair of toJudge) {
|
|
116
|
+
const key = pairKey(pair.memoryIdA, pair.memoryIdB);
|
|
117
|
+
const result = {
|
|
118
|
+
memoryIdA: pair.memoryIdA,
|
|
119
|
+
memoryIdB: pair.memoryIdB,
|
|
120
|
+
verdict: "needs-user",
|
|
121
|
+
rationale: "LLM call failed; requires manual review",
|
|
122
|
+
confidence: 0
|
|
123
|
+
};
|
|
124
|
+
results.set(key, result);
|
|
125
|
+
judged++;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return { results, cached, judged, elapsed: Date.now() - startTime };
|
|
129
|
+
}
|
|
130
|
+
async function callLlm(client, config, userMessage) {
|
|
131
|
+
const messages = [
|
|
132
|
+
{ role: "system", content: CONTRADICTION_JUDGE_PROMPT },
|
|
133
|
+
{ role: "user", content: userMessage }
|
|
134
|
+
];
|
|
135
|
+
if ("chatCompletion" in client && typeof client.chatCompletion === "function") {
|
|
136
|
+
const result = await client.chatCompletion(messages, {
|
|
137
|
+
temperature: 0.1,
|
|
138
|
+
maxTokens: 4096
|
|
139
|
+
});
|
|
140
|
+
return result?.content ?? "";
|
|
141
|
+
}
|
|
142
|
+
if ("complete" in client && typeof client.complete === "function") {
|
|
143
|
+
const result = await client.complete(messages);
|
|
144
|
+
return result.content ?? "";
|
|
145
|
+
}
|
|
146
|
+
return "";
|
|
147
|
+
}
|
|
148
|
+
function parseJudgeResponse(candidates, inputs) {
|
|
149
|
+
const VALID_VERDICTS = ["contradicts", "independent", "duplicates", "needs-user"];
|
|
150
|
+
for (const candidate of candidates) {
|
|
151
|
+
try {
|
|
152
|
+
const parsed = JSON.parse(candidate);
|
|
153
|
+
const items = Array.isArray(parsed) ? parsed : [parsed];
|
|
154
|
+
const results = [];
|
|
155
|
+
const matchedKeys = /* @__PURE__ */ new Set();
|
|
156
|
+
for (const item of items) {
|
|
157
|
+
if (!item || typeof item !== "object") continue;
|
|
158
|
+
const verdict = typeof item.verdict === "string" && VALID_VERDICTS.includes(item.verdict) ? item.verdict : "needs-user";
|
|
159
|
+
const pairKeyVal = typeof item.pairKey === "string" ? item.pairKey : null;
|
|
160
|
+
const input = pairKeyVal ? inputs.find((p) => pairKey(p.memoryIdA, p.memoryIdB) === pairKeyVal) : null;
|
|
161
|
+
const fallbackInput = input ?? inputs[results.length] ?? inputs[0];
|
|
162
|
+
if (!fallbackInput) continue;
|
|
163
|
+
matchedKeys.add(pairKey(fallbackInput.memoryIdA, fallbackInput.memoryIdB));
|
|
164
|
+
const confidence = typeof item.confidence === "number" ? Math.min(1, Math.max(0, item.confidence)) : 0.5;
|
|
165
|
+
results.push({
|
|
166
|
+
memoryIdA: fallbackInput.memoryIdA,
|
|
167
|
+
memoryIdB: fallbackInput.memoryIdB,
|
|
168
|
+
verdict,
|
|
169
|
+
rationale: typeof item.rationale === "string" ? item.rationale : "No rationale provided",
|
|
170
|
+
confidence
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
for (const inp of inputs) {
|
|
174
|
+
const key = pairKey(inp.memoryIdA, inp.memoryIdB);
|
|
175
|
+
if (!matchedKeys.has(key)) {
|
|
176
|
+
results.push({
|
|
177
|
+
memoryIdA: inp.memoryIdA,
|
|
178
|
+
memoryIdB: inp.memoryIdB,
|
|
179
|
+
verdict: "needs-user",
|
|
180
|
+
rationale: "LLM response omitted this pair",
|
|
181
|
+
confidence: 0
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (results.length > 0) return results;
|
|
186
|
+
} catch {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return inputs.map((p) => ({
|
|
191
|
+
memoryIdA: p.memoryIdA,
|
|
192
|
+
memoryIdB: p.memoryIdB,
|
|
193
|
+
verdict: "needs-user",
|
|
194
|
+
rationale: "Failed to parse judge response",
|
|
195
|
+
confidence: 0
|
|
196
|
+
}));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// ../remnic-core/src/contradiction/contradiction-scan.ts
|
|
200
|
+
var ACTIVE_STATUSES = /* @__PURE__ */ new Set(["active"]);
|
|
201
|
+
var SCAN_CATEGORIES = /* @__PURE__ */ new Set([
|
|
202
|
+
"decision",
|
|
203
|
+
"principle",
|
|
204
|
+
"rule",
|
|
205
|
+
"entity",
|
|
206
|
+
"fact",
|
|
207
|
+
"preference"
|
|
208
|
+
]);
|
|
209
|
+
async function runContradictionScan(deps) {
|
|
210
|
+
const startTime = Date.now();
|
|
211
|
+
const { storage, config, memoryDir, embeddingLookup, embeddingLookupFactory, localLlm, fallbackLlm, namespace } = deps;
|
|
212
|
+
const scanConfig = config.contradictionScan;
|
|
213
|
+
const scopedEmbeddingLookup = embeddingLookupFactory ? embeddingLookupFactory(storage) : embeddingLookup;
|
|
214
|
+
if (!scanConfig.enabled) {
|
|
215
|
+
log.info("[contradiction-scan] disabled by config");
|
|
216
|
+
return { scanned: 0, candidates: 0, judged: 0, queued: 0, cooledDown: 0, elapsedMs: 0 };
|
|
217
|
+
}
|
|
218
|
+
const memories = await loadEligibleMemories(storage, namespace);
|
|
219
|
+
log.info("[contradiction-scan] loaded %d eligible memories", memories.length);
|
|
220
|
+
if (memories.length < 2) {
|
|
221
|
+
return { scanned: memories.length, candidates: 0, judged: 0, queued: 0, cooledDown: 0, elapsedMs: Date.now() - startTime };
|
|
222
|
+
}
|
|
223
|
+
const existingPairs = listPairs(memoryDir, { filter: "all", namespace, limit: 1e4 }).pairs;
|
|
224
|
+
const existingMap = /* @__PURE__ */ new Map();
|
|
225
|
+
for (const p of existingPairs) {
|
|
226
|
+
existingMap.set(p.pairId, p);
|
|
227
|
+
}
|
|
228
|
+
const candidates = await generatePairs(memories, existingMap, scanConfig, scopedEmbeddingLookup);
|
|
229
|
+
const cooledDown = candidates.skipped;
|
|
230
|
+
log.info("[contradiction-scan] generated %d candidates (%d cooled down)", candidates.pairs.length, cooledDown);
|
|
231
|
+
if (candidates.pairs.length === 0) {
|
|
232
|
+
return {
|
|
233
|
+
scanned: memories.length,
|
|
234
|
+
candidates: 0,
|
|
235
|
+
judged: 0,
|
|
236
|
+
queued: 0,
|
|
237
|
+
cooledDown,
|
|
238
|
+
elapsedMs: Date.now() - startTime
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
const capped = candidates.pairs.sort((a, b) => computePairId(a.idA, a.idB).localeCompare(computePairId(b.idA, b.idB))).slice(0, scanConfig.maxPairsPerRun);
|
|
242
|
+
const judgeInputs = capped.map((pair) => ({
|
|
243
|
+
memoryIdA: pair.idA,
|
|
244
|
+
memoryIdB: pair.idB,
|
|
245
|
+
textA: pair.textA,
|
|
246
|
+
textB: pair.textB,
|
|
247
|
+
categoryA: pair.categoryA,
|
|
248
|
+
categoryB: pair.categoryB
|
|
249
|
+
}));
|
|
250
|
+
const scanCache = /* @__PURE__ */ new Map();
|
|
251
|
+
const judgeResult = await judgeContradictionPairs(judgeInputs, config, localLlm, fallbackLlm, scanCache);
|
|
252
|
+
log.info("[contradiction-scan] judge completed: %d judged, %d cached in %dms", judgeResult.judged, judgeResult.cached, judgeResult.elapsed);
|
|
253
|
+
const queueEntries = [];
|
|
254
|
+
for (const [key, result] of judgeResult.results) {
|
|
255
|
+
queueEntries.push({
|
|
256
|
+
memoryIds: [result.memoryIdA, result.memoryIdB],
|
|
257
|
+
verdict: result.verdict,
|
|
258
|
+
rationale: result.rationale,
|
|
259
|
+
confidence: result.confidence,
|
|
260
|
+
detectedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
261
|
+
// Set lastReviewedAt for non-actionable verdicts so cooldown prevents re-judging
|
|
262
|
+
lastReviewedAt: result.verdict === "independent" ? (/* @__PURE__ */ new Date()).toISOString() : void 0,
|
|
263
|
+
namespace
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
const written = writePairs(memoryDir, queueEntries);
|
|
267
|
+
const elapsed = Date.now() - startTime;
|
|
268
|
+
log.info("[contradiction-scan] complete: %d queued in %dms", written.length, elapsed);
|
|
269
|
+
return {
|
|
270
|
+
scanned: memories.length,
|
|
271
|
+
candidates: candidates.pairs.length,
|
|
272
|
+
judged: judgeResult.judged,
|
|
273
|
+
queued: written.length,
|
|
274
|
+
cooledDown,
|
|
275
|
+
elapsedMs: elapsed
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
async function generatePairs(memories, existingPairs, scanConfig, embeddingLookup) {
|
|
279
|
+
const pairs = [];
|
|
280
|
+
const embeddingPairs = [];
|
|
281
|
+
let skipped = 0;
|
|
282
|
+
const seen = /* @__PURE__ */ new Set();
|
|
283
|
+
const byEntity = /* @__PURE__ */ new Map();
|
|
284
|
+
for (const mem of memories) {
|
|
285
|
+
const entity = mem.frontmatter.entityRef;
|
|
286
|
+
if (entity) {
|
|
287
|
+
const existing = byEntity.get(entity) ?? [];
|
|
288
|
+
existing.push(mem);
|
|
289
|
+
byEntity.set(entity, existing);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
for (const [, group] of byEntity) {
|
|
293
|
+
if (group.length < 2) continue;
|
|
294
|
+
for (let i = 0; i < group.length; i++) {
|
|
295
|
+
for (let j = i + 1; j < group.length; j++) {
|
|
296
|
+
const a = group[i];
|
|
297
|
+
const b = group[j];
|
|
298
|
+
const pairId = computePairId(a.frontmatter.id, b.frontmatter.id);
|
|
299
|
+
if (seen.has(pairId)) continue;
|
|
300
|
+
seen.add(pairId);
|
|
301
|
+
const existing = existingPairs.get(pairId);
|
|
302
|
+
if (existing && isCoolingDown(existing, scanConfig.cooldownDays)) {
|
|
303
|
+
skipped++;
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
pairs.push({
|
|
307
|
+
idA: a.frontmatter.id,
|
|
308
|
+
idB: b.frontmatter.id,
|
|
309
|
+
textA: a.content,
|
|
310
|
+
textB: b.content,
|
|
311
|
+
categoryA: a.frontmatter.category,
|
|
312
|
+
categoryB: b.frontmatter.category
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
const noEntity = memories.filter((m) => !m.frontmatter.entityRef);
|
|
318
|
+
for (let i = 0; i < noEntity.length; i++) {
|
|
319
|
+
for (let j = i + 1; j < noEntity.length; j++) {
|
|
320
|
+
const a = noEntity[i];
|
|
321
|
+
const b = noEntity[j];
|
|
322
|
+
const overlap = jaccardOverlap(
|
|
323
|
+
a.frontmatter.tags ?? [],
|
|
324
|
+
b.frontmatter.tags ?? []
|
|
325
|
+
);
|
|
326
|
+
if (overlap < scanConfig.topicOverlapFloor) continue;
|
|
327
|
+
const pairId = computePairId(a.frontmatter.id, b.frontmatter.id);
|
|
328
|
+
if (seen.has(pairId)) continue;
|
|
329
|
+
seen.add(pairId);
|
|
330
|
+
const existing = existingPairs.get(pairId);
|
|
331
|
+
if (existing && isCoolingDown(existing, scanConfig.cooldownDays)) {
|
|
332
|
+
skipped++;
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
pairs.push({
|
|
336
|
+
idA: a.frontmatter.id,
|
|
337
|
+
idB: b.frontmatter.id,
|
|
338
|
+
textA: a.content,
|
|
339
|
+
textB: b.content,
|
|
340
|
+
categoryA: a.frontmatter.category,
|
|
341
|
+
categoryB: b.frontmatter.category
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
if (embeddingLookup) {
|
|
346
|
+
const memoryById = new Map(memories.map((m) => [m.frontmatter.id, m]));
|
|
347
|
+
for (const mem of memories) {
|
|
348
|
+
const id = mem.frontmatter.id;
|
|
349
|
+
try {
|
|
350
|
+
const hits = await embeddingLookup(mem.content, 20);
|
|
351
|
+
for (const hit of hits) {
|
|
352
|
+
if (hit.score < scanConfig.similarityFloor) continue;
|
|
353
|
+
if (hit.id === id) continue;
|
|
354
|
+
const peer = memoryById.get(hit.id);
|
|
355
|
+
if (!peer) continue;
|
|
356
|
+
const pairId = computePairId(id, hit.id);
|
|
357
|
+
if (seen.has(pairId)) continue;
|
|
358
|
+
seen.add(pairId);
|
|
359
|
+
const existing = existingPairs.get(pairId);
|
|
360
|
+
if (existing && isCoolingDown(existing, scanConfig.cooldownDays)) {
|
|
361
|
+
skipped++;
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
embeddingPairs.push({
|
|
365
|
+
idA: id,
|
|
366
|
+
idB: hit.id,
|
|
367
|
+
textA: mem.content,
|
|
368
|
+
textB: peer.content,
|
|
369
|
+
categoryA: mem.frontmatter.category,
|
|
370
|
+
categoryB: peer.frontmatter.category
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
} catch {
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
pairs.push(...embeddingPairs);
|
|
378
|
+
return { pairs, skipped };
|
|
379
|
+
}
|
|
380
|
+
async function loadEligibleMemories(storage, namespace) {
|
|
381
|
+
let all;
|
|
382
|
+
try {
|
|
383
|
+
all = await storage.readAllMemories();
|
|
384
|
+
} catch {
|
|
385
|
+
return [];
|
|
386
|
+
}
|
|
387
|
+
return all.filter((mem) => {
|
|
388
|
+
const fm = mem.frontmatter;
|
|
389
|
+
const status = fm.status ?? "active";
|
|
390
|
+
if (!ACTIVE_STATUSES.has(status)) return false;
|
|
391
|
+
const category = fm.category;
|
|
392
|
+
if (category && !SCAN_CATEGORIES.has(category)) return false;
|
|
393
|
+
if (!mem.content || mem.content.trim().length === 0) return false;
|
|
394
|
+
if (!fm.id) return false;
|
|
395
|
+
return true;
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
function jaccardOverlap(a, b) {
|
|
399
|
+
if (a.length === 0 && b.length === 0) return 0;
|
|
400
|
+
const setA = new Set(a.map((t) => t.toLowerCase()));
|
|
401
|
+
const setB = new Set(b.map((t) => t.toLowerCase()));
|
|
402
|
+
let intersection = 0;
|
|
403
|
+
for (const item of setA) {
|
|
404
|
+
if (setB.has(item)) intersection++;
|
|
405
|
+
}
|
|
406
|
+
const union = setA.size + setB.size - intersection;
|
|
407
|
+
return union === 0 ? 0 : intersection / union;
|
|
408
|
+
}
|
|
409
|
+
export {
|
|
410
|
+
ACTIVE_STATUSES,
|
|
411
|
+
runContradictionScan
|
|
412
|
+
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CompoundingEngine,
|
|
3
3
|
defaultTierMigrationCycleBudget
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-PFH73PN6.js";
|
|
5
|
+
import "./chunk-JJSNPSCD.js";
|
|
6
|
+
import "./chunk-6OJAU466.js";
|
|
6
7
|
import "./chunk-UFU5GGGA.js";
|
|
7
8
|
import "./chunk-MLKGABMK.js";
|
|
8
9
|
export {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EXTRACTION_JUDGE_VERDICT_CATEGORY,
|
|
3
|
+
judgeTelemetryPath,
|
|
4
|
+
readJudgeVerdictStats,
|
|
5
|
+
recordJudgeVerdict
|
|
6
|
+
} from "./chunk-5ZW5XJQ6.js";
|
|
7
|
+
import "./chunk-UFU5GGGA.js";
|
|
8
|
+
import "./chunk-MLKGABMK.js";
|
|
9
|
+
export {
|
|
10
|
+
EXTRACTION_JUDGE_VERDICT_CATEGORY,
|
|
11
|
+
judgeTelemetryPath,
|
|
12
|
+
readJudgeVerdictStats,
|
|
13
|
+
recordJudgeVerdict
|
|
14
|
+
};
|