@joshuaswarren/openclaw-engram 8.3.80 → 8.3.81

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
@@ -9137,6 +9137,7 @@ var LastRecallStore = class {
9137
9137
  queryHash,
9138
9138
  queryLen: opts.query.length,
9139
9139
  memoryIds: opts.memoryIds,
9140
+ policyVersion: opts.policyVersion,
9140
9141
  identityInjectionMode: opts.identityInjection?.mode,
9141
9142
  identityInjectedChars: opts.identityInjection?.injectedChars,
9142
9143
  identityInjectionTruncated: opts.identityInjection?.truncated
@@ -13166,7 +13167,7 @@ function sanitizeRuntimePolicyValues(values, options) {
13166
13167
  function isRuntimeParameter(parameter) {
13167
13168
  return parameter === "recencyWeight" || parameter === "lifecyclePromoteHeatThreshold" || parameter === "lifecycleStaleDecayThreshold" || parameter === "cronRecallInstructionHeavyTokenCap";
13168
13169
  }
13169
- async function readSnapshot(filePath) {
13170
+ async function readRuntimePolicySnapshot(filePath, options) {
13170
13171
  try {
13171
13172
  const raw = await readFile18(filePath, "utf-8");
13172
13173
  const parsed = JSON.parse(raw);
@@ -13176,7 +13177,9 @@ async function readSnapshot(filePath) {
13176
13177
  return {
13177
13178
  version: parsed.version,
13178
13179
  updatedAt: parsed.updatedAt,
13179
- values: sanitizeRuntimePolicyValues(parsed.values),
13180
+ values: sanitizeRuntimePolicyValues(parsed.values, {
13181
+ maxStaleDecayThreshold: options?.maxStaleDecayThreshold
13182
+ }),
13180
13183
  sourceAdjustmentCount: parsed.sourceAdjustmentCount
13181
13184
  };
13182
13185
  } catch {
@@ -13201,14 +13204,16 @@ var PolicyRuntimeManager = class {
13201
13204
  runtimePath;
13202
13205
  runtimePrevPath;
13203
13206
  async loadRuntimeValues() {
13204
- const snapshot = await readSnapshot(this.runtimePath);
13205
- if (!snapshot) return null;
13206
- return sanitizeRuntimePolicyValues(snapshot.values, {
13207
+ const snapshot = await readRuntimePolicySnapshot(this.runtimePath, {
13207
13208
  maxStaleDecayThreshold: this.config.lifecycleArchiveDecayThreshold
13208
13209
  });
13210
+ if (!snapshot) return null;
13211
+ return snapshot.values;
13209
13212
  }
13210
13213
  async rollback() {
13211
- const previous = await readSnapshot(this.runtimePrevPath);
13214
+ const previous = await readRuntimePolicySnapshot(this.runtimePrevPath, {
13215
+ maxStaleDecayThreshold: this.config.lifecycleArchiveDecayThreshold
13216
+ });
13212
13217
  if (!previous) return false;
13213
13218
  await writeSnapshotAtomic(this.runtimePath, {
13214
13219
  ...previous,
@@ -13225,7 +13230,9 @@ var PolicyRuntimeManager = class {
13225
13230
  ...this.config.behaviorLoopProtectedParams,
13226
13231
  ...state.protectedParams
13227
13232
  ]);
13228
- const existing = await readSnapshot(this.runtimePath);
13233
+ const existing = await readRuntimePolicySnapshot(this.runtimePath, {
13234
+ maxStaleDecayThreshold: this.config.lifecycleArchiveDecayThreshold
13235
+ });
13229
13236
  const candidate = {
13230
13237
  recencyWeight: existing?.values.recencyWeight ?? this.config.recencyWeight,
13231
13238
  lifecyclePromoteHeatThreshold: existing?.values.lifecyclePromoteHeatThreshold ?? this.config.lifecyclePromoteHeatThreshold,
@@ -13755,6 +13762,16 @@ var Orchestrator = class _Orchestrator {
13755
13762
  effectiveCronRecallInstructionHeavyTokenCap() {
13756
13763
  return this.runtimePolicyValues?.cronRecallInstructionHeavyTokenCap ?? this.config.cronRecallInstructionHeavyTokenCap;
13757
13764
  }
13765
+ currentPolicyVersion() {
13766
+ const thresholds = this.effectiveLifecycleThresholds();
13767
+ const payload = {
13768
+ recencyWeight: this.effectiveRecencyWeight(),
13769
+ lifecyclePromoteHeatThreshold: thresholds.promoteHeatThreshold,
13770
+ lifecycleStaleDecayThreshold: thresholds.staleDecayThreshold,
13771
+ cronRecallInstructionHeavyTokenCap: this.effectiveCronRecallInstructionHeavyTokenCap()
13772
+ };
13773
+ return createHash6("sha256").update(JSON.stringify(payload)).digest("hex").slice(0, 12);
13774
+ }
13758
13775
  effectiveLifecycleThresholds() {
13759
13776
  const archiveDecayThreshold = this.config.lifecycleArchiveDecayThreshold;
13760
13777
  const staleDecayThreshold = Math.min(
@@ -14559,6 +14576,7 @@ ${r.snippet.trim()}
14559
14576
  });
14560
14577
  const retrievalQuery = queryPolicy.retrievalQuery || prompt;
14561
14578
  const retrievalQueryHash = createHash6("sha256").update(retrievalQuery).digest("hex");
14579
+ const policyVersion = this.currentPolicyVersion();
14562
14580
  let impressionRecorded = false;
14563
14581
  let recallSource = "none";
14564
14582
  let recalledMemoryCount = 0;
@@ -14609,6 +14627,7 @@ ${r.snippet.trim()}
14609
14627
  recalledMemoryCount,
14610
14628
  injected: false,
14611
14629
  contextChars: 0,
14630
+ policyVersion,
14612
14631
  identityInjectionMode: identityInjectionModeUsed,
14613
14632
  identityInjectedChars,
14614
14633
  identityInjectionTruncated,
@@ -15180,6 +15199,7 @@ _Context: ${topQuestion.context}_`);
15180
15199
  sessionKey,
15181
15200
  query: retrievalQuery,
15182
15201
  memoryIds: [],
15202
+ policyVersion,
15183
15203
  identityInjection: {
15184
15204
  mode: identityInjectionModeUsed,
15185
15205
  injectedChars: identityInjectedChars,
@@ -15206,6 +15226,7 @@ _Context: ${topQuestion.context}_`);
15206
15226
  recalledMemoryCount,
15207
15227
  injected: context.length > 0,
15208
15228
  contextChars: context.length,
15229
+ policyVersion,
15209
15230
  identityInjectionMode: identityInjectionModeUsed,
15210
15231
  identityInjectedChars,
15211
15232
  identityInjectionTruncated,
@@ -16956,6 +16977,7 @@ ${lines.join("\n\n")}`;
16956
16977
  sessionKey: options.sessionKey,
16957
16978
  query: options.retrievalQuery,
16958
16979
  memoryIds: unique,
16980
+ policyVersion: this.currentPolicyVersion(),
16959
16981
  identityInjection: options.identityInjection
16960
16982
  }).catch((err) => log.debug(`last recall record failed: ${err}`));
16961
16983
  }
@@ -19810,6 +19832,7 @@ mistakes: ${res.mistakesCount} patterns`
19810
19832
  // src/cli.ts
19811
19833
  import path45 from "path";
19812
19834
  import { access as access3, readFile as readFile31, readdir as readdir19, unlink as unlink5 } from "fs/promises";
19835
+ import { createHash as createHash9 } from "crypto";
19813
19836
 
19814
19837
  // src/transfer/export-json.ts
19815
19838
  import path31 from "path";
@@ -22099,6 +22122,171 @@ async function runTierMigrateCliCommand(orchestrator, options = {}) {
22099
22122
  limit: options.limit
22100
22123
  });
22101
22124
  }
22125
+ function effectivePolicyValuesForVersion(values, config) {
22126
+ const candidate = {
22127
+ recencyWeight: values.recencyWeight ?? config.recencyWeight,
22128
+ lifecyclePromoteHeatThreshold: values.lifecyclePromoteHeatThreshold ?? config.lifecyclePromoteHeatThreshold,
22129
+ lifecycleStaleDecayThreshold: values.lifecycleStaleDecayThreshold ?? config.lifecycleStaleDecayThreshold,
22130
+ cronRecallInstructionHeavyTokenCap: values.cronRecallInstructionHeavyTokenCap ?? config.cronRecallInstructionHeavyTokenCap
22131
+ };
22132
+ const normalized = sanitizeRuntimePolicyValues(candidate, {
22133
+ maxStaleDecayThreshold: config.lifecycleArchiveDecayThreshold
22134
+ });
22135
+ return {
22136
+ recencyWeight: normalized.recencyWeight ?? config.recencyWeight,
22137
+ lifecyclePromoteHeatThreshold: normalized.lifecyclePromoteHeatThreshold ?? config.lifecyclePromoteHeatThreshold,
22138
+ lifecycleStaleDecayThreshold: normalized.lifecycleStaleDecayThreshold ?? config.lifecycleStaleDecayThreshold,
22139
+ cronRecallInstructionHeavyTokenCap: normalized.cronRecallInstructionHeavyTokenCap ?? config.cronRecallInstructionHeavyTokenCap
22140
+ };
22141
+ }
22142
+ function policyVersionForValues(values, config) {
22143
+ const normalized = effectivePolicyValuesForVersion(values, config);
22144
+ return createHash9("sha256").update(JSON.stringify(normalized)).digest("hex").slice(0, 12);
22145
+ }
22146
+ async function readRuntimePolicySnapshot2(config, fileName) {
22147
+ const filePath = path45.join(config.memoryDir, "state", fileName);
22148
+ const snapshot = await readRuntimePolicySnapshot(filePath, {
22149
+ maxStaleDecayThreshold: config.lifecycleArchiveDecayThreshold
22150
+ });
22151
+ if (!snapshot) return null;
22152
+ return {
22153
+ version: snapshot.version,
22154
+ updatedAt: snapshot.updatedAt,
22155
+ values: snapshot.values,
22156
+ sourceAdjustmentCount: Math.max(0, Math.floor(snapshot.sourceAdjustmentCount))
22157
+ };
22158
+ }
22159
+ function parseSinceDurationMs(since) {
22160
+ const trimmed = since.trim().toLowerCase();
22161
+ const match = trimmed.match(/^(\d+)\s*([mhd])$/);
22162
+ if (!match) {
22163
+ throw new Error(`invalid --since value: ${since} (expected formats like 30m, 12h, 7d)`);
22164
+ }
22165
+ const amount = Number.parseInt(match[1] ?? "0", 10);
22166
+ const unit = match[2];
22167
+ if (!Number.isFinite(amount) || amount <= 0) {
22168
+ throw new Error(`invalid --since value: ${since}`);
22169
+ }
22170
+ if (unit === "m") return amount * 60 * 1e3;
22171
+ if (unit === "h") return amount * 60 * 60 * 1e3;
22172
+ return amount * 24 * 60 * 60 * 1e3;
22173
+ }
22174
+ function resolvePolicySignalNamespaces(orchestrator) {
22175
+ const names = /* @__PURE__ */ new Set([orchestrator.config.defaultNamespace]);
22176
+ if (orchestrator.config.namespacesEnabled) {
22177
+ names.add(orchestrator.config.sharedNamespace);
22178
+ for (const policy of orchestrator.config.namespacePolicies) {
22179
+ if (policy?.name) names.add(policy.name);
22180
+ }
22181
+ }
22182
+ return [...names];
22183
+ }
22184
+ async function readBehaviorSignalsForNamespaces(orchestrator, limitPerNamespace) {
22185
+ const namespaces = resolvePolicySignalNamespaces(orchestrator);
22186
+ const merged = [];
22187
+ for (const namespace of namespaces) {
22188
+ const storage = await orchestrator.getStorage(namespace);
22189
+ const events = await storage.readBehaviorSignals(limitPerNamespace);
22190
+ merged.push(...events);
22191
+ }
22192
+ return merged;
22193
+ }
22194
+ function summarizeTopSignals(signals, cutoffIso, topN = 5) {
22195
+ const cutoffMs = cutoffIso ? Date.parse(cutoffIso) : Number.NEGATIVE_INFINITY;
22196
+ const grouped = /* @__PURE__ */ new Map();
22197
+ for (const signal of signals) {
22198
+ const ts = Date.parse(signal.timestamp);
22199
+ if (Number.isFinite(cutoffMs) && (!Number.isFinite(ts) || ts < cutoffMs)) continue;
22200
+ const key = `${signal.signalType}:${signal.direction}`;
22201
+ const existing = grouped.get(key);
22202
+ if (existing) {
22203
+ existing.count += 1;
22204
+ if (signal.timestamp > existing.lastSeenAt) {
22205
+ existing.lastSeenAt = signal.timestamp;
22206
+ }
22207
+ } else {
22208
+ grouped.set(key, {
22209
+ signalType: signal.signalType,
22210
+ direction: signal.direction,
22211
+ count: 1,
22212
+ lastSeenAt: signal.timestamp
22213
+ });
22214
+ }
22215
+ }
22216
+ return [...grouped.values()].sort((a, b) => b.count - a.count || b.lastSeenAt.localeCompare(a.lastSeenAt)).slice(0, Math.max(1, topN));
22217
+ }
22218
+ async function runPolicyStatusCliCommand(orchestrator) {
22219
+ const now = /* @__PURE__ */ new Date();
22220
+ const current = await readRuntimePolicySnapshot2(orchestrator.config, "policy-runtime.json");
22221
+ const previous = await readRuntimePolicySnapshot2(orchestrator.config, "policy-runtime.prev.json");
22222
+ const signals = await readBehaviorSignalsForNamespaces(orchestrator, 1e3);
22223
+ const defaultWindowMs = Math.max(0, orchestrator.config.behaviorLoopLearningWindowDays) * 24 * 60 * 60 * 1e3;
22224
+ const cutoffIso = defaultWindowMs > 0 ? new Date(now.getTime() - defaultWindowMs).toISOString() : void 0;
22225
+ return {
22226
+ generatedAt: now.toISOString(),
22227
+ autoTuneEnabled: orchestrator.config.behaviorLoopAutoTuneEnabled,
22228
+ current: current ? {
22229
+ ...current,
22230
+ policyVersion: policyVersionForValues(current.values, orchestrator.config)
22231
+ } : null,
22232
+ previous: previous ? {
22233
+ ...previous,
22234
+ policyVersion: policyVersionForValues(previous.values, orchestrator.config)
22235
+ } : null,
22236
+ topContributingSignals: summarizeTopSignals(signals, cutoffIso)
22237
+ };
22238
+ }
22239
+ async function runPolicyDiffCliCommand(orchestrator, options = {}) {
22240
+ const since = options.since?.trim() || "7d";
22241
+ const sinceMs = parseSinceDurationMs(since);
22242
+ const sinceIso = new Date(Date.now() - sinceMs).toISOString();
22243
+ const current = await readRuntimePolicySnapshot2(orchestrator.config, "policy-runtime.json");
22244
+ const previous = await readRuntimePolicySnapshot2(orchestrator.config, "policy-runtime.prev.json");
22245
+ const currentValues = current?.values ?? {};
22246
+ const previousValues = previous?.values ?? {};
22247
+ const parameterKeys = /* @__PURE__ */ new Set([
22248
+ ...Object.keys(currentValues),
22249
+ ...Object.keys(previousValues)
22250
+ ]);
22251
+ const deltas = [];
22252
+ for (const parameter of parameterKeys) {
22253
+ const previousRaw = previousValues[parameter];
22254
+ const nextRaw = currentValues[parameter];
22255
+ const previousValue = typeof previousRaw === "number" ? previousRaw : null;
22256
+ const nextValue = typeof nextRaw === "number" ? nextRaw : null;
22257
+ if (previousValue === nextValue) continue;
22258
+ deltas.push({
22259
+ parameter,
22260
+ previousValue,
22261
+ nextValue,
22262
+ delta: (nextValue ?? 0) - (previousValue ?? 0),
22263
+ evidenceCount: current?.sourceAdjustmentCount ?? 0
22264
+ });
22265
+ }
22266
+ deltas.sort((a, b) => Math.abs(b.delta) - Math.abs(a.delta) || a.parameter.localeCompare(b.parameter));
22267
+ const signals = await readBehaviorSignalsForNamespaces(orchestrator, 1e3);
22268
+ return {
22269
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
22270
+ since,
22271
+ sinceIso,
22272
+ currentPolicyVersion: current ? policyVersionForValues(current.values, orchestrator.config) : null,
22273
+ previousPolicyVersion: previous ? policyVersionForValues(previous.values, orchestrator.config) : null,
22274
+ deltas,
22275
+ topContributingSignals: summarizeTopSignals(signals, sinceIso)
22276
+ };
22277
+ }
22278
+ async function runPolicyRollbackCliCommand(orchestrator) {
22279
+ const rolledBack = await orchestrator.rollbackBehaviorRuntimePolicy();
22280
+ const current = await readRuntimePolicySnapshot2(orchestrator.config, "policy-runtime.json");
22281
+ return {
22282
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
22283
+ rolledBack,
22284
+ current: current ? {
22285
+ ...current,
22286
+ policyVersion: policyVersionForValues(current.values, orchestrator.config)
22287
+ } : null
22288
+ };
22289
+ }
22102
22290
  function incrementCounter(target, key) {
22103
22291
  const normalized = key && key.length > 0 ? key : "unknown";
22104
22292
  target[normalized] = (target[normalized] ?? 0) + 1;
@@ -22818,6 +23006,23 @@ function registerCli(api, orchestrator) {
22818
23006
  console.log(JSON.stringify(summary, null, 2));
22819
23007
  console.log("OK");
22820
23008
  });
23009
+ cmd.command("policy-status").description("Show runtime behavior-loop policy status and top contributing signals").action(async () => {
23010
+ const status = await runPolicyStatusCliCommand(orchestrator);
23011
+ console.log(JSON.stringify(status, null, 2));
23012
+ console.log("OK");
23013
+ });
23014
+ cmd.command("policy-diff").description("Show runtime policy deltas and evidence since a relative duration (default: 7d)").option("--since <window>", "Relative duration window like 30m, 12h, 7d", "7d").action(async (...args) => {
23015
+ const options = args[0] ?? {};
23016
+ const since = typeof options.since === "string" ? options.since : "7d";
23017
+ const report = await runPolicyDiffCliCommand(orchestrator, { since });
23018
+ console.log(JSON.stringify(report, null, 2));
23019
+ console.log("OK");
23020
+ });
23021
+ cmd.command("policy-rollback").description("Roll back runtime behavior policy to the previous snapshot").action(async () => {
23022
+ const report = await runPolicyRollbackCliCommand(orchestrator);
23023
+ console.log(JSON.stringify(report, null, 2));
23024
+ console.log("OK");
23025
+ });
22821
23026
  cmd.command("action-audit").description("Show namespace-aware memory action policy outcomes").option("--namespace <name>", "Filter to a single namespace").option("--limit <n>", "Max events to read per namespace", "200").action(async (...args) => {
22822
23027
  const options = args[0] ?? {};
22823
23028
  const limitRaw = parseInt(String(options.limit ?? "200"), 10);