fix(goal): don't halt the goal loop on a STUCK run - #4381
Open
all-hands-bot wants to merge 1 commit into
Open
Conversation
The goal loop treated a STUCK run (the stuck-detector heuristic firing) the same as PAUSED/ERROR -- a hard terminal stop that emitted "interrupted" and required a manual resume. This defeated the purpose of the goal command: a goal is supposed to keep working until finished. The stuck detector is a heuristic tuned for single-turn chat and often fires during legitimate iteration (re-running a test, retrying an edit). The goal loop already has an authoritative judge LLM that audits completion each round, which is a far better progress signal. So a STUCK run should not terminate the whole goal; only PAUSED/ERROR (real stop signals) should. Now a STUCK run proceeds to the judge, which either marks the goal complete or sends a followup nudge that breaks the agent out of any genuine loop. Worst case it caps out at max_iterations (bounded), which is strictly better than halting early. Co-authored-by: openhands <openhands@all-hands.dev>
Contributor
Python API breakage checks — ✅ PASSEDResult: ✅ PASSED |
Contributor
REST API breakage checks (OpenAPI) — ✅ PASSEDResult: ✅ PASSED |
Contributor
Coverage Report •
|
||||||||||||||||||||
Collaborator
Author
|
👋 This PR needs a couple of things fixed before OpenHands can review it:
Push an update once this is addressed and this check re-runs automatically. This is an automated check - no AI was used to generate this comment. |
neubig
self-requested a review
August 5, 2026 17:37
enyst
reviewed
Aug 5, 2026
| # let it decide continue-vs-stop (sending a followup nudge | ||
| # that breaks the agent out of any genuine loop). Only | ||
| # PAUSED/ERROR (real stop signals) terminate the goal. | ||
| logger.info("Goal loop continuing past stuck run") |
Member
There was a problem hiding this comment.
The risk with this is what the agent noticed in the linked issue: that if the LLM truly is and remains stuck on some basin, then it will continue up to max_iterations. I think maybe we can try it; but it’s good to be aware of that and keep an eye on it?
enyst
approved these changes
Aug 5, 2026
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.
Summary
Fixes #4380
The
/goalloop was halting asinterruptedwhenever an individual agent run ended inSTUCKstatus, forcing a manual "resume" click. This defeated the purpose of the goal command — a goal is supposed to keep working until finished.Root cause
_run_goal_looptreatedSTUCKthe same asPAUSED/ERROR— a hard terminal stop:STUCKcomes from theStuckDetector, a heuristic that fires on repetitive action/observation patterns with aggressive thresholds (action_observation=4,action_error=3,monologue=3). These were tuned for single-turn chat. During a goal loop the agent intentionally iterates — re-running a test, retrying an edit — so it regularly trips the detector during legitimate work, ending the run asSTUCKand halting the whole goal prematurely.Fix
Remove
STUCKfrom the set of statuses that terminate the goal loop. OnlyPAUSEDandERROR(real stop signals) halt it. ASTUCKrun now proceeds to the judge path, which either marks the goal complete or sends a followup nudge that breaks the agent out of any genuine loop. Worst case the goal caps out atmax_iterations(bounded), which is strictly better than halting early at round 4.The goal loop already has an authoritative judge LLM (
GoalController+judge_goal) that audits completion each round — a far better progress signal than the stuck detector's repetition heuristic. This change lets the judge do its job instead of being preempted by the heuristic.Test
Added
test_goal_loop_continues_past_stuck_run, which forces the first run to endSTUCKand asserts the loop continues to the judge and completes (rather than emittinginterrupted). Verified the test fails before the fix (assert 'interrupted' == 'complete') and passes after.All 18 existing goal-loop tests and 18 SDK goal tests continue to pass.
This PR was created by an AI agent (OpenHands) on behalf of a user.
Agent Server images for this PR
• GHCR package: https://github.com/OpenHands/agent-sdk/pkgs/container/agent-server
Variants & Base Images
eclipse-temurin:17-jdknikolaik/python-nodejs:python3.13-nodejs22-slimgolang:1.21-bookwormPull (multi-arch manifest)
# Each variant is a multi-arch manifest supporting both amd64 and arm64 docker pull ghcr.io/openhands/agent-server:4ee3376-pythonRun
All tags pushed for this build
About Multi-Architecture Support
4ee3376-python) is a multi-arch manifest supporting both amd64 and arm644ee3376-python-amd64) are also available if needed