@joshuaswarren/openclaw-engram 8.3.61 → 8.3.63
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/index.js +80 -18
- package/dist/index.js.map +1 -1
- package/openclaw.plugin.json +15 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -418,6 +418,9 @@ function parseConfig(raw) {
|
|
|
418
418
|
causalGraphEnabled: cfg.causalGraphEnabled !== false,
|
|
419
419
|
maxGraphTraversalSteps: typeof cfg.maxGraphTraversalSteps === "number" ? Math.max(0, cfg.maxGraphTraversalSteps) : 3,
|
|
420
420
|
graphActivationDecay: typeof cfg.graphActivationDecay === "number" ? Math.min(1, Math.max(0, cfg.graphActivationDecay)) : 0.7,
|
|
421
|
+
graphExpansionActivationWeight: typeof cfg.graphExpansionActivationWeight === "number" ? Math.min(1, Math.max(0, cfg.graphExpansionActivationWeight)) : 0.65,
|
|
422
|
+
graphExpansionBlendMin: typeof cfg.graphExpansionBlendMin === "number" ? Math.min(1, Math.max(0, cfg.graphExpansionBlendMin)) : 0.05,
|
|
423
|
+
graphExpansionBlendMax: typeof cfg.graphExpansionBlendMax === "number" ? Math.min(1, Math.max(0, cfg.graphExpansionBlendMax)) : 0.95,
|
|
421
424
|
maxEntityGraphEdgesPerMemory: typeof cfg.maxEntityGraphEdgesPerMemory === "number" ? Math.max(0, cfg.maxEntityGraphEdgesPerMemory) : 10,
|
|
422
425
|
// v8.2: Temporal Memory Tree
|
|
423
426
|
temporalMemoryTreeEnabled: cfg.temporalMemoryTreeEnabled === true,
|
|
@@ -8600,6 +8603,22 @@ var NegativeExampleStore = class {
|
|
|
8600
8603
|
import { appendFile as appendFile3, mkdir as mkdir8, readFile as readFile8, writeFile as writeFile8 } from "fs/promises";
|
|
8601
8604
|
import path10 from "path";
|
|
8602
8605
|
import { createHash as createHash2 } from "crypto";
|
|
8606
|
+
function clampGraphRecallExpandedEntries(entries, maxEntries = 64) {
|
|
8607
|
+
const limit = Math.max(1, Math.floor(maxEntries));
|
|
8608
|
+
if (!Array.isArray(entries)) return [];
|
|
8609
|
+
return entries.filter((item) => !!item && typeof item === "object").map((item) => {
|
|
8610
|
+
const graphType = item.graphType === "entity" || item.graphType === "time" || item.graphType === "causal" ? item.graphType : "entity";
|
|
8611
|
+
return {
|
|
8612
|
+
path: typeof item.path === "string" ? item.path : "",
|
|
8613
|
+
score: typeof item.score === "number" && Number.isFinite(item.score) ? item.score : 0,
|
|
8614
|
+
namespace: typeof item.namespace === "string" ? item.namespace : "",
|
|
8615
|
+
seed: typeof item.seed === "string" ? item.seed : "",
|
|
8616
|
+
hopDepth: typeof item.hopDepth === "number" && Number.isFinite(item.hopDepth) ? Math.max(0, Math.floor(item.hopDepth)) : 0,
|
|
8617
|
+
decayedWeight: typeof item.decayedWeight === "number" && Number.isFinite(item.decayedWeight) ? Math.max(0, item.decayedWeight) : 0,
|
|
8618
|
+
graphType
|
|
8619
|
+
};
|
|
8620
|
+
}).filter((item) => item.path.length > 0 && item.namespace.length > 0).slice(0, limit);
|
|
8621
|
+
}
|
|
8603
8622
|
var LastRecallStore = class {
|
|
8604
8623
|
statePath;
|
|
8605
8624
|
impressionsPath;
|
|
@@ -11004,10 +11023,11 @@ var GraphIndex = class {
|
|
|
11004
11023
|
}
|
|
11005
11024
|
const seedSet = new Set(seeds);
|
|
11006
11025
|
const scores = /* @__PURE__ */ new Map();
|
|
11026
|
+
const provenance = /* @__PURE__ */ new Map();
|
|
11007
11027
|
const visited = new Set(seeds);
|
|
11008
|
-
const queue = seeds.map((s) => [s, 0]);
|
|
11028
|
+
const queue = seeds.map((s) => [s, 0, s]);
|
|
11009
11029
|
while (queue.length > 0) {
|
|
11010
|
-
const [node, hop] = queue.shift();
|
|
11030
|
+
const [node, hop, sourceSeed] = queue.shift();
|
|
11011
11031
|
if (hop >= steps) continue;
|
|
11012
11032
|
const edges = adj.get(node) ?? [];
|
|
11013
11033
|
for (const edge of edges) {
|
|
@@ -11016,14 +11036,30 @@ var GraphIndex = class {
|
|
|
11016
11036
|
if (!seedSet.has(neighbor)) {
|
|
11017
11037
|
const existing = scores.get(neighbor) ?? 0;
|
|
11018
11038
|
scores.set(neighbor, existing + score);
|
|
11039
|
+
const prev = provenance.get(neighbor);
|
|
11040
|
+
if (!prev || hop + 1 < prev.hopDepth || hop + 1 === prev.hopDepth && score > prev.decayedWeight) {
|
|
11041
|
+
provenance.set(neighbor, {
|
|
11042
|
+
seed: sourceSeed,
|
|
11043
|
+
hopDepth: hop + 1,
|
|
11044
|
+
decayedWeight: score,
|
|
11045
|
+
graphType: edge.type
|
|
11046
|
+
});
|
|
11047
|
+
}
|
|
11019
11048
|
}
|
|
11020
11049
|
if (!visited.has(neighbor)) {
|
|
11021
11050
|
visited.add(neighbor);
|
|
11022
|
-
queue.push([neighbor, hop + 1]);
|
|
11051
|
+
queue.push([neighbor, hop + 1, sourceSeed]);
|
|
11023
11052
|
}
|
|
11024
11053
|
}
|
|
11025
11054
|
}
|
|
11026
|
-
return Array.from(scores.entries()).map(([p, score]) => ({
|
|
11055
|
+
return Array.from(scores.entries()).map(([p, score]) => ({
|
|
11056
|
+
path: p,
|
|
11057
|
+
score,
|
|
11058
|
+
seed: provenance.get(p)?.seed ?? "",
|
|
11059
|
+
hopDepth: provenance.get(p)?.hopDepth ?? 0,
|
|
11060
|
+
decayedWeight: provenance.get(p)?.decayedWeight ?? 0,
|
|
11061
|
+
graphType: provenance.get(p)?.graphType ?? "entity"
|
|
11062
|
+
})).sort((a, b) => b.score - a.score);
|
|
11027
11063
|
} catch (err) {
|
|
11028
11064
|
const { log: log2 } = await import("./logger-KPTKTANX.js");
|
|
11029
11065
|
log2.warn(`[graph] spreadingActivation error: ${err}`);
|
|
@@ -12534,10 +12570,20 @@ function graphPathRelativeToStorage(storageDir, candidatePath) {
|
|
|
12534
12570
|
if (rel.startsWith("..")) return null;
|
|
12535
12571
|
return rel.split(path25.sep).join("/");
|
|
12536
12572
|
}
|
|
12537
|
-
function
|
|
12573
|
+
function normalizeGraphActivationScore(score) {
|
|
12538
12574
|
const bounded = Number.isFinite(score) && score > 0 ? score : 0;
|
|
12539
|
-
|
|
12540
|
-
|
|
12575
|
+
return bounded / (1 + bounded);
|
|
12576
|
+
}
|
|
12577
|
+
function blendGraphExpandedRecallScore(options) {
|
|
12578
|
+
const graphNorm = normalizeGraphActivationScore(options.graphActivationScore);
|
|
12579
|
+
const seedScore = Number.isFinite(options.seedRecallScore) ? Math.min(1, Math.max(0, options.seedRecallScore)) : 0;
|
|
12580
|
+
const weight = Math.min(1, Math.max(0, options.activationWeight));
|
|
12581
|
+
const rawMin = Math.min(1, Math.max(0, options.blendMin));
|
|
12582
|
+
const rawMax = Math.min(1, Math.max(0, options.blendMax));
|
|
12583
|
+
const minBound = Math.min(rawMin, rawMax);
|
|
12584
|
+
const maxBound = Math.max(rawMin, rawMax);
|
|
12585
|
+
const blended = graphNorm * weight + seedScore * (1 - weight);
|
|
12586
|
+
return Math.max(minBound, Math.min(maxBound, blended));
|
|
12541
12587
|
}
|
|
12542
12588
|
function mergeArtifactRecallCandidates(candidatesByNamespace, limit) {
|
|
12543
12589
|
const cappedLimit = Math.max(0, limit);
|
|
@@ -13061,9 +13107,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
13061
13107
|
seedCount: typeof parsed.seedCount === "number" ? parsed.seedCount : 0,
|
|
13062
13108
|
expandedCount: typeof parsed.expandedCount === "number" ? parsed.expandedCount : 0,
|
|
13063
13109
|
seeds: Array.isArray(parsed.seeds) ? parsed.seeds.filter((v) => typeof v === "string") : [],
|
|
13064
|
-
expanded:
|
|
13065
|
-
(v) => !!v && typeof v === "object" && typeof v.path === "string" && typeof v.score === "number" && typeof v.namespace === "string"
|
|
13066
|
-
) : []
|
|
13110
|
+
expanded: clampGraphRecallExpandedEntries(parsed.expanded, 64)
|
|
13067
13111
|
};
|
|
13068
13112
|
} catch {
|
|
13069
13113
|
return null;
|
|
@@ -13084,7 +13128,9 @@ var Orchestrator = class _Orchestrator {
|
|
|
13084
13128
|
`Seed paths (${snapshot.seedCount}):`,
|
|
13085
13129
|
...snapshot.seeds.map((p) => `- ${p}`),
|
|
13086
13130
|
`Expanded paths (${snapshot.expandedCount}, showing ${expanded.length}):`,
|
|
13087
|
-
...expanded.map(
|
|
13131
|
+
...expanded.map(
|
|
13132
|
+
(e) => `- ${e.path} (score=${e.score.toFixed(3)}, ns=${e.namespace}, seed=${e.seed || "unknown"}, hop=${e.hopDepth}, w=${e.decayedWeight.toFixed(3)}, type=${e.graphType})`
|
|
13133
|
+
)
|
|
13088
13134
|
].join("\n");
|
|
13089
13135
|
}
|
|
13090
13136
|
async searchConversationRecallResults(retrievalQuery, topK) {
|
|
@@ -13430,8 +13476,10 @@ ${r.snippet.trim()}
|
|
|
13430
13476
|
const expandedResults = [];
|
|
13431
13477
|
for (const [namespace, nsResults] of byNamespace.entries()) {
|
|
13432
13478
|
const storage = await this.storageRouter.storageFor(namespace);
|
|
13433
|
-
const
|
|
13479
|
+
const seedCandidates = nsResults.slice(0, perNamespaceSeedCap);
|
|
13480
|
+
const seedRelativePaths = seedCandidates.map((result) => graphPathRelativeToStorage(storage.dir, result.path)).filter((value) => typeof value === "string" && value.length > 0);
|
|
13434
13481
|
if (seedRelativePaths.length === 0) continue;
|
|
13482
|
+
const seedRecallScore = seedCandidates.reduce((max, item) => Math.max(max, item.score), 0);
|
|
13435
13483
|
seedPaths.push(...seedRelativePaths.map((rel) => path25.join(storage.dir, rel)));
|
|
13436
13484
|
const seedSet = new Set(seedRelativePaths);
|
|
13437
13485
|
const expanded = await this.graphIndexFor(storage).spreadingActivation(
|
|
@@ -13447,7 +13495,13 @@ ${r.snippet.trim()}
|
|
|
13447
13495
|
if (isArtifactMemoryPath(memory.path)) continue;
|
|
13448
13496
|
if (memory.frontmatter.status && memory.frontmatter.status !== "active") continue;
|
|
13449
13497
|
const snippet = memory.content.slice(0, 400);
|
|
13450
|
-
const score =
|
|
13498
|
+
const score = blendGraphExpandedRecallScore({
|
|
13499
|
+
graphActivationScore: candidate.score,
|
|
13500
|
+
seedRecallScore,
|
|
13501
|
+
activationWeight: this.config.graphExpansionActivationWeight,
|
|
13502
|
+
blendMin: this.config.graphExpansionBlendMin,
|
|
13503
|
+
blendMax: this.config.graphExpansionBlendMax
|
|
13504
|
+
});
|
|
13451
13505
|
expandedResults.push({
|
|
13452
13506
|
docid: memory.frontmatter.id,
|
|
13453
13507
|
path: memory.path,
|
|
@@ -13457,7 +13511,11 @@ ${r.snippet.trim()}
|
|
|
13457
13511
|
expandedPaths.push({
|
|
13458
13512
|
path: memory.path,
|
|
13459
13513
|
score,
|
|
13460
|
-
namespace
|
|
13514
|
+
namespace,
|
|
13515
|
+
seed: path25.resolve(storage.dir, candidate.seed),
|
|
13516
|
+
hopDepth: candidate.hopDepth,
|
|
13517
|
+
decayedWeight: candidate.decayedWeight,
|
|
13518
|
+
graphType: candidate.graphType
|
|
13461
13519
|
});
|
|
13462
13520
|
}
|
|
13463
13521
|
}
|
|
@@ -13472,16 +13530,20 @@ ${r.snippet.trim()}
|
|
|
13472
13530
|
const snapshotPath = path25.join(options.storage.dir, "state", "last_graph_recall.json");
|
|
13473
13531
|
await mkdir18(path25.dirname(snapshotPath), { recursive: true });
|
|
13474
13532
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
13533
|
+
const totalSeedCount = options.seedPaths.length;
|
|
13534
|
+
const totalExpandedCount = options.expandedPaths.length;
|
|
13535
|
+
const seeds = options.seedPaths.slice(0, 64);
|
|
13536
|
+
const expanded = clampGraphRecallExpandedEntries(options.expandedPaths, 64);
|
|
13475
13537
|
const payload = {
|
|
13476
13538
|
recordedAt: now,
|
|
13477
13539
|
mode: options.recallMode,
|
|
13478
13540
|
queryHash: createHash5("sha256").update(options.prompt).digest("hex"),
|
|
13479
13541
|
queryLength: options.prompt.length,
|
|
13480
13542
|
namespaces: options.recallNamespaces,
|
|
13481
|
-
seedCount:
|
|
13482
|
-
expandedCount:
|
|
13483
|
-
seeds
|
|
13484
|
-
expanded
|
|
13543
|
+
seedCount: totalSeedCount,
|
|
13544
|
+
expandedCount: totalExpandedCount,
|
|
13545
|
+
seeds,
|
|
13546
|
+
expanded
|
|
13485
13547
|
};
|
|
13486
13548
|
await writeFile17(snapshotPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
13487
13549
|
} catch (err) {
|