@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 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]) => ({ path: p, score })).sort((a, b) => b.score - a.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 graphActivationScoreToRecallScore(score) {
12573
+ function normalizeGraphActivationScore(score) {
12538
12574
  const bounded = Number.isFinite(score) && score > 0 ? score : 0;
12539
- const normalized = bounded / (1 + bounded);
12540
- return Math.max(0.05, Math.min(0.95, normalized));
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: Array.isArray(parsed.expanded) ? parsed.expanded.filter(
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((e) => `- ${e.path} (score=${e.score.toFixed(3)}, ns=${e.namespace})`)
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 seedRelativePaths = nsResults.slice(0, perNamespaceSeedCap).map((result) => graphPathRelativeToStorage(storage.dir, result.path)).filter((value) => typeof value === "string" && value.length > 0);
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 = graphActivationScoreToRecallScore(candidate.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: options.seedPaths.length,
13482
- expandedCount: options.expandedPaths.length,
13483
- seeds: options.seedPaths,
13484
- expanded: options.expandedPaths
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) {