Dream consolidation

Dream is garbage collection for memories: near-duplicates are clustered by vector similarity and merged, memories that have not been used for a long time lose weight, and memories that are both old and unimportant are forgotten. It is the only automated flow that deletes memories, which is why the defaults stay conservative.

Trigger manual / 30-minute check Greedy clustering similarity ≥ 0.85 Pick the keeper importance → more public → earlier Merge importance +0.05 · access sum · newest time Decay / forget unused >30d → ×0.8; >180d and <0.15 → forgotten Writes back LastRunAt and stats: Merged / Decayed / Forgotten / Remaining / duration
The order is fixed: merge, then decay, then forget. Every step reports its counters so you can tell what changed.

Triggers

ModeBehaviour
ManualPOST /api/memories/dream runs immediately and returns the stats
BackgroundDreamMemoryService checks once on startup and then polls every 30 minutes
PreconditionEnabled = true and more than IntervalHours (default 24 h) since the last run

Configuration and defaults

SettingDefaultConstraint
EnabledtrueDisabling stops the background run; manual execution still works
IntervalHours241–720
MergeThreshold0.850.5–0.99
DecayDays301–3650
ForgetDays180Must be ≥ DecayDays
ForgetBelowImportance0.150.01–1
LastRunAt—Written by the run; saving settings never overwrites it, otherwise every edit would reset the cadence

The settings key is DreamConfig.

Clustering and merging

  1. Load every non-deleted memory and cluster greedily by embedding similarity, using MergeThreshold as the cutoff.
  2. Pick one keeper per cluster: higher Importance → more public scope (Global < Project < Session) → earlier CreatedAt.
  3. Update the keeper: Importance += 0.05 capped at 1, AccessCount adds the absorbed counts, LastAccessedAt takes the newest in the cluster.
  4. Absorbed memories are removed along with their vectors.
The merge prefers the more public and older wording: project- or session-scoped duplicates get absorbed into a global memory — worth a glance afterwards to confirm the surviving text is still accurate.

Decay and forgetting

StageConditionAction
DecayNot accessed for > DecayDays and Importance > 0.05Importance ×= 0.8, floor 0.05
ForgetNot accessed for > ForgetDays and Importance < ForgetBelowImportanceSoft-delete and remove the embedding

Results and observability

  • Stats returned as DreamResultDto: Merged / Decayed / Forgotten / Remaining / DurationMs / RanAt.
  • Logs: startup 记忆 Dream 巩固服务已启动; automatic runs [Dream] 自动巩固完成:…; manual runs [Dream] 记忆巩固完成:…; failures Dream 自动巩固失败 / Dream 记忆巩固失败.
  • Failures never kill the background service: exceptions are caught and logged, and only that run is skipped.

Practice notes

  • Dream is irreversible: there is no memory version history, so merges and forgetting hit the database directly. Understand the consequences before lowering thresholds.
  • "Memories disappeared" is usually not a bug: check ForgetDays, ForgetBelowImportance and those memories' LastAccessedAt — never-recalled memories decay below the cutoff.
  • To keep a memory, raise Importance above 0.2 and let it be recalled occasionally; both signals block forgetting.
  • Switching embedding models changes what a similarity threshold means; run one manual pass and read Merged before re-enabling the schedule.