fix(agent-runner): loop recovery — satisfice, corrective nudge, fetch/search dedup#230
Merged
Conversation
…ge, fetch/search dedup
Follow-up to the loop-breaker. The breaker stopped the 80-step burn but only
PAUSED — a hard research checkpoint got stuck, paused, and resume re-entered the
same loop. Three improvements so achievable projects actually complete and hard
ones fail fast instead of endlessly:
1. SATISFICE prompt guidance: the next-action prompt now explicitly tells the
model to use partial/imperfect data and move on rather than chase perfect
results, and to NEVER re-run a search/fetch that already returned something.
2. Corrective NUDGE before pausing: when the same (skill, result) repeats, inject
a strong "[LOOP DETECTED — CHANGE APPROACH]" directive into history (mirrors
the permission-correction nudge) telling the model to proceed with what it has
or try a different source — and only PAUSE if it repeats AGAIN after the nudge
(per-signature once, global cap _MAX_LOOP_NUDGES=3). Nudge state is seeded from
history so a resume can't re-earn fresh nudges for an already-nudged loop.
3. Pre-execution DEDUP: refuse to re-run the EXACT same web_fetch (by URL) or
web_search (by normalized query) within a checkpoint — returns a directive
instead of re-executing. Stops the JS-rendered-shell fetch loop the 4-bit model
gets stuck in (verified live: many target pages — Product Hunt, TechCrunch,
ToolChase — are client-rendered SPAs whose static HTML web_fetch gets is just a
nav shell with no content).
Net effect (verified end-to-end against the live daemon): an achievable research
project ("3 well-known AI writing tools -> file") now runs to COMPLETED with a
real deliverable and zero loops. A very hard open-ended one ("5 brand-new startups
launched this week, from live JS-rendered sources") still can't be completed by
the local 4-bit Qwen — but now it fails FAST (~9 steps, clear reason) instead of
grinding all 80. That residual is a model-capability ceiling, not a code bug: the
detection/redirection all fire correctly; the model just won't satisfice or change
approach when told.
Verified: 127 related tests pass, ruff clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to the loop-breaker (#229). The breaker stopped the 80-step burn but only paused — a hard research checkpoint got stuck, paused, and resume re-entered the same loop. Three improvements:
Net effect (verified live): an achievable research project now runs to COMPLETED with a real deliverable, zero loops. A very hard open-ended one ("5 brand-new startups from live JS sources") still can't complete on the local 4-bit Qwen — but now fails fast (~9 steps, clear reason) not 80. That residual is a model-capability ceiling, not a bug.
127 tests pass, ruff clean.
🤖 Generated with Claude Code