diff --git a/litellm/llms/anthropic/messages/adapters/handler.py b/litellm/llms/anthropic/messages/adapters/handler.py index 71ccfbaf915..6658e3fd897 100644 --- a/litellm/llms/anthropic/messages/adapters/handler.py +++ b/litellm/llms/anthropic/messages/adapters/handler.py @@ -646,6 +646,7 @@ class LiteLLMMessagesToCompletionTransformationHandler: request_data["output_config"] = extra_kwargs["output_config"] custom_llm_provider: Final = extra_kwargs.get("custom_llm_provider") + base_model: Final = extra_kwargs.get("base_model") ( openai_request, tool_name_mapping, @@ -653,6 +654,7 @@ class LiteLLMMessagesToCompletionTransformationHandler: request_data, custom_llm_provider=custom_llm_provider if isinstance(custom_llm_provider, str) else None, drop_params=drops_unsupported_params(extra_kwargs.get("drop_params")), + base_model=base_model if isinstance(base_model, str) else None, ) if openai_request is None: diff --git a/litellm/llms/anthropic/messages/adapters/transformation.py b/litellm/llms/anthropic/messages/adapters/transformation.py index 15843d19f49..6743c4fd329 100644 --- a/litellm/llms/anthropic/messages/adapters/transformation.py +++ b/litellm/llms/anthropic/messages/adapters/transformation.py @@ -16,7 +16,7 @@ from litellm.llms.anthropic.messages.utils import ( json_copy_or_original, prompt_cache_key_from_user_id, ) -from litellm.llms.bedrock.common_utils import is_bedrock_application_inference_profile_arn +from litellm.llms.bedrock.common_utils import bedrock_capability_model, is_bedrock_application_inference_profile_arn from litellm.responses.utils import auto_reasoning_summary # OpenAI has a 64-character limit for function/tool names @@ -256,7 +256,12 @@ class AnthropicAdapter: return result def translate_completion_input_params_with_tool_mapping( - self, kwargs, *, custom_llm_provider: str | None = None, drop_params: bool = True + self, + kwargs, + *, + custom_llm_provider: str | None = None, + drop_params: bool = True, + base_model: str | None = None, ) -> tuple[ChatCompletionRequest | None, dict[str, str]]: """ Translate Anthropic request params to OpenAI format, returning tool name mapping. @@ -291,6 +296,7 @@ class AnthropicAdapter: anthropic_message_request=request_body, custom_llm_provider=custom_llm_provider, drop_params=drop_params, + base_model=base_model, ) return translated_body, tool_name_mapping @@ -369,8 +375,8 @@ _BlockT: Final = TypeVar("_BlockT", bound=Mapping[str, object]) _CLAUDE_OVER_REASONING_EFFORT_PROVIDERS: Final = frozenset({LlmProviders.KYMA.value}) UNRESOLVED_ARN_EFFORT_WITHOUT_THINKING_WARNING: Final = ( "Dropping `output_config` for model=%s under drop_params: an application inference profile ARN does not name " - "its model, so LiteLLM cannot tell whether it takes an effort without a `thinking` block. Turn off drop_params " - "on the deployment to send it." + "its model, so LiteLLM cannot tell whether it takes an effort without a `thinking` block. Set `base_model` on " + "the deployment (for example `us.anthropic.claude-opus-4-8`) to send it." ) @@ -1210,6 +1216,7 @@ class LiteLLMAnthropicMessagesAdapter: anthropic_message_request: AnthropicMessagesRequest, new_kwargs: ChatCompletionRequest, drop_params: bool, + base_model: str | None, ) -> None: """Forward the effort-bearing part of ``output_config`` to a Bedrock Claude target. @@ -1231,7 +1238,7 @@ class LiteLLMAnthropicMessagesAdapter: if ( drop_params and not anthropic_message_request.get("thinking") - and is_bedrock_application_inference_profile_arn(model) + and is_bedrock_application_inference_profile_arn(bedrock_capability_model(model, base_model)) ): litellm.verbose_logger.warning(UNRESOLVED_ARN_EFFORT_WITHOUT_THINKING_WARNING, model) return @@ -1283,6 +1290,7 @@ class LiteLLMAnthropicMessagesAdapter: custom_llm_provider: str | None = None, preserve_midturn_system: bool = False, drop_params: bool = True, + base_model: str | None = None, ) -> tuple[ChatCompletionRequest, dict[str, str]]: """ This is used by the beta Anthropic Adapter, for translating anthropic `/v1/messages` requests to the openai format. @@ -1341,6 +1349,7 @@ class LiteLLMAnthropicMessagesAdapter: anthropic_message_request=anthropic_message_request, new_kwargs=new_kwargs, drop_params=drop_params, + base_model=base_model, ) ## CONVERT STOP_SEQUENCES self._translate_stop_sequences_to_openai( diff --git a/tests/unit/llms/anthropic/messages/adapters/test_anthropic_messages_adapters_transformation.py b/tests/unit/llms/anthropic/messages/adapters/test_anthropic_messages_adapters_transformation.py index 8256fa034b6..9808b2dfb8e 100644 --- a/tests/unit/llms/anthropic/messages/adapters/test_anthropic_messages_adapters_transformation.py +++ b/tests/unit/llms/anthropic/messages/adapters/test_anthropic_messages_adapters_transformation.py @@ -5560,17 +5560,19 @@ _APPLICATION_INFERENCE_PROFILE: Final = ( @pytest.mark.asyncio @pytest.mark.parametrize( - ("thinking", "drop_params", "forwards_effort"), + ("thinking", "drop_params", "base_model", "forwards_effort"), [ - pytest.param(None, False, True, id="no_thinking"), - pytest.param(None, True, False, id="no_thinking_drop_params"), - pytest.param({"type": "enabled", "budget_tokens": 1024}, True, True, id="thinking_drop_params"), + pytest.param(None, False, None, True, id="no_thinking"), + pytest.param(None, True, None, False, id="no_thinking_drop_params"), + pytest.param({"type": "enabled", "budget_tokens": 1024}, True, None, True, id="thinking_drop_params"), + pytest.param(None, True, _CONVERSE_EFFORT_MODEL, True, id="no_thinking_drop_params_base_model"), ], ) -async def test_bedrock_application_inference_profile_loses_the_effort_only_without_thinking_under_drop_params( +async def test_bedrock_application_inference_profile_loses_the_effort_only_when_unresolved_without_thinking( _converse_route: respx.Route, thinking: Mapping[str, object] | None, drop_params: bool, + base_model: str | None, forwards_effort: bool, ) -> None: await litellm.anthropic.messages.acreate( @@ -5580,6 +5582,7 @@ async def test_bedrock_application_inference_profile_loses_the_effort_only_witho output_config={"effort": "high", "format": _CITY_FORMAT}, drop_params=drop_params, **({"thinking": thinking} if thinking else {}), + **({"base_model": base_model} if base_model else {}), ) sent: Final = _sent_converse_fields(_converse_route)