refactor: share memory dreaming cron constants

This commit is contained in:
Peter Steinberger
2026-04-27 11:19:00 +01:00
parent 9b0a0fb0a7
commit f6ee2877e0
4 changed files with 37 additions and 45 deletions

View File

@@ -7,6 +7,15 @@ import {
DEFAULT_MEMORY_DEEP_DREAMING_MIN_SCORE as DEFAULT_MEMORY_DREAMING_MIN_SCORE,
DEFAULT_MEMORY_DEEP_DREAMING_MIN_UNIQUE_QUERIES as DEFAULT_MEMORY_DREAMING_MIN_UNIQUE_QUERIES,
DEFAULT_MEMORY_DEEP_DREAMING_RECENCY_HALF_LIFE_DAYS as DEFAULT_MEMORY_DREAMING_RECENCY_HALF_LIFE_DAYS,
LEGACY_MEMORY_LIGHT_DREAMING_CRON_NAME as LEGACY_LIGHT_SLEEP_CRON_NAME,
LEGACY_MEMORY_LIGHT_DREAMING_CRON_TAG as LEGACY_LIGHT_SLEEP_CRON_TAG,
LEGACY_MEMORY_LIGHT_DREAMING_EVENT_TEXT as LEGACY_LIGHT_SLEEP_EVENT_TEXT,
LEGACY_MEMORY_REM_DREAMING_CRON_NAME as LEGACY_REM_SLEEP_CRON_NAME,
LEGACY_MEMORY_REM_DREAMING_CRON_TAG as LEGACY_REM_SLEEP_CRON_TAG,
LEGACY_MEMORY_REM_DREAMING_EVENT_TEXT as LEGACY_REM_SLEEP_EVENT_TEXT,
MANAGED_MEMORY_DREAMING_CRON_NAME as MANAGED_DREAMING_CRON_NAME,
MANAGED_MEMORY_DREAMING_CRON_TAG as MANAGED_DREAMING_CRON_TAG,
MEMORY_DREAMING_SYSTEM_EVENT_TEXT as DREAMING_SYSTEM_EVENT_TEXT,
resolveMemoryCorePluginConfig,
resolveMemoryDeepDreamingConfig,
resolveMemoryDreamingWorkspaces,
@@ -26,15 +35,6 @@ import {
rankShortTermPromotionCandidates,
} from "./short-term-promotion.js";
const MANAGED_DREAMING_CRON_NAME = "Memory Dreaming Promotion";
const MANAGED_DREAMING_CRON_TAG = "[managed-by=memory-core.short-term-promotion]";
const DREAMING_SYSTEM_EVENT_TEXT = "__openclaw_memory_core_short_term_promotion_dream__";
const LEGACY_LIGHT_SLEEP_CRON_NAME = "Memory Light Dreaming";
const LEGACY_LIGHT_SLEEP_CRON_TAG = "[managed-by=memory-core.dreaming.light]";
const LEGACY_LIGHT_SLEEP_EVENT_TEXT = "__openclaw_memory_core_light_sleep__";
const LEGACY_REM_SLEEP_CRON_NAME = "Memory REM Dreaming";
const LEGACY_REM_SLEEP_CRON_TAG = "[managed-by=memory-core.dreaming.rem]";
const LEGACY_REM_SLEEP_EVENT_TEXT = "__openclaw_memory_core_rem_sleep__";
const RUNTIME_CRON_RECONCILE_INTERVAL_MS = 60_000;
const HEARTBEAT_ISOLATED_SESSION_SUFFIX = ":heartbeat";

View File

@@ -2,27 +2,13 @@ import fs from "node:fs/promises";
import path from "node:path";
import { describe, expect, it } from "vitest";
// Mirrored constants in src/commands/doctor-cron-dreaming-payload-migration.ts
// must match the source-of-truth values in
// extensions/memory-core/src/dreaming.ts. There is no shared module today
// because src/ does not import from extensions/, so this drift check stands
// in for that boundary: rename either side without updating the other and
// this test fails before the doctor migration silently stops matching jobs.
const MIRROR_PATH = path.resolve(__dirname, "doctor-cron-dreaming-payload-migration.ts");
const SOURCE_PATH = path.resolve(
__dirname,
"..",
"..",
"extensions",
"memory-core",
"src",
"dreaming.ts",
);
const SOURCE_PATH = path.resolve(__dirname, "..", "..", "src", "memory-host-sdk", "dreaming.ts");
const NAMES = [
"MANAGED_DREAMING_CRON_NAME",
"MANAGED_DREAMING_CRON_TAG",
"DREAMING_SYSTEM_EVENT_TEXT",
"MANAGED_MEMORY_DREAMING_CRON_NAME",
"MANAGED_MEMORY_DREAMING_CRON_TAG",
"MEMORY_DREAMING_SYSTEM_EVENT_TEXT",
] as const;
function extractStringConst(source: string, name: string): string {
@@ -35,19 +21,17 @@ function extractStringConst(source: string, name: string): string {
}
describe("dreaming payload-migration constants drift", () => {
it("matches the source-of-truth values from extensions/memory-core/src/dreaming.ts", async () => {
it("imports the source-of-truth values from the memory host SDK", async () => {
const [mirror, source] = await Promise.all([
fs.readFile(MIRROR_PATH, "utf-8"),
fs.readFile(SOURCE_PATH, "utf-8"),
]);
for (const name of NAMES) {
const mirrorValue = extractStringConst(mirror, name);
const sourceValue = extractStringConst(source, name);
expect(
mirrorValue,
`${name} drift: mirror in src/commands does not match extensions/memory-core/src/dreaming.ts`,
).toBe(sourceValue);
expect(sourceValue).toBeTruthy();
expect(mirror).toContain(name);
expect(mirror).not.toMatch(new RegExp(`\\bconst ${name}\\b`));
}
});
});

View File

@@ -1,33 +1,31 @@
import {
MANAGED_MEMORY_DREAMING_CRON_NAME,
MANAGED_MEMORY_DREAMING_CRON_TAG,
MEMORY_DREAMING_SYSTEM_EVENT_TEXT,
} from "../memory-host-sdk/dreaming.js";
import {
normalizeOptionalLowercaseString,
normalizeOptionalString,
} from "../shared/string-coerce.js";
// Constants are owned by the memory-core dreaming implementation. Mirrored here
// so doctor can rewrite stale jobs without taking a runtime dep on the
// extension. Keep in sync if the memory-core constants change.
const MANAGED_DREAMING_CRON_NAME = "Memory Dreaming Promotion";
const MANAGED_DREAMING_CRON_TAG = "[managed-by=memory-core.short-term-promotion]";
const DREAMING_SYSTEM_EVENT_TEXT = "__openclaw_memory_core_short_term_promotion_dream__";
type UnknownRecord = Record<string, unknown>;
function isManagedDreamingJob(raw: UnknownRecord): boolean {
const description = normalizeOptionalString(raw.description);
if (description?.includes(MANAGED_DREAMING_CRON_TAG)) {
if (description?.includes(MANAGED_MEMORY_DREAMING_CRON_TAG)) {
return true;
}
const name = normalizeOptionalString(raw.name);
if (name !== MANAGED_DREAMING_CRON_NAME) {
if (name !== MANAGED_MEMORY_DREAMING_CRON_NAME) {
return false;
}
const payload = (raw.payload as UnknownRecord | undefined) ?? undefined;
const payloadKind = normalizeOptionalLowercaseString(payload?.kind);
if (payloadKind === "systemevent") {
return normalizeOptionalString(payload?.text) === DREAMING_SYSTEM_EVENT_TEXT;
return normalizeOptionalString(payload?.text) === MEMORY_DREAMING_SYSTEM_EVENT_TEXT;
}
if (payloadKind === "agentturn") {
return normalizeOptionalString(payload?.message) === DREAMING_SYSTEM_EVENT_TEXT;
return normalizeOptionalString(payload?.message) === MEMORY_DREAMING_SYSTEM_EVENT_TEXT;
}
return false;
}
@@ -57,7 +55,7 @@ function rewriteDreamingJobShape(raw: UnknownRecord): void {
raw.sessionTarget = "isolated";
raw.payload = {
kind: "agentTurn",
message: DREAMING_SYSTEM_EVENT_TEXT,
message: MEMORY_DREAMING_SYSTEM_EVENT_TEXT,
lightContext: true,
};
raw.delivery = { mode: "none" };

View File

@@ -16,6 +16,16 @@ export const DEFAULT_MEMORY_DREAMING_STORAGE_MODE = "separate";
export const DEFAULT_MEMORY_DREAMING_SEPARATE_REPORTS = false;
export const DEFAULT_MEMORY_DREAMING_FREQUENCY = "0 3 * * *";
export const DEFAULT_MEMORY_DREAMING_PLUGIN_ID = "memory-core";
export const MANAGED_MEMORY_DREAMING_CRON_NAME = "Memory Dreaming Promotion";
export const MANAGED_MEMORY_DREAMING_CRON_TAG = "[managed-by=memory-core.short-term-promotion]";
export const MEMORY_DREAMING_SYSTEM_EVENT_TEXT =
"__openclaw_memory_core_short_term_promotion_dream__";
export const LEGACY_MEMORY_LIGHT_DREAMING_CRON_NAME = "Memory Light Dreaming";
export const LEGACY_MEMORY_LIGHT_DREAMING_CRON_TAG = "[managed-by=memory-core.dreaming.light]";
export const LEGACY_MEMORY_LIGHT_DREAMING_EVENT_TEXT = "__openclaw_memory_core_light_sleep__";
export const LEGACY_MEMORY_REM_DREAMING_CRON_NAME = "Memory REM Dreaming";
export const LEGACY_MEMORY_REM_DREAMING_CRON_TAG = "[managed-by=memory-core.dreaming.rem]";
export const LEGACY_MEMORY_REM_DREAMING_EVENT_TEXT = "__openclaw_memory_core_rem_sleep__";
export const DEFAULT_MEMORY_LIGHT_DREAMING_CRON_EXPR = "0 */6 * * *";
export const DEFAULT_MEMORY_LIGHT_DREAMING_LOOKBACK_DAYS = 2;