From 8a9080e7c3d5b18dba823dfb4b2dddd0790816f3 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Fri, 20 Feb 2026 10:51:03 -0500 Subject: [PATCH] fix(memory): close the content gap so agents can actually write and retrieve learnings - run-selected-prompt.mjs: set SCHEDULER_MEMORY_FILE env var before spawning each agent so store.mjs has a well-known path to read from (memory-updates/__.md) - retrieve.mjs: format memories.md using m.summary + date/tags in readable markdown sections instead of raw m.content blobs; agents can now scan injected context at a glance - store.mjs: remove semantically-empty fallback placeholder events that polluted the store and degraded retrieval quality; also fix default cadence 'weekly' -> 'daily' to match retrieve - scheduler-flow.md: replace vague "write insights" instruction with a concrete three-section template (Key findings / Patterns / Warnings) and clarify that $SCHEDULER_MEMORY_FILE is set by the scheduler automatically Co-Authored-By: Claude Sonnet 4.6 --- scripts/agent/run-selected-prompt.mjs | 8 ++++++ scripts/memory/retrieve.mjs | 12 ++++++++- scripts/memory/store.mjs | 35 ++++----------------------- src/prompts/scheduler-flow.md | 16 +++++++++++- 4 files changed, 39 insertions(+), 32 deletions(-) diff --git a/scripts/agent/run-selected-prompt.mjs b/scripts/agent/run-selected-prompt.mjs index ff36178..a622aef 100644 --- a/scripts/agent/run-selected-prompt.mjs +++ b/scripts/agent/run-selected-prompt.mjs @@ -67,12 +67,20 @@ async function main() { } const runner = resolveRunner(promptMarkdown); + + // Compute a stable, per-run memory output file path so agents know where to write learnings. + // store.mjs reads this env var; if absent it falls back to the root memory-update.md placeholder. + const agentName = process.env.SCHEDULER_AGENT || 'unknown-agent'; + const runTs = new Date().toISOString().replace(/:/g, '-').replace(/\.\d+Z$/, 'Z'); + const memoryFile = `memory-updates/${runTs}__${agentName}.md`; + const child = spawn(runner.command, runner.args, { cwd: process.cwd(), env: { ...process.env, SCHEDULER_PROMPT_PATH: promptPath, SCHEDULER_PROMPT_MARKDOWN: promptMarkdown, + SCHEDULER_MEMORY_FILE: memoryFile, }, stdio: 'inherit', }); diff --git a/scripts/memory/retrieve.mjs b/scripts/memory/retrieve.mjs index 22442ed..4bdda00 100644 --- a/scripts/memory/retrieve.mjs +++ b/scripts/memory/retrieve.mjs @@ -84,7 +84,17 @@ try { writeFileSync(path.join(sessionDir, 'retrieve.json'), JSON.stringify(artifact, null, 2)); writeFileSync(path.join(sessionDir, 'retrieve.ok'), 'MEMORY_RETRIEVED\n'); writeFileSync(path.join(latestDir, 'retrieve.ok'), 'MEMORY_RETRIEVED\n'); - writeFileSync(path.join(latestDir, 'memories.md'), retrieved.map(m => `- ${m.content}`).join('\n')); + // Format retrieved memories as readable markdown sections. + // Prefer m.summary (compact excerpt) over m.content (full blob) for prompt injection. + const memoriesMarkdown = retrieved.length > 0 + ? retrieved.map((m, i) => { + const date = new Date(m.created_at || m.last_seen || Date.now()).toISOString().split('T')[0]; + const tagStr = Array.isArray(m.tags) && m.tags.length > 0 ? m.tags.join(', ') : ''; + const text = (m.summary || m.content || '').trim(); + return `### ${i + 1}. [${date}]${tagStr ? ` (${tagStr})` : ''}\n\n${text}`; + }).join('\n\n---\n\n') + : '_No memories found for this agent. This may be the first run or the memory store is empty._'; + writeFileSync(path.join(latestDir, 'memories.md'), memoriesMarkdown); // 5. Output success marker to stdout (for scheduler verification) console.log('MEMORY_RETRIEVED'); diff --git a/scripts/memory/store.mjs b/scripts/memory/store.mjs index fef7db1..cf0e170 100644 --- a/scripts/memory/store.mjs +++ b/scripts/memory/store.mjs @@ -3,7 +3,7 @@ import { mkdirSync, readFileSync, writeFileSync, existsSync } from 'node:fs'; import path from 'node:path'; // Parse environment variables -const fallbackCadence = 'weekly'; +const fallbackCadence = 'daily'; const cadence = process.env.SCHEDULER_CADENCE || fallbackCadence; const agentId = process.env.SCHEDULER_AGENT || `scheduler-memory-${cadence}`; const promptPath = process.env.SCHEDULER_PROMPT_PATH || ''; @@ -69,34 +69,9 @@ if (memoryContent) { } }); } else { - // Fallback if no file provided (preserve existing behavior for compatibility) - console.warn(`No memory input found (checked --file, env SCHEDULER_MEMORY_FILE=${envFile}, or default ${defaultFile}). using fallback placeholder.`); - events = [ - { - agent_id: agentId, - content: `Store memory event A for ${cadence} :: ${promptIntent}`, - timestamp: baseTs, - tags: ['scheduler', cadence, 'store'], - metadata: { - session_id: runId, - source: 'scheduler-store', - importance: 0.55, - prompt_path: promptPath - } - }, - { - agent_id: agentId, - content: `Store memory event B for ${cadence} :: ${promptIntent}`, - timestamp: baseTs + 1, - tags: ['scheduler', cadence, 'store'], - metadata: { - session_id: runId, - source: 'scheduler-store', - importance: 0.55, - prompt_path: promptPath - } - } - ]; + // No memory file found — skip ingest rather than storing meaningless placeholder events. + // Placeholder events pollute the store and degrade retrieval quality on future runs. + console.warn(`No memory input found (checked --file, env SCHEDULER_MEMORY_FILE=${envFile}, and default ${defaultFile}). Skipping ingest.`); } try { @@ -120,7 +95,7 @@ try { promptPath, promptIntent, events: events.length, - sourceFile: targetFile || 'fallback' + sourceFile: targetFile || 'none' }, outputs: { storedCount: stored.length, diff --git a/src/prompts/scheduler-flow.md b/src/prompts/scheduler-flow.md index 6aa4548..80ead39 100644 --- a/src/prompts/scheduler-flow.md +++ b/src/prompts/scheduler-flow.md @@ -38,7 +38,21 @@ Every agent prompt invoked by the schedulers (daily/weekly) MUST enforce this co - **Agent Action**: Review `.scheduler-memory/latest//memories.md` for relevant context. 5. **Store memory after implementation and before completion publish**: - - **Agent Action**: Write any new insights, learnings, or patterns to the file specified by `$SCHEDULER_MEMORY_FILE` (defaulting to `memory-updates/__.md`). + - **Agent Action**: Write any new insights, learnings, or patterns to the file specified by `$SCHEDULER_MEMORY_FILE`. The scheduler sets this env var to `memory-updates/__.md` automatically — do not compute a path yourself. + - **What to write** — use this template (keep each bullet to 1-2 lines; omit sections with nothing to say): + ```markdown + # Memory Update — — + + ## Key findings + - + + ## Patterns / reusable knowledge + - + + ## Warnings / gotchas + - + ``` + - Write only facts that will help the **same agent** on its **next run**. Skip meta-commentary about the task structure. - Run configured memory storage workflow after prompt execution (for example via `scheduler.memoryPolicyByCadence..storeCommand`) - Storage command MUST call real memory services (`src/services/memory/index.js#ingestEvents`, which uses ingestor/summarizer pipeline) and MUST emit deterministic marker `MEMORY_STORED`. - Storage command MUST ingest content from the file at `$SCHEDULER_MEMORY_FILE` (or fallback to `memory-update.md` if present).