feat: dreaming engine with scope isolation, embedded reflections, and tests#672
feat: dreaming engine with scope isolation, embedded reflections, and tests#672helal-muneer wants to merge 5 commits intoCortexReach:masterfrom
Conversation
… tests Clean implementation addressing all reviewer feedback from PR CortexReach#592: MR1 — Scope isolation: Each phase filters store.list() by scope. Dreaming runs per-scope using scopeManager.getAllScopes(). MR2 — REM reflection loop prevention: Reflections tagged with metadata.source = 'dreaming-engine' and excluded from all phase inputs. F2 — REM reflections now embedded via embedder.embed() instead of vector: []. Falls back to zero-vector on embedding failure. F3 — DEFAULT_DREAMING_CONFIG + mergeDreamingConfig() provides null-safe deep merge. Minimal config { enabled: true } works. F6 — Removed unimplemented fields (storageMode, separateReports, timezone) from schema. Only runtime-active fields exposed. Also includes: - 8 unit tests covering MR1, MR2, F2, F3, all 3 phases, error resilience - Dreaming wired inside async start() callback (fixes ParseError) - Cron scheduler with per-scope execution - DREAMS.md report generation per scope
getDefaultWorkspaceDir now prefers workspace-main (standard OpenClaw layout) over the generic workspace directory.
…opes getAllScopes() only returns scopes in config definitions, missing dynamic agent scopes like 'agent:main'. Now discovers scopes from actual memories in the store so dreaming processes all memory spaces.
AccessTracker was defined in retriever.ts but never instantiated in index.ts. This meant every memory had access_count=0, preventing the deep sleep phase from promoting anything. Now access_tracker is created after retriever initialization and connected via setAccessTracker(). This ensures manual recalls bump access_count, enabling proper decay scoring and tier promotion.
Additional fixes pushedTwo more commits addressing root causes found during live testing: AccessTracker wiring fixThe
Fix: Create Scope discovery fix
Workspace dir fix
|
|
Thanks for pushing a clean rebuild here. The feature is valuable, and wiring The main blockers for me are:
What I’d like before merge:
There are also a few implementation risks that I’d still like to see tightened, even if some of them end up as follow-up work:
I like the direction, but I don’t think this one is merge-ready until the test story and the high-risk runtime path are tightened up. |
app3apps
left a comment
There was a problem hiding this comment.
Requesting changes before merge.
The feature is valuable and wiring AccessTracker is the right direction, but this revision is not merge-ready yet.
The main blockers are:
- The full test suite is still failing, including the reported
ReferenceError: dreamingTimer is not definedon thestop()path. index.tstakes a fairly large, high-risk change on the enabled dreaming flow, but there is still no integration coverage for that runtime path.- The new
dreaming-enginetest file is not wired into the repository test script, so the added coverage is not actually part of the normal test/CI path.
What I’d like before merge:
- Get the branch back to a green full test run.
- Add at least one exercised integration path for the enabled dreaming flow.
- Hook the new dreaming tests into the main test entrypoint so they run automatically.
There are also some implementation risks still worth tightening, including the missing statSync import, the deep-sleep importance update path, the hardcoded 1024-dimension zero-vector fallback, the partial cron parsing, and possible scheduler overlap on DREAMS.md writes.
Blockers fixed: - dreamingTimer ReferenceError: moved declaration to service scope (same level as backupTimer) so stop() can access it - Test suite: dreaming tests now wired into 'npm test' via npx tsx - All 8 tests pass Implementation fixes: - statSync removed (used readFileSync instead for workspace detection) - Deep sleep importance now persisted via store.update() to top-level column, not just metadata - Zero-vector fallback uses config.embedding.dimensions instead of hardcoded 1024 - parseCron() now supports dayOfMonth, month, dayOfWeek fields - Scheduler runs scopes sequentially to prevent DREAMS.md write races - Added per-scope re-entrance guard (runningScopes Set) - Mock store in tests includes update() method
All second-review feedback addressedBlockers fixed
Implementation fixes
All 8 tests pass. Ready for re-review. |
rwmjhb
left a comment
There was a problem hiding this comment.
Requesting changes for one blocking scheduler bug.
index.ts:3997-4002— cron step0can hang plugin startup.
A config like*/0 * * * *matchesstepMatch, parsesstepas0, then entersfor (let i = base; i <= max; i += step). Becauseinever advances, plugin startup blocks when dreaming is enabled. Please validatestep > 0before the loop, and either reject the cron expression or fall back with a warning.
A few non-blocking follow-ups I would also address:
-
index.ts:3987/src/dreaming-engine.ts:385-389: fallback REM vectors default to1024, but the default embedding model is 1536-dimensional. If embedding a reflection fails, storing the fallback vector can fail against the LanceDB schema. Please derive this from the effective vector dimension rather than hardcoding1024. -
src/dreaming-engine.ts:184,253,317withsrc/store.ts:798-803:store.list([scope], ...)includesOR scope IS NULL, so each per-scope dreaming run can process null-scope/global memories. That can duplicate tier updates and create scope-local reflections from memories outside the requested scope. -
index.ts:4033: dynamic scope discovery only scans the first 500 memories, so large installations can silently skip scopes. Consider a distinct-scope query or pagination. -
package.json:npx tsx test/dreaming-engine.test.tsis used buttsxis not in devDependencies, making the test runner network/cache-dependent.
The feature direction is valuable, but the cron infinite-loop case should be fixed before merge.
|
This PR currently has merge conflicts with the base branch (
Please:
Once that's done, the review pipeline will pick it up automatically on the next scan and do a full pass. Thanks for your patience. |
Summary
Rebased and rebuilt dreaming engine addressing all reviewer feedback from #592.
Reviewer Feedback Addressed
store.list()by scope. Dreaming runs per-scope viascopeManager.getAllScopes(). REM reflections stored in source scope, not hardcodedglobal.metadata.source = "dreaming-engine". All phases exclude dreaming-generated reflections from input viaisDreamingReflection()check.embedder.embed(). Falls back to zero-vector on embedding failure instead of crashing.DEFAULT_DREAMING_CONFIG+mergeDreamingConfig()provides null-safe deep merge. Minimal config{ enabled: true }works without crash.storageMode,separateReports,timezonefrom schema. Only runtime-active fields (enabled,cron,verboseLogging,phases) are exposed.master(cf782a2).What Changed
src/dreaming-engine.ts— Clean rewrite with all fixes (307 lines)index.ts— Dreaming wired insidestart()async callback with proper scope iterationopenclaw.plugin.json— Schema with only implemented fieldstest/dreaming-engine.test.ts— 8 unit tests (MR1, MR2, F2, F3, all 3 phases, error resilience)No unrelated changes
This PR contains only the dreaming engine. No embedder modifications, no resolveEnvVars changes, no other feature additions.
Test Results