@joshuaswarren/openclaw-engram 8.3.20 → 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 +389 -20
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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);
|
|
@@ -10562,7 +10565,7 @@ title: ${opts.title.replace(/\n/g, " ").slice(0, 200)}
|
|
|
10562
10565
|
};
|
|
10563
10566
|
|
|
10564
10567
|
// src/compounding/engine.ts
|
|
10565
|
-
import { mkdir as mkdir15, readFile as readFile15, writeFile as writeFile14 } from "fs/promises";
|
|
10568
|
+
import { mkdir as mkdir15, readFile as readFile15, readdir as readdir10, writeFile as writeFile14 } from "fs/promises";
|
|
10566
10569
|
import path21 from "path";
|
|
10567
10570
|
import os4 from "os";
|
|
10568
10571
|
function isoWeekId(d) {
|
|
@@ -10574,6 +10577,22 @@ function isoWeekId(d) {
|
|
|
10574
10577
|
const yyyy = dt.getUTCFullYear();
|
|
10575
10578
|
return `${yyyy}-W${String(week).padStart(2, "0")}`;
|
|
10576
10579
|
}
|
|
10580
|
+
function isoMonthId(d) {
|
|
10581
|
+
return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, "0")}`;
|
|
10582
|
+
}
|
|
10583
|
+
function monthIdFromIsoWeek(weekId) {
|
|
10584
|
+
const match = weekId.match(/^(\d{4})-W(\d{2})$/);
|
|
10585
|
+
if (!match) return isoMonthId(/* @__PURE__ */ new Date());
|
|
10586
|
+
const year = Number(match[1]);
|
|
10587
|
+
const week = Number(match[2]);
|
|
10588
|
+
const jan4 = new Date(Date.UTC(year, 0, 4));
|
|
10589
|
+
const jan4Day = jan4.getUTCDay() || 7;
|
|
10590
|
+
const isoWeekOneMonday = new Date(jan4);
|
|
10591
|
+
isoWeekOneMonday.setUTCDate(jan4.getUTCDate() - (jan4Day - 1));
|
|
10592
|
+
const monday = new Date(isoWeekOneMonday);
|
|
10593
|
+
monday.setUTCDate(isoWeekOneMonday.getUTCDate() + (week - 1) * 7);
|
|
10594
|
+
return isoMonthId(monday);
|
|
10595
|
+
}
|
|
10577
10596
|
function sharedContextDir(config) {
|
|
10578
10597
|
if (typeof config.sharedContextDir === "string" && config.sharedContextDir.length > 0) {
|
|
10579
10598
|
return config.sharedContextDir;
|
|
@@ -10586,10 +10605,20 @@ var CompoundingEngine = class {
|
|
|
10586
10605
|
this.weeklyDir = path21.join(config.memoryDir, "compounding", "weekly");
|
|
10587
10606
|
this.mistakesPath = path21.join(config.memoryDir, "compounding", "mistakes.json");
|
|
10588
10607
|
this.feedbackInboxPath = path21.join(sharedContextDir(config), "feedback", "inbox.jsonl");
|
|
10608
|
+
this.identityAnchorPath = path21.join(config.memoryDir, "identity", "identity-anchor.md");
|
|
10609
|
+
this.identityIncidentsDir = path21.join(config.memoryDir, "identity", "incidents");
|
|
10610
|
+
this.identityAuditWeeklyDir = path21.join(config.memoryDir, "identity", "audits", "weekly");
|
|
10611
|
+
this.identityAuditMonthlyDir = path21.join(config.memoryDir, "identity", "audits", "monthly");
|
|
10612
|
+
this.identityImprovementLoopsPath = path21.join(config.memoryDir, "identity", "improvement-loops.md");
|
|
10589
10613
|
}
|
|
10590
10614
|
weeklyDir;
|
|
10591
10615
|
mistakesPath;
|
|
10592
10616
|
feedbackInboxPath;
|
|
10617
|
+
identityAnchorPath;
|
|
10618
|
+
identityIncidentsDir;
|
|
10619
|
+
identityAuditWeeklyDir;
|
|
10620
|
+
identityAuditMonthlyDir;
|
|
10621
|
+
identityImprovementLoopsPath;
|
|
10593
10622
|
async ensureDirs() {
|
|
10594
10623
|
await mkdir15(this.weeklyDir, { recursive: true });
|
|
10595
10624
|
await mkdir15(path21.dirname(this.mistakesPath), { recursive: true });
|
|
@@ -10599,13 +10628,77 @@ var CompoundingEngine = class {
|
|
|
10599
10628
|
const weekId = opts?.weekId ?? isoWeekId(/* @__PURE__ */ new Date());
|
|
10600
10629
|
const entries = await this.readFeedbackEntriesForWeek(weekId);
|
|
10601
10630
|
const mistakes = this.buildMistakes(entries);
|
|
10631
|
+
const continuity = await this.readContinuityAuditReferences(weekId);
|
|
10602
10632
|
const reportPath = path21.join(this.weeklyDir, `${weekId}.md`);
|
|
10603
|
-
const md = this.formatWeeklyReport(weekId, entries, mistakes.patterns);
|
|
10633
|
+
const md = this.formatWeeklyReport(weekId, entries, mistakes.patterns, continuity);
|
|
10604
10634
|
await writeFile14(reportPath, md, "utf-8");
|
|
10605
10635
|
await writeFile14(this.mistakesPath, JSON.stringify(mistakes, null, 2) + "\n", "utf-8");
|
|
10606
10636
|
log.info(`compounding: wrote weekly=${reportPath} mistakes=${this.mistakesPath}`);
|
|
10607
10637
|
return { weekId, reportPath, mistakesCount: mistakes.patterns.length };
|
|
10608
10638
|
}
|
|
10639
|
+
async synthesizeContinuityAudit(opts) {
|
|
10640
|
+
const period = opts?.period === "monthly" ? "monthly" : "weekly";
|
|
10641
|
+
const key = opts?.key?.trim() || (period === "weekly" ? isoWeekId(/* @__PURE__ */ new Date()) : isoMonthId(/* @__PURE__ */ new Date()));
|
|
10642
|
+
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
10643
|
+
const [anchorPresent, improvementLoopPresent, incidents, mistakes] = await Promise.all([
|
|
10644
|
+
this.readNonEmptyFile(this.identityAnchorPath),
|
|
10645
|
+
this.readNonEmptyFile(this.identityImprovementLoopsPath),
|
|
10646
|
+
this.readContinuityIncidents(),
|
|
10647
|
+
this.readMistakes()
|
|
10648
|
+
]);
|
|
10649
|
+
const openIncidents = incidents.filter((i) => i.state === "open");
|
|
10650
|
+
const closedIncidents = incidents.filter((i) => i.state === "closed");
|
|
10651
|
+
const hardeningCandidates = [];
|
|
10652
|
+
if (!anchorPresent) {
|
|
10653
|
+
hardeningCandidates.push("Create/update identity anchor baseline and verify recovery injection path.");
|
|
10654
|
+
}
|
|
10655
|
+
if (openIncidents.length > 0) {
|
|
10656
|
+
hardeningCandidates.push(
|
|
10657
|
+
`Close or downgrade ${openIncidents.length} open continuity incident${openIncidents.length === 1 ? "" : "s"}.`
|
|
10658
|
+
);
|
|
10659
|
+
}
|
|
10660
|
+
if (!improvementLoopPresent) {
|
|
10661
|
+
hardeningCandidates.push("Initialize continuity improvement-loops register with cadence and kill conditions.");
|
|
10662
|
+
}
|
|
10663
|
+
if ((mistakes?.patterns.length ?? 0) > 0) {
|
|
10664
|
+
hardeningCandidates.push("Review latest compounding mistakes and convert one pattern into preventive continuity rule.");
|
|
10665
|
+
}
|
|
10666
|
+
const nextAction = hardeningCandidates[0] ?? "No critical drift detected; keep weekly/monthly continuity audit cadence.";
|
|
10667
|
+
const lines = [
|
|
10668
|
+
`# Continuity Audit \u2014 ${period} ${key}`,
|
|
10669
|
+
"",
|
|
10670
|
+
`Generated: ${nowIso}`,
|
|
10671
|
+
`Scope: ${period}`,
|
|
10672
|
+
"",
|
|
10673
|
+
"## Signal Summary",
|
|
10674
|
+
`- Identity anchor present: ${anchorPresent ? "yes" : "no"}`,
|
|
10675
|
+
`- Improvement-loop register present: ${improvementLoopPresent ? "yes" : "no"}`,
|
|
10676
|
+
`- Open incidents: ${openIncidents.length}`,
|
|
10677
|
+
`- Closed incidents: ${closedIncidents.length}`,
|
|
10678
|
+
`- Compounding mistake patterns: ${mistakes?.patterns.length ?? 0}`,
|
|
10679
|
+
"",
|
|
10680
|
+
"## Drift Checks",
|
|
10681
|
+
`- Identity anchor drift: ${anchorPresent ? "pass" : "needs attention"}`,
|
|
10682
|
+
`- Incident backlog: ${openIncidents.length === 0 ? "pass" : "needs attention"}`,
|
|
10683
|
+
`- Improvement-loop coverage: ${improvementLoopPresent ? "pass" : "needs attention"}`,
|
|
10684
|
+
"",
|
|
10685
|
+
"## Stale Rule Detection",
|
|
10686
|
+
`- Open incidents older than closure window: ${openIncidents.length > 0 ? "possible" : "none detected"}`,
|
|
10687
|
+
`- Preventive rule coverage on closed incidents: ${closedIncidents.some((i) => (i.preventiveRule ?? "").trim().length > 0) ? "present" : "not detected"}`,
|
|
10688
|
+
"",
|
|
10689
|
+
"## Next Hardening Action",
|
|
10690
|
+
`- ${nextAction}`,
|
|
10691
|
+
"",
|
|
10692
|
+
"## Open Incident IDs",
|
|
10693
|
+
...openIncidents.length > 0 ? openIncidents.slice(0, 20).map((i) => `- ${i.id}`) : ["- (none)"],
|
|
10694
|
+
""
|
|
10695
|
+
];
|
|
10696
|
+
const dir = period === "weekly" ? this.identityAuditWeeklyDir : this.identityAuditMonthlyDir;
|
|
10697
|
+
await mkdir15(dir, { recursive: true });
|
|
10698
|
+
const reportPath = path21.join(dir, `${key}.md`);
|
|
10699
|
+
await writeFile14(reportPath, lines.join("\n"), "utf-8");
|
|
10700
|
+
return { period, key, reportPath };
|
|
10701
|
+
}
|
|
10609
10702
|
async readMistakes() {
|
|
10610
10703
|
try {
|
|
10611
10704
|
const raw = await readFile15(this.mistakesPath, "utf-8");
|
|
@@ -10650,7 +10743,7 @@ var CompoundingEngine = class {
|
|
|
10650
10743
|
const uniq = Array.from(new Set(patterns)).slice(0, 500);
|
|
10651
10744
|
return { updatedAt: (/* @__PURE__ */ new Date()).toISOString(), patterns: uniq };
|
|
10652
10745
|
}
|
|
10653
|
-
formatWeeklyReport(weekId, entries, patterns) {
|
|
10746
|
+
formatWeeklyReport(weekId, entries, patterns, continuity) {
|
|
10654
10747
|
const byAgent = /* @__PURE__ */ new Map();
|
|
10655
10748
|
for (const e of entries) {
|
|
10656
10749
|
const list = byAgent.get(e.agent) ?? [];
|
|
@@ -10689,8 +10782,61 @@ var CompoundingEngine = class {
|
|
|
10689
10782
|
for (const p of patterns.slice(0, 100)) lines.push(`- ${p}`);
|
|
10690
10783
|
}
|
|
10691
10784
|
lines.push("");
|
|
10785
|
+
if (this.config.continuityAuditEnabled) {
|
|
10786
|
+
lines.push("## Continuity Audits");
|
|
10787
|
+
if (continuity.weeklyPath) {
|
|
10788
|
+
lines.push(`- weekly: ${continuity.weeklyPath}`);
|
|
10789
|
+
} else {
|
|
10790
|
+
lines.push(`- weekly: (missing for ${weekId})`);
|
|
10791
|
+
}
|
|
10792
|
+
if (continuity.monthlyPath) {
|
|
10793
|
+
lines.push(`- monthly: ${continuity.monthlyPath}`);
|
|
10794
|
+
} else {
|
|
10795
|
+
lines.push(`- monthly: (missing for ${continuity.monthId})`);
|
|
10796
|
+
}
|
|
10797
|
+
lines.push("");
|
|
10798
|
+
}
|
|
10692
10799
|
return lines.join("\n");
|
|
10693
10800
|
}
|
|
10801
|
+
async readNonEmptyFile(filePath) {
|
|
10802
|
+
try {
|
|
10803
|
+
const raw = await readFile15(filePath, "utf-8");
|
|
10804
|
+
return raw.trim().length > 0;
|
|
10805
|
+
} catch {
|
|
10806
|
+
return false;
|
|
10807
|
+
}
|
|
10808
|
+
}
|
|
10809
|
+
async readContinuityIncidents() {
|
|
10810
|
+
const incidents = [];
|
|
10811
|
+
try {
|
|
10812
|
+
const names = await readdir10(this.identityIncidentsDir);
|
|
10813
|
+
const files = names.filter((n) => n.endsWith(".md")).sort().reverse();
|
|
10814
|
+
for (const file of files) {
|
|
10815
|
+
const filePath = path21.join(this.identityIncidentsDir, file);
|
|
10816
|
+
try {
|
|
10817
|
+
const raw = await readFile15(filePath, "utf-8");
|
|
10818
|
+
const parsed = parseContinuityIncident(raw);
|
|
10819
|
+
if (parsed) incidents.push(parsed);
|
|
10820
|
+
} catch {
|
|
10821
|
+
}
|
|
10822
|
+
}
|
|
10823
|
+
} catch {
|
|
10824
|
+
}
|
|
10825
|
+
return incidents;
|
|
10826
|
+
}
|
|
10827
|
+
async readContinuityAuditReferences(weekId) {
|
|
10828
|
+
const monthId = monthIdFromIsoWeek(weekId);
|
|
10829
|
+
const weeklyPath = path21.join(this.identityAuditWeeklyDir, `${weekId}.md`);
|
|
10830
|
+
const monthlyPath = path21.join(this.identityAuditMonthlyDir, `${monthId}.md`);
|
|
10831
|
+
const weeklyExists = await this.readNonEmptyFile(weeklyPath);
|
|
10832
|
+
const monthlyExists = await this.readNonEmptyFile(monthlyPath);
|
|
10833
|
+
return {
|
|
10834
|
+
weekId,
|
|
10835
|
+
monthId,
|
|
10836
|
+
weeklyPath: weeklyExists ? weeklyPath : null,
|
|
10837
|
+
monthlyPath: monthlyExists ? monthlyPath : null
|
|
10838
|
+
};
|
|
10839
|
+
}
|
|
10694
10840
|
};
|
|
10695
10841
|
|
|
10696
10842
|
// src/orchestrator.ts
|
|
@@ -10828,6 +10974,22 @@ function resolveEffectiveRecallMode(options) {
|
|
|
10828
10974
|
}
|
|
10829
10975
|
return plannedMode;
|
|
10830
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
|
+
}
|
|
10831
10993
|
function computeArtifactCandidateFetchLimit(targetCount) {
|
|
10832
10994
|
const cappedTarget = Math.max(0, targetCount);
|
|
10833
10995
|
if (cappedTarget === 0) return 0;
|
|
@@ -11679,6 +11841,9 @@ var Orchestrator = class _Orchestrator {
|
|
|
11679
11841
|
let impressionRecorded = false;
|
|
11680
11842
|
let recallSource = "none";
|
|
11681
11843
|
let recalledMemoryCount = 0;
|
|
11844
|
+
let identityInjectionModeUsed = "none";
|
|
11845
|
+
let identityInjectedChars = 0;
|
|
11846
|
+
let identityInjectionTruncated = false;
|
|
11682
11847
|
timings.queryPolicy = `${queryPolicy.promptShape}/${queryPolicy.retrievalBudgetMode}${queryPolicy.skipConversationRecall ? "/skip-conv" : ""}`;
|
|
11683
11848
|
const recallMode = resolveEffectiveRecallMode({
|
|
11684
11849
|
plannerEnabled: this.config.recallPlannerEnabled,
|
|
@@ -11723,6 +11888,9 @@ var Orchestrator = class _Orchestrator {
|
|
|
11723
11888
|
recalledMemoryCount,
|
|
11724
11889
|
injected: false,
|
|
11725
11890
|
contextChars: 0,
|
|
11891
|
+
identityInjectionMode: identityInjectionModeUsed,
|
|
11892
|
+
identityInjectedChars,
|
|
11893
|
+
identityInjectionTruncated,
|
|
11726
11894
|
durationMs: Date.now() - recallStart,
|
|
11727
11895
|
timings: { ...timings }
|
|
11728
11896
|
});
|
|
@@ -11756,6 +11924,16 @@ var Orchestrator = class _Orchestrator {
|
|
|
11756
11924
|
timings.profile = `${Date.now() - t0}ms`;
|
|
11757
11925
|
return profile2 || null;
|
|
11758
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
|
+
})();
|
|
11759
11937
|
const knowledgeIndexPromise = (async () => {
|
|
11760
11938
|
if (!this.config.knowledgeIndexEnabled) return null;
|
|
11761
11939
|
const t0 = Date.now();
|
|
@@ -11813,9 +11991,10 @@ var Orchestrator = class _Orchestrator {
|
|
|
11813
11991
|
timings.qmd = `${Date.now() - t0}ms`;
|
|
11814
11992
|
return { memoryResultsLists: [filteredResults], globalResults: [] };
|
|
11815
11993
|
})();
|
|
11816
|
-
const [sharedCtx, profile, kiResult, artifacts, qmdResult] = await Promise.all([
|
|
11994
|
+
const [sharedCtx, profile, identityContinuity, kiResult, artifacts, qmdResult] = await Promise.all([
|
|
11817
11995
|
sharedContextPromise,
|
|
11818
11996
|
profilePromise,
|
|
11997
|
+
identityContinuityPromise,
|
|
11819
11998
|
knowledgeIndexPromise,
|
|
11820
11999
|
artifactsPromise,
|
|
11821
12000
|
qmdPromise
|
|
@@ -11824,6 +12003,12 @@ var Orchestrator = class _Orchestrator {
|
|
|
11824
12003
|
if (profile) sections.push(`## User Profile
|
|
11825
12004
|
|
|
11826
12005
|
${profile}`);
|
|
12006
|
+
if (identityContinuity) {
|
|
12007
|
+
sections.push(identityContinuity.section);
|
|
12008
|
+
identityInjectionModeUsed = identityContinuity.mode;
|
|
12009
|
+
identityInjectedChars = identityContinuity.injectedChars;
|
|
12010
|
+
identityInjectionTruncated = identityContinuity.truncated;
|
|
12011
|
+
}
|
|
11827
12012
|
if (kiResult?.result) {
|
|
11828
12013
|
sections.push(kiResult.result);
|
|
11829
12014
|
log.debug(`Knowledge Index: ${kiResult.result.split("\n").length - 4} entities, ${kiResult.result.length} chars${kiResult.cached ? " (cached)" : ""}`);
|
|
@@ -11935,7 +12120,12 @@ ${tmtNode.summary}`);
|
|
|
11935
12120
|
results: memoryResults,
|
|
11936
12121
|
sections,
|
|
11937
12122
|
retrievalQuery,
|
|
11938
|
-
sessionKey
|
|
12123
|
+
sessionKey,
|
|
12124
|
+
identityInjection: {
|
|
12125
|
+
mode: identityInjectionModeUsed,
|
|
12126
|
+
injectedChars: identityInjectedChars,
|
|
12127
|
+
truncated: identityInjectionTruncated
|
|
12128
|
+
}
|
|
11939
12129
|
});
|
|
11940
12130
|
impressionRecorded = true;
|
|
11941
12131
|
} else {
|
|
@@ -11958,7 +12148,12 @@ ${tmtNode.summary}`);
|
|
|
11958
12148
|
results: scoped,
|
|
11959
12149
|
sections,
|
|
11960
12150
|
retrievalQuery,
|
|
11961
|
-
sessionKey
|
|
12151
|
+
sessionKey,
|
|
12152
|
+
identityInjection: {
|
|
12153
|
+
mode: identityInjectionModeUsed,
|
|
12154
|
+
injectedChars: identityInjectedChars,
|
|
12155
|
+
truncated: identityInjectionTruncated
|
|
12156
|
+
}
|
|
11962
12157
|
});
|
|
11963
12158
|
impressionRecorded = true;
|
|
11964
12159
|
} else {
|
|
@@ -11975,7 +12170,12 @@ ${tmtNode.summary}`);
|
|
|
11975
12170
|
results: longTerm,
|
|
11976
12171
|
sections,
|
|
11977
12172
|
retrievalQuery,
|
|
11978
|
-
sessionKey
|
|
12173
|
+
sessionKey,
|
|
12174
|
+
identityInjection: {
|
|
12175
|
+
mode: identityInjectionModeUsed,
|
|
12176
|
+
injectedChars: identityInjectedChars,
|
|
12177
|
+
truncated: identityInjectionTruncated
|
|
12178
|
+
}
|
|
11979
12179
|
});
|
|
11980
12180
|
impressionRecorded = true;
|
|
11981
12181
|
}
|
|
@@ -12021,7 +12221,12 @@ ${tmtNode.summary}`);
|
|
|
12021
12221
|
results: scoped,
|
|
12022
12222
|
sections,
|
|
12023
12223
|
retrievalQuery,
|
|
12024
|
-
sessionKey
|
|
12224
|
+
sessionKey,
|
|
12225
|
+
identityInjection: {
|
|
12226
|
+
mode: identityInjectionModeUsed,
|
|
12227
|
+
injectedChars: identityInjectedChars,
|
|
12228
|
+
truncated: identityInjectionTruncated
|
|
12229
|
+
}
|
|
12025
12230
|
});
|
|
12026
12231
|
impressionRecorded = true;
|
|
12027
12232
|
} else {
|
|
@@ -12056,7 +12261,12 @@ ${tmtNode.summary}`);
|
|
|
12056
12261
|
results: recent,
|
|
12057
12262
|
sections,
|
|
12058
12263
|
retrievalQuery,
|
|
12059
|
-
sessionKey
|
|
12264
|
+
sessionKey,
|
|
12265
|
+
identityInjection: {
|
|
12266
|
+
mode: identityInjectionModeUsed,
|
|
12267
|
+
injectedChars: identityInjectedChars,
|
|
12268
|
+
truncated: identityInjectionTruncated
|
|
12269
|
+
}
|
|
12060
12270
|
});
|
|
12061
12271
|
impressionRecorded = true;
|
|
12062
12272
|
} else {
|
|
@@ -12073,7 +12283,12 @@ ${tmtNode.summary}`);
|
|
|
12073
12283
|
results: longTerm,
|
|
12074
12284
|
sections,
|
|
12075
12285
|
retrievalQuery,
|
|
12076
|
-
sessionKey
|
|
12286
|
+
sessionKey,
|
|
12287
|
+
identityInjection: {
|
|
12288
|
+
mode: identityInjectionModeUsed,
|
|
12289
|
+
injectedChars: identityInjectedChars,
|
|
12290
|
+
truncated: identityInjectionTruncated
|
|
12291
|
+
}
|
|
12077
12292
|
});
|
|
12078
12293
|
impressionRecorded = true;
|
|
12079
12294
|
}
|
|
@@ -12092,7 +12307,12 @@ ${tmtNode.summary}`);
|
|
|
12092
12307
|
results: longTerm,
|
|
12093
12308
|
sections,
|
|
12094
12309
|
retrievalQuery,
|
|
12095
|
-
sessionKey
|
|
12310
|
+
sessionKey,
|
|
12311
|
+
identityInjection: {
|
|
12312
|
+
mode: identityInjectionModeUsed,
|
|
12313
|
+
injectedChars: identityInjectedChars,
|
|
12314
|
+
truncated: identityInjectionTruncated
|
|
12315
|
+
}
|
|
12096
12316
|
});
|
|
12097
12317
|
impressionRecorded = true;
|
|
12098
12318
|
}
|
|
@@ -12231,7 +12451,16 @@ _Context: ${topQuestion.context}_`);
|
|
|
12231
12451
|
const timingParts = Object.entries(timings).map(([k, v]) => `${k}=${v}`).join(", ");
|
|
12232
12452
|
log.debug(`recall: ${timingParts}`);
|
|
12233
12453
|
if (!impressionRecorded && sessionKey && this.config.recordEmptyRecallImpressions) {
|
|
12234
|
-
this.lastRecall.record({
|
|
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}`));
|
|
12235
12464
|
}
|
|
12236
12465
|
const context = sections.length === 0 ? "" : sections.join("\n\n---\n\n");
|
|
12237
12466
|
this.emitTrace({
|
|
@@ -12252,6 +12481,9 @@ _Context: ${topQuestion.context}_`);
|
|
|
12252
12481
|
recalledMemoryCount,
|
|
12253
12482
|
injected: context.length > 0,
|
|
12254
12483
|
contextChars: context.length,
|
|
12484
|
+
identityInjectionMode: identityInjectionModeUsed,
|
|
12485
|
+
identityInjectedChars,
|
|
12486
|
+
identityInjectionTruncated,
|
|
12255
12487
|
durationMs: Date.now() - recallStart,
|
|
12256
12488
|
timings: { ...timings }
|
|
12257
12489
|
});
|
|
@@ -13347,6 +13579,86 @@ ${snippet}`;
|
|
|
13347
13579
|
|
|
13348
13580
|
${lines.join("\n\n")}`;
|
|
13349
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
|
+
}
|
|
13350
13662
|
emitTrace(event) {
|
|
13351
13663
|
try {
|
|
13352
13664
|
const cb = globalThis.__openclawEngramTrace;
|
|
@@ -13360,7 +13672,12 @@ ${lines.join("\n\n")}`;
|
|
|
13360
13672
|
this.trackMemoryAccess(memoryIds);
|
|
13361
13673
|
if (options.sessionKey) {
|
|
13362
13674
|
const unique = Array.from(new Set(memoryIds)).slice(0, 40);
|
|
13363
|
-
this.lastRecall.record({
|
|
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}`));
|
|
13364
13681
|
}
|
|
13365
13682
|
options.sections.push(this.formatQmdResults(options.title, options.results));
|
|
13366
13683
|
}
|
|
@@ -14011,6 +14328,57 @@ ${formatted}`
|
|
|
14011
14328
|
},
|
|
14012
14329
|
{ name: "memory_search" }
|
|
14013
14330
|
);
|
|
14331
|
+
api.registerTool(
|
|
14332
|
+
{
|
|
14333
|
+
name: "continuity_audit_generate",
|
|
14334
|
+
label: "Generate Continuity Audit",
|
|
14335
|
+
description: "Generate a deterministic identity continuity audit report (weekly/monthly) and persist it under identity/audits.",
|
|
14336
|
+
parameters: Type.Object({
|
|
14337
|
+
period: Type.Optional(
|
|
14338
|
+
Type.String({
|
|
14339
|
+
enum: ["weekly", "monthly"],
|
|
14340
|
+
description: "Audit period. Defaults to weekly."
|
|
14341
|
+
})
|
|
14342
|
+
),
|
|
14343
|
+
key: Type.Optional(
|
|
14344
|
+
Type.String({
|
|
14345
|
+
description: "Optional period key (weekly: YYYY-Www, monthly: YYYY-MM). Defaults to current period."
|
|
14346
|
+
})
|
|
14347
|
+
)
|
|
14348
|
+
}),
|
|
14349
|
+
async execute(_toolCallId, params) {
|
|
14350
|
+
if (!orchestrator.config.identityContinuityEnabled) {
|
|
14351
|
+
return toolResult(
|
|
14352
|
+
"Identity continuity is disabled. Enable `identityContinuityEnabled: true` to generate continuity audits."
|
|
14353
|
+
);
|
|
14354
|
+
}
|
|
14355
|
+
if (!orchestrator.config.continuityAuditEnabled) {
|
|
14356
|
+
return toolResult(
|
|
14357
|
+
"Continuity audits are disabled. Enable `continuityAuditEnabled: true` to generate continuity audits."
|
|
14358
|
+
);
|
|
14359
|
+
}
|
|
14360
|
+
if (!orchestrator.compounding) {
|
|
14361
|
+
return toolResult(
|
|
14362
|
+
"Compounding engine is disabled. Enable `compoundingEnabled: true` to generate continuity audits."
|
|
14363
|
+
);
|
|
14364
|
+
}
|
|
14365
|
+
const period = params.period === "monthly" ? "monthly" : "weekly";
|
|
14366
|
+
const key = typeof params.key === "string" ? params.key : void 0;
|
|
14367
|
+
const audit = await orchestrator.compounding.synthesizeContinuityAudit({
|
|
14368
|
+
period,
|
|
14369
|
+
key
|
|
14370
|
+
});
|
|
14371
|
+
return toolResult(
|
|
14372
|
+
`OK
|
|
14373
|
+
|
|
14374
|
+
period: ${audit.period}
|
|
14375
|
+
key: ${audit.key}
|
|
14376
|
+
report: ${audit.reportPath}`
|
|
14377
|
+
);
|
|
14378
|
+
}
|
|
14379
|
+
},
|
|
14380
|
+
{ name: "continuity_audit_generate" }
|
|
14381
|
+
);
|
|
14014
14382
|
api.registerTool(
|
|
14015
14383
|
{
|
|
14016
14384
|
name: "continuity_incident_open",
|
|
@@ -14303,6 +14671,7 @@ NOTE: You did not provide sessionKey; under concurrency this may not match your
|
|
|
14303
14671
|
"",
|
|
14304
14672
|
`Recorded at: ${snap.recordedAt}`,
|
|
14305
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"}`,
|
|
14306
14675
|
`Memories (${snap.memoryIds.length}):`,
|
|
14307
14676
|
...snap.memoryIds.map((id) => `- ${id}`)
|
|
14308
14677
|
].join("\n")
|
|
@@ -15045,7 +15414,7 @@ mistakes: ${res.mistakesCount} patterns`
|
|
|
15045
15414
|
|
|
15046
15415
|
// src/cli.ts
|
|
15047
15416
|
import path33 from "path";
|
|
15048
|
-
import { access as access2, readFile as readFile22, readdir as
|
|
15417
|
+
import { access as access2, readFile as readFile22, readdir as readdir13, unlink as unlink3 } from "fs/promises";
|
|
15049
15418
|
|
|
15050
15419
|
// src/transfer/export-json.ts
|
|
15051
15420
|
import path25 from "path";
|
|
@@ -15057,7 +15426,7 @@ var EXPORT_SCHEMA_VERSION = 1;
|
|
|
15057
15426
|
|
|
15058
15427
|
// src/transfer/fs-utils.ts
|
|
15059
15428
|
import { createHash as createHash6 } from "crypto";
|
|
15060
|
-
import { mkdir as mkdir17, readdir as
|
|
15429
|
+
import { mkdir as mkdir17, readdir as readdir11, readFile as readFile17, stat as stat3, writeFile as writeFile16 } from "fs/promises";
|
|
15061
15430
|
import path24 from "path";
|
|
15062
15431
|
async function sha256File(filePath) {
|
|
15063
15432
|
const buf = await readFile17(filePath);
|
|
@@ -15080,7 +15449,7 @@ async function readJsonFile(filePath) {
|
|
|
15080
15449
|
async function listFilesRecursive(rootDir) {
|
|
15081
15450
|
const out = [];
|
|
15082
15451
|
async function walk(dir) {
|
|
15083
|
-
const entries = await
|
|
15452
|
+
const entries = await readdir11(dir, { withFileTypes: true });
|
|
15084
15453
|
for (const ent of entries) {
|
|
15085
15454
|
const fp = path24.join(dir, ent.name);
|
|
15086
15455
|
if (ent.isDirectory()) {
|
|
@@ -15208,7 +15577,7 @@ async function looksLikeEngramMdExport(fromDir) {
|
|
|
15208
15577
|
|
|
15209
15578
|
// src/transfer/backup.ts
|
|
15210
15579
|
import path27 from "path";
|
|
15211
|
-
import { mkdir as mkdir20, readdir as
|
|
15580
|
+
import { mkdir as mkdir20, readdir as readdir12, rm as rm2 } from "fs/promises";
|
|
15212
15581
|
function timestampDirName(now) {
|
|
15213
15582
|
return now.toISOString().replace(/[:.]/g, "-");
|
|
15214
15583
|
}
|
|
@@ -15229,7 +15598,7 @@ async function backupMemoryDir(opts) {
|
|
|
15229
15598
|
return backupDir;
|
|
15230
15599
|
}
|
|
15231
15600
|
async function enforceRetention(outDirAbs, retentionDays) {
|
|
15232
|
-
const entries = await
|
|
15601
|
+
const entries = await readdir12(outDirAbs, { withFileTypes: true });
|
|
15233
15602
|
const cutoffMs = Date.now() - retentionDays * 24 * 60 * 60 * 1e3;
|
|
15234
15603
|
for (const ent of entries) {
|
|
15235
15604
|
if (!ent.isDirectory()) continue;
|
|
@@ -15598,7 +15967,7 @@ async function readAllMemoryFiles(memoryDir) {
|
|
|
15598
15967
|
const walk = async (dir) => {
|
|
15599
15968
|
let entries;
|
|
15600
15969
|
try {
|
|
15601
|
-
entries = await
|
|
15970
|
+
entries = await readdir13(dir, { withFileTypes: true });
|
|
15602
15971
|
} catch {
|
|
15603
15972
|
return;
|
|
15604
15973
|
}
|