@joshuaswarren/openclaw-engram 9.0.31 → 9.0.32

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
@@ -36,6 +36,7 @@ AI agents forget everything between conversations. Engram fixes that.
36
36
  - **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.
37
37
  - **Trust-zone promotion path** — Engram can now, when `trustZonesEnabled` and `quarantinePromotionEnabled` are enabled, persist typed quarantine, working, and trusted records, plan explicit promotions, block direct `quarantine -> trusted` jumps, and require anchored provenance before promoting risky working records into `trusted`.
38
38
  - **Trust-zone recall** — Engram can now, when `trustZoneRecallEnabled` is enabled, inject prompt-relevant `working` and `trusted` trust-zone records into recall context as a separate `Trust Zones` section while keeping `quarantine` material out of recall by default.
39
+ - **Provenance trust scoring** — Engram can now, when `memoryPoisoningDefenseEnabled` is enabled, score trust-zone provenance deterministically from source class and evidence anchors so poisoning defenses start with measurable trust signals instead of opaque heuristics.
39
40
  - **Zero-config start** — Install, add an API key, restart. Engram works out of the box with sensible defaults and progressively unlocks advanced features as you enable them.
40
41
 
41
42
  ## Quick Start
@@ -197,6 +198,7 @@ Key settings:
197
198
  | `quarantinePromotionEnabled` | `false` | Allow explicit trust-zone promotions such as `quarantine -> working` and guarded `working -> trusted` |
198
199
  | `trustZoneStoreDir` | `{memoryDir}/state/trust-zones` | Root directory for trust-zone records |
199
200
  | `trustZoneRecallEnabled` | `false` | Inject prompt-relevant working and trusted trust-zone records into recall context |
201
+ | `memoryPoisoningDefenseEnabled` | `false` | Enable deterministic provenance trust scoring in trust-zone status output as the first poisoning-defense signal |
200
202
 
201
203
  Full reference: [Config Reference](docs/config-reference.md)
202
204
 
package/dist/index.js CHANGED
@@ -300,6 +300,7 @@ function parseConfig(raw) {
300
300
  quarantinePromotionEnabled: cfg.quarantinePromotionEnabled === true,
301
301
  trustZoneStoreDir: typeof cfg.trustZoneStoreDir === "string" && cfg.trustZoneStoreDir.trim().length > 0 ? cfg.trustZoneStoreDir.trim() : path.join(memoryDir, "state", "trust-zones"),
302
302
  trustZoneRecallEnabled: cfg.trustZoneRecallEnabled === true,
303
+ memoryPoisoningDefenseEnabled: cfg.memoryPoisoningDefenseEnabled === true,
303
304
  // Local LLM Provider (v2.1)
304
305
  localLlmEnabled: cfg.localLlmEnabled === true || cfg.localLlmEnabled === "true",
305
306
  // default: false
@@ -14672,6 +14673,40 @@ function dedupeStrings(values) {
14672
14673
  if (out.length === 0) return void 0;
14673
14674
  return [...new Set(out)];
14674
14675
  }
14676
+ var SOURCE_CLASS_WEIGHTS = {
14677
+ manual: 0.9,
14678
+ system_memory: 0.85,
14679
+ user_input: 0.75,
14680
+ tool_output: 0.55,
14681
+ subagent_trace: 0.45,
14682
+ web_content: 0.35
14683
+ };
14684
+ function roundTrustScore(value) {
14685
+ return Math.round(value * 1e3) / 1e3;
14686
+ }
14687
+ function trustScoreBand(total) {
14688
+ if (total >= 0.8) return "high";
14689
+ if (total >= 0.5) return "medium";
14690
+ return "low";
14691
+ }
14692
+ function scoreTrustZoneProvenance(record) {
14693
+ const sourceClassWeight = SOURCE_CLASS_WEIGHTS[record.provenance.sourceClass];
14694
+ const sourceIdBonus = typeof record.provenance.sourceId === "string" ? 0.1 : 0;
14695
+ const evidenceHashBonus = typeof record.provenance.evidenceHash === "string" ? 0.2 : 0;
14696
+ const sessionKeyBonus = typeof record.provenance.sessionKey === "string" ? 0.05 : 0;
14697
+ const total = roundTrustScore(
14698
+ Math.min(1, sourceClassWeight + sourceIdBonus + evidenceHashBonus + sessionKeyBonus)
14699
+ );
14700
+ return {
14701
+ total,
14702
+ band: trustScoreBand(total),
14703
+ anchored: hasAnchoredProvenance(record),
14704
+ sourceClassWeight,
14705
+ sourceIdBonus,
14706
+ evidenceHashBonus,
14707
+ sessionKeyBonus
14708
+ };
14709
+ }
14675
14710
  function planTrustZonePromotion(options) {
14676
14711
  const { record, targetZone } = options;
14677
14712
  const reasons = [];
@@ -14865,13 +14900,23 @@ async function getTrustZoneStoreStatus(options) {
14865
14900
  records.sort((a, b) => b.recordedAt.localeCompare(a.recordedAt));
14866
14901
  const byZone = {};
14867
14902
  const byKind = {};
14903
+ const byTrustBand = {};
14904
+ let trustScoreTotal = 0;
14868
14905
  for (const record of records) {
14869
14906
  byZone[record.zone] = (byZone[record.zone] ?? 0) + 1;
14870
14907
  byKind[record.kind] = (byKind[record.kind] ?? 0) + 1;
14908
+ if (options.poisoningDefenseEnabled === true) {
14909
+ const score = scoreTrustZoneProvenance(record);
14910
+ byTrustBand[score.band] = (byTrustBand[score.band] ?? 0) + 1;
14911
+ trustScoreTotal += score.total;
14912
+ }
14871
14913
  }
14914
+ const averageTrustScore = options.poisoningDefenseEnabled === true && records.length > 0 ? roundTrustScore(trustScoreTotal / records.length) : void 0;
14915
+ const latestRecordTrustScore = options.poisoningDefenseEnabled === true && records[0] ? scoreTrustZoneProvenance(records[0]) : void 0;
14872
14916
  return {
14873
14917
  enabled: options.enabled,
14874
14918
  promotionEnabled: options.promotionEnabled,
14919
+ poisoningDefenseEnabled: options.poisoningDefenseEnabled,
14875
14920
  rootDir,
14876
14921
  zonesDir,
14877
14922
  records: {
@@ -14882,9 +14927,12 @@ async function getTrustZoneStoreStatus(options) {
14882
14927
  byKind,
14883
14928
  latestRecordId: records[0]?.recordId,
14884
14929
  latestRecordedAt: records[0]?.recordedAt,
14885
- latestZone: records[0]?.zone
14930
+ latestZone: records[0]?.zone,
14931
+ averageTrustScore,
14932
+ byTrustBand: options.poisoningDefenseEnabled === true ? byTrustBand : void 0
14886
14933
  },
14887
14934
  latestRecord: records[0],
14935
+ latestRecordTrustScore,
14888
14936
  invalidRecords
14889
14937
  };
14890
14938
  }
@@ -26808,7 +26856,8 @@ async function runTrustZoneStatusCliCommand(options) {
26808
26856
  memoryDir: options.memoryDir,
26809
26857
  trustZoneStoreDir: options.trustZoneStoreDir,
26810
26858
  enabled: options.trustZonesEnabled,
26811
- promotionEnabled: options.quarantinePromotionEnabled
26859
+ promotionEnabled: options.quarantinePromotionEnabled,
26860
+ poisoningDefenseEnabled: options.memoryPoisoningDefenseEnabled
26812
26861
  });
26813
26862
  }
26814
26863
  async function runTrustZonePromoteCliCommand(options) {
@@ -27992,7 +28041,8 @@ function registerCli(api, orchestrator) {
27992
28041
  memoryDir: orchestrator.config.memoryDir,
27993
28042
  trustZoneStoreDir: orchestrator.config.trustZoneStoreDir,
27994
28043
  trustZonesEnabled: orchestrator.config.trustZonesEnabled,
27995
- quarantinePromotionEnabled: orchestrator.config.quarantinePromotionEnabled
28044
+ quarantinePromotionEnabled: orchestrator.config.quarantinePromotionEnabled,
28045
+ memoryPoisoningDefenseEnabled: orchestrator.config.memoryPoisoningDefenseEnabled
27996
28046
  });
27997
28047
  console.log(JSON.stringify(status, null, 2));
27998
28048
  console.log("OK");