@joshuaswarren/openclaw-engram 8.3.58 → 8.3.60
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 +214 -20
- package/dist/index.js.map +1 -1
- package/openclaw.plugin.json +20 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -377,6 +377,8 @@ function parseConfig(raw) {
|
|
|
377
377
|
proactiveExtractionEnabled: cfg.proactiveExtractionEnabled === true,
|
|
378
378
|
contextCompressionActionsEnabled: cfg.contextCompressionActionsEnabled === true,
|
|
379
379
|
compressionGuidelineLearningEnabled: cfg.compressionGuidelineLearningEnabled === true,
|
|
380
|
+
compressionGuidelineSemanticRefinementEnabled: cfg.compressionGuidelineSemanticRefinementEnabled === true,
|
|
381
|
+
compressionGuidelineSemanticTimeoutMs: typeof cfg.compressionGuidelineSemanticTimeoutMs === "number" ? Math.max(1, Math.floor(cfg.compressionGuidelineSemanticTimeoutMs)) : 2500,
|
|
380
382
|
maxProactiveQuestionsPerExtraction: typeof cfg.maxProactiveQuestionsPerExtraction === "number" ? Math.max(0, Math.floor(cfg.maxProactiveQuestionsPerExtraction)) : 2,
|
|
381
383
|
maxCompressionTokensPerHour: typeof cfg.maxCompressionTokensPerHour === "number" ? Math.max(0, Math.floor(cfg.maxCompressionTokensPerHour)) : 1500,
|
|
382
384
|
// v8.0 phase 1
|
|
@@ -9498,6 +9500,13 @@ function nextOptimizerVersion(previousState) {
|
|
|
9498
9500
|
function roundDelta(value) {
|
|
9499
9501
|
return Math.round(value * 1e3) / 1e3;
|
|
9500
9502
|
}
|
|
9503
|
+
function confidenceForDelta(delta) {
|
|
9504
|
+
const magnitude = Math.abs(delta);
|
|
9505
|
+
return magnitude >= 0.09 ? "high" : magnitude >= 0.04 ? "medium" : "low";
|
|
9506
|
+
}
|
|
9507
|
+
function directionForDelta(delta) {
|
|
9508
|
+
return delta > 0 ? "increase" : delta < 0 ? "decrease" : "hold";
|
|
9509
|
+
}
|
|
9501
9510
|
function computeCompressionGuidelineCandidate(events, options = {}) {
|
|
9502
9511
|
const generatedAt = options.generatedAtIso ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
9503
9512
|
const previousState = options.previousState ?? null;
|
|
@@ -9551,7 +9560,7 @@ function computeCompressionGuidelineCandidate(events, options = {}) {
|
|
|
9551
9560
|
const qualitySignal = qualitySeen > 0 ? (summary.quality.good - summary.quality.poor) / qualitySeen : 0;
|
|
9552
9561
|
const rawDelta = clamp((successRate - failureRate) * 0.12 + qualitySignal * 0.06, -MAX_DELTA, MAX_DELTA);
|
|
9553
9562
|
const delta = roundDelta(rawDelta);
|
|
9554
|
-
const direction = delta
|
|
9563
|
+
const direction = directionForDelta(delta);
|
|
9555
9564
|
if (direction === "decrease" && summary.outcomes.failed > summary.outcomes.applied) {
|
|
9556
9565
|
notes.push("Failures exceed applied outcomes; conservative down-adjustment.");
|
|
9557
9566
|
} else if (direction === "increase" && summary.quality.good > summary.quality.poor) {
|
|
@@ -9561,8 +9570,7 @@ function computeCompressionGuidelineCandidate(events, options = {}) {
|
|
|
9561
9570
|
} else {
|
|
9562
9571
|
notes.push("Outcomes are stable; keep bounded adjustments.");
|
|
9563
9572
|
}
|
|
9564
|
-
const
|
|
9565
|
-
const confidence = magnitude >= 0.09 ? "high" : magnitude >= 0.04 ? "medium" : "low";
|
|
9573
|
+
const confidence = confidenceForDelta(delta);
|
|
9566
9574
|
return {
|
|
9567
9575
|
action: summary.action,
|
|
9568
9576
|
delta,
|
|
@@ -9584,6 +9592,56 @@ function computeCompressionGuidelineCandidate(events, options = {}) {
|
|
|
9584
9592
|
optimizerVersion: nextOptimizerVersion(previousState)
|
|
9585
9593
|
};
|
|
9586
9594
|
}
|
|
9595
|
+
async function refineCompressionGuidelineCandidateSemantically(baseline, options) {
|
|
9596
|
+
if (!options.enabled) return baseline;
|
|
9597
|
+
if (typeof options.runRefinement !== "function") return baseline;
|
|
9598
|
+
const timeoutMs = Math.max(1, Math.floor(options.timeoutMs));
|
|
9599
|
+
let timeoutId = null;
|
|
9600
|
+
const timeout = new Promise((resolve) => {
|
|
9601
|
+
timeoutId = setTimeout(() => resolve(null), timeoutMs);
|
|
9602
|
+
});
|
|
9603
|
+
const refinementPromise = options.runRefinement(baseline).catch(() => null);
|
|
9604
|
+
let refinement = null;
|
|
9605
|
+
try {
|
|
9606
|
+
refinement = await Promise.race([refinementPromise, timeout]);
|
|
9607
|
+
} catch {
|
|
9608
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
9609
|
+
return baseline;
|
|
9610
|
+
}
|
|
9611
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
9612
|
+
if (!refinement || !Array.isArray(refinement.updates) || refinement.updates.length === 0) {
|
|
9613
|
+
return baseline;
|
|
9614
|
+
}
|
|
9615
|
+
const updatesByAction = /* @__PURE__ */ new Map();
|
|
9616
|
+
for (const update of refinement.updates) {
|
|
9617
|
+
if (!update || typeof update.action !== "string") continue;
|
|
9618
|
+
updatesByAction.set(update.action, update);
|
|
9619
|
+
}
|
|
9620
|
+
let changed = false;
|
|
9621
|
+
const ruleUpdates = baseline.ruleUpdates.map((rule) => {
|
|
9622
|
+
const patch = updatesByAction.get(rule.action);
|
|
9623
|
+
if (!patch) return rule;
|
|
9624
|
+
const nextDelta = typeof patch.delta === "number" && Number.isFinite(patch.delta) ? roundDelta(clamp(patch.delta, -MAX_DELTA, MAX_DELTA)) : rule.delta;
|
|
9625
|
+
const nextConfidence = patch.confidence ?? confidenceForDelta(nextDelta);
|
|
9626
|
+
const nextDirection = directionForDelta(nextDelta);
|
|
9627
|
+
const nextNotes = typeof patch.note === "string" && patch.note.trim().length > 0 ? [patch.note.trim()] : rule.notes;
|
|
9628
|
+
if (nextDelta !== rule.delta || nextDirection !== rule.direction || nextConfidence !== rule.confidence || nextNotes.join("\n") !== rule.notes.join("\n")) {
|
|
9629
|
+
changed = true;
|
|
9630
|
+
}
|
|
9631
|
+
return {
|
|
9632
|
+
...rule,
|
|
9633
|
+
delta: nextDelta,
|
|
9634
|
+
direction: nextDirection,
|
|
9635
|
+
confidence: nextConfidence,
|
|
9636
|
+
notes: nextNotes
|
|
9637
|
+
};
|
|
9638
|
+
});
|
|
9639
|
+
if (!changed) return baseline;
|
|
9640
|
+
return {
|
|
9641
|
+
...baseline,
|
|
9642
|
+
ruleUpdates
|
|
9643
|
+
};
|
|
9644
|
+
}
|
|
9587
9645
|
function renderCompressionGuidelinesMarkdown(candidate) {
|
|
9588
9646
|
const actionLines = candidate.actionSummaries.length === 0 ? ["- (none)"] : candidate.actionSummaries.map((item) => `- ${item.action}: ${item.total}`);
|
|
9589
9647
|
const outcomeLines = [
|
|
@@ -15105,30 +15163,123 @@ ${texts.map((t, i) => `[${i + 1}] ${t}`).join("\n\n")}`;
|
|
|
15105
15163
|
log.info("consolidation complete");
|
|
15106
15164
|
return { memoriesProcessed: allMemories.length, merged, invalidated };
|
|
15107
15165
|
}
|
|
15108
|
-
async
|
|
15109
|
-
|
|
15110
|
-
|
|
15111
|
-
|
|
15112
|
-
|
|
15113
|
-
|
|
15114
|
-
|
|
15115
|
-
|
|
15116
|
-
|
|
15117
|
-
|
|
15118
|
-
|
|
15166
|
+
async optimizeCompressionGuidelines(options) {
|
|
15167
|
+
const dryRun = options?.dryRun === true;
|
|
15168
|
+
const eventLimit = typeof options?.eventLimit === "number" ? Math.max(0, Math.floor(options.eventLimit)) : 500;
|
|
15169
|
+
const previousState = await this.storage.readCompressionGuidelineOptimizerState();
|
|
15170
|
+
if (!this.config.compressionGuidelineLearningEnabled) {
|
|
15171
|
+
return {
|
|
15172
|
+
enabled: false,
|
|
15173
|
+
dryRun,
|
|
15174
|
+
eventCount: 0,
|
|
15175
|
+
previousGuidelineVersion: previousState?.guidelineVersion ?? null,
|
|
15176
|
+
nextGuidelineVersion: previousState?.guidelineVersion ?? 0,
|
|
15177
|
+
changedRules: 0,
|
|
15178
|
+
semanticRefinementApplied: false,
|
|
15179
|
+
persisted: false
|
|
15180
|
+
};
|
|
15181
|
+
}
|
|
15182
|
+
const events = await this.storage.readMemoryActionEvents(eventLimit);
|
|
15183
|
+
const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
15184
|
+
const candidate = computeCompressionGuidelineCandidate(events, {
|
|
15185
|
+
generatedAtIso: generatedAt,
|
|
15186
|
+
previousState
|
|
15187
|
+
});
|
|
15188
|
+
const refinedCandidate = await refineCompressionGuidelineCandidateSemantically(candidate, {
|
|
15189
|
+
enabled: this.config.compressionGuidelineSemanticRefinementEnabled,
|
|
15190
|
+
timeoutMs: this.config.compressionGuidelineSemanticTimeoutMs,
|
|
15191
|
+
runRefinement: async (baseline) => {
|
|
15192
|
+
const prompt = [
|
|
15193
|
+
"You refine compression policy suggestions conservatively.",
|
|
15194
|
+
"Return JSON only in this shape:",
|
|
15195
|
+
'{"updates":[{"action":"summarize_node","delta":0.02,"confidence":"medium","note":"..."}]}',
|
|
15196
|
+
"Constraints:",
|
|
15197
|
+
"- Keep updates sparse and conservative.",
|
|
15198
|
+
"- delta must stay between -0.15 and 0.15.",
|
|
15199
|
+
"- Only include actions present in the input.",
|
|
15200
|
+
"Input candidate:",
|
|
15201
|
+
JSON.stringify(baseline)
|
|
15202
|
+
].join("\n");
|
|
15203
|
+
const response = await this.localLlm.chatCompletion(
|
|
15204
|
+
[
|
|
15205
|
+
{ role: "system", content: "Respond with strict JSON only. No markdown." },
|
|
15206
|
+
{ role: "user", content: prompt }
|
|
15207
|
+
],
|
|
15208
|
+
{
|
|
15209
|
+
temperature: 0.1,
|
|
15210
|
+
maxTokens: 400,
|
|
15211
|
+
timeoutMs: this.config.compressionGuidelineSemanticTimeoutMs,
|
|
15212
|
+
operation: "compression_guideline_semantic_refinement"
|
|
15213
|
+
}
|
|
15214
|
+
);
|
|
15215
|
+
return this.parseCompressionSemanticRefinement(response?.content ?? "");
|
|
15216
|
+
}
|
|
15217
|
+
});
|
|
15218
|
+
const content = renderCompressionGuidelinesMarkdown(refinedCandidate);
|
|
15219
|
+
const semanticRefinementApplied = JSON.stringify(refinedCandidate.ruleUpdates) !== JSON.stringify(candidate.ruleUpdates);
|
|
15220
|
+
const changedRules = refinedCandidate.ruleUpdates.filter((rule) => rule.delta !== 0).length;
|
|
15221
|
+
if (!dryRun) {
|
|
15119
15222
|
await this.storage.writeCompressionGuidelines(content);
|
|
15120
15223
|
await this.storage.writeCompressionGuidelineOptimizerState({
|
|
15121
|
-
version:
|
|
15122
|
-
updatedAt:
|
|
15123
|
-
sourceWindow:
|
|
15124
|
-
eventCounts:
|
|
15125
|
-
guidelineVersion:
|
|
15224
|
+
version: refinedCandidate.optimizerVersion,
|
|
15225
|
+
updatedAt: refinedCandidate.generatedAt,
|
|
15226
|
+
sourceWindow: refinedCandidate.sourceWindow,
|
|
15227
|
+
eventCounts: refinedCandidate.eventCounts,
|
|
15228
|
+
guidelineVersion: refinedCandidate.guidelineVersion
|
|
15126
15229
|
});
|
|
15127
|
-
|
|
15230
|
+
}
|
|
15231
|
+
return {
|
|
15232
|
+
enabled: true,
|
|
15233
|
+
dryRun,
|
|
15234
|
+
eventCount: events.length,
|
|
15235
|
+
previousGuidelineVersion: previousState?.guidelineVersion ?? null,
|
|
15236
|
+
nextGuidelineVersion: refinedCandidate.guidelineVersion,
|
|
15237
|
+
changedRules,
|
|
15238
|
+
semanticRefinementApplied,
|
|
15239
|
+
persisted: !dryRun
|
|
15240
|
+
};
|
|
15241
|
+
}
|
|
15242
|
+
async runCompressionGuidelineLearningPass() {
|
|
15243
|
+
if (!this.config.compressionGuidelineLearningEnabled) return;
|
|
15244
|
+
try {
|
|
15245
|
+
const result = await this.optimizeCompressionGuidelines({ dryRun: false, eventLimit: 500 });
|
|
15246
|
+
log.info(`compression guideline learning updated (${result.eventCount} events)`);
|
|
15128
15247
|
} catch (err) {
|
|
15129
15248
|
log.warn(`compression guideline learning failed (ignored): ${err}`);
|
|
15130
15249
|
}
|
|
15131
15250
|
}
|
|
15251
|
+
parseCompressionSemanticRefinement(raw) {
|
|
15252
|
+
if (typeof raw !== "string" || raw.trim().length === 0) return null;
|
|
15253
|
+
const trimmed = raw.trim();
|
|
15254
|
+
const start = trimmed.indexOf("{");
|
|
15255
|
+
const end = trimmed.lastIndexOf("}");
|
|
15256
|
+
if (start === -1 || end === -1 || end <= start) return null;
|
|
15257
|
+
try {
|
|
15258
|
+
const parsed = JSON.parse(trimmed.slice(start, end + 1));
|
|
15259
|
+
if (!Array.isArray(parsed?.updates)) return null;
|
|
15260
|
+
const validActions = /* @__PURE__ */ new Set([
|
|
15261
|
+
"store_episode",
|
|
15262
|
+
"store_note",
|
|
15263
|
+
"update_note",
|
|
15264
|
+
"create_artifact",
|
|
15265
|
+
"summarize_node",
|
|
15266
|
+
"discard",
|
|
15267
|
+
"link_graph"
|
|
15268
|
+
]);
|
|
15269
|
+
const updates = parsed.updates.filter((item) => item && typeof item.action === "string" && validActions.has(item.action)).map((item) => {
|
|
15270
|
+
const confidence = item.confidence === "low" || item.confidence === "medium" || item.confidence === "high" ? item.confidence : void 0;
|
|
15271
|
+
return {
|
|
15272
|
+
action: item.action,
|
|
15273
|
+
delta: typeof item.delta === "number" && Number.isFinite(item.delta) ? item.delta : void 0,
|
|
15274
|
+
confidence,
|
|
15275
|
+
note: typeof item.note === "string" ? item.note : void 0
|
|
15276
|
+
};
|
|
15277
|
+
});
|
|
15278
|
+
return { updates };
|
|
15279
|
+
} catch {
|
|
15280
|
+
return null;
|
|
15281
|
+
}
|
|
15282
|
+
}
|
|
15132
15283
|
async runLifecyclePolicyPass(allMemories) {
|
|
15133
15284
|
const now = /* @__PURE__ */ new Date();
|
|
15134
15285
|
const nowIso = now.toISOString();
|
|
@@ -17447,6 +17598,49 @@ NOTE: You did not provide sessionKey; under concurrency this may not match your
|
|
|
17447
17598
|
},
|
|
17448
17599
|
{ name: "memory_action_apply" }
|
|
17449
17600
|
);
|
|
17601
|
+
api.registerTool(
|
|
17602
|
+
{
|
|
17603
|
+
name: "compression_guidelines_optimize",
|
|
17604
|
+
label: "Optimize Compression Guidelines",
|
|
17605
|
+
description: "Run compression guideline optimizer and optionally persist the new guideline/state (v8.11).",
|
|
17606
|
+
parameters: Type.Object({
|
|
17607
|
+
dryRun: Type.Optional(
|
|
17608
|
+
Type.Boolean({
|
|
17609
|
+
description: "When true, compute candidate/output but do not persist changes."
|
|
17610
|
+
})
|
|
17611
|
+
),
|
|
17612
|
+
eventLimit: Type.Optional(
|
|
17613
|
+
Type.Number({
|
|
17614
|
+
description: "Max telemetry events to analyze (default: 500)."
|
|
17615
|
+
})
|
|
17616
|
+
)
|
|
17617
|
+
}),
|
|
17618
|
+
async execute(_toolCallId, params) {
|
|
17619
|
+
const { dryRun, eventLimit } = params;
|
|
17620
|
+
const result = await orchestrator.optimizeCompressionGuidelines({
|
|
17621
|
+
dryRun: dryRun === true,
|
|
17622
|
+
eventLimit
|
|
17623
|
+
});
|
|
17624
|
+
if (!result.enabled) {
|
|
17625
|
+
return toolResult(
|
|
17626
|
+
"Compression guideline learning is disabled. Enable `compressionGuidelineLearningEnabled: true` to run optimizer."
|
|
17627
|
+
);
|
|
17628
|
+
}
|
|
17629
|
+
return toolResult(
|
|
17630
|
+
[
|
|
17631
|
+
"Compression guideline optimization complete.",
|
|
17632
|
+
`dryRun=${result.dryRun}`,
|
|
17633
|
+
`persisted=${result.persisted}`,
|
|
17634
|
+
`eventCount=${result.eventCount}`,
|
|
17635
|
+
`guidelineVersion: ${result.previousGuidelineVersion ?? "none"} -> ${result.nextGuidelineVersion}`,
|
|
17636
|
+
`changedRules=${result.changedRules}`,
|
|
17637
|
+
`semanticRefinementApplied=${result.semanticRefinementApplied}`
|
|
17638
|
+
].join("\n")
|
|
17639
|
+
);
|
|
17640
|
+
}
|
|
17641
|
+
},
|
|
17642
|
+
{ name: "compression_guidelines_optimize" }
|
|
17643
|
+
);
|
|
17450
17644
|
api.registerTool(
|
|
17451
17645
|
{
|
|
17452
17646
|
name: "memory_store",
|