@joshuaswarren/openclaw-engram 8.3.21 → 8.3.22

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
@@ -8238,7 +8238,10 @@ var LastRecallStore = class {
8238
8238
  recordedAt: now,
8239
8239
  queryHash,
8240
8240
  queryLen: opts.query.length,
8241
- memoryIds: opts.memoryIds
8241
+ memoryIds: opts.memoryIds,
8242
+ identityInjectionMode: opts.identityInjection?.mode,
8243
+ identityInjectedChars: opts.identityInjection?.injectedChars,
8244
+ identityInjectionTruncated: opts.identityInjection?.truncated
8242
8245
  };
8243
8246
  this.state[opts.sessionKey] = snapshot;
8244
8247
  const keys = Object.keys(this.state);
@@ -10971,6 +10974,22 @@ function resolveEffectiveRecallMode(options) {
10971
10974
  }
10972
10975
  return plannedMode;
10973
10976
  }
10977
+ function hasIdentityRecoveryIntent(prompt) {
10978
+ const text = typeof prompt === "string" ? prompt.toLowerCase() : "";
10979
+ if (!text) return false;
10980
+ return /\b(identity|continuity|recover(?:y|ing|ed)?|incident|drift|restore|regress(?:ion|ed|ing)?)\b/i.test(
10981
+ text
10982
+ );
10983
+ }
10984
+ function resolveEffectiveIdentityInjectionMode(options) {
10985
+ if (options.configuredMode === "recovery_only" && !hasIdentityRecoveryIntent(options.prompt)) {
10986
+ return { mode: "recovery_only", shouldInject: false };
10987
+ }
10988
+ if (options.recallMode === "minimal" && options.configuredMode === "full") {
10989
+ return { mode: "minimal", shouldInject: true };
10990
+ }
10991
+ return { mode: options.configuredMode, shouldInject: true };
10992
+ }
10974
10993
  function computeArtifactCandidateFetchLimit(targetCount) {
10975
10994
  const cappedTarget = Math.max(0, targetCount);
10976
10995
  if (cappedTarget === 0) return 0;
@@ -11822,6 +11841,9 @@ var Orchestrator = class _Orchestrator {
11822
11841
  let impressionRecorded = false;
11823
11842
  let recallSource = "none";
11824
11843
  let recalledMemoryCount = 0;
11844
+ let identityInjectionModeUsed = "none";
11845
+ let identityInjectedChars = 0;
11846
+ let identityInjectionTruncated = false;
11825
11847
  timings.queryPolicy = `${queryPolicy.promptShape}/${queryPolicy.retrievalBudgetMode}${queryPolicy.skipConversationRecall ? "/skip-conv" : ""}`;
11826
11848
  const recallMode = resolveEffectiveRecallMode({
11827
11849
  plannerEnabled: this.config.recallPlannerEnabled,
@@ -11866,6 +11888,9 @@ var Orchestrator = class _Orchestrator {
11866
11888
  recalledMemoryCount,
11867
11889
  injected: false,
11868
11890
  contextChars: 0,
11891
+ identityInjectionMode: identityInjectionModeUsed,
11892
+ identityInjectedChars,
11893
+ identityInjectionTruncated,
11869
11894
  durationMs: Date.now() - recallStart,
11870
11895
  timings: { ...timings }
11871
11896
  });
@@ -11899,6 +11924,16 @@ var Orchestrator = class _Orchestrator {
11899
11924
  timings.profile = `${Date.now() - t0}ms`;
11900
11925
  return profile2 || null;
11901
11926
  })();
11927
+ const identityContinuityPromise = (async () => {
11928
+ const t0 = Date.now();
11929
+ const section = await this.buildIdentityContinuitySection({
11930
+ storage: profileStorage,
11931
+ recallMode,
11932
+ prompt: retrievalQuery
11933
+ });
11934
+ timings.identityContinuity = `${Date.now() - t0}ms`;
11935
+ return section;
11936
+ })();
11902
11937
  const knowledgeIndexPromise = (async () => {
11903
11938
  if (!this.config.knowledgeIndexEnabled) return null;
11904
11939
  const t0 = Date.now();
@@ -11956,9 +11991,10 @@ var Orchestrator = class _Orchestrator {
11956
11991
  timings.qmd = `${Date.now() - t0}ms`;
11957
11992
  return { memoryResultsLists: [filteredResults], globalResults: [] };
11958
11993
  })();
11959
- const [sharedCtx, profile, kiResult, artifacts, qmdResult] = await Promise.all([
11994
+ const [sharedCtx, profile, identityContinuity, kiResult, artifacts, qmdResult] = await Promise.all([
11960
11995
  sharedContextPromise,
11961
11996
  profilePromise,
11997
+ identityContinuityPromise,
11962
11998
  knowledgeIndexPromise,
11963
11999
  artifactsPromise,
11964
12000
  qmdPromise
@@ -11967,6 +12003,12 @@ var Orchestrator = class _Orchestrator {
11967
12003
  if (profile) sections.push(`## User Profile
11968
12004
 
11969
12005
  ${profile}`);
12006
+ if (identityContinuity) {
12007
+ sections.push(identityContinuity.section);
12008
+ identityInjectionModeUsed = identityContinuity.mode;
12009
+ identityInjectedChars = identityContinuity.injectedChars;
12010
+ identityInjectionTruncated = identityContinuity.truncated;
12011
+ }
11970
12012
  if (kiResult?.result) {
11971
12013
  sections.push(kiResult.result);
11972
12014
  log.debug(`Knowledge Index: ${kiResult.result.split("\n").length - 4} entities, ${kiResult.result.length} chars${kiResult.cached ? " (cached)" : ""}`);
@@ -12078,7 +12120,12 @@ ${tmtNode.summary}`);
12078
12120
  results: memoryResults,
12079
12121
  sections,
12080
12122
  retrievalQuery,
12081
- sessionKey
12123
+ sessionKey,
12124
+ identityInjection: {
12125
+ mode: identityInjectionModeUsed,
12126
+ injectedChars: identityInjectedChars,
12127
+ truncated: identityInjectionTruncated
12128
+ }
12082
12129
  });
12083
12130
  impressionRecorded = true;
12084
12131
  } else {
@@ -12101,7 +12148,12 @@ ${tmtNode.summary}`);
12101
12148
  results: scoped,
12102
12149
  sections,
12103
12150
  retrievalQuery,
12104
- sessionKey
12151
+ sessionKey,
12152
+ identityInjection: {
12153
+ mode: identityInjectionModeUsed,
12154
+ injectedChars: identityInjectedChars,
12155
+ truncated: identityInjectionTruncated
12156
+ }
12105
12157
  });
12106
12158
  impressionRecorded = true;
12107
12159
  } else {
@@ -12118,7 +12170,12 @@ ${tmtNode.summary}`);
12118
12170
  results: longTerm,
12119
12171
  sections,
12120
12172
  retrievalQuery,
12121
- sessionKey
12173
+ sessionKey,
12174
+ identityInjection: {
12175
+ mode: identityInjectionModeUsed,
12176
+ injectedChars: identityInjectedChars,
12177
+ truncated: identityInjectionTruncated
12178
+ }
12122
12179
  });
12123
12180
  impressionRecorded = true;
12124
12181
  }
@@ -12164,7 +12221,12 @@ ${tmtNode.summary}`);
12164
12221
  results: scoped,
12165
12222
  sections,
12166
12223
  retrievalQuery,
12167
- sessionKey
12224
+ sessionKey,
12225
+ identityInjection: {
12226
+ mode: identityInjectionModeUsed,
12227
+ injectedChars: identityInjectedChars,
12228
+ truncated: identityInjectionTruncated
12229
+ }
12168
12230
  });
12169
12231
  impressionRecorded = true;
12170
12232
  } else {
@@ -12199,7 +12261,12 @@ ${tmtNode.summary}`);
12199
12261
  results: recent,
12200
12262
  sections,
12201
12263
  retrievalQuery,
12202
- sessionKey
12264
+ sessionKey,
12265
+ identityInjection: {
12266
+ mode: identityInjectionModeUsed,
12267
+ injectedChars: identityInjectedChars,
12268
+ truncated: identityInjectionTruncated
12269
+ }
12203
12270
  });
12204
12271
  impressionRecorded = true;
12205
12272
  } else {
@@ -12216,7 +12283,12 @@ ${tmtNode.summary}`);
12216
12283
  results: longTerm,
12217
12284
  sections,
12218
12285
  retrievalQuery,
12219
- sessionKey
12286
+ sessionKey,
12287
+ identityInjection: {
12288
+ mode: identityInjectionModeUsed,
12289
+ injectedChars: identityInjectedChars,
12290
+ truncated: identityInjectionTruncated
12291
+ }
12220
12292
  });
12221
12293
  impressionRecorded = true;
12222
12294
  }
@@ -12235,7 +12307,12 @@ ${tmtNode.summary}`);
12235
12307
  results: longTerm,
12236
12308
  sections,
12237
12309
  retrievalQuery,
12238
- sessionKey
12310
+ sessionKey,
12311
+ identityInjection: {
12312
+ mode: identityInjectionModeUsed,
12313
+ injectedChars: identityInjectedChars,
12314
+ truncated: identityInjectionTruncated
12315
+ }
12239
12316
  });
12240
12317
  impressionRecorded = true;
12241
12318
  }
@@ -12374,7 +12451,16 @@ _Context: ${topQuestion.context}_`);
12374
12451
  const timingParts = Object.entries(timings).map(([k, v]) => `${k}=${v}`).join(", ");
12375
12452
  log.debug(`recall: ${timingParts}`);
12376
12453
  if (!impressionRecorded && sessionKey && this.config.recordEmptyRecallImpressions) {
12377
- this.lastRecall.record({ sessionKey, query: retrievalQuery, memoryIds: [] }).catch((err) => log.debug(`last recall record failed: ${err}`));
12454
+ this.lastRecall.record({
12455
+ sessionKey,
12456
+ query: retrievalQuery,
12457
+ memoryIds: [],
12458
+ identityInjection: {
12459
+ mode: identityInjectionModeUsed,
12460
+ injectedChars: identityInjectedChars,
12461
+ truncated: identityInjectionTruncated
12462
+ }
12463
+ }).catch((err) => log.debug(`last recall record failed: ${err}`));
12378
12464
  }
12379
12465
  const context = sections.length === 0 ? "" : sections.join("\n\n---\n\n");
12380
12466
  this.emitTrace({
@@ -12395,6 +12481,9 @@ _Context: ${topQuestion.context}_`);
12395
12481
  recalledMemoryCount,
12396
12482
  injected: context.length > 0,
12397
12483
  contextChars: context.length,
12484
+ identityInjectionMode: identityInjectionModeUsed,
12485
+ identityInjectedChars,
12486
+ identityInjectionTruncated,
12398
12487
  durationMs: Date.now() - recallStart,
12399
12488
  timings: { ...timings }
12400
12489
  });
@@ -13490,6 +13579,86 @@ ${snippet}`;
13490
13579
 
13491
13580
  ${lines.join("\n\n")}`;
13492
13581
  }
13582
+ summarizeIdentityText(raw, maxLines, maxChars) {
13583
+ const lines = raw.replace(/\r/g, "").split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
13584
+ const compact = lines.slice(0, Math.max(1, maxLines)).join(" ");
13585
+ if (compact.length <= maxChars) return compact;
13586
+ return `${compact.slice(0, Math.max(0, maxChars - 1))}\u2026`;
13587
+ }
13588
+ formatOpenIncidentLine(incident, includeDetails) {
13589
+ const base = `[${incident.id}] ${incident.symptom.trim()}`;
13590
+ if (!includeDetails) return `- ${base}`;
13591
+ const parts = [base];
13592
+ if (incident.suspectedCause) parts.push(`cause: ${incident.suspectedCause.trim()}`);
13593
+ if (incident.triggerWindow) parts.push(`window: ${incident.triggerWindow.trim()}`);
13594
+ return `- ${parts.join(" | ")}`;
13595
+ }
13596
+ trimIdentitySection(content, maxChars) {
13597
+ if (maxChars <= 0) return { text: "", truncated: false };
13598
+ if (content.length <= maxChars) return { text: content, truncated: false };
13599
+ const suffix = "\n\n...(identity continuity trimmed)";
13600
+ if (maxChars <= suffix.length) {
13601
+ return { text: content.slice(0, maxChars), truncated: true };
13602
+ }
13603
+ const headroom = Math.max(0, maxChars - suffix.length);
13604
+ return { text: `${content.slice(0, headroom)}${suffix}`, truncated: true };
13605
+ }
13606
+ async buildIdentityContinuitySection(options) {
13607
+ if (!this.config.identityContinuityEnabled) return null;
13608
+ if (this.config.identityMaxInjectChars <= 0) return null;
13609
+ const resolved = resolveEffectiveIdentityInjectionMode({
13610
+ configuredMode: this.config.identityInjectionMode,
13611
+ recallMode: options.recallMode,
13612
+ prompt: options.prompt
13613
+ });
13614
+ if (!resolved.shouldInject) return null;
13615
+ const [anchorRaw, loopsRaw, incidents] = await Promise.all([
13616
+ options.storage.readIdentityAnchor(),
13617
+ options.storage.readIdentityImprovementLoops(),
13618
+ options.storage.readContinuityIncidents(200)
13619
+ ]);
13620
+ const openIncidents = incidents.filter((incident) => incident.state === "open");
13621
+ const lines = [];
13622
+ if (resolved.mode === "full") {
13623
+ lines.push("## Identity Continuity");
13624
+ if (anchorRaw && anchorRaw.trim().length > 0) {
13625
+ lines.push("", "### Anchor", "", anchorRaw.trim());
13626
+ }
13627
+ if (loopsRaw && loopsRaw.trim().length > 0) {
13628
+ lines.push("", "### Improvement Loops", "", loopsRaw.trim());
13629
+ }
13630
+ lines.push("", "### Open Incidents", "");
13631
+ if (openIncidents.length === 0) {
13632
+ lines.push("- none");
13633
+ } else {
13634
+ lines.push(
13635
+ ...openIncidents.slice(0, 5).map((incident) => this.formatOpenIncidentLine(incident, true))
13636
+ );
13637
+ }
13638
+ } else {
13639
+ const anchorSummary = anchorRaw ? this.summarizeIdentityText(anchorRaw, 3, 320) : "";
13640
+ const loopsSummary = loopsRaw ? this.summarizeIdentityText(loopsRaw, 2, 240) : "";
13641
+ lines.push("## Identity Continuity Signals", "");
13642
+ if (anchorSummary) lines.push(`- anchor: ${anchorSummary}`);
13643
+ if (loopsSummary) lines.push(`- loops: ${loopsSummary}`);
13644
+ if (openIncidents.length === 0) {
13645
+ lines.push("- incidents: 0 open");
13646
+ } else {
13647
+ lines.push(`- incidents: ${openIncidents.length} open`);
13648
+ lines.push(...openIncidents.slice(0, 2).map((incident) => this.formatOpenIncidentLine(incident, false)));
13649
+ }
13650
+ }
13651
+ const body = lines.join("\n").trim();
13652
+ if (!body) return null;
13653
+ const { text, truncated } = this.trimIdentitySection(body, this.config.identityMaxInjectChars);
13654
+ if (!text) return null;
13655
+ return {
13656
+ section: text,
13657
+ mode: resolved.mode,
13658
+ injectedChars: text.length,
13659
+ truncated
13660
+ };
13661
+ }
13493
13662
  emitTrace(event) {
13494
13663
  try {
13495
13664
  const cb = globalThis.__openclawEngramTrace;
@@ -13503,7 +13672,12 @@ ${lines.join("\n\n")}`;
13503
13672
  this.trackMemoryAccess(memoryIds);
13504
13673
  if (options.sessionKey) {
13505
13674
  const unique = Array.from(new Set(memoryIds)).slice(0, 40);
13506
- this.lastRecall.record({ sessionKey: options.sessionKey, query: options.retrievalQuery, memoryIds: unique }).catch((err) => log.debug(`last recall record failed: ${err}`));
13675
+ this.lastRecall.record({
13676
+ sessionKey: options.sessionKey,
13677
+ query: options.retrievalQuery,
13678
+ memoryIds: unique,
13679
+ identityInjection: options.identityInjection
13680
+ }).catch((err) => log.debug(`last recall record failed: ${err}`));
13507
13681
  }
13508
13682
  options.sections.push(this.formatQmdResults(options.title, options.results));
13509
13683
  }
@@ -14497,6 +14671,7 @@ NOTE: You did not provide sessionKey; under concurrency this may not match your
14497
14671
  "",
14498
14672
  `Recorded at: ${snap.recordedAt}`,
14499
14673
  `Query hash: ${snap.queryHash} (len=${snap.queryLen})`,
14674
+ `Identity injection: mode=${snap.identityInjectionMode ?? "none"}, chars=${snap.identityInjectedChars ?? 0}, truncated=${snap.identityInjectionTruncated === true ? "yes" : "no"}`,
14500
14675
  `Memories (${snap.memoryIds.length}):`,
14501
14676
  ...snap.memoryIds.map((id) => `- ${id}`)
14502
14677
  ].join("\n")