fix(dreaming): default storage.mode to "separate" so phase blocks stop polluting daily memory files

Closes #66328.

Before this change, every dreaming installation that did not explicitly
set `plugins.entries.memory-core.config.dreaming.storage.mode` accepted
the silent default of `"inline"`, which routes Light Sleep and REM Sleep
phase blocks (the structured staged-candidate lists with their
`<!-- openclaw:dreaming:{phase}:start -->` markers) into
`memory/YYYY-MM-DD.md`. On heavy days the inline blocks dominate the
daily memory file - the reporter measured 340 lines for the Light phase
alone, and a second cross-host check on a v2026.4.12 install observed
475 inline lines from Light plus 14 from REM in a single sweep, leaving
the daily file unusable as a "what happened today" record.

The `"separate"` storage mode that was already wired up in
`writeDailyDreamingPhaseBlock` writes the same content to
`memory/dreaming/{phase}/YYYY-MM-DD.md` instead, leaving the daily file
untouched. `stripManagedDailyDreamingLines` was already in place so the
daily-ingestion scanner does not re-record dream blocks as recall
candidates either way, but flipping the default also avoids the
incidental round-trip where the dreaming pipeline writes inline output
and then reads its own output back as fresh recall material in the next
cycle.

Operators who want the previous behavior can still opt in explicitly:

    plugins.entries.memory-core.config.dreaming.storage.mode: "inline"

The host helper `normalizeStorageMode` continues to accept all three
documented modes (`inline | separate | both`); only the unset-default
fallback changes.

Test changes:
- src/memory-host-sdk/dreaming.test.ts adds two new assertions: one
  pinning the new default shape and one confirming explicit `"inline"`
  still round-trips for opt-in callers.
- extensions/memory-core/src/dreaming.test.ts updates four
  default-output assertions in `resolveShortTermPromotionDreamingConfig`
  to expect `mode: "separate"`.
- extensions/memory-core/src/dreaming-phases.test.ts pins
  `LIGHT_DREAMING_TEST_CONFIG` and the inline-mode harness in
  "checkpoints daily ingestion and skips unchanged daily files" to
  `storage.mode: "inline"` with a comment, since those tests rely on
  inline-mode side effects on `memory/<day>.md` and now need to opt in
  explicitly.

The schema accept-test in extensions/memory-core/src/config.test.ts and
the inline-mode write-path tests in
extensions/memory-core/src/dreaming-markdown.test.ts intentionally keep
asserting `mode: "inline"` because they cover input handling and the
inline write path itself, both of which still need to work.
This commit is contained in:
mjamiv
2026-04-14 07:49:00 +00:00
committed by Josh Lehman
parent a1b01f0281
commit a036c50c25
5 changed files with 41 additions and 5 deletions

View File

@@ -20,6 +20,8 @@ Docs: https://docs.openclaw.ai
- Agents/context + Memory: trim default startup/skills prompt budgets, cap `memory_get` excerpts by default with explicit continuation metadata, and keep QMD reads aligned with the same bounded excerpt contract so long sessions pull less context by default without losing deterministic follow-up reads.
- Matrix/commands: skip DM pairing-store reads on room traffic now that room control-command authorization ignores pairing-store entries, keeping the room path narrower without changing room auth behavior. (#67325) Thanks @gumadeiras.
- Memory-core/dreaming: skip dreaming narrative transcripts from session-store metadata before bootstrap records land so dream diary prompt/prose lines do not pollute session ingestion. (#67315) thanks @jalehman.
- Agents/local models: clarify low-context preflight hints for self-hosted models, point config-backed caps at the relevant OpenClaw setting, and stop suggesting larger models when `agents.defaults.contextTokens` is the real limit. (#66236) Thanks @ImLukeF.
- Dreaming/memory-core: change the default `dreaming.storage.mode` from `inline` to `separate` so Dreaming phase blocks (`## Light Sleep`, `## REM Sleep`) land in `memory/dreaming/{phase}/YYYY-MM-DD.md` instead of being injected into `memory/YYYY-MM-DD.md`. Daily memory files no longer get dominated by structured candidate output, and the daily-ingestion scanner that already strips dream marker blocks no longer has to compete with hundreds of phase-block lines on every run. Operators who want the previous behavior can opt in by setting `plugins.entries.memory-core.config.dreaming.storage.mode: "inline"`. (#66412) Thanks @mjamiv.
## 2026.4.15-beta.1

View File

@@ -27,6 +27,11 @@ const LIGHT_DREAMING_TEST_CONFIG: OpenClawConfig = {
dreaming: {
enabled: true,
timezone: "UTC",
// The existing tests in this file were written when "inline" was the
// default storage mode and assert against `memory/<day>.md` directly.
// Pin the storage mode explicitly so they keep covering inline mode
// after the default flipped to "separate" in #66328.
storage: { mode: "inline", separateReports: false },
phases: {
light: {
enabled: true,
@@ -305,6 +310,10 @@ describe("memory-core dreaming phases", () => {
config: {
dreaming: {
enabled: true,
// This test asserts inline-mode side effects on the daily
// file; pin storage explicitly after the default flipped to
// "separate" in #66328.
storage: { mode: "inline", separateReports: false },
phases: {
light: {
enabled: true,

View File

@@ -184,7 +184,7 @@ describe("short-term dreaming config", () => {
maxAgeDays: 30,
verboseLogging: false,
storage: {
mode: "inline",
mode: "separate",
separateReports: false,
},
});
@@ -223,7 +223,7 @@ describe("short-term dreaming config", () => {
maxAgeDays: 30,
verboseLogging: true,
storage: {
mode: "inline",
mode: "separate",
separateReports: false,
},
});
@@ -259,7 +259,7 @@ describe("short-term dreaming config", () => {
maxAgeDays: 45,
verboseLogging: false,
storage: {
mode: "inline",
mode: "separate",
separateReports: false,
},
});
@@ -294,7 +294,7 @@ describe("short-term dreaming config", () => {
maxAgeDays: 30,
verboseLogging: false,
storage: {
mode: "inline",
mode: "separate",
separateReports: false,
},
});

View File

@@ -90,6 +90,31 @@ describe("memory dreaming host helpers", () => {
});
});
it("defaults storage mode to separate so phase blocks do not pollute daily memory files", () => {
const resolved = resolveMemoryDreamingConfig({
pluginConfig: {},
});
expect(resolved.storage).toEqual({
mode: "separate",
separateReports: false,
});
});
it("preserves explicit inline storage mode for callers that opt in", () => {
const resolved = resolveMemoryDreamingConfig({
pluginConfig: {
dreaming: {
storage: {
mode: "inline",
},
},
},
});
expect(resolved.storage.mode).toBe("inline");
});
it("applies top-level dreaming frequency across all phases", () => {
const resolved = resolveMemoryDreamingConfig({
pluginConfig: {

View File

@@ -12,7 +12,7 @@ import {
export const DEFAULT_MEMORY_DREAMING_ENABLED = false;
export const DEFAULT_MEMORY_DREAMING_TIMEZONE = undefined;
export const DEFAULT_MEMORY_DREAMING_VERBOSE_LOGGING = false;
export const DEFAULT_MEMORY_DREAMING_STORAGE_MODE = "inline";
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";