@joshuaswarren/openclaw-engram 8.3.75 → 8.3.76
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 +217 -16
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8805,6 +8805,18 @@ function clampGraphRecallExpandedEntries(entries, maxEntries = 64) {
|
|
|
8805
8805
|
};
|
|
8806
8806
|
}).filter((item) => item.path.length > 0 && item.namespace.length > 0).slice(0, limit);
|
|
8807
8807
|
}
|
|
8808
|
+
var DEFAULT_TIER_MIGRATION_STATUS = {
|
|
8809
|
+
updatedAt: (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
8810
|
+
lastCycle: null,
|
|
8811
|
+
totals: {
|
|
8812
|
+
cycles: 0,
|
|
8813
|
+
scanned: 0,
|
|
8814
|
+
migrated: 0,
|
|
8815
|
+
promoted: 0,
|
|
8816
|
+
demoted: 0,
|
|
8817
|
+
errors: 0
|
|
8818
|
+
}
|
|
8819
|
+
};
|
|
8808
8820
|
var LastRecallStore = class {
|
|
8809
8821
|
statePath;
|
|
8810
8822
|
impressionsPath;
|
|
@@ -8870,6 +8882,70 @@ var LastRecallStore = class {
|
|
|
8870
8882
|
}
|
|
8871
8883
|
}
|
|
8872
8884
|
};
|
|
8885
|
+
var TierMigrationStatusStore = class {
|
|
8886
|
+
statePath;
|
|
8887
|
+
state = structuredClone(DEFAULT_TIER_MIGRATION_STATUS);
|
|
8888
|
+
constructor(memoryDir) {
|
|
8889
|
+
this.statePath = path10.join(memoryDir, "state", "tier-migration-status.json");
|
|
8890
|
+
}
|
|
8891
|
+
async load() {
|
|
8892
|
+
try {
|
|
8893
|
+
const raw = await readFile8(this.statePath, "utf-8");
|
|
8894
|
+
const parsed = JSON.parse(raw);
|
|
8895
|
+
if (!parsed || typeof parsed !== "object") {
|
|
8896
|
+
this.state = structuredClone(DEFAULT_TIER_MIGRATION_STATUS);
|
|
8897
|
+
return;
|
|
8898
|
+
}
|
|
8899
|
+
const totals = parsed.totals && typeof parsed.totals === "object" ? parsed.totals : DEFAULT_TIER_MIGRATION_STATUS.totals;
|
|
8900
|
+
this.state = {
|
|
8901
|
+
updatedAt: typeof parsed.updatedAt === "string" && parsed.updatedAt.length > 0 ? parsed.updatedAt : DEFAULT_TIER_MIGRATION_STATUS.updatedAt,
|
|
8902
|
+
lastCycle: parsed.lastCycle && typeof parsed.lastCycle === "object" ? parsed.lastCycle : null,
|
|
8903
|
+
totals: {
|
|
8904
|
+
cycles: typeof totals.cycles === "number" && Number.isFinite(totals.cycles) ? totals.cycles : 0,
|
|
8905
|
+
scanned: typeof totals.scanned === "number" && Number.isFinite(totals.scanned) ? totals.scanned : 0,
|
|
8906
|
+
migrated: typeof totals.migrated === "number" && Number.isFinite(totals.migrated) ? totals.migrated : 0,
|
|
8907
|
+
promoted: typeof totals.promoted === "number" && Number.isFinite(totals.promoted) ? totals.promoted : 0,
|
|
8908
|
+
demoted: typeof totals.demoted === "number" && Number.isFinite(totals.demoted) ? totals.demoted : 0,
|
|
8909
|
+
errors: typeof totals.errors === "number" && Number.isFinite(totals.errors) ? totals.errors : 0
|
|
8910
|
+
}
|
|
8911
|
+
};
|
|
8912
|
+
} catch {
|
|
8913
|
+
this.state = structuredClone(DEFAULT_TIER_MIGRATION_STATUS);
|
|
8914
|
+
}
|
|
8915
|
+
}
|
|
8916
|
+
get() {
|
|
8917
|
+
return {
|
|
8918
|
+
updatedAt: this.state.updatedAt,
|
|
8919
|
+
lastCycle: this.state.lastCycle ? { ...this.state.lastCycle } : null,
|
|
8920
|
+
totals: { ...this.state.totals }
|
|
8921
|
+
};
|
|
8922
|
+
}
|
|
8923
|
+
async recordCycle(summary) {
|
|
8924
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
8925
|
+
const migratedDelta = summary.dryRun ? 0 : Math.max(0, summary.migrated);
|
|
8926
|
+
const promotedDelta = summary.dryRun ? 0 : Math.max(0, summary.promoted);
|
|
8927
|
+
const demotedDelta = summary.dryRun ? 0 : Math.max(0, summary.demoted);
|
|
8928
|
+
const next = {
|
|
8929
|
+
updatedAt: now,
|
|
8930
|
+
lastCycle: { ...summary },
|
|
8931
|
+
totals: {
|
|
8932
|
+
cycles: this.state.totals.cycles + 1,
|
|
8933
|
+
scanned: this.state.totals.scanned + Math.max(0, summary.scanned),
|
|
8934
|
+
migrated: this.state.totals.migrated + migratedDelta,
|
|
8935
|
+
promoted: this.state.totals.promoted + promotedDelta,
|
|
8936
|
+
demoted: this.state.totals.demoted + demotedDelta,
|
|
8937
|
+
errors: this.state.totals.errors + Math.max(0, summary.errorCount ?? 0)
|
|
8938
|
+
}
|
|
8939
|
+
};
|
|
8940
|
+
this.state = next;
|
|
8941
|
+
try {
|
|
8942
|
+
await mkdir8(path10.dirname(this.statePath), { recursive: true });
|
|
8943
|
+
await writeFile8(this.statePath, JSON.stringify(next, null, 2), "utf-8");
|
|
8944
|
+
} catch (err) {
|
|
8945
|
+
log.debug(`tier migration status write failed: ${err}`);
|
|
8946
|
+
}
|
|
8947
|
+
}
|
|
8948
|
+
};
|
|
8873
8949
|
|
|
8874
8950
|
// src/session-observer-state.ts
|
|
8875
8951
|
import path11 from "path";
|
|
@@ -13218,6 +13294,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
13218
13294
|
relevance;
|
|
13219
13295
|
negatives;
|
|
13220
13296
|
lastRecall;
|
|
13297
|
+
tierMigrationStatus;
|
|
13221
13298
|
embeddingFallback;
|
|
13222
13299
|
conversationIndexDir;
|
|
13223
13300
|
extraction;
|
|
@@ -13311,6 +13388,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
13311
13388
|
this.relevance = new RelevanceStore(config.memoryDir);
|
|
13312
13389
|
this.negatives = new NegativeExampleStore(config.memoryDir);
|
|
13313
13390
|
this.lastRecall = new LastRecallStore(config.memoryDir);
|
|
13391
|
+
this.tierMigrationStatus = new TierMigrationStatusStore(config.memoryDir);
|
|
13314
13392
|
this.sessionObserver = new SessionObserverState({
|
|
13315
13393
|
memoryDir: config.memoryDir,
|
|
13316
13394
|
debounceMs: config.sessionObserverDebounceMs ?? 12e4,
|
|
@@ -13455,6 +13533,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
13455
13533
|
await this.relevance.load();
|
|
13456
13534
|
await this.negatives.load();
|
|
13457
13535
|
await this.lastRecall.load();
|
|
13536
|
+
await this.tierMigrationStatus.load();
|
|
13458
13537
|
await this.sessionObserver.load();
|
|
13459
13538
|
if (this.config.factDeduplicationEnabled) {
|
|
13460
13539
|
const stateDir2 = path26.join(this.config.memoryDir, "state");
|
|
@@ -15047,13 +15126,69 @@ _Context: ${topQuestion.context}_`);
|
|
|
15047
15126
|
this.requestQmdMaintenance();
|
|
15048
15127
|
await this.runTierMigrationCycle(storage, "extraction");
|
|
15049
15128
|
}
|
|
15050
|
-
async runTierMigrationCycle(storage, trigger) {
|
|
15051
|
-
|
|
15052
|
-
|
|
15053
|
-
if (this.
|
|
15054
|
-
|
|
15129
|
+
async runTierMigrationCycle(storage, trigger, options) {
|
|
15130
|
+
const dryRun = options?.dryRun === true;
|
|
15131
|
+
const persistSkipped = options?.force === true || trigger === "manual";
|
|
15132
|
+
if (!this.config.qmdTierMigrationEnabled && options?.force !== true) {
|
|
15133
|
+
const skipped = {
|
|
15134
|
+
trigger,
|
|
15135
|
+
scanned: 0,
|
|
15136
|
+
migrated: 0,
|
|
15137
|
+
promoted: 0,
|
|
15138
|
+
demoted: 0,
|
|
15139
|
+
limit: 0,
|
|
15140
|
+
dryRun,
|
|
15141
|
+
skipped: "tier_migration_disabled"
|
|
15142
|
+
};
|
|
15143
|
+
if (persistSkipped) await this.tierMigrationStatus.recordCycle(skipped);
|
|
15144
|
+
return skipped;
|
|
15145
|
+
}
|
|
15146
|
+
if (trigger === "maintenance" && !this.config.qmdTierAutoBackfillEnabled && options?.force !== true) {
|
|
15147
|
+
const skipped = {
|
|
15148
|
+
trigger,
|
|
15149
|
+
scanned: 0,
|
|
15150
|
+
migrated: 0,
|
|
15151
|
+
promoted: 0,
|
|
15152
|
+
demoted: 0,
|
|
15153
|
+
limit: 0,
|
|
15154
|
+
dryRun,
|
|
15155
|
+
skipped: "maintenance_backfill_disabled"
|
|
15156
|
+
};
|
|
15157
|
+
if (persistSkipped) await this.tierMigrationStatus.recordCycle(skipped);
|
|
15158
|
+
return skipped;
|
|
15159
|
+
}
|
|
15160
|
+
if (this.tierMigrationInFlight) {
|
|
15161
|
+
const skipped = {
|
|
15162
|
+
trigger,
|
|
15163
|
+
scanned: 0,
|
|
15164
|
+
migrated: 0,
|
|
15165
|
+
promoted: 0,
|
|
15166
|
+
demoted: 0,
|
|
15167
|
+
limit: 0,
|
|
15168
|
+
dryRun,
|
|
15169
|
+
skipped: "migration_in_flight"
|
|
15170
|
+
};
|
|
15171
|
+
if (persistSkipped) await this.tierMigrationStatus.recordCycle(skipped);
|
|
15172
|
+
return skipped;
|
|
15173
|
+
}
|
|
15174
|
+
const budgetTrigger = trigger === "manual" ? "maintenance" : trigger;
|
|
15175
|
+
const budget = this.compounding?.tierMigrationCycleBudget(budgetTrigger) ?? defaultTierMigrationCycleBudget(this.config, budgetTrigger);
|
|
15176
|
+
const limit = options?.limitOverride !== void 0 ? Math.max(0, Math.floor(options.limitOverride)) : budget.limit;
|
|
15055
15177
|
const nowMs = Date.now();
|
|
15056
|
-
if (nowMs - this.lastTierMigrationRunAtMs < budget.minIntervalMs)
|
|
15178
|
+
if (options?.force !== true && nowMs - this.lastTierMigrationRunAtMs < budget.minIntervalMs) {
|
|
15179
|
+
const skipped = {
|
|
15180
|
+
trigger,
|
|
15181
|
+
scanned: 0,
|
|
15182
|
+
migrated: 0,
|
|
15183
|
+
promoted: 0,
|
|
15184
|
+
demoted: 0,
|
|
15185
|
+
limit,
|
|
15186
|
+
dryRun,
|
|
15187
|
+
skipped: "min_interval"
|
|
15188
|
+
};
|
|
15189
|
+
if (persistSkipped) await this.tierMigrationStatus.recordCycle(skipped);
|
|
15190
|
+
return skipped;
|
|
15191
|
+
}
|
|
15057
15192
|
const policy = {
|
|
15058
15193
|
enabled: this.config.qmdTierMigrationEnabled,
|
|
15059
15194
|
demotionMinAgeDays: this.config.qmdTierDemotionMinAgeDays,
|
|
@@ -15083,29 +15218,70 @@ _Context: ${topQuestion.context}_`);
|
|
|
15083
15218
|
autoEmbed: this.config.qmdAutoEmbedEnabled
|
|
15084
15219
|
});
|
|
15085
15220
|
let migrated = 0;
|
|
15221
|
+
let promoted = 0;
|
|
15222
|
+
let demoted = 0;
|
|
15086
15223
|
for (const candidate of candidates) {
|
|
15087
|
-
if (migrated >=
|
|
15224
|
+
if (migrated >= limit) break;
|
|
15088
15225
|
const decision = decideTierTransition(candidate.memory, candidate.tier, policy, now);
|
|
15089
15226
|
if (!decision.changed) continue;
|
|
15090
|
-
|
|
15091
|
-
|
|
15092
|
-
|
|
15093
|
-
|
|
15094
|
-
|
|
15095
|
-
|
|
15096
|
-
|
|
15227
|
+
if (!dryRun) {
|
|
15228
|
+
const res = await migration.migrateMemory({
|
|
15229
|
+
memory: candidate.memory,
|
|
15230
|
+
fromTier: candidate.tier,
|
|
15231
|
+
toTier: decision.nextTier,
|
|
15232
|
+
reason: `${trigger}:${decision.reason}`
|
|
15233
|
+
});
|
|
15234
|
+
if (!res.changed) continue;
|
|
15235
|
+
}
|
|
15236
|
+
migrated += 1;
|
|
15237
|
+
if (decision.nextTier === "cold") demoted += 1;
|
|
15238
|
+
if (decision.nextTier === "hot") promoted += 1;
|
|
15097
15239
|
}
|
|
15098
|
-
this.lastTierMigrationRunAtMs = Date.now();
|
|
15240
|
+
if (!dryRun) this.lastTierMigrationRunAtMs = Date.now();
|
|
15099
15241
|
log.debug(
|
|
15100
|
-
`tier migration cycle completed: trigger=${trigger} scanned=${candidates.length} migrated=${migrated} limit=${
|
|
15242
|
+
`tier migration cycle completed: trigger=${trigger} scanned=${candidates.length} migrated=${migrated} limit=${limit}${dryRun ? " dryRun=true" : ""}`
|
|
15101
15243
|
);
|
|
15244
|
+
const summary = {
|
|
15245
|
+
trigger,
|
|
15246
|
+
scanned: candidates.length,
|
|
15247
|
+
migrated,
|
|
15248
|
+
promoted,
|
|
15249
|
+
demoted,
|
|
15250
|
+
limit,
|
|
15251
|
+
dryRun
|
|
15252
|
+
};
|
|
15253
|
+
const shouldPersistCycle = trigger === "manual" || migrated > 0;
|
|
15254
|
+
if (shouldPersistCycle) await this.tierMigrationStatus.recordCycle(summary);
|
|
15255
|
+
return summary;
|
|
15102
15256
|
} catch (err) {
|
|
15103
15257
|
this.lastTierMigrationRunAtMs = Date.now();
|
|
15104
15258
|
log.warn(`tier migration cycle failed (${trigger}, fail-open): ${err}`);
|
|
15259
|
+
const failed = {
|
|
15260
|
+
trigger,
|
|
15261
|
+
scanned: 0,
|
|
15262
|
+
migrated: 0,
|
|
15263
|
+
promoted: 0,
|
|
15264
|
+
demoted: 0,
|
|
15265
|
+
limit,
|
|
15266
|
+
dryRun,
|
|
15267
|
+
errorCount: 1
|
|
15268
|
+
};
|
|
15269
|
+
await this.tierMigrationStatus.recordCycle(failed);
|
|
15270
|
+
return failed;
|
|
15105
15271
|
} finally {
|
|
15106
15272
|
this.tierMigrationInFlight = false;
|
|
15107
15273
|
}
|
|
15108
15274
|
}
|
|
15275
|
+
async getTierMigrationStatus() {
|
|
15276
|
+
return this.tierMigrationStatus.get();
|
|
15277
|
+
}
|
|
15278
|
+
async runTierMigrationNow(options) {
|
|
15279
|
+
return this.runTierMigrationCycle(this.storage, "manual", {
|
|
15280
|
+
dryRun: options?.dryRun === true,
|
|
15281
|
+
limitOverride: options?.limit,
|
|
15282
|
+
force: false
|
|
15283
|
+
});
|
|
15284
|
+
}
|
|
15109
15285
|
maybeScheduleConsolidation(nonZeroExtraction) {
|
|
15110
15286
|
if (this.config.consolidationRequireNonZeroExtraction && !nonZeroExtraction) return;
|
|
15111
15287
|
if (this.nonZeroExtractionsSinceConsolidation < this.config.consolidateEveryN) return;
|
|
@@ -21523,6 +21699,15 @@ async function runGraphHealthCliCommand(options) {
|
|
|
21523
21699
|
includeRepairGuidance: options.includeRepairGuidance
|
|
21524
21700
|
});
|
|
21525
21701
|
}
|
|
21702
|
+
async function runTierStatusCliCommand(orchestrator) {
|
|
21703
|
+
return orchestrator.getTierMigrationStatus();
|
|
21704
|
+
}
|
|
21705
|
+
async function runTierMigrateCliCommand(orchestrator, options = {}) {
|
|
21706
|
+
return orchestrator.runTierMigrationNow({
|
|
21707
|
+
dryRun: options.dryRun === true,
|
|
21708
|
+
limit: options.limit
|
|
21709
|
+
});
|
|
21710
|
+
}
|
|
21526
21711
|
function incrementCounter(target, key) {
|
|
21527
21712
|
const normalized = key && key.length > 0 ? key : "unknown";
|
|
21528
21713
|
target[normalized] = (target[normalized] ?? 0) + 1;
|
|
@@ -22226,6 +22411,22 @@ function registerCli(api, orchestrator) {
|
|
|
22226
22411
|
console.log(JSON.stringify(report, null, 2));
|
|
22227
22412
|
console.log("OK");
|
|
22228
22413
|
});
|
|
22414
|
+
cmd.command("tier-status").description("Show tier migration telemetry and last-cycle summary").action(async () => {
|
|
22415
|
+
const status = await runTierStatusCliCommand(orchestrator);
|
|
22416
|
+
console.log(JSON.stringify(status, null, 2));
|
|
22417
|
+
console.log("OK");
|
|
22418
|
+
});
|
|
22419
|
+
cmd.command("tier-migrate").description("Run one tier migration pass (dry-run by default)").option("--dry-run", "Evaluate and report moves without writing").option("--write", "Apply migration writes (default: dry-run)").option("--limit <n>", "Override migration move limit for this run").action(async (...args) => {
|
|
22420
|
+
const options = args[0] ?? {};
|
|
22421
|
+
const limitRaw = parseInt(String(options.limit ?? ""), 10);
|
|
22422
|
+
const explicitDryRun = options.dryRun === true;
|
|
22423
|
+
const summary = await runTierMigrateCliCommand(orchestrator, {
|
|
22424
|
+
dryRun: explicitDryRun || options.write !== true,
|
|
22425
|
+
limit: Number.isFinite(limitRaw) ? Math.max(0, limitRaw) : void 0
|
|
22426
|
+
});
|
|
22427
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
22428
|
+
console.log("OK");
|
|
22429
|
+
});
|
|
22229
22430
|
cmd.command("action-audit").description("Show namespace-aware memory action policy outcomes").option("--namespace <name>", "Filter to a single namespace").option("--limit <n>", "Max events to read per namespace", "200").action(async (...args) => {
|
|
22230
22431
|
const options = args[0] ?? {};
|
|
22231
22432
|
const limitRaw = parseInt(String(options.limit ?? "200"), 10);
|