Don't force `tool_choice` on OpenRouter Anthropic models that reject it

Closed
NI
1mo ago
+124-0

Claude Fable 5.1 and Claude Opus 5.5 reject a forced tool_choice outright, and OpenRouter passes the 400 back. OpenRouterProvider.model_profile now carries the upstream profile's anthropic_supports_forced_tool_choice=False over to openai_supports_tool_choice_required=False, which is the flag the OpenRouter route reads. It's only set when forcing is unsupported, so other models' profiles are unchanged.

With the fix, a structured output_type on these models falls back to tool_choice='auto' (the same soft fallback the thinking path already uses), and an explicit tool_choice='required' raises a UserError instead of a 400 from the provider. Verified live against anthropic/claude-opus-5.5 on OpenRouter: 400 before, a normal response after.

Tests follow the existing tool_choice tests: a profile check in tests/providers/test_openrouter.py and a mocked-client check of the wire tool_choice in tests/models/test_openrouter.py (cassette matchers don't compare request bodies).

Related: #8637, #8640

Checklist

  • Any AI generated code has been reviewed line-by-line by the human PR author, who stands by it.
  • No breaking changes in accordance with the version policy.
  • Any permitted compatibility impact has a label, warning, migration, release note, and exact API-check waiver.
  • PR title is fit for the release changelog.

🤖 Generated with Claude Code