diff --git a/extensions/memory-core/src/dreaming.test.ts b/extensions/memory-core/src/dreaming.test.ts index d0a393f6447..6cf7611737e 100644 --- a/extensions/memory-core/src/dreaming.test.ts +++ b/extensions/memory-core/src/dreaming.test.ts @@ -1470,6 +1470,74 @@ describe("gateway startup reconciliation", () => { clearInternalHooks(); } }); + + it("does not fall back to startup plugin config when live memory-core config is removed", async () => { + clearInternalHooks(); + const logger = createLogger(); + const harness = createCronHarness(); + const onMock = vi.fn(); + const runtimeLoadConfig = vi.fn( + () => + ({ + agents: { + list: [{ id: "main", default: true }], + }, + }) as OpenClawConfig, + ); + const api: DreamingPluginApiTestDouble = { + config: { + plugins: { + entries: { + "memory-core": { + config: { + dreaming: { + enabled: true, + frequency: "15 4 * * *", + timezone: "UTC", + }, + }, + }, + }, + }, + } as OpenClawConfig, + pluginConfig: {}, + logger, + runtime: { + config: { + loadConfig: runtimeLoadConfig, + }, + }, + on: onMock, + }; + + try { + registerShortTermPromotionDreamingForTest(api); + await triggerGatewayStart(onMock, { + config: api.config, + getCron: () => harness.cron, + }); + + const sessionKey = "agent:main:main"; + enqueueSystemEvent(constants.DREAMING_SYSTEM_EVENT_TEXT, { + sessionKey, + contextKey: "cron:memory-dreaming", + }); + + const beforeAgentReply = getBeforeAgentReplyHandler(onMock); + const result = await beforeAgentReply( + { cleanedBody: constants.DREAMING_SYSTEM_EVENT_TEXT }, + { trigger: "heartbeat", workspaceDir: ".", sessionKey }, + ); + + expect(runtimeLoadConfig).toHaveBeenCalled(); + expect(result).toEqual({ + handled: true, + reason: "memory-core: short-term dreaming disabled", + }); + } finally { + clearInternalHooks(); + } + }); }); describe("short-term dreaming trigger", () => { diff --git a/extensions/memory-core/src/dreaming.ts b/extensions/memory-core/src/dreaming.ts index 25c65dd4cc6..874681c02cd 100644 --- a/extensions/memory-core/src/dreaming.ts +++ b/extensions/memory-core/src/dreaming.ts @@ -664,11 +664,14 @@ export function registerShortTermPromotionDreaming(api: OpenClawPluginApi): void }): Promise => { const startupCfg = params.reason === "startup" ? (params.startupConfig ?? api.config) : resolveCurrentConfig(); + const pluginConfig = + params.reason === "runtime" + ? resolveMemoryCorePluginConfig(startupCfg) + : (resolveMemoryCorePluginConfig(startupCfg) ?? + resolveMemoryCorePluginConfig(api.config) ?? + api.pluginConfig); const config = resolveShortTermPromotionDreamingConfig({ - pluginConfig: - resolveMemoryCorePluginConfig(startupCfg) ?? - resolveMemoryCorePluginConfig(api.config) ?? - api.pluginConfig, + pluginConfig, cfg: startupCfg, }); if (params.reason === "startup") { diff --git a/src/plugins/contracts/boundary-invariants.test.ts b/src/plugins/contracts/boundary-invariants.test.ts index d0c8ada819e..2cb8fd6138e 100644 --- a/src/plugins/contracts/boundary-invariants.test.ts +++ b/src/plugins/contracts/boundary-invariants.test.ts @@ -51,6 +51,11 @@ const BUNDLED_LIVE_CONFIG_HOOK_GUARDS = { 'resolvePluginConfigObject(api.runtime.config.loadConfig(), "active-memory")', "api.runtime.config.loadConfig()", ], + "extensions/memory-core/src/dreaming.ts": [ + 'params.reason === "runtime"', + "resolveMemoryCorePluginConfig(startupCfg)", + "api.runtime.config?.loadConfig?.() ?? api.config", + ], "extensions/memory-lancedb/index.ts": [ 'resolvePluginConfigObject(runtimeConfig, "memory-lancedb")', "api.runtime.config?.loadConfig?.()",