From 2a39713189dafb223c1a7ea2dc5f93998894415b Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 17 Feb 2026 15:19:52 +0000 Subject: [PATCH] feat(scheduler): generate unique memory update files per run to avoid merge conflicts - Modified `scripts/agent/run-scheduler-cycle.mjs` to generate a unique `memory-updates/__.md` path and pass it via `SCHEDULER_MEMORY_FILE` env var. - Updated `scripts/memory/store.mjs` to prioritize `SCHEDULER_MEMORY_FILE` for ingestion. - Updated `src/prompts/scheduler-flow.md` to instruct agents to write to the unique memory file. - Updated `src/prompts/daily/torch-garbage-collection-agent.md` to include `memory-updates/*.md` in the cleanup scope. - Moved existing `memory-update.md` to `memory-updates/legacy-memory-update-.md` to clear the root. Co-authored-by: PR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> --- memory-updates/.gitkeep | 0 .../legacy-memory-update-1771341291.md | 0 scripts/agent/run-scheduler-cycle.mjs | 18 ++++++++++--- scripts/memory/store.mjs | 26 +++++++++---------- .../daily/torch-garbage-collection-agent.md | 16 +++++++----- src/prompts/scheduler-flow.md | 4 +-- 6 files changed, 39 insertions(+), 25 deletions(-) create mode 100644 memory-updates/.gitkeep rename memory-update.md => memory-updates/legacy-memory-update-1771341291.md (100%) diff --git a/memory-updates/.gitkeep b/memory-updates/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/memory-update.md b/memory-updates/legacy-memory-update-1771341291.md similarity index 100% rename from memory-update.md rename to memory-updates/legacy-memory-update-1771341291.md diff --git a/scripts/agent/run-scheduler-cycle.mjs b/scripts/agent/run-scheduler-cycle.mjs index cc9e8b9..8f5167b 100644 --- a/scripts/agent/run-scheduler-cycle.mjs +++ b/scripts/agent/run-scheduler-cycle.mjs @@ -900,9 +900,21 @@ async function main() { const runStartMs = Date.parse(runArtifactSince); const outputChunks = []; + const memoryDir = path.resolve(process.cwd(), 'memory-updates'); + await fs.mkdir(memoryDir, { recursive: true }); + const memoryFile = path.join(memoryDir, `${ts()}__${selectedAgent}.md`); + const schedulerEnv = { + AGENT_PLATFORM: platform, + ...(model ? { AGENT_MODEL: model } : {}), + SCHEDULER_AGENT: selectedAgent, + SCHEDULER_CADENCE: cadence, + SCHEDULER_PROMPT_PATH: promptPath, + SCHEDULER_MEMORY_FILE: memoryFile, + }; + if (schedulerConfig.memoryPolicy.retrieveCommand) { const retrieveResult = await runCommand('bash', ['-lc', schedulerConfig.memoryPolicy.retrieveCommand], { - env: { AGENT_PLATFORM: platform, ...(model ? { AGENT_MODEL: model } : {}), SCHEDULER_AGENT: selectedAgent, SCHEDULER_CADENCE: cadence, SCHEDULER_PROMPT_PATH: promptPath }, + env: schedulerEnv, }); outputChunks.push(retrieveResult.stdout, retrieveResult.stderr); if (retrieveResult.code !== 0) { @@ -921,7 +933,7 @@ async function main() { if (schedulerConfig.handoffCommand) { const handoff = await runCommand('bash', ['-lc', schedulerConfig.handoffCommand], { - env: { AGENT_PLATFORM: platform, ...(model ? { AGENT_MODEL: model } : {}), SCHEDULER_AGENT: selectedAgent, SCHEDULER_CADENCE: cadence, SCHEDULER_PROMPT_PATH: promptPath }, + env: schedulerEnv, }); outputChunks.push(handoff.stdout, handoff.stderr); if (handoff.code !== 0) { @@ -954,7 +966,7 @@ async function main() { if (schedulerConfig.memoryPolicy.storeCommand) { const storeResult = await runCommand('bash', ['-lc', schedulerConfig.memoryPolicy.storeCommand], { - env: { AGENT_PLATFORM: platform, ...(model ? { AGENT_MODEL: model } : {}), SCHEDULER_AGENT: selectedAgent, SCHEDULER_CADENCE: cadence, SCHEDULER_PROMPT_PATH: promptPath }, + env: schedulerEnv, }); outputChunks.push(storeResult.stdout, storeResult.stderr); if (storeResult.code !== 0) { diff --git a/scripts/memory/store.mjs b/scripts/memory/store.mjs index 7151510..fef7db1 100644 --- a/scripts/memory/store.mjs +++ b/scripts/memory/store.mjs @@ -34,21 +34,21 @@ let memoryContent = ''; const cliArgs = process.argv.slice(2); const fileArgIndex = cliArgs.indexOf('--file'); const explicitFile = fileArgIndex !== -1 ? cliArgs[fileArgIndex + 1] : null; +const envFile = process.env.SCHEDULER_MEMORY_FILE; const defaultFile = 'memory-update.md'; -if (explicitFile && existsSync(explicitFile)) { +const targetFile = explicitFile || (envFile && existsSync(envFile) ? envFile : (existsSync(defaultFile) ? defaultFile : null)); + +if (targetFile) { try { - memoryContent = readFileSync(explicitFile, 'utf8').trim(); - console.log(`Loaded memory content from ${explicitFile}`); + if (existsSync(targetFile)) { + memoryContent = readFileSync(targetFile, 'utf8').trim(); + console.log(`Loaded memory content from ${targetFile}`); + } else { + console.warn(`Target memory file does not exist: ${targetFile}`); + } } catch (err) { - console.warn(`Failed to read memory file ${explicitFile}:`, err.message); - } -} else if (!explicitFile && existsSync(defaultFile)) { - try { - memoryContent = readFileSync(defaultFile, 'utf8').trim(); - console.log(`Loaded memory content from default file ${defaultFile}`); - } catch (err) { - console.warn(`Failed to read default memory file ${defaultFile}:`, err.message); + console.warn(`Failed to read memory file ${targetFile}:`, err.message); } } @@ -70,7 +70,7 @@ if (memoryContent) { }); } else { // Fallback if no file provided (preserve existing behavior for compatibility) - console.warn('No memory input found (checked --file or default memory-update.md). using fallback placeholder.'); + console.warn(`No memory input found (checked --file, env SCHEDULER_MEMORY_FILE=${envFile}, or default ${defaultFile}). using fallback placeholder.`); events = [ { agent_id: agentId, @@ -120,7 +120,7 @@ try { promptPath, promptIntent, events: events.length, - sourceFile: explicitFile || (memoryContent ? defaultFile : 'fallback') + sourceFile: targetFile || 'fallback' }, outputs: { storedCount: stored.length, diff --git a/src/prompts/daily/torch-garbage-collection-agent.md b/src/prompts/daily/torch-garbage-collection-agent.md index fc2efe1..de483ae 100644 --- a/src/prompts/daily/torch-garbage-collection-agent.md +++ b/src/prompts/daily/torch-garbage-collection-agent.md @@ -8,9 +8,9 @@ - Memory contract (required): execute configured memory retrieval before implementation and configured memory storage after implementation, preserving scheduler evidence markers/artifacts. - Completion ownership (required): **do not** run `lock:complete` and **do not** create final `task-logs//____completed.md` or `__failed.md`; spawned agents hand results back to the scheduler, and the scheduler owns completion publishing/logging. -You are: **torch-garbage-collection-agent**, a repository hygiene agent focused on removing stale log files. +You are: **torch-garbage-collection-agent**, a repository hygiene agent focused on removing stale log files and ephemeral memory updates. -Mission: keep the repository tree clean by deleting log files older than 14 days, while ensuring deletion is scoped to the repository root only and is always reviewable. +Mission: keep the repository tree clean by deleting log files and memory updates older than 14 days, while ensuring deletion is scoped to the repository root only and is always reviewable. --- @@ -18,12 +18,13 @@ Mission: keep the repository tree clean by deleting log files older than 14 days In scope: - Log files under the current repository root only. +- Ephemeral memory files in `memory-updates/`. - Files older than 14 days. - Safe cleanup with a pre-delete review list. Out of scope: - Any file outside the repository root. -- Non-log files. +- Non-log/non-memory files. - Rewriting build/test configs. --- @@ -31,10 +32,11 @@ Out of scope: ## Safety Rules 1. **Hard boundary:** never delete anything outside the repository root. -2. **Log-only:** only target names that look like logs: +2. **Target-only:** only target names that look like logs or memory updates: - `*.log` - `*.log.*` - `*.out.log` + - `memory-updates/*.md` 3. **Age gate:** only delete files with `mtime > 14 days`. 4. **Two-step flow:** - First produce and inspect a candidate list. @@ -51,14 +53,14 @@ Out of scope: - Verify `package.json` exists to confirm you are in a project root. 2. Generate candidate list: - - `find . -type f \( -name "*.log" -o -name "*.log.*" -o -name "*.out.log" \) -mtime +14 | sort` + - `find . -type f \( -name "*.log" -o -name "*.log.*" -o -name "*.out.log" -o -path "./memory-updates/*.md" \) -mtime +14 | sort` 3. Validate candidate list: - Ensure every path is relative to the current directory (`./...`) or within the repo scope. - - If list is empty: report "No stale log files found" and stop. + - If list is empty: report "No stale files found" and stop. 4. Delete only listed files: - - `find . -type f \( -name "*.log" -o -name "*.log.*" -o -name "*.out.log" \) -mtime +14 -delete` + - `find . -type f \( -name "*.log" -o -name "*.log.*" -o -name "*.out.log" -o -path "./memory-updates/*.md" \) -mtime +14 -delete` 5. Post-delete verification: - Re-run the candidate list command. diff --git a/src/prompts/scheduler-flow.md b/src/prompts/scheduler-flow.md index 33a87c4..3fc52cf 100644 --- a/src/prompts/scheduler-flow.md +++ b/src/prompts/scheduler-flow.md @@ -38,10 +38,10 @@ 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 `memory-update.md`. + - **Agent Action**: Write any new insights, learnings, or patterns to the file specified by `$SCHEDULER_MEMORY_FILE` (defaulting to `memory-updates/__.md`). - 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 `memory-update.md` if present. + - Storage command MUST ingest content from the file at `$SCHEDULER_MEMORY_FILE` (or fallback to `memory-update.md` if present). - Storage command MUST write cadence-scoped evidence artifacts: - `.scheduler-memory/store-.ok` - `.scheduler-memory/store-.json` containing operation inputs/outputs (`agentId`, input event count, stored count, generated summaries).