@joshuaswarren/openclaw-engram 9.0.9 → 9.0.11
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 +80 -4
- package/dist/index.js.map +1 -1
- package/openclaw.plugin.json +10 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -474,6 +474,8 @@ function parseConfig(raw) {
|
|
|
474
474
|
recallConfidenceGateEnabled: cfg.recallConfidenceGateEnabled === true,
|
|
475
475
|
recallConfidenceGateThreshold: typeof cfg.recallConfidenceGateThreshold === "number" ? Math.max(0, Math.min(1, cfg.recallConfidenceGateThreshold)) : 0.12,
|
|
476
476
|
causalRuleExtractionEnabled: cfg.causalRuleExtractionEnabled === true,
|
|
477
|
+
memoryReconstructionEnabled: cfg.memoryReconstructionEnabled === true,
|
|
478
|
+
memoryReconstructionMaxExpansions: typeof cfg.memoryReconstructionMaxExpansions === "number" ? Math.max(0, Math.round(cfg.memoryReconstructionMaxExpansions)) : 3,
|
|
477
479
|
graphLateralInhibitionEnabled: cfg.graphLateralInhibitionEnabled !== false,
|
|
478
480
|
graphLateralInhibitionBeta: typeof cfg.graphLateralInhibitionBeta === "number" ? Math.max(0, Math.min(1, cfg.graphLateralInhibitionBeta)) : 0.15,
|
|
479
481
|
graphLateralInhibitionTopM: typeof cfg.graphLateralInhibitionTopM === "number" ? Math.max(0, Math.round(cfg.graphLateralInhibitionTopM)) : 7,
|
|
@@ -4179,6 +4181,26 @@ function rescoreMemoryImportance(memory) {
|
|
|
4179
4181
|
return scoreImportance(memory.content, memory.frontmatter.category, memory.frontmatter.tags ?? []);
|
|
4180
4182
|
}
|
|
4181
4183
|
|
|
4184
|
+
// src/reconstruct.ts
|
|
4185
|
+
function findUnresolvedEntityRefs(recalledSnippets, recalledEntityRefs, knownEntities) {
|
|
4186
|
+
const refSet = new Set(recalledEntityRefs.map((r) => r.toLowerCase()));
|
|
4187
|
+
const combinedText = recalledSnippets.join(" ").toLowerCase();
|
|
4188
|
+
const sorted = [...knownEntities].sort((a, b) => b.length - a.length);
|
|
4189
|
+
const matched = /* @__PURE__ */ new Set();
|
|
4190
|
+
const unresolved = [];
|
|
4191
|
+
for (const entity of sorted) {
|
|
4192
|
+
const lower = entity.toLowerCase();
|
|
4193
|
+
if (refSet.has(lower)) continue;
|
|
4194
|
+
const escaped = lower.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
4195
|
+
const pattern = new RegExp(`(?:^|[\\s,;:'"(\\[])${escaped}(?:$|[\\s,;:'".)\\]])`, "i");
|
|
4196
|
+
if (pattern.test(combinedText) && !matched.has(lower)) {
|
|
4197
|
+
unresolved.push(entity);
|
|
4198
|
+
matched.add(lower);
|
|
4199
|
+
}
|
|
4200
|
+
}
|
|
4201
|
+
return unresolved;
|
|
4202
|
+
}
|
|
4203
|
+
|
|
4182
4204
|
// src/search/noop-backend.ts
|
|
4183
4205
|
var NoopSearchBackend = class {
|
|
4184
4206
|
async probe() {
|
|
@@ -12536,6 +12558,9 @@ function serializeBoxFrontmatter(fm) {
|
|
|
12536
12558
|
];
|
|
12537
12559
|
if (fm.sessionKey) lines.push(`sessionKey: ${fm.sessionKey}`);
|
|
12538
12560
|
if (fm.traceId) lines.push(`traceId: ${fm.traceId}`);
|
|
12561
|
+
if (fm.goal) lines.push(`goal: ${fm.goal.replace(/[\r\n]+/g, " ")}`);
|
|
12562
|
+
if (fm.toolsUsed?.length) lines.push(`toolsUsed: [${fm.toolsUsed.map((t) => `"${t}"`).join(", ")}]`);
|
|
12563
|
+
if (fm.outcome) lines.push(`outcome: ${fm.outcome}`);
|
|
12539
12564
|
lines.push("---");
|
|
12540
12565
|
return lines.join("\n");
|
|
12541
12566
|
}
|
|
@@ -12555,6 +12580,7 @@ function parseBoxFrontmatter(raw) {
|
|
|
12555
12580
|
if (!m) return [];
|
|
12556
12581
|
return m[1].split(",").map((s) => s.trim().replace(/^"|"$/g, "")).filter(Boolean);
|
|
12557
12582
|
};
|
|
12583
|
+
const outcome = fm.outcome;
|
|
12558
12584
|
return {
|
|
12559
12585
|
id: fm.id ?? "",
|
|
12560
12586
|
memoryKind: "box",
|
|
@@ -12564,7 +12590,10 @@ function parseBoxFrontmatter(raw) {
|
|
|
12564
12590
|
sessionKey: fm.sessionKey,
|
|
12565
12591
|
topics: parseArray(fm.topics),
|
|
12566
12592
|
memoryIds: parseArray(fm.memoryIds),
|
|
12567
|
-
traceId: fm.traceId
|
|
12593
|
+
traceId: fm.traceId,
|
|
12594
|
+
goal: fm.goal || void 0,
|
|
12595
|
+
toolsUsed: fm.toolsUsed ? parseArray(fm.toolsUsed) : void 0,
|
|
12596
|
+
outcome: outcome && ["success", "failure", "partial", "unknown"].includes(outcome) ? outcome : void 0
|
|
12568
12597
|
};
|
|
12569
12598
|
}
|
|
12570
12599
|
var BoxBuilder = class {
|
|
@@ -12650,6 +12679,10 @@ var BoxBuilder = class {
|
|
|
12650
12679
|
const topicSet = /* @__PURE__ */ new Set([...this.openBox.topics, ...newTopics]);
|
|
12651
12680
|
this.openBox.topics = [...topicSet];
|
|
12652
12681
|
this.openBox.memoryIds.push(...event.memoryIds);
|
|
12682
|
+
if (event.toolsUsed?.length) {
|
|
12683
|
+
const toolSet = /* @__PURE__ */ new Set([...this.openBox.toolsUsed ?? [], ...event.toolsUsed]);
|
|
12684
|
+
this.openBox.toolsUsed = [...toolSet];
|
|
12685
|
+
}
|
|
12653
12686
|
await this.sealCurrent("max_memories");
|
|
12654
12687
|
} else if (topicShifted) {
|
|
12655
12688
|
await this.sealCurrent("topic_shift");
|
|
@@ -12664,6 +12697,10 @@ var BoxBuilder = class {
|
|
|
12664
12697
|
const topicSet = /* @__PURE__ */ new Set([...this.openBox.topics, ...newTopics]);
|
|
12665
12698
|
this.openBox.topics = [...topicSet];
|
|
12666
12699
|
this.openBox.lastActivityAt = now.toISOString();
|
|
12700
|
+
if (event.toolsUsed?.length) {
|
|
12701
|
+
const toolSet = /* @__PURE__ */ new Set([...this.openBox.toolsUsed ?? [], ...event.toolsUsed]);
|
|
12702
|
+
this.openBox.toolsUsed = [...toolSet];
|
|
12703
|
+
}
|
|
12667
12704
|
await this.saveOpenBox();
|
|
12668
12705
|
}
|
|
12669
12706
|
} else {
|
|
@@ -12681,7 +12718,9 @@ var BoxBuilder = class {
|
|
|
12681
12718
|
createdAt: ts,
|
|
12682
12719
|
lastActivityAt: ts,
|
|
12683
12720
|
topics: event.topics.filter(Boolean),
|
|
12684
|
-
memoryIds: [...event.memoryIds]
|
|
12721
|
+
memoryIds: [...event.memoryIds],
|
|
12722
|
+
goal: event.goal,
|
|
12723
|
+
toolsUsed: event.toolsUsed?.length ? [...event.toolsUsed] : void 0
|
|
12685
12724
|
};
|
|
12686
12725
|
}
|
|
12687
12726
|
/**
|
|
@@ -12713,7 +12752,10 @@ var BoxBuilder = class {
|
|
|
12713
12752
|
sealReason: reason,
|
|
12714
12753
|
topics: box.topics,
|
|
12715
12754
|
memoryIds: box.memoryIds,
|
|
12716
|
-
traceId
|
|
12755
|
+
traceId,
|
|
12756
|
+
goal: box.goal,
|
|
12757
|
+
toolsUsed: box.toolsUsed?.length ? box.toolsUsed : void 0,
|
|
12758
|
+
outcome: "unknown"
|
|
12717
12759
|
};
|
|
12718
12760
|
const content = `${serializeBoxFrontmatter(fm)}
|
|
12719
12761
|
|
|
@@ -17842,6 +17884,37 @@ ${tmtNode.summary}`);
|
|
|
17842
17884
|
confidenceGateRejected = true;
|
|
17843
17885
|
}
|
|
17844
17886
|
memoryResults = memoryResults.slice(0, recallResultLimit);
|
|
17887
|
+
if (this.config.memoryReconstructionEnabled && memoryResults.length > 0) {
|
|
17888
|
+
try {
|
|
17889
|
+
const snippets = memoryResults.map((r) => r.snippet);
|
|
17890
|
+
const coveredRefs = memoryResults.map((r) => r.path).filter((p) => p.startsWith("entities/")).map((p) => p.replace(/^entities\//, "").replace(/\.md$/, ""));
|
|
17891
|
+
const knownEntities = await profileStorage.listEntityNames();
|
|
17892
|
+
const missing = findUnresolvedEntityRefs(snippets, coveredRefs, knownEntities);
|
|
17893
|
+
if (missing.length > 0) {
|
|
17894
|
+
const budget = this.config.memoryReconstructionMaxExpansions;
|
|
17895
|
+
let expanded = 0;
|
|
17896
|
+
for (const entityName of missing) {
|
|
17897
|
+
if (expanded >= budget) break;
|
|
17898
|
+
const raw = await profileStorage.readEntity(entityName);
|
|
17899
|
+
if (raw && raw.length > 0) {
|
|
17900
|
+
const snippet = raw.length > 300 ? raw.slice(0, 300) + "\u2026" : raw;
|
|
17901
|
+
memoryResults.push({
|
|
17902
|
+
docid: `entity:${entityName}`,
|
|
17903
|
+
path: `entities/${entityName}.md`,
|
|
17904
|
+
snippet: `[Entity: ${entityName}] ${snippet}`,
|
|
17905
|
+
score: 0.1
|
|
17906
|
+
});
|
|
17907
|
+
expanded++;
|
|
17908
|
+
}
|
|
17909
|
+
}
|
|
17910
|
+
if (expanded > 0) {
|
|
17911
|
+
log.debug(`recall: reconstructed ${expanded} entity contexts`);
|
|
17912
|
+
}
|
|
17913
|
+
}
|
|
17914
|
+
} catch (err) {
|
|
17915
|
+
log.warn("recall: memory reconstruction failed (non-fatal)", err);
|
|
17916
|
+
}
|
|
17917
|
+
}
|
|
17845
17918
|
if (memoryResults.length > 0) {
|
|
17846
17919
|
recallSource = "hot_qmd";
|
|
17847
17920
|
recalledMemoryCount = memoryResults.length;
|
|
@@ -18387,10 +18460,13 @@ _Context: ${topQuestion.context}_`
|
|
|
18387
18460
|
await clearBuffer();
|
|
18388
18461
|
if (this.config.memoryBoxesEnabled && persistedIds.length > 0) {
|
|
18389
18462
|
const extractionTopics = deriveTopicsFromExtraction(result);
|
|
18463
|
+
const firstUserTurn = turns.find((t) => t.role === "user");
|
|
18464
|
+
const boxGoal = firstUserTurn?.content?.slice(0, 100)?.trim() || void 0;
|
|
18390
18465
|
await this.boxBuilderFor(storage).onExtraction({
|
|
18391
18466
|
topics: extractionTopics,
|
|
18392
18467
|
memoryIds: persistedIds,
|
|
18393
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
18468
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18469
|
+
goal: boxGoal
|
|
18394
18470
|
}).catch((err) => log.warn("[boxes] onExtraction failed (non-fatal)", err));
|
|
18395
18471
|
}
|
|
18396
18472
|
if (this.config.threadingEnabled && threadIdForExtraction && persistedIds.length > 0) {
|