fix(memory-core): use startup config for dreaming cron reconciliation (#63873)

Merged via squash.

Prepared head SHA: 2ec22920cd
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky
This commit is contained in:
Mariano
2026-04-09 21:36:36 +02:00
committed by GitHub
parent 6af17b39e1
commit 2f130c418f
3 changed files with 82 additions and 2 deletions

View File

@@ -2,9 +2,16 @@ import fs from "node:fs/promises";
import path from "node:path";
import type { OpenClawConfig } from "openclaw/plugin-sdk/memory-core";
import { describe, expect, it, vi } from "vitest";
import {
clearInternalHooks,
createInternalHookEvent,
registerInternalHook,
triggerInternalHook,
} from "../../../src/hooks/internal-hooks.js";
import {
__testing,
reconcileShortTermDreamingCronJob,
registerShortTermPromotionDreaming,
resolveShortTermPromotionDreamingConfig,
runShortTermDreamingPromotionIfTriggered,
} from "./dreaming.js";
@@ -661,6 +668,63 @@ describe("short-term dreaming cron reconciliation", () => {
});
});
describe("gateway startup reconciliation", () => {
it("uses the startup cfg when reconciling the managed dreaming cron job", async () => {
clearInternalHooks();
const logger = createLogger();
const harness = createCronHarness();
const api = {
config: { plugins: { entries: {} } },
pluginConfig: {},
logger,
runtime: {},
registerHook: (event: string, handler: Parameters<typeof registerInternalHook>[1]) => {
registerInternalHook(event, handler);
},
on: vi.fn(),
} as never;
try {
registerShortTermPromotionDreaming(api);
await triggerInternalHook(
createInternalHookEvent("gateway", "startup", "gateway:startup", {
cfg: {
hooks: { internal: { enabled: true } },
plugins: {
entries: {
"memory-core": {
config: {
dreaming: {
enabled: true,
frequency: "15 4 * * *",
timezone: "UTC",
},
},
},
},
},
} as OpenClawConfig,
deps: { cron: harness.cron },
}),
);
expect(harness.addCalls).toHaveLength(1);
expect(harness.addCalls[0]).toMatchObject({
schedule: {
kind: "cron",
expr: "15 4 * * *",
tz: "UTC",
},
});
expect(logger.info).toHaveBeenCalledWith(
expect.stringContaining("created managed dreaming cron job"),
);
} finally {
clearInternalHooks();
}
});
});
describe("short-term dreaming trigger", () => {
it("applies promotions when the managed dreaming heartbeat event fires", async () => {
const logger = createLogger();

View File

@@ -307,6 +307,16 @@ function resolveCronServiceFromStartupEvent(event: unknown): CronServiceLike | n
return cron as CronServiceLike;
}
function resolveStartupConfigFromEvent(event: unknown, fallback: OpenClawConfig): OpenClawConfig {
const startupEvent = asRecord(event);
const startupContext = asRecord(startupEvent?.context);
const startupCfg = asRecord(startupContext?.cfg);
if (!startupCfg) {
return fallback;
}
return startupCfg as OpenClawConfig;
}
export function resolveShortTermPromotionDreamingConfig(params: {
pluginConfig?: Record<string, unknown>;
cfg?: OpenClawConfig;
@@ -584,9 +594,14 @@ export function registerShortTermPromotionDreaming(api: OpenClawPluginApi): void
"gateway:startup",
async (event: unknown) => {
try {
// Use the resolved startup snapshot so cron reconciliation matches the boot config.
const startupCfg = resolveStartupConfigFromEvent(event, api.config);
const config = resolveShortTermPromotionDreamingConfig({
pluginConfig: resolveMemoryCorePluginConfig(api.config) ?? api.pluginConfig,
cfg: api.config,
pluginConfig:
resolveMemoryCorePluginConfig(startupCfg) ??
resolveMemoryCorePluginConfig(api.config) ??
api.pluginConfig,
cfg: startupCfg,
});
const cron = resolveCronServiceFromStartupEvent(event);
if (!cron && config.enabled) {