docs: Dreaming v2 architecture (OpenClaw parity) - #147
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
More reviews will be available in 17 minutes and 57 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughAdds a new DREAMING.md describing the dreaming v2 memory-governance pipeline (Light, REM, Deep, Diary), with budget gating, deterministic promotion rules, runtime/sandbox constraints, scheduler/workflow mappings, agent/prompt restrictions, and an ARCHITECTURE.md cross-reference. ChangesDreaming v2 Memory Pipeline
Sequence Diagram(s)(Skipped — the change set is large and includes many components; a single compact sequence diagram would oversimplify multiple coordinated flows.) Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
✨ Finishing Touches🧪 Generate unit tests (beta)
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
docs/DREAMING.md (1)
80-80: ⚡ Quick winConsider making the cross-reference more specific.
The phrase "see scheduling note below" is vague. Consider linking to the specific section, e.g., "see Budget integration > Scheduling when budget-blocked".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/DREAMING.md` at line 80, The table cell text "see scheduling note below" is vague—replace it with a specific cross-reference to the exact section (for example: "see Budget integration > Scheduling when budget-blocked") and make it a clickable/internal link if your docs system supports anchors; update the table row string shown (the Budget row in DREAMING.md) to use that explicit section title or anchor link so readers jump directly to the Scheduling when budget-blocked note.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/DREAMING.md`:
- Around line 87-97: The fenced code block in DREAMING.md lacks a language
specifier; update the block that shows app/api/cron/liveness/route.ts →
runAgentEventScheduler() → enqueueAgentEvent({ type: 'dreaming' }) and the
agent-runtime entries (handleDreaming, handleHeartbeat, sweep orchestrator) to
start with a language tag such as ```text or ```plaintext so syntax highlighters
and linters properly recognize it; ensure the opening fence before the lines
containing runAgentEventScheduler(), enqueueAgentEvent, handleDreaming(),
handleHeartbeat, and the memory-core sweep note is replaced with ```text (or
```plaintext) and the closing fence remains unchanged.
---
Nitpick comments:
In `@docs/DREAMING.md`:
- Line 80: The table cell text "see scheduling note below" is vague—replace it
with a specific cross-reference to the exact section (for example: "see Budget
integration > Scheduling when budget-blocked") and make it a clickable/internal
link if your docs system supports anchors; update the table row string shown
(the Budget row in DREAMING.md) to use that explicit section title or anchor
link so readers jump directly to the Scheduling when budget-blocked note.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 7aca2f8d-a8ae-4bdc-9819-99c6387d086a
📒 Files selected for processing (2)
docs/ARCHITECTURE.mddocs/DREAMING.md
Document the full memory-core pipeline (Light, REM, Deep, diary report and best-effort narrative), budget gates, sandbox layout, and OpenClaw parity targets. Link from ARCHITECTURE.md. Co-authored-by: Tommaso <tommaso.carnemolla@gmail.com>
Co-authored-by: Tommaso <tommaso.carnemolla@gmail.com>
f894824 to
c289652
Compare
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (3)
packages/ai/agent-runtime/memory-core/extract.ts (1)
25-27: ⚡ Quick winPrefer
for...ofiteration for line scanningThis loop is index-based even though iteration is sequential. Converting to
for...ofwithentries()simplifies the control flow while preserving line numbers.As per coding guidelines, “Prefer
for...ofloops over.forEach()and indexedforloops.”🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/ai/agent-runtime/memory-core/extract.ts` around lines 25 - 27, Replace the indexed for loop with a for...of over lines.entries() to iterate sequentially while preserving the line index; specifically change the loop that currently uses "for (let index = 0; index < lines.length; index += 1)" and references "lines[index]"/"rawText" to use "for (const [index, rawLine] of lines.entries())" (or equivalent), then feed rawLine.trim() into normalizeCandidateText and keep using the same index variable where line numbers are required (e.g., in calls that use normalized or rawText) so behavior and line-numbering remain unchanged.Source: Coding guidelines
packages/ai/agent-runtime/memory-core/rank.ts (1)
32-32: ⚡ Quick winExtract
86_400_000into a named constantThe repeated day-milliseconds literal is a magic number. Define a single constant (for example
MILLISECONDS_PER_DAY) and reuse it in both age calculations.As per coding guidelines, “Use meaningful variable names instead of magic numbers - extract constants with descriptive names.”
Also applies to: 54-54
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/ai/agent-runtime/memory-core/rank.ts` at line 32, Replace the magic number 86_400_000 with a well-named constant (e.g., MILLISECONDS_PER_DAY) and use it for all day-to-millisecond conversions in this module; specifically, introduce const MILLISECONDS_PER_DAY = 86_400_000 at the top of packages/ai/agent-runtime/memory-core/rank.ts and update the age calculation(s) that compute ageDays (and the second occurrence around the other age calculation at the same file) to use ageDays = ageMs / MILLISECONDS_PER_DAY so both places reuse the descriptive constant.Source: Coding guidelines
packages/ai/agent-runtime/workflows/session/tools/sandbox-file-helpers/paths.test.ts (1)
11-23: ⚡ Quick winAdd a prefix-path assertion for runtime-owned coverage.
Current test covers only exact path matching. Add a case for a nested path (e.g.,
memory/.dreams/subdir/file.txt) to protect thestartsWithbranch inisRuntimeOwnedPath(Line 76 inpaths.ts).Suggested test addition
it('blocks runtime-owned dreaming store paths', () => { expect(isRuntimeOwnedPath('memory/.dreams/dreaming.sqlite')).toBe(true) + expect(isRuntimeOwnedPath('memory/.dreams/subdir/file.txt')).toBe(true)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/ai/agent-runtime/workflows/session/tools/sandbox-file-helpers/paths.test.ts` around lines 11 - 23, Add a test case that asserts runtime-owned paths are detected for nested/prefix paths (not just exact matches): call isRuntimeOwnedPath('memory/.dreams/subdir/file.txt') and expect true, then pass normalizeSandboxPath('memory/.dreams/subdir/file.txt') into assertWritableSandboxPath and assertAgentVisibleSandboxPath and expect both to throw SandboxPathError; this covers the startsWith branch in isRuntimeOwnedPath and ensures the same protection as the existing exact-path case.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/ai/agent-runtime/memory-core/extract.ts`:
- Around line 48-49: The loop currently treats input.maxSnippets with a truthy
check so a value of 0 is ignored; change the condition to explicitly check for
undefined/null (e.g., input.maxSnippets != null) before enforcing the cap so
maxSnippets = 0 acts as a limit; update the condition that uses
input.maxSnippets and snippets (the if block shown) to break when
snippets.length >= input.maxSnippets only when input.maxSnippets is not
null/undefined, leaving other behavior unchanged.
In `@packages/ai/agent-runtime/memory-core/sanitize.ts`:
- Around line 3-4: The current DREAMING_MANAGED_BLOCK_RE can remove content
between a start and a non-matching end marker; update the regex in sanitize.ts
(symbol DREAMING_MANAGED_BLOCK_RE) to capture the label after
"outname:dreaming:" and use a backreference for the closing marker so the
start/end names must match (e.g. change to capture group for ([\w-]+) and use \1
in the corresponding :end part), keeping the global flag and
non-greedy/single-line behavior.
In `@packages/ai/agent-runtime/memory-core/store/migrations.ts`:
- Around line 47-78: The CREATE TABLE statements for evidence_snippets,
phase_signals and promotions define relation columns (candidate_key, source_id,
sweep_id, query_key) but lack FOREIGN KEY REFERENCES clauses, so SQLite won't
enforce integrity; update the CREATE TABLE for evidence_snippets to add
REFERENCES to the table that holds candidates (e.g., candidate_key REFERENCES
candidates(key)) and to the table that holds sources (e.g., source_id REFERENCES
sources(id)) and query_key REFERENCES queries(key); update phase_signals to add
sweep_id REFERENCES sweeps(id) and candidate_key REFERENCES candidates(key);
update promotions to add sweep_id REFERENCES sweeps(id) (and key if it should
reference another table) and include appropriate ON DELETE/ON UPDATE behavior
(CASCADE or RESTRICT) as needed; keep the existing PRAGMA foreign_keys = ON and
ensure the new REFERENCES clauses use the exact primary key column names of the
referenced tables.
In `@packages/ai/agent-runtime/memory-core/store/operations.ts`:
- Around line 42-48: The upsert conflict handler in operations.ts currently
updates sweeps via .onConflictDoUpdate(...) setting attempt, error, and status
but leaves completedAt unchanged; update the conflict update set (in the
.onConflictDoUpdate block for sweeps) to explicitly reset completedAt to null
when reopening a sweep (e.g., include completedAt: null alongside attempt,
error, and status) so a retried/replayed sweep cannot retain a stale completion
timestamp.
---
Nitpick comments:
In `@packages/ai/agent-runtime/memory-core/extract.ts`:
- Around line 25-27: Replace the indexed for loop with a for...of over
lines.entries() to iterate sequentially while preserving the line index;
specifically change the loop that currently uses "for (let index = 0; index <
lines.length; index += 1)" and references "lines[index]"/"rawText" to use "for
(const [index, rawLine] of lines.entries())" (or equivalent), then feed
rawLine.trim() into normalizeCandidateText and keep using the same index
variable where line numbers are required (e.g., in calls that use normalized or
rawText) so behavior and line-numbering remain unchanged.
In `@packages/ai/agent-runtime/memory-core/rank.ts`:
- Line 32: Replace the magic number 86_400_000 with a well-named constant (e.g.,
MILLISECONDS_PER_DAY) and use it for all day-to-millisecond conversions in this
module; specifically, introduce const MILLISECONDS_PER_DAY = 86_400_000 at the
top of packages/ai/agent-runtime/memory-core/rank.ts and update the age
calculation(s) that compute ageDays (and the second occurrence around the other
age calculation at the same file) to use ageDays = ageMs / MILLISECONDS_PER_DAY
so both places reuse the descriptive constant.
In
`@packages/ai/agent-runtime/workflows/session/tools/sandbox-file-helpers/paths.test.ts`:
- Around line 11-23: Add a test case that asserts runtime-owned paths are
detected for nested/prefix paths (not just exact matches): call
isRuntimeOwnedPath('memory/.dreams/subdir/file.txt') and expect true, then pass
normalizeSandboxPath('memory/.dreams/subdir/file.txt') into
assertWritableSandboxPath and assertAgentVisibleSandboxPath and expect both to
throw SandboxPathError; this covers the startsWith branch in isRuntimeOwnedPath
and ensures the same protection as the existing exact-path case.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: d187a519-d11f-4dd0-aa6f-6c852a2e61a6
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (53)
apps/app/app/agents/[agentId]/memory/dreams/page.tsxapps/app/app/agents/[agentId]/memory/page.tsxnext.config.tspackages/ai/agent-runtime/memory-core/config.tspackages/ai/agent-runtime/memory-core/diary.test.tspackages/ai/agent-runtime/memory-core/diary.tspackages/ai/agent-runtime/memory-core/extract.tspackages/ai/agent-runtime/memory-core/markers.test.tspackages/ai/agent-runtime/memory-core/markers.tspackages/ai/agent-runtime/memory-core/promote.test.tspackages/ai/agent-runtime/memory-core/promote.tspackages/ai/agent-runtime/memory-core/rank.tspackages/ai/agent-runtime/memory-core/sanitize.tspackages/ai/agent-runtime/memory-core/store/migrations.tspackages/ai/agent-runtime/memory-core/store/operations.tspackages/ai/agent-runtime/memory-core/store/sandbox.tspackages/ai/agent-runtime/memory-core/store/schema.tspackages/ai/agent-runtime/memory-core/store/sql-js.test.tspackages/ai/agent-runtime/memory-core/store/sql-js.tspackages/ai/agent-runtime/memory-core/types.tspackages/ai/agent-runtime/server/agent-event-keys.test.tspackages/ai/agent-runtime/server/agent-event-keys.tspackages/ai/agent-runtime/server/agent-event-store.tspackages/ai/agent-runtime/server/agent-event-transcript-store.tspackages/ai/agent-runtime/server/event-scheduler.tspackages/ai/agent-runtime/server/session-events.test.tspackages/ai/agent-runtime/server/session-events.tspackages/ai/agent-runtime/workflows/agent-events/workflow.tspackages/ai/agent-runtime/workflows/events/steps/event-store.tspackages/ai/agent-runtime/workflows/events/workflow.workflow.unit.test.tspackages/ai/agent-runtime/workflows/session/agent-factory.tspackages/ai/agent-runtime/workflows/session/compose-system-prompt.tspackages/ai/agent-runtime/workflows/session/handlers/handle-dreaming.tspackages/ai/agent-runtime/workflows/session/handlers/handle-dreaming.unit.test.tspackages/ai/agent-runtime/workflows/session/handlers/handle-heartbeat.tspackages/ai/agent-runtime/workflows/session/handlers/handle-heartbeat.unit.test.tspackages/ai/agent-runtime/workflows/session/steps/dreaming/dreaming-steps.tspackages/ai/agent-runtime/workflows/session/tools/sandbox-file-helpers/grep.tspackages/ai/agent-runtime/workflows/session/tools/sandbox-file-helpers/list.tspackages/ai/agent-runtime/workflows/session/tools/sandbox-file-helpers/paths.test.tspackages/ai/agent-runtime/workflows/session/tools/sandbox-file-helpers/paths.tspackages/ai/agent-runtime/workflows/session/tools/sandbox-file-helpers/read.tspackages/ai/package.jsonpackages/ai/sql-js.d.tspackages/shared/agents/api/creation-chat/create-requested-agent.tspackages/shared/agents/api/creation-chat/schemas.tspackages/shared/agents/components/agent-form/dreaming-settings.tsxpackages/shared/agents/components/agent-memory-pages.tsxpackages/shared/agents/server/agents-md-template.tspackages/shared/agents/server/bootstrap-files.tspackages/shared/content/blog/posts.tstsconfig.jsontsconfig.vitest.json
💤 Files with no reviewable changes (2)
- packages/ai/agent-runtime/workflows/session/agent-factory.ts
- packages/ai/agent-runtime/workflows/session/handlers/handle-heartbeat.unit.test.ts
✅ Files skipped from review due to trivial changes (12)
- apps/app/app/agents/[agentId]/memory/dreams/page.tsx
- next.config.ts
- tsconfig.json
- packages/ai/sql-js.d.ts
- tsconfig.vitest.json
- packages/shared/agents/components/agent-memory-pages.tsx
- apps/app/app/agents/[agentId]/memory/page.tsx
- packages/ai/agent-runtime/server/agent-event-keys.test.ts
- packages/ai/agent-runtime/memory-core/config.ts
- packages/shared/agents/api/creation-chat/schemas.ts
- packages/shared/agents/server/agents-md-template.ts
- packages/shared/agents/components/agent-form/dreaming-settings.tsx
| if (input.maxSnippets && snippets.length >= input.maxSnippets) { | ||
| break |
There was a problem hiding this comment.
maxSnippets = 0 currently behaves as “no limit”
Line 48 uses a truthy check, so 0 is ignored and extraction continues unbounded. Use an explicit undefined/null check for the cap.
Suggested fix
export function extractEvidenceSnippets(
input: ExtractEvidenceInput
): EvidenceSnippet[] {
+ if ((input.maxSnippets ?? Infinity) <= 0) {
+ return []
+ }
const cleaned = stripManagedDreamingContent(input.text)
const snippets: EvidenceSnippet[] = []
const lines = cleaned.split('\n')
@@
- if (input.maxSnippets && snippets.length >= input.maxSnippets) {
+ if (
+ input.maxSnippets !== undefined &&
+ snippets.length >= input.maxSnippets
+ ) {
break
}
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/ai/agent-runtime/memory-core/extract.ts` around lines 48 - 49, The
loop currently treats input.maxSnippets with a truthy check so a value of 0 is
ignored; change the condition to explicitly check for undefined/null (e.g.,
input.maxSnippets != null) before enforcing the cap so maxSnippets = 0 acts as a
limit; update the condition that uses input.maxSnippets and snippets (the if
block shown) to break when snippets.length >= input.maxSnippets only when
input.maxSnippets is not null/undefined, leaving other behavior unchanged.
| const DREAMING_MANAGED_BLOCK_RE = | ||
| /<!--\s*outname:dreaming:[\w-]+:start\b[\s\S]*?<!--\s*outname:dreaming:[\w-]+:end\s*-->/g |
There was a problem hiding this comment.
Managed-block regex can over-strip unrelated content
The regex does not require the :end marker label to match the :start label. A mismatched pair can remove arbitrary intervening markdown, which risks data loss during sanitization.
Suggested fix
-const DREAMING_MANAGED_BLOCK_RE =
- /<!--\s*outname:dreaming:[\w-]+:start\b[\s\S]*?<!--\s*outname:dreaming:[\w-]+:end\s*-->/g
+const DREAMING_MANAGED_BLOCK_RE =
+ /<!--\s*outname:dreaming:([\w-]+):start\b[\s\S]*?<!--\s*outname:dreaming:\1:end\s*-->/g📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const DREAMING_MANAGED_BLOCK_RE = | |
| /<!--\s*outname:dreaming:[\w-]+:start\b[\s\S]*?<!--\s*outname:dreaming:[\w-]+:end\s*-->/g | |
| const DREAMING_MANAGED_BLOCK_RE = | |
| /<!--\s*outname:dreaming:([\w-]+):start\b[\s\S]*?<!--\s*outname:dreaming:\1:end\s*-->/g |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/ai/agent-runtime/memory-core/sanitize.ts` around lines 3 - 4, The
current DREAMING_MANAGED_BLOCK_RE can remove content between a start and a
non-matching end marker; update the regex in sanitize.ts (symbol
DREAMING_MANAGED_BLOCK_RE) to capture the label after "outname:dreaming:" and
use a backreference for the closing marker so the start/end names must match
(e.g. change to capture group for ([\w-]+) and use \1 in the corresponding :end
part), keeping the global flag and non-greedy/single-line behavior.
| CREATE TABLE IF NOT EXISTS evidence_snippets ( | ||
| id TEXT PRIMARY KEY, | ||
| candidate_key TEXT NOT NULL, | ||
| source_type TEXT NOT NULL, | ||
| source_id TEXT NOT NULL, | ||
| path TEXT, | ||
| line INTEGER, | ||
| text TEXT NOT NULL, | ||
| observed_at TEXT NOT NULL, | ||
| query_key TEXT NOT NULL | ||
| ) | ||
| `) | ||
| sqlite.run(` | ||
| CREATE TABLE IF NOT EXISTS phase_signals ( | ||
| id TEXT PRIMARY KEY, | ||
| sweep_id TEXT NOT NULL, | ||
| phase TEXT NOT NULL, | ||
| candidate_key TEXT, | ||
| signal_type TEXT NOT NULL, | ||
| score REAL, | ||
| metadata_json TEXT NOT NULL, | ||
| created_at TEXT NOT NULL | ||
| ) | ||
| `) | ||
| sqlite.run(` | ||
| CREATE TABLE IF NOT EXISTS promotions ( | ||
| key TEXT PRIMARY KEY, | ||
| sweep_id TEXT NOT NULL, | ||
| marker TEXT NOT NULL, | ||
| promoted_at TEXT NOT NULL, | ||
| memory_path TEXT NOT NULL | ||
| ) |
There was a problem hiding this comment.
Add actual FK constraints for relation columns.
Line 6 enables foreign keys, but Lines 47-78 define relation columns without REFERENCES, so SQLite will not enforce integrity and orphan rows can be written.
Suggested schema adjustment
sqlite.run(`
CREATE TABLE IF NOT EXISTS evidence_snippets (
id TEXT PRIMARY KEY,
- candidate_key TEXT NOT NULL,
+ candidate_key TEXT NOT NULL REFERENCES recall_candidates(key) ON DELETE CASCADE,
source_type TEXT NOT NULL,
source_id TEXT NOT NULL,
path TEXT,
line INTEGER,
text TEXT NOT NULL,
observed_at TEXT NOT NULL,
query_key TEXT NOT NULL
)
`)
sqlite.run(`
CREATE TABLE IF NOT EXISTS phase_signals (
id TEXT PRIMARY KEY,
- sweep_id TEXT NOT NULL,
+ sweep_id TEXT NOT NULL REFERENCES sweeps(id) ON DELETE CASCADE,
phase TEXT NOT NULL,
- candidate_key TEXT,
+ candidate_key TEXT REFERENCES recall_candidates(key) ON DELETE SET NULL,
signal_type TEXT NOT NULL,
score REAL,
metadata_json TEXT NOT NULL,
created_at TEXT NOT NULL
)
`)
sqlite.run(`
CREATE TABLE IF NOT EXISTS promotions (
key TEXT PRIMARY KEY,
- sweep_id TEXT NOT NULL,
+ sweep_id TEXT NOT NULL REFERENCES sweeps(id) ON DELETE CASCADE,
marker TEXT NOT NULL,
promoted_at TEXT NOT NULL,
memory_path TEXT NOT NULL
)
`)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/ai/agent-runtime/memory-core/store/migrations.ts` around lines 47 -
78, The CREATE TABLE statements for evidence_snippets, phase_signals and
promotions define relation columns (candidate_key, source_id, sweep_id,
query_key) but lack FOREIGN KEY REFERENCES clauses, so SQLite won't enforce
integrity; update the CREATE TABLE for evidence_snippets to add REFERENCES to
the table that holds candidates (e.g., candidate_key REFERENCES candidates(key))
and to the table that holds sources (e.g., source_id REFERENCES sources(id)) and
query_key REFERENCES queries(key); update phase_signals to add sweep_id
REFERENCES sweeps(id) and candidate_key REFERENCES candidates(key); update
promotions to add sweep_id REFERENCES sweeps(id) (and key if it should reference
another table) and include appropriate ON DELETE/ON UPDATE behavior (CASCADE or
RESTRICT) as needed; keep the existing PRAGMA foreign_keys = ON and ensure the
new REFERENCES clauses use the exact primary key column names of the referenced
tables.
| .onConflictDoUpdate({ | ||
| target: sweeps.id, | ||
| set: { | ||
| attempt: input.attempt, | ||
| error: null, | ||
| status: 'running', | ||
| }, |
There was a problem hiding this comment.
Reset completedAt when re-opening an existing sweep row.
At Line 44, conflict updates leave completedAt untouched. If the same sweepId is retried/replayed, you can persist status: 'running' with a stale completion timestamp.
Suggested fix
.onConflictDoUpdate({
target: sweeps.id,
set: {
attempt: input.attempt,
+ completedAt: null,
error: null,
+ startedAt: input.nowIso,
status: 'running',
},
})📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| .onConflictDoUpdate({ | |
| target: sweeps.id, | |
| set: { | |
| attempt: input.attempt, | |
| error: null, | |
| status: 'running', | |
| }, | |
| .onConflictDoUpdate({ | |
| target: sweeps.id, | |
| set: { | |
| attempt: input.attempt, | |
| completedAt: null, | |
| error: null, | |
| startedAt: input.nowIso, | |
| status: 'running', | |
| }, |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/ai/agent-runtime/memory-core/store/operations.ts` around lines 42 -
48, The upsert conflict handler in operations.ts currently updates sweeps via
.onConflictDoUpdate(...) setting attempt, error, and status but leaves
completedAt unchanged; update the conflict update set (in the
.onConflictDoUpdate block for sweeps) to explicitly reset completedAt to null
when reopening a sweep (e.g., include completedAt: null alongside attempt,
error, and status) so a retried/replayed sweep cannot retain a stale completion
timestamp.
Summary
Adds
docs/DREAMING.md, the target architecture for agent memory consolidation (Light → REM → Deep, diary report + best-effort narrative, budget gates, sandbox layout). Links fromdocs/ARCHITECTURE.md.Design-only PR — no runtime changes.
Key decisions documented
MEMORY.mdpromotions only from Deep;DREAMS.mdis non-canonicalFiles
docs/DREAMING.md(new)docs/ARCHITECTURE.md(link to dreaming doc)Summary by CodeRabbit
New Features
Documentation