Conversation
Build on the refusal precedence correction proposed in leookun#423. Preserve typed refusal failures through recording, run retry decisions, and Cursor error details, with HTTP/SSE integration coverage. Co-authored-by: kevin9327 <kevin9327@users.noreply.github.com>
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.
When Anthropic returns
stop_reason: "refusal"alongside streamed tool blocks, the turn must stop without executing those tools or automatically requesting the same refused turn again. This change carries a typed refusal through the provider, model cycle, run failure, recorder, and Cursor error response, so it is non-retryable at both the server and client boundaries.This builds on the refusal precedence fix proposed by @kevin9327 in #423. That proposal correctly prevents tool execution by producing a finish-reason disagreement, but the existing run loop treats that protocol failure as retryable. In our earlier controlled end-to-end test of that proposal, a persistent refusal caused 9 requests over approximately 40 seconds. The typed failure in this PR ends after one request and emits no Cursor execution messages.
Both
message_stopand the EOF fallback use the same finish classification. A refusal stays recorded even if a later delta reports another stop reason. Plain-text refusals still finish normally; ordinary tool calls, length-limit failures, partial text/thinking, token usage, and transient-error retries retain their existing behavior. Recorded refusals use the existing provider error category; no database changes are needed.Validation:
is_retryable=false, and immediate error display.Only the server fix and regression tests are included. This PR is independent of #487 and contains no fork customization or release changes. Related: #423; it does not require that PR to be merged first.
Revalidated on current upstream
main(9a8fde2):cargo test -p cursor-server --all-targetspassed all 267 tests; server all-targets Clippy with-D warnings,cargo fmt --all -- --check, andgit diff --checkpassed. This upstream-only branch contains seven production files and one integration-test file.