Skip to content

fix(core): surface refusal category and explanation on content filter - #37392

Closed
cyllas wants to merge 1 commit into
anomalyco:devfrom
cyllas:surface-refusal-category
Closed

fix(core): surface refusal category and explanation on content filter#37392
cyllas wants to merge 1 commit into
anomalyco:devfrom
cyllas:surface-refusal-category

Conversation

@cyllas

Copy link
Copy Markdown

Issue for this PR

Closes#35736

Type of change

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

What does this PR do?

When Anthropic returns stop_reason: "refusal", opencode maps it to a
content-filter finish and shows one hardcoded message — "The response was
blocked by the provider's content filter" — dropping the stop_details the
provider sends. As #35736 notes, that makes every refusal look identical even
though the categories call for different responses.

Anthropic's stop_details.category can be cyber, bio, frontier_llm, or
reasoning_extraction (see Anthropic's "Refusals and fallback" docs).
@ai-sdk/anthropic already surfaces these on the finish event's
providerMetadata.anthropic.stopDetails, but they were never read.

This PR:

  • extends ContentFilterError with optional category and explanation
  • reads the refusal details from the finish event in the session processor
  • includes them in the error message (e.g. Response refused by provider (reasoning_extraction): ...) when present, falling back to the current
    message when they are not

No behavior change when stop_details is absent — every non-refusal stop, or a
refusal with no named category.

How did you verify your code works?

  • Reproduced a real reasoning_extraction refusal from claude-fable-5 end to
    end. The surfaced error changed from the generic message to
    Response refused by provider (reasoning_extraction): <explanation>. Confirmed
    providerMetadata.anthropic.stopDetails arrives on the step-finish event with
    category/explanation and is read correctly.
  • Added test/session/content-filter.test.ts covering the metadata parsing
    (category + explanation, partial, and the empty/absent cases); bun test passes.
  • bun typecheck passes in packages/core and packages/opencode.

Screenshots / recordings

N/A (error text change).

Checklist

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

@github-actions

Copy link
Copy Markdown
Contributor

Automated PR Cleanup

Thank you for contributing to opencode.

Due to the high volume of PRs from users and AI agents, we periodically close older PRs using automated criteria so maintainers can focus review time on the most active and community-supported contributions.

This PR was closed because it matched the following cleanup criteria:

  • The PR was created more than 1 month ago
  • The PR had fewer than 2 positive reactions
  • Positive reactions are counted as thumbs-up, heart, celebration, or rocket reactions on the PR

PRs created within the last month are not affected by this cleanup.

If you believe this PR was closed incorrectly, or if you are still actively working on it, please leave a comment explaining why it should be reopened. A maintainer can review and reopen it if appropriate.

Thanks again for taking the time to contribute.

Sign up for freeto 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.

bug: Vertex provider errors (404, socket close, stop_reason:refusal) all surface identically as "blocked by content filter"

1 participant

@cyllas