fix(anthropic): thread real provider through capability probes instead of pinning anthropic - #32874
Merged
mateo-berri merged 4 commits intoJul 11, 2026
Conversation
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.
Relevant issues
Linear ticket
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
@greptileaito re-request a review after pushing changes)Delays in PR merge?
If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).
Screenshots / Proof of Fix
Unit-level proof, reproduced before the fix and passing after. Before (base commit 109193f, verified by stashing the
litellm/changes and running the new regression tests against the unmodified code): withsupports_adaptive_thinkingflipped tofalseon the exactglobal.anthropic.claude-opus-4-8cost-map entry, the Bedrock Invoke/v1/messagestransformation still emittedthinking.type='adaptive', sotest_bedrock_messages_thinking_shape_follows_exact_bedrock_entry_flagfailed withAssertionError: assert 'adaptive' == 'enabled', and bothTestCapabilityProbeUsesCallerProvidertests failed. After (commit 02fa810): all three regression tests pass, and the full mapped suites for every touched module pass (2,518 passed across the anthropic, bedrock, databricks, azure_ai and vertex partner-model test trees; the single failure intest_vertex_ai_partner_models_anthropic_messages_config.pyis a missingvertexaipackage in the local env and fails identically on base)The branch has since been rebased twice onto litellm_internal_staging: first onto a4199d3 (picking up #32831, #32833, #32840, #32867, #32875, #32882 and #32752; the same sweep plus the tests those PRs added passed, 2,616 passed with the same single pre-existing env failure), then onto f604034 after the companion #32873 merged, giving the current head abc3893. On that final head the mapped suites for every touched module plus the full anthropic test tree pass again (1,223 passed; the 16 failures are pre-existing local-env artifacts, async mock awaits in modules this PR does not modify, unrelated to these changes)
Live proxy demonstration (real AWS Bedrock, no mocks)
All runs below are live end to end: a proxy on localhost making real SigV4-signed calls to AWS Bedrock us-west-2 against the real
us.anthropic.claude-sonnet-4-6inference profile, costing real money. The proxy is started withLITELLM_LOCAL_MODEL_COST_MAP=Trueso the locally edited cost map is exactly what it reads. Sonnet 4.6 accepts both thinking payload shapes, which is why all runs return real 200s; the observable difference is the outbound request body in the--detailed_debuglogThe operator override, flipping
supports_adaptive_thinkingtofalseon the exact Bedrock entry:python3 -c "import json; p='litellm/model_prices_and_context_window_backup.json'; d=json.load(open(p)); d['us.anthropic.claude-sonnet-4-6']['supports_adaptive_thinking']=False; json.dump(d, open(p,'w'), indent=4)"qa_config.yaml:Proxy start (AWS credentials and
LITELLM_MASTER_KEYexported in the shell,AWS_BEARER_TOKEN_BEDROCKunset):The identical request sent in every run:
Before, at 109193f (the merge base). The request succeeds, but the outbound Bedrock body still uses adaptive thinking; the
falseon the exact Bedrock entry is silently ignored because the probe pinscustom_llm_provider="anthropic"Outbound request in the before log:
After, captured at the final head abc3893 (re-run after the review follow-up commit and both rebases; the first after-capture at 02fa810 behaved identically). Same override, same request; the outbound body now uses manual thinking with a budget derived from
reasoning_effort, proving the bedrock-namespaced exact entry drives the probeOutbound request in the after log:
Control pair with the override reverted (
git checkout -- litellm/model_prices_and_context_window_backup.json, entry back to its committedsupports_adaptive_thinking: true): the identical request returned HTTP 200 with"thinking": {"type": "adaptive"}, "output_config": {"effort": "low"}in the outbound body at 109193f, at 02fa810 and again at the final head abc3893 (X-Amz-Date 20260711T194022Z in the control log). The PR changes which cost-map entry is authoritative for the probe; default behavior is unchangedType
🐛 Bug Fix
Changes
AnthropicModelInfo._supports_model_capabilitypinnedcustom_llm_provider="anthropic"on every capability probe. For provider-prefixed ids this made the probe ignore the exact cost-map entry entirely:_check_provider_matchrejected e.g. the Bedrock-namespacedglobal.anthropic.claude-opus-4-8entry against the pinned "anthropic", and the anthropic-scoped fallback-generalization rule answered instead. Verified live, settingsupports_adaptive_thinkingtofalseon that entry changed nothing, because the rule short-circuitsTruebefore the raw-entry backstop is consulted. Operators therefore had no per-entry override, and the documented precedence of "exact entry beats rule" was silently violated on provider-prefixed idsThis PR threads the caller's real provider through the probe chain as a required
custom_llm_providerparameter:_supports_model_capability,_is_adaptive_thinking_model,is_effort_used,get_anthropic_beta_list,_supports_effort_level,_validate_effort_for_model,_model_supports_effort_param,_map_reasoning_effort(kept separate from its existingllm_providererror tag, whose values likebedrock_converseare not valid lookup providers), and the/v1/messagespass-through translation helpers._get_model_capability(the raw model-cost walk with its alias ladder) stays provider-less and keeps its place as the backstop after the provider-aware lookupCall sites now pass their own namespace: "bedrock" in the Converse and Invoke chat transformations and the Bedrock Invoke
/v1/messagestransformation (via acustom_llm_providerproperty override onAmazonAnthropicClaudeMessagesConfig), "databricks" in the Databricks chat transformation, "vertex_ai" in the Vertex partner-model transformation andoutput_params_utils, and "anthropic" in the direct Anthropic paths.AnthropicMessagesConfiggained acustom_llm_providerproperty returning "anthropic" so the shared pass-through helpers thread whichever subclass invokes them; subclasses other than Bedrock Invoke keep their previous effective namespace. The Claude Platform on AWS config passes "anthropic" for itsis_effort_usedcall because its model ids are Anthropic-native (claude-opus-4-8style; theclaude_platform/route prefix is stripped before transformation) and noclaude_platformnamespace exists in the cost map, so its entries resolve under "anthropic"; this preserves current behavior. Theazure_aiconfig needed no explicit change:get_anthropic_headersonly consumes precomputed booleans and never probes, while the Azure probes flow through the inheritedAnthropicConfigmethods which now use the instance'scustom_llm_provider("azure_ai"), where exactazure_ai/claude-*entries exist. Thesupports_mid_conversation_systemprobe that #32831 added to the Bedrock Invoke/v1/messagesconfig already passes "bedrock" straight to_supports_factory, so it needed no change on rebase and resolves against bedrock-namespaced exact entries like the rest. The adaptive-to-legacy downgrade helper #32867 added to the pass-through base (_translate_adaptive_effort_for_non_adaptive_model) landed while this PR was in flight with the old provider-less probe calls; it is threaded here the same way as the other pass-through helpersBehavior: for mapped models nothing changes except that exact-entry flags now win, which is the fix. For unmapped ids under non-anthropic providers most pre-#32873 fallback rules were anthropic-scoped, so capability probes returned
False(except where the bedrock-scoped 4.8+ rule from #32831 matched); the companion fallback-generalizations rework #32873 (splitting rules into routing plus provider-neutral capability kinds) has since merged and this branch is rebased past it, so provider-neutral capability rules now answer for unmapped ids under every provider. No real shipped model is unmapped today, so the gap was confined to not-yet-released model idsReview follow-up: several config subclasses never overrode the inherited
custom_llm_providerproperty, so their probes still read the anthropic namespace and operator overrides on their own cost-map entries were ignored. The/v1/messagesconfigs for Azure AI, Vertex partner models, GitHub Copilot and JSON-configured OpenAI-compatible providers plus the Databricks chat config now override it, returning "azure_ai", "vertex_ai", "github_copilot", the provider's slug and "databricks" respectively._supports_model_capabilityalso treats the provider-aware lookup as authoritative when it resolves an explicit flag, sosupports_adaptive_thinking: falseon an exact provider-namespaced entry likeazure_ai/claude-opus-4-8now beats the anthropic-scoped fallback rule; regression tests flip that flag on theazure_ai/andvertex_ai/entries and assert the emitted thinking shape switches from adaptive to manual, and they fail without the overrides. The Claude Platform/v1/messagesconfig keeps the inherited "anthropic" deliberately, matching its chat sibling's probes, since its ids are Anthropic-native with no provider-namespaced entries; the generic OpenAI-like messages config also keeps "anthropic" because it has no class-level namespace. A follow-up commit (80294a9) takes a reviewer nit and consolidates the repeatedself.custom_llm_provider or "anthropic"fallback in the chat and messages configs into a single_resolved_providerproperty, so future call sites cannot forget the fallback; no behavior changeNote
Medium Risk
Changes how reasoning and adaptive-thinking payloads are built across Bedrock, Vertex, Azure, and other Anthropic-compatible routes; unmapped models on non-anthropic providers may probe differently until related fallback work lands.
Overview
Anthropic-related capability probes no longer hard-code
custom_llm_provider="anthropic". They take the caller's provider so Bedrock, Vertex, Azure AI, Databricks, and similar paths read provider-namespaced cost-map entries when deciding adaptive thinking, effort tiers,output_config, and beta headers._supports_model_capabilitynow resolves flags viaget_llm_provider+_get_model_info_helperfirst; an explicitsupports_*: falseon the exact provider entry wins over anthropic-scoped fallback rules. Shared helpers (_map_reasoning_effort, effort validation,/v1/messagestranslation) and Bedrock/Vertex/Databricks call sites pass"bedrock","vertex_ai","databricks", etc. Several configs exposecustom_llm_provideron the subclass (azure_ai, Bedrock messages, GitHub Copilot, JSON OpenAI-like providers) so pass-through transforms probe the right namespace.Observable effect: operator overrides on per-provider model JSON (e.g. flipping
supports_adaptive_thinking) actually change outboundthinking/output_configinstead of being ignored; default mapped behavior is unchanged when flags match.Reviewed by Cursor Bugbot for commit abc3893. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by CodeRabbit