Skip to content

fix(coding-agent): pause a stalled goal instead of looping continuations - #1113

Closed
romankhadka wants to merge 3 commits into
PrimeIntellect-ai:mainfrom
romankhadka:fix/986-goal-stall-pause
Closed

fix(coding-agent): pause a stalled goal instead of looping continuations#1113
romankhadka wants to merge 3 commits into
PrimeIntellect-ai:mainfrom
romankhadka:fix/986-goal-stall-pause

Conversation

@romankhadka

@romankhadka romankhadka commented Aug 10, 2026

Copy link
Copy Markdown

Summary

  • Fixes Goal Mode Keeps Looping After Completion #986: an active goal with no token budget injected identical goal_context continuations forever when the model was blocked on user input (a required approval, credential, or unanswered question).
  • _getGoalContinuationMessages now checks the run for stalled continuation windows before re-arming. When the trailing three goal-context windows all ended without a tool call or a user message, the goal pauses (status: "paused" with a new optional pausedBy: "user" | "host" field and an explanatory lastReason) instead of injecting another identical context.
  • A goal paused this way (pausedBy: "host") resumes automatically on the next genuine user message, whether it arrives via prompt(), steer(), or followUp(). Host-generated prompts and custom-message deliveries (heartbeats, agent messages) do not resume it. An explicit /goal pause sets pausedBy: "user" and still requires /goal resume.
  • The continuation prompt now tells the model to state what it is waiting for and end the turn without tool calls when blocked, so the pause and the model's behavior agree.

Design notes

  • The threshold is three consecutive stalled windows. A continuation after a toolless turn is a legitimate nudge (the existing goal suite depends on two consecutive nudges before completion), so a one-strike rule would break intended behavior. Three preserves the nudge and bounds the loop.
  • Detection is a pure function over the run's messages (goalContinuationIsStalled in goals.ts), so no extra mutable state is needed: any tool call, user message, or new run resets the window naturally.
  • The detector treats any tool call as progress: a model that polls a tool (for example goal.get) on every continuation is not paused by this change. That variant does observable work each turn and is bounded by a token budget when one is set; the updated continuation prompt instructs blocked models to end the turn without tool calls, which makes sanctioned waiting detectable. Stream-level degenerate repetition is a separate concern (No safeguard against degenerate model repetition: "The the the..." thinking stream until manual abort #1029).
  • pausedBy is optional and normalized to exist only while status is "paused"; older builds reading a persisted goal state see an ordinary paused goal. A discriminator was chosen over a boolean so future pause causes extend the same field.

Validation

  • cd packages/coding-agent && npx tsx ../../node_modules/vitest/dist/cli.js --run test/suite/regressions/986-goal-continuation-loop.test.ts test/suite/agent-session-goal.test.ts test/suite/agent-session-queue.test.ts: 147 passed
  • npx tsx ../../node_modules/vitest/dist/cli.js --run test/suite/agent-session-autonomous.test.ts test/kernel-goal-skill.test.ts test/suite/regressions/4482-heartbeat-injected-prompt.test.ts: 38 passed, 3 skipped (kernel skill tests skip without the Python runtime)
  • The new regression file fails on unpatched main (verified by reverting the fix); the explicit-pause test guards existing behavior.
  • Test fixtures are derived from MAX_STALLED_GOAL_CONTINUATIONS, and the followUp() resume path has its own test.
  • npm run check: passed

Note

Pause stalled Goal Mode instead of injecting continuations indefinitely

  • When consecutive goal continuations end without a tool call or user message, getContinuationMessages in agent-session.ts now pauses the goal (tagged pausedBy: 'host') instead of looping.
  • Stall detection is implemented in goals.ts via goalContinuationIsStalled, which checks the last MAX_STALLED_GOAL_CONTINUATIONS (3) continuation windows for tool calls or user messages.
  • A host-paused goal resumes automatically when the next real user prompt, steer prompt, or follow-up prompt is admitted; an explicitly user-paused goal is unaffected.
  • Continuation prompts now instruct the model to stop calling tools and end its turn when blocked on user input.
  • Behavioral Change: goals that previously looped on stalled continuations will now pause and surface to the user for input.

Macroscope summarized 513f66a.

A goal whose continuations repeatedly end without a tool call or new user
message cannot progress by re-presenting the same context. After three
consecutive stalled continuation windows the goal now pauses as waiting
for user input, and it resumes automatically on the next user prompt.
An explicit /goal pause still requires /goal resume.

fixes PrimeIntellect-ai#986
…/follow-up resume gap

- Replace the waitingForUser flag with pausedBy: "user" | "host" so the
  pause cause is a single field and normalizeGoalState no longer repairs a
  cross-field invariant.
- Collapse the stall detector's accumulator into direct early returns and
  absorb the single-use progress helper.
- Resume a host-paused goal for user input delivered via steer() and
  followUp(), which bypass prompt(); previously only prompt() resumed it.
- Derive regression-test fixtures from MAX_STALLED_GOAL_CONTINUATIONS and
  cover the followUp resume path.
@sethkarten

Copy link
Copy Markdown
Contributor

Thank you for the report and proposed work. This root cause is now covered by maintainer-owned stacked PR #1165, authored independently from upstream/main.

We did not inspect or reuse this PR's diff, branch, commits, implementation code, or tests; its public description/comments were used only as a bug report. To keep one review surface, this PR is superseded by #1165 and is being closed.

The complete review stack is #1158#1165. It is being left unmerged for human review after CI and review-bot findings are cleared.

@sethkarten sethkarten closed this Aug 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Goal Mode Keeps Looping After Completion

2 participants