Skip to content

fix(core): stop repeated tool call loops and stalled streams - #53032

Open
davtur19 wants to merge 2 commits into
anomalyco:v2from
davtur19:loop-protection
Open

davtur19 wants to merge 2 commits into
anomalyco:v2from
davtur19:loop-protection

Conversation

@davtur19

@davtur19 davtur19 commented Oct 3, 2026 •

Copy link
Copy Markdown

Issue for this PR

Closes #45442

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Two protections for runs that never terminate on their own:

  • Two-strike doom-loop detection: before a tool call runs, the runner compares it against the assistant's tool calls since the last user message. A third identical call (same tool, same input) fires the existing doom_loop permission as a warning; if it repeats once more after the warning, the turn stops with a session error. Below the threshold nothing changes, and an allowing doom_loop rule still executes the call as before.
  • Stall watchdog: when a provider stream goes silent for 90 seconds after its first event, the step is cut off and retried instead of hanging, covering the missing heartbeat timeout called out in the issue. Tool execution time does not count toward the silence window, and time to first event is not treated as a stall.

How did you verify your code works?

bun test in packages/core: 233 tests pass in the touched files (session-runner, session-step, doom-loop), full suite matches vanilla upstream/v2. bun typecheck passes.

Screenshots / recordings

Not a UI change.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

Davide added 2 commits October 4, 2026 00:18
Ports the fork's stall watchdog: a provider stream that goes silent — no events, no error — never fails on its own and hangs the step until the user stops it. The drain races a silence check over the step's stream clock (90 seconds, polled every 5); silence before the first event is a slow time to first token and silence while a tool call is pending is a long local or hosted execution idling the stream by design, and neither counts. A stall fails the attempt with the incomplete-stream classification so recovery reuses the established paths — pre-output stalls retry, post-output stalls continue — instead of the fork's TransientTurnError, bounded by the step-level retry schedule and its renewed phases.
@github-actions

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

Thanks for your contribution!

This PR doesn't have a linked issue. All PRs must reference an existing issue.

Please:

  1. Open an issue describing the bug/feature (if one doesn't exist)
  2. Add Fixes #<number> or Closes #<number> to this PR description

See CONTRIBUTING.md for details.

@github-actions

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant