@joshuaswarren/openclaw-engram 9.0.52 → 9.0.54

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 CHANGED
@@ -33,6 +33,7 @@ AI agents forget everything between conversations. Engram fixes that.
33
33
  - **Benchmark-first roadmap** — Engram now has an evaluation harness with live shadow recall recording and a CI benchmark delta gate, so memory improvements can be measured and regression-checked instead of argued from anecdotes.
34
34
  - **Baseline snapshot discipline** — Engram can now, when `benchmarkBaselineSnapshotsEnabled` is enabled, capture typed baseline snapshots of the latest completed benchmark runs so later PR delta reporting can compare candidates against a stable stored reference instead of an ad hoc branch state.
35
35
  - **Named baseline delta reporting** — Engram can now, when `benchmarkDeltaReporterEnabled` is enabled, compare the current eval store against a stored baseline snapshot, emit a machine-readable delta report plus markdown summary, and fail fast when a candidate regresses a benchmark that previously passed.
36
+ - **Required CI baseline gate** — Engram's `eval-benchmark-gate` workflow now reads a named stored baseline snapshot from the base branch fixture store and blocks merges when the candidate branch regresses relative to that required baseline.
36
37
  - **Objective-state recall** — Engram can now store normalized file, process, and tool outcomes and, when `objectiveStateRecallEnabled` is enabled, inject the most relevant objective-state snapshots back into recall context as a separate `Objective State` section.
37
38
  - **Causal trajectory graph foundation** — Engram can now persist typed `goal -> action -> observation -> outcome -> follow-up` chains when `causalTrajectoryMemoryEnabled` is enabled and, with `actionGraphRecallEnabled`, emit deterministic action-conditioned edges into the causal graph for later trajectory-aware retrieval.
38
39
  - **Causal trajectory recall** — Engram can now, when `causalTrajectoryRecallEnabled` is enabled, inject prompt-relevant causal chains back into recall context as a separate `Causal Trajectories` section with lightweight match explainability.
@@ -215,6 +216,12 @@ Key settings:
215
216
  | `evalShadowModeEnabled` | `false` | Record live recall decisions to the eval store without changing injected output |
216
217
  | `benchmarkBaselineSnapshotsEnabled` | `false` | Enable versioned baseline snapshot artifacts for the latest completed benchmark runs |
217
218
  | `benchmarkDeltaReporterEnabled` | `false` | Enable named-baseline delta reports against the current eval store |
219
+
220
+ The repo's required benchmark check uses the committed fixture snapshot at
221
+ `tests/fixtures/eval-ci/store/baselines/required-main.json` as the stable
222
+ release baseline for PR gating. During the rollout PR that first introduces
223
+ that file, the gate bootstraps from the candidate branch snapshot once; after
224
+ that, PRs resolve the required baseline from the base branch checkout.
218
225
  | `evalStoreDir` | `{memoryDir}/state/evals` | Root directory for benchmark packs, run summaries, and shadow recall records |
219
226
  | `objectiveStateMemoryEnabled` | `false` | Enable the objective-state memory foundation for normalized world/tool state snapshots |
220
227
  | `objectiveStateSnapshotWritesEnabled` | `false` | Permit objective-state snapshot writers to persist typed state records |
package/dist/index.js CHANGED
@@ -6780,7 +6780,7 @@ function serializeFrontmatter(fm) {
6780
6780
  lines.push(` - targetId: ${link.targetId}`);
6781
6781
  lines.push(` linkType: ${link.linkType}`);
6782
6782
  lines.push(` strength: ${link.strength}`);
6783
- if (link.reason) lines.push(` reason: "${link.reason.replace(/"/g, '\\"')}"`);
6783
+ if (link.reason) lines.push(` reason: ${JSON.stringify(link.reason)}`);
6784
6784
  }
6785
6785
  }
6786
6786
  if (fm.intentGoal) lines.push(`intentGoal: ${fm.intentGoal}`);
@@ -6795,6 +6795,18 @@ function serializeFrontmatter(fm) {
6795
6795
  lines.push("---");
6796
6796
  return lines.join("\n");
6797
6797
  }
6798
+ function parseLinkReasonValue(rawValue) {
6799
+ const legacyValue = rawValue.replace(/\\"/g, '"');
6800
+ const looksLikeLegacyPath = !rawValue.includes("\\\\") && (/[A-Za-z]:\\[A-Za-z0-9._ -]+(?:\\[A-Za-z0-9._ -]+)+/.test(rawValue) || /\\[A-Za-z0-9._ -]+\\[A-Za-z0-9._ -]+/.test(rawValue));
6801
+ if (looksLikeLegacyPath) {
6802
+ return legacyValue;
6803
+ }
6804
+ try {
6805
+ return JSON.parse(`"${rawValue}"`);
6806
+ } catch {
6807
+ return legacyValue;
6808
+ }
6809
+ }
6798
6810
  function parseFrontmatter3(raw) {
6799
6811
  const match = raw.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
6800
6812
  if (!match) return null;
@@ -6897,14 +6909,14 @@ function parseFrontmatter3(raw) {
6897
6909
  if (fmBlock.includes("links:")) {
6898
6910
  const links = [];
6899
6911
  const linkMatches = fmBlock.matchAll(
6900
- /- targetId: (\S+)\s+linkType: (\S+)\s+strength: ([\d.]+)(?:\s+reason: "([^"]*)")?/g
6912
+ /- targetId: (\S+)\s+linkType: (\S+)\s+strength: ([\d.]+)(?:\s+reason: "((?:\\.|[^"\\])*)")?/g
6901
6913
  );
6902
6914
  for (const match2 of linkMatches) {
6903
6915
  links.push({
6904
6916
  targetId: match2[1],
6905
6917
  linkType: match2[2],
6906
6918
  strength: parseFloat(match2[3]),
6907
- reason: match2[4] || void 0
6919
+ reason: match2[4] ? parseLinkReasonValue(match2[4]) : void 0
6908
6920
  });
6909
6921
  }
6910
6922
  if (links.length > 0) {
@@ -12239,6 +12251,13 @@ async function runEvalBaselineDeltaReport(options) {
12239
12251
  if (!baselineSnapshot) {
12240
12252
  throw new Error(`benchmark baseline snapshot not found: ${snapshotId}`);
12241
12253
  }
12254
+ return buildEvalBaselineDeltaReport({
12255
+ baselineSnapshot,
12256
+ candidateSnapshot
12257
+ });
12258
+ }
12259
+ function buildEvalBaselineDeltaReport(options) {
12260
+ const { baselineSnapshot, candidateSnapshot } = options;
12242
12261
  const regressions = [];
12243
12262
  const improvements = [];
12244
12263
  if (candidateSnapshot.status.invalidBenchmarks.length > 0) {