@joshuaswarren/openclaw-engram 8.3.7 → 8.3.9
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 +126 -14
- package/dist/index.js.map +1 -1
- package/openclaw.plugin.json +47 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -322,6 +322,12 @@ function parseConfig(raw) {
|
|
|
322
322
|
(c) => typeof c === "string" && VALID_MEMORY_CATEGORIES.has(c)
|
|
323
323
|
) : ["decision", "principle", "commitment", "preference"],
|
|
324
324
|
lifecycleMetricsEnabled: typeof cfg.lifecycleMetricsEnabled === "boolean" ? cfg.lifecycleMetricsEnabled : cfg.lifecyclePolicyEnabled === true,
|
|
325
|
+
// v8.3 proactive + policy learning (default off)
|
|
326
|
+
proactiveExtractionEnabled: cfg.proactiveExtractionEnabled === true,
|
|
327
|
+
contextCompressionActionsEnabled: cfg.contextCompressionActionsEnabled === true,
|
|
328
|
+
compressionGuidelineLearningEnabled: cfg.compressionGuidelineLearningEnabled === true,
|
|
329
|
+
maxProactiveQuestionsPerExtraction: typeof cfg.maxProactiveQuestionsPerExtraction === "number" ? Math.max(0, Math.floor(cfg.maxProactiveQuestionsPerExtraction)) : 2,
|
|
330
|
+
maxCompressionTokensPerHour: typeof cfg.maxCompressionTokensPerHour === "number" ? Math.max(0, Math.floor(cfg.maxCompressionTokensPerHour)) : 1500,
|
|
325
331
|
// v8.0 phase 1
|
|
326
332
|
recallPlannerEnabled: cfg.recallPlannerEnabled !== false,
|
|
327
333
|
recallPlannerMaxQmdResultsMinimal: typeof cfg.recallPlannerMaxQmdResultsMinimal === "number" ? cfg.recallPlannerMaxQmdResultsMinimal : 4,
|
|
@@ -3975,7 +3981,7 @@ ${stderr}`.trim();
|
|
|
3975
3981
|
};
|
|
3976
3982
|
|
|
3977
3983
|
// src/storage.ts
|
|
3978
|
-
import { readdir, readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, unlink } from "fs/promises";
|
|
3984
|
+
import { readdir, readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, unlink, appendFile } from "fs/promises";
|
|
3979
3985
|
import { appendFileSync, mkdirSync as mkdirSync2, statSync } from "fs";
|
|
3980
3986
|
import { createHash } from "crypto";
|
|
3981
3987
|
import path4 from "path";
|
|
@@ -4535,6 +4541,12 @@ var StorageManager = class _StorageManager {
|
|
|
4535
4541
|
get profilePath() {
|
|
4536
4542
|
return path4.join(this.baseDir, "profile.md");
|
|
4537
4543
|
}
|
|
4544
|
+
get memoryActionsPath() {
|
|
4545
|
+
return path4.join(this.stateDir, "memory-actions.jsonl");
|
|
4546
|
+
}
|
|
4547
|
+
get compressionGuidelinesPath() {
|
|
4548
|
+
return path4.join(this.stateDir, "compression-guidelines.md");
|
|
4549
|
+
}
|
|
4538
4550
|
/**
|
|
4539
4551
|
* Load user-defined entity aliases from config/aliases.json in the memory store.
|
|
4540
4552
|
* File format: { "variant": "canonical", "variant2": "canonical", ... }
|
|
@@ -5086,6 +5098,55 @@ ${memory.content}
|
|
|
5086
5098
|
const metaPath = path4.join(this.stateDir, "meta.json");
|
|
5087
5099
|
await writeFile2(metaPath, JSON.stringify(state, null, 2), "utf-8");
|
|
5088
5100
|
}
|
|
5101
|
+
async appendMemoryActionEvents(events) {
|
|
5102
|
+
if (events.length === 0) return 0;
|
|
5103
|
+
await this.ensureDirectories();
|
|
5104
|
+
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
5105
|
+
const payload = events.map((event) => {
|
|
5106
|
+
const normalized = {
|
|
5107
|
+
...event,
|
|
5108
|
+
timestamp: event.timestamp && event.timestamp.length > 0 ? event.timestamp : nowIso
|
|
5109
|
+
};
|
|
5110
|
+
return `${JSON.stringify(normalized)}
|
|
5111
|
+
`;
|
|
5112
|
+
}).join("");
|
|
5113
|
+
await appendFile(this.memoryActionsPath, payload, "utf-8");
|
|
5114
|
+
return events.length;
|
|
5115
|
+
}
|
|
5116
|
+
async readMemoryActionEvents(limit = 200) {
|
|
5117
|
+
const cappedLimit = Math.max(0, Math.floor(limit));
|
|
5118
|
+
if (cappedLimit === 0) return [];
|
|
5119
|
+
try {
|
|
5120
|
+
const raw = await readFile2(this.memoryActionsPath, "utf-8");
|
|
5121
|
+
const out = [];
|
|
5122
|
+
const lines = raw.split("\n");
|
|
5123
|
+
for (let i = lines.length - 1; i >= 0 && out.length < cappedLimit; i -= 1) {
|
|
5124
|
+
const line = lines[i]?.trim();
|
|
5125
|
+
if (!line) continue;
|
|
5126
|
+
try {
|
|
5127
|
+
const parsed = JSON.parse(line);
|
|
5128
|
+
if (typeof parsed.timestamp === "string" && typeof parsed.action === "string" && typeof parsed.outcome === "string") {
|
|
5129
|
+
out.push(parsed);
|
|
5130
|
+
}
|
|
5131
|
+
} catch {
|
|
5132
|
+
}
|
|
5133
|
+
}
|
|
5134
|
+
return out.reverse();
|
|
5135
|
+
} catch {
|
|
5136
|
+
return [];
|
|
5137
|
+
}
|
|
5138
|
+
}
|
|
5139
|
+
async writeCompressionGuidelines(content) {
|
|
5140
|
+
await this.ensureDirectories();
|
|
5141
|
+
await writeFile2(this.compressionGuidelinesPath, content, "utf-8");
|
|
5142
|
+
}
|
|
5143
|
+
async readCompressionGuidelines() {
|
|
5144
|
+
try {
|
|
5145
|
+
return await readFile2(this.compressionGuidelinesPath, "utf-8");
|
|
5146
|
+
} catch {
|
|
5147
|
+
return null;
|
|
5148
|
+
}
|
|
5149
|
+
}
|
|
5089
5150
|
// ---------------------------------------------------------------------------
|
|
5090
5151
|
// Question storage
|
|
5091
5152
|
// ---------------------------------------------------------------------------
|
|
@@ -6275,7 +6336,7 @@ function extractTopics(memories, topN = 50) {
|
|
|
6275
6336
|
}
|
|
6276
6337
|
|
|
6277
6338
|
// src/transcript.ts
|
|
6278
|
-
import { appendFile, mkdir as mkdir4, readdir as readdir3, readFile as readFile4, unlink as unlink2, writeFile as writeFile4 } from "fs/promises";
|
|
6339
|
+
import { appendFile as appendFile2, mkdir as mkdir4, readdir as readdir3, readFile as readFile4, unlink as unlink2, writeFile as writeFile4 } from "fs/promises";
|
|
6279
6340
|
import path6 from "path";
|
|
6280
6341
|
var TranscriptManager = class _TranscriptManager {
|
|
6281
6342
|
transcriptsDir;
|
|
@@ -6384,7 +6445,7 @@ var TranscriptManager = class _TranscriptManager {
|
|
|
6384
6445
|
const channelDir = path6.join(this.toolUsageDir, dir);
|
|
6385
6446
|
await mkdir4(channelDir, { recursive: true });
|
|
6386
6447
|
const filePath = path6.join(channelDir, file);
|
|
6387
|
-
await
|
|
6448
|
+
await appendFile2(filePath, JSON.stringify(entry) + "\n", "utf-8");
|
|
6388
6449
|
}
|
|
6389
6450
|
async readToolUse(sessionKey, startTime, endTime) {
|
|
6390
6451
|
const { dir } = this.getToolUsagePath(sessionKey);
|
|
@@ -6439,7 +6500,7 @@ var TranscriptManager = class _TranscriptManager {
|
|
|
6439
6500
|
const filePath = path6.join(channelDir, file);
|
|
6440
6501
|
await mkdir4(channelDir, { recursive: true });
|
|
6441
6502
|
const line = JSON.stringify(entry) + "\n";
|
|
6442
|
-
await
|
|
6503
|
+
await appendFile2(filePath, line, "utf-8");
|
|
6443
6504
|
log.debug(`appended transcript entry for ${entry.sessionKey}: ${entry.turnId}`);
|
|
6444
6505
|
} catch (err) {
|
|
6445
6506
|
log.error("failed to append transcript entry:", err);
|
|
@@ -7604,7 +7665,7 @@ var NegativeExampleStore = class {
|
|
|
7604
7665
|
};
|
|
7605
7666
|
|
|
7606
7667
|
// src/recall-state.ts
|
|
7607
|
-
import { appendFile as
|
|
7668
|
+
import { appendFile as appendFile3, mkdir as mkdir8, readFile as readFile8, writeFile as writeFile8 } from "fs/promises";
|
|
7608
7669
|
import path10 from "path";
|
|
7609
7670
|
import { createHash as createHash2 } from "crypto";
|
|
7610
7671
|
var LastRecallStore = class {
|
|
@@ -7663,7 +7724,7 @@ var LastRecallStore = class {
|
|
|
7663
7724
|
}
|
|
7664
7725
|
try {
|
|
7665
7726
|
await mkdir8(path10.dirname(this.impressionsPath), { recursive: true });
|
|
7666
|
-
await
|
|
7727
|
+
await appendFile3(this.impressionsPath, JSON.stringify(snapshot) + "\n", "utf-8");
|
|
7667
7728
|
} catch (err) {
|
|
7668
7729
|
log.debug(`recall impressions append failed: ${err}`);
|
|
7669
7730
|
}
|
|
@@ -9201,7 +9262,7 @@ function recencyWindowFromPrompt(prompt, nowMs = Date.now()) {
|
|
|
9201
9262
|
}
|
|
9202
9263
|
|
|
9203
9264
|
// src/graph.ts
|
|
9204
|
-
import { mkdir as mkdir12, appendFile as
|
|
9265
|
+
import { mkdir as mkdir12, appendFile as appendFile4, readFile as readFile13 } from "fs/promises";
|
|
9205
9266
|
import * as path16 from "path";
|
|
9206
9267
|
var CAUSAL_PHRASES = [
|
|
9207
9268
|
"as a result",
|
|
@@ -9223,7 +9284,7 @@ async function ensureGraphsDir(memoryDir) {
|
|
|
9223
9284
|
async function appendEdge(memoryDir, edge) {
|
|
9224
9285
|
await ensureGraphsDir(memoryDir);
|
|
9225
9286
|
const line = JSON.stringify(edge) + "\n";
|
|
9226
|
-
await
|
|
9287
|
+
await appendFile4(graphFilePath(memoryDir, edge.type), line, "utf8");
|
|
9227
9288
|
}
|
|
9228
9289
|
async function readEdges(memoryDir, type) {
|
|
9229
9290
|
const filePath = graphFilePath(memoryDir, type);
|
|
@@ -9587,7 +9648,7 @@ function recallNamespacesForPrincipal(principal, config) {
|
|
|
9587
9648
|
}
|
|
9588
9649
|
|
|
9589
9650
|
// src/shared-context/manager.ts
|
|
9590
|
-
import { mkdir as mkdir14, readFile as readFile14, readdir as readdir9, appendFile as
|
|
9651
|
+
import { mkdir as mkdir14, readFile as readFile14, readdir as readdir9, appendFile as appendFile5, writeFile as writeFile13, stat as stat2 } from "fs/promises";
|
|
9591
9652
|
import path20 from "path";
|
|
9592
9653
|
import os3 from "os";
|
|
9593
9654
|
import { z as z3 } from "zod";
|
|
@@ -9709,7 +9770,7 @@ title: ${opts.title.replace(/\n/g, " ").slice(0, 200)}
|
|
|
9709
9770
|
}
|
|
9710
9771
|
async appendFeedback(entry) {
|
|
9711
9772
|
const parsed = SharedFeedbackEntrySchema.parse(entry);
|
|
9712
|
-
await
|
|
9773
|
+
await appendFile5(this.feedbackInboxPath, JSON.stringify(parsed) + "\n", "utf-8");
|
|
9713
9774
|
}
|
|
9714
9775
|
async appendPrioritiesInbox(opts) {
|
|
9715
9776
|
const stamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -9720,7 +9781,7 @@ title: ${opts.title.replace(/\n/g, " ").slice(0, 200)}
|
|
|
9720
9781
|
opts.text.trimEnd(),
|
|
9721
9782
|
""
|
|
9722
9783
|
].join("\n");
|
|
9723
|
-
await
|
|
9784
|
+
await appendFile5(this.prioritiesInboxPath, lines, "utf-8");
|
|
9724
9785
|
}
|
|
9725
9786
|
async curateDaily(opts) {
|
|
9726
9787
|
const date = opts.date ?? ymd(/* @__PURE__ */ new Date());
|
|
@@ -9937,6 +9998,42 @@ function filterRecallCandidates(candidates, options) {
|
|
|
9937
9998
|
const scopedByNamespace = options.namespacesEnabled ? candidates.filter((r) => options.recallNamespaces.includes(options.resolveNamespace(r.path))) : candidates;
|
|
9938
9999
|
return scopedByNamespace.filter((r) => !isArtifactMemoryPath(r.path)).slice(0, Math.max(0, options.limit));
|
|
9939
10000
|
}
|
|
10001
|
+
function hasLifecycleMetadata(frontmatter) {
|
|
10002
|
+
return frontmatter.lifecycleState !== void 0 || frontmatter.verificationState !== void 0 || frontmatter.policyClass !== void 0 || frontmatter.lastValidatedAt !== void 0 || frontmatter.decayScore !== void 0 || frontmatter.heatScore !== void 0;
|
|
10003
|
+
}
|
|
10004
|
+
function shouldFilterLifecycleRecallCandidate(frontmatter, options) {
|
|
10005
|
+
if (!options.lifecyclePolicyEnabled || !options.lifecycleFilterStaleEnabled) return false;
|
|
10006
|
+
if (!hasLifecycleMetadata(frontmatter)) return false;
|
|
10007
|
+
const lifecycleState = resolveLifecycleState(frontmatter);
|
|
10008
|
+
return lifecycleState === "stale" || lifecycleState === "archived";
|
|
10009
|
+
}
|
|
10010
|
+
function lifecycleRecallScoreAdjustment(frontmatter, options) {
|
|
10011
|
+
if (!options.lifecyclePolicyEnabled) return 0;
|
|
10012
|
+
if (!hasLifecycleMetadata(frontmatter)) return 0;
|
|
10013
|
+
let delta = 0;
|
|
10014
|
+
const lifecycleState = resolveLifecycleState(frontmatter);
|
|
10015
|
+
switch (lifecycleState) {
|
|
10016
|
+
case "active":
|
|
10017
|
+
delta += 0.05;
|
|
10018
|
+
break;
|
|
10019
|
+
case "validated":
|
|
10020
|
+
delta += 0.03;
|
|
10021
|
+
break;
|
|
10022
|
+
case "candidate":
|
|
10023
|
+
delta -= 0.01;
|
|
10024
|
+
break;
|
|
10025
|
+
case "stale":
|
|
10026
|
+
delta -= 0.06;
|
|
10027
|
+
break;
|
|
10028
|
+
case "archived":
|
|
10029
|
+
delta -= 0.08;
|
|
10030
|
+
break;
|
|
10031
|
+
}
|
|
10032
|
+
if (frontmatter.verificationState === "disputed") {
|
|
10033
|
+
delta -= 0.12;
|
|
10034
|
+
}
|
|
10035
|
+
return delta;
|
|
10036
|
+
}
|
|
9940
10037
|
function computeArtifactRecallLimit(recallMode, recallResultLimit, verbatimArtifactsMaxRecall) {
|
|
9941
10038
|
if (recallMode === "no_recall") return 0;
|
|
9942
10039
|
if (Math.max(0, recallResultLimit) === 0) return 0;
|
|
@@ -12402,10 +12499,19 @@ ${lines.join("\n\n")}`;
|
|
|
12402
12499
|
tagCandidates = capSet(rawTags);
|
|
12403
12500
|
}
|
|
12404
12501
|
}
|
|
12405
|
-
|
|
12502
|
+
let lifecycleFilteredCount = 0;
|
|
12503
|
+
const boosted = [];
|
|
12504
|
+
for (const r of results) {
|
|
12406
12505
|
const memory = memoryByPath.get(r.path);
|
|
12407
12506
|
let score = r.score;
|
|
12408
12507
|
if (memory) {
|
|
12508
|
+
if (shouldFilterLifecycleRecallCandidate(memory.frontmatter, {
|
|
12509
|
+
lifecyclePolicyEnabled: this.config.lifecyclePolicyEnabled,
|
|
12510
|
+
lifecycleFilterStaleEnabled: this.config.lifecycleFilterStaleEnabled
|
|
12511
|
+
})) {
|
|
12512
|
+
lifecycleFilteredCount += 1;
|
|
12513
|
+
continue;
|
|
12514
|
+
}
|
|
12409
12515
|
if (this.config.recencyWeight > 0) {
|
|
12410
12516
|
const createdAt = new Date(memory.frontmatter.created).getTime();
|
|
12411
12517
|
const ageMs = now - createdAt;
|
|
@@ -12456,9 +12562,15 @@ ${lines.join("\n\n")}`;
|
|
|
12456
12562
|
score += 0.06;
|
|
12457
12563
|
}
|
|
12458
12564
|
}
|
|
12565
|
+
score += lifecycleRecallScoreAdjustment(memory.frontmatter, {
|
|
12566
|
+
lifecyclePolicyEnabled: this.config.lifecyclePolicyEnabled
|
|
12567
|
+
});
|
|
12459
12568
|
}
|
|
12460
|
-
|
|
12461
|
-
}
|
|
12569
|
+
boosted.push({ ...r, score });
|
|
12570
|
+
}
|
|
12571
|
+
if (lifecycleFilteredCount > 0) {
|
|
12572
|
+
log.debug(`lifecycle retrieval filter removed ${lifecycleFilteredCount} stale/archived candidates`);
|
|
12573
|
+
}
|
|
12462
12574
|
return boosted.sort((a, b) => b.score - a.score);
|
|
12463
12575
|
}
|
|
12464
12576
|
/**
|