Stop the dream cycle aborting when memory consolidation returns early - #495
Merged
Conversation
deploy/docker-compose/agent-data/ is the bind-mounted runtime directory for the compose agent — it holds the agent profile markdown, the long-term memory store, the knowledge graph, and full conversation transcripts. It was untracked but not ignored, so `git add -A` would stage the entire local agent state (517 files in a working setup) into the repository. Also ignores agent.extra.env, the optional env_file escape hatch for raw .NET config keys, which sits next to the already-ignored .env and can likewise contain provider credentials. Neither belongs in source control: both are per-operator local state. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The memory consolidation pass ran inline at the top of DreamAsync, and its two early exits — fewer than two stored entries, or a null result from the LLM — used a bare `return`. That returned from the whole dream cycle, not just the pass, so every later pass was silently skipped. The worst case is a freshly provisioned agent. With an empty memory store, consolidation hits the `all.Count < 2` guard on every cycle, so memory mining never runs and the store can never reach two entries. It is a deadlock: the agent cannot mine its first memory, and nothing in the logs says why, because the cycle reports as started but never reports as complete. Extracted the pass into RunMemoryConsolidationPassAsync, returning its deleted and saved counts, so its early exits return from the pass and the cycle continues. Also in this change, both dream-subsystem fixes found alongside it: - Dream:MemoryConsolidationEnabled (default true, so existing deployments are unaffected). Consolidation is the only pass that rewrites stored entries rather than only adding or deleting them, which makes it the only place a dream model can introduce detail no source entry contained. Turning it off costs duplicate merging, importance re-scoring and decay, all of which live inside the pass. - Dream:ModelTier (default Balanced, matching the previous behaviour). One pass was hardcoded to ModelTier.Balanced while the rest of the cycle honoured the configured tier. Dream passes are structured extraction, so being able to point them at a different tier from the conversational one is useful in its own right. Tests cover the toggle default, environment-style binding, and independence from Dream:MemoryMiningEnabled. Full RockBot.Host.Tests suite passes (1080). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The memory consolidation pass ran inline at the top of
DreamAsync, and its two early exits — fewer than two stored entries, or a null result from the LLM — used a barereturn. That returned from the whole dream cycle, not just the pass, so every pass behind it was silently skipped.The worst case is a freshly provisioned agent. With an empty memory store, consolidation hits the
all.Count < 2guard on every cycle, so memory mining never runs and the store can never reach two entries. It is a deadlock: the agent cannot mine its first memory, and nothing in the logs says why — the cycle logs as started but never logs as complete.Extracted into
RunMemoryConsolidationPassAsync, returning its deleted/saved counts, so the early exits return from the pass and the cycle continues.Most of the diff is re-indentation from that extraction; reviewing with
?w=1shows the real change is ~100 lines.Also in this change
Two dream-subsystem fixes found while scoping the above. Calling them out rather than burying them:
Dream:MemoryConsolidationEnabled(defaulttrue, so existing deployments are unaffected). Consolidation is the only pass that rewrites stored entries rather than only adding or deleting them, which makes it the only place a dream model can introduce detail that no source entry contained — and since it reads the memory store as its own input, anything it invents is re-ingested as fact next cycle. Mining, episode and entity extraction all derive from the conversation log and can be checked against it. Turning it off costs duplicate merging, importance re-scoring and decay, all of which live inside the pass.Dream:ModelTier(defaultBalanced, matching previous behaviour). One pass was hardcoded toModelTier.Balancedwhile the rest of the cycle honoured the configured tier. Dream passes are structured extraction — read a transcript, return JSON — so pointing them at a different tier from the conversational one is useful independently of the bug.Testing
DreamMemoryConsolidationToggleTests: default-enabled, environment-style binding (Dream__MemoryConsolidationEnabled), and independence fromDream:MemoryMiningEnabled.RockBot.Host.Testssuite passes (1080), verified with only this change applied and rebased onto currentmain.Note on the first commit
This branch also carries a one-line
.gitignorefix.deploy/docker-compose/agent-data/is the bind-mounted runtime directory for the compose agent — profile markdown, long-term memory store, knowledge graph, conversation transcripts. It was untracked but not ignored, sogit add -Awould stage the entire local agent state. It has never been committed; this only prevents it.agent.extra.envis ignored alongside it for the same reason as the existing.enventry: it can carry provider credentials.Happy to split that into its own PR if preferred — it is unrelated to the dream fix, but it seemed worth landing promptly.
🤖 Generated with Claude Code