From 4740515f2f8e52d40f400ad2dc39b0fb92a912c1 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 28 Feb 2026 12:04:18 +0900 Subject: [PATCH] fix(agents): replace active polling with notification-based waiting for background tasks Sisyphus prompt instructed 'your next action is background_output' which caused agents to repeatedly poll running tasks instead of ending their response and waiting for the system notification. - Replace 'STOP all other output' with 'end your response' (actionable) - Add system-reminder notification mechanism explanation - Add explicit 'Do NOT poll' prohibition - Reduce background_cancel(all=true) mentions from 5x to 1x (Hard Blocks) - Reduce Oracle collect obligation from 4x to 2x - Remove motivational fluff ('blind spots', 'normal and expected') Net: -2 lines, clearer mechanism, eliminates polling loop root cause. --- src/agents/dynamic-agent-prompt-builder.ts | 17 ++++++++--------- src/agents/sisyphus.ts | 15 +++++++-------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/agents/dynamic-agent-prompt-builder.ts b/src/agents/dynamic-agent-prompt-builder.ts index 5685431b..79a6a17f 100644 --- a/src/agents/dynamic-agent-prompt-builder.ts +++ b/src/agents/dynamic-agent-prompt-builder.ts @@ -277,12 +277,11 @@ Briefly announce "Consulting Oracle for [reason]" before invocation. ### Oracle Background Task Policy: -**You MUST collect Oracle results before your final answer. No exceptions.** +**Collect Oracle results before your final answer. No exceptions.** -- Oracle may take several minutes. This is normal and expected. -- When Oracle is running and you finish your own exploration/analysis, your next action is \`background_output(task_id="...")\` on Oracle — NOT delivering a final answer. -- Oracle catches blind spots you cannot see — its value is HIGHEST when you think you don't need it. -- **NEVER** cancel Oracle. **NEVER** use \`background_cancel(all=true)\` when Oracle is running. Cancel disposable tasks (explore, librarian) individually by taskId instead. +- Oracle takes minutes. When done with your own work: **end your response** — wait for the \`\`. +- Do NOT poll \`background_output\` on a running Oracle. The notification will come. +- Never cancel Oracle. ` } @@ -292,8 +291,8 @@ export function buildHardBlocksSection(): string { "- Commit without explicit request — **Never**", "- Speculate about unread code — **Never**", "- Leave code in broken state after failures — **Never**", - "- `background_cancel(all=true)` when Oracle is running — **Never.** Cancel tasks individually by taskId.", - "- Delivering final answer before collecting Oracle result — **Never.** Always `background_output` Oracle first.", + "- `background_cancel(all=true)` — **Never.** Always cancel individually by taskId.", + "- Delivering final answer before collecting Oracle result — **Never.**", ] return `## Hard Blocks (NEVER violate) @@ -308,8 +307,8 @@ export function buildAntiPatternsSection(): string { "- **Testing**: Deleting failing tests to \"pass\"", "- **Search**: Firing agents for single-line typos or obvious syntax errors", "- **Debugging**: Shotgun debugging, random changes", - "- **Background Tasks**: `background_cancel(all=true)` — always cancel individually by taskId", - "- **Oracle**: Skipping Oracle results when Oracle was launched — ALWAYS collect via `background_output`", + "- **Background Tasks**: Polling `background_output` on running tasks — end response and wait for notification", + "- **Oracle**: Delivering answer without collecting Oracle results", ] return `## Anti-Patterns (BLOCKING violations) diff --git a/src/agents/sisyphus.ts b/src/agents/sisyphus.ts index 06debf11..950df6b1 100644 --- a/src/agents/sisyphus.ts +++ b/src/agents/sisyphus.ts @@ -329,7 +329,7 @@ task(subagent_type="explore", run_in_background=true, load_skills=[], descriptio // Reference Grep (external) task(subagent_type="librarian", run_in_background=true, load_skills=[], description="Find JWT security docs", prompt="I'm implementing JWT auth and need current security best practices to choose token storage (httpOnly cookies vs localStorage) and set expiration policy. Find: OWASP auth guidelines, recommended token lifetimes, refresh token rotation strategies, common JWT vulnerabilities. Skip 'what is JWT' tutorials — production security guidance only.") task(subagent_type="librarian", run_in_background=true, load_skills=[], description="Find Express auth patterns", prompt="I'm building Express auth middleware and need production-quality patterns to structure my middleware chain. Find how established Express apps (1000+ stars) handle: middleware ordering, token refresh, role-based access control, auth error propagation. Skip basic tutorials — I need battle-tested patterns with proper error handling.") -// Continue working immediately. Collect with background_output when needed. +// Continue working immediately. System notifies on completion — collect with background_output then. // WRONG: Sequential or blocking result = task(..., run_in_background=false) // Never wait synchronously for explore/librarian @@ -337,10 +337,10 @@ result = task(..., run_in_background=false) // Never wait synchronously for exp ### Background Result Collection: 1. Launch parallel agents \u2192 receive task_ids -2. Continue immediate work (explore, librarian results) -3. When results needed: \`background_output(task_id="...")\` -4. **If Oracle is running**: STOP all other output. Follow Oracle Completion Protocol in . -5. Cleanup: Cancel disposable tasks (explore, librarian) individually via \`background_cancel(taskId="...")\`. Never use \`background_cancel(all=true)\`. +2. Continue immediate work +3. System sends \`\` on each task completion — then call \`background_output(task_id="...")\` +4. Need results not yet ready? **End your response.** The notification will trigger your next turn. +5. Cleanup: Cancel disposable tasks individually via \`background_cancel(taskId="...")\` ### Search Stop Conditions @@ -477,9 +477,8 @@ If verification fails: 3. Report: "Done. Note: found N pre-existing lint errors unrelated to my changes." ### Before Delivering Final Answer: -- **If Oracle is running**: STOP. Follow Oracle Completion Protocol in . Do NOT deliver any answer. -- Cancel disposable background tasks (explore, librarian) individually via \`background_cancel(taskId="...")\`. -- **Never use \`background_cancel(all=true)\`.** +- If Oracle is running: **end your response** and wait for the completion notification first. +- Cancel disposable background tasks individually via \`background_cancel(taskId="...")\`. ${oracleSection}