Abort a model that loops on repeated output - #350
Merged
Conversation
TheGreatAxios
force-pushed
the
cl-5577-repetition-guard
branch
2 times, most recently
from
August 7, 2026 08:13
f41f407 to
2d0825a
Compare
The stall watchdog measured silence, so a model streaming the same line on repeat never tripped it: tokens kept arriving, lastActivityAt kept refreshing, and the run burned tokens until a human noticed and interrupted it. The watchdog now also folds streamed text into a bounded buffer and checks it for a line repeated past a threshold, aborting immediately on detection regardless of how fast the loop is producing output. The recovery message names it as the model repeating itself and reports the tokens spent on the looped span, so a retry reads as reasonable rather than papering over a hang.
Line-splitting missed the captured incident outright: the looping sentences ran together with no newline between them, so the whole span collapsed into one line and never reached the occurrence check. Detection now finds the smallest period the streamed tail exactly repeats, which catches the no-newline shape the same way it catches a line-level loop. Line counting also flagged ordinary structure — a repeated markdown table row, a few identical code lines — as degeneration. The period search requires more repeats and enough character variety in the repeating unit to rule those out, verified against both plus a monochrome run (a repeated rule or the same character streamed many times), which is trivially periodic at every length and would otherwise be the easiest false trigger of all. The per-delta check is now throttled to run once per chunk of new text rather than once per token, since a repeating tail cannot appear or disappear between two three-character tokens. The idle notice also now checks the repetition flag directly, so a stream that is looping but not silent can no longer be labeled a silent hang.
A tool call ended a streaming cycle but left the repetition buffer intact, so several short narration lines said before separate tool calls in one turn concatenated into an apparent loop and aborted an otherwise ordinary turn. A genuinely degenerate model repeats within one unbroken stream; narration between tool calls does not, so the buffer now clears whenever a tool call begins.
Clearing the repetition buffer on every tool call fixed the narration false positive but went too far: a model that loops while interleaving even a no-op tool call between repeats was no longer caught at all, since nothing carried across the reset. Keep a cheap fingerprint of each completed cycle instead of its raw text, and flag only once several consecutive cycles fingerprint alike. Narration varies enough cycle to cycle to clear that bar; an unvarying repeated block does not, and now trips within a small, bounded number of cycles rather than never.
TheGreatAxios
force-pushed
the
cl-5577-repetition-guard
branch
from
August 7, 2026 08:24
2d0825a to
bcc3bc8
Compare
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
Verification
bun run typecheckpassesbun run buildpassesbun run testpasses (3916 pass, 0 fail), including regression tests for the incident string with no newlines, a repeated markdown table row, repeated code lines, and a monochrome character runCloses CL-5577