Repository navigation
Conversation
An endpoint that keeps answering with nothing (empty content, stop_reason refusal) made an unbounded Flash run call the model about once a second for as long as the caller waited. flash.max_silent_turns (default 5) ends the run as failed with the last stop reason; 0 disables the guard.
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
flash.max_turnsdefaults to 0, which means unbounded. A turn without a tool call is nudged and the loop continues. When the model keeps answering with nothing, an unbounded Flash run calls the model about once a second until the caller gives up. An empty reply (stop_reasonrefusal, 0 output tokens) is one such case.I hit this with Claude Opus 5.5 on Amazon Bedrock. One run reached turn 449 before I stopped it, and every turn was a full-context call.
This PR adds
flash.max_silent_turns(default 5). After that many consecutive turns without a tool call, the run ends asfailed. The explanation names the count, the laststop_reasonand the start of the last reply, so the cause is visible in the report. Any tool call resets the counter. Setting it to 0 disables the guard. A single nudged turn still continues exactly as before.Tests
tests/unit/agents/test_flash_runner_ledger.pyadds two tests:max_silent_turns=3end the run after exactly 3 model calls, and the explanation carries the stop reason;The existing "no-tool-call turn is nudged, not terminated" test still passes.
make test,make lintandmake typecheckpass.Related
The refusals themselves came from the Flash prompt wording, which I'm fixing in a separate PR. This guard is still worth having on its own, because any endpoint can degrade to empty replies.