Skip to content

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

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

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

@cyllas cyllas commented Jul 16, 2026

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

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

Labels

None yet

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