fix(bedrock): read an inference profile's base_model from model_info and keep shadow eval's effort with thinking

This commit is contained in:
mateo-berri 2026-11-03 21:42:12 -08:00
parent 731bbed432
commit afb8eb7dfe
4 changed files with 50 additions and 9 deletions

View file

@ -134,7 +134,9 @@ def _chat_request_from_anthropic_messages(
)
)
translated, _ = adapter.translate_anthropic_to_openai(request) # pyright: ignore[reportArgumentType] # wire-body mapping is the surface's native request shape; the adapter is duck-typed and read-only here
return translated
if request.get("thinking"):
return translated
return MappingProxyType({k: v for k, v in translated.items() if k != "output_config"})
def _chat_request_from_responses(

View file

@ -607,6 +607,7 @@ class LiteLLMMessagesToCompletionTransformationHandler:
from litellm.litellm_core_utils.litellm_logging import (
Logging as LiteLLMLoggingObject,
)
from litellm.responses.bridge_check import str_keyed_mapping
request_data: Final[dict[str, object]] = {
"model": model,
@ -646,7 +647,8 @@ 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")
model_info: Final = str_keyed_mapping(extra_kwargs.get("model_info"))
base_model: Final = extra_kwargs.get("base_model") or (model_info.get("base_model") if model_info else None)
(
openai_request,
tool_name_mapping,

View file

@ -405,6 +405,34 @@ class TestSurfaceNormalization:
assert "stream" not in shadow_call
assert shadow_call["metadata"][INTERNAL_CALL_ORIGIN_METADATA_KEY] == SHADOW_EVAL_ROUTER_CALL_ORIGIN
@pytest.mark.parametrize(
("thinking", "forwards_effort"),
[
pytest.param(None, False, id="no_thinking"),
pytest.param({"type": "enabled", "budget_tokens": 1024}, True, id="thinking"),
],
)
async def test_anthropic_arm_sends_a_bedrock_claude_effort_to_the_shadow_model_only_with_thinking(
self, thinking: Mapping[str, object] | None, forwards_effort: bool
):
hook_kwargs = _success_kwargs(call_type="anthropic_messages")
hook_kwargs["model"] = "converse/us.anthropic.claude-sonnet-4-6"
hook_kwargs["messages"] = [{"role": "user", "content": [{"type": "text", "text": "hi"}]}]
hook_kwargs["litellm_params"]["proxy_server_request"] = {
"body": {
"model": "converse-sonnet",
"messages": [],
"max_tokens": 2048,
"output_config": {"effort": "high"},
**({"thinking": thinking} if thinking else {}),
}
}
_, router = await self._drive(hook_kwargs, RESPONSE)
shadow_call = router.acompletion.call_args_list[0].kwargs
assert shadow_call.get("output_config") == ({"effort": "high"} if forwards_effort else None)
async def test_responses_arm_translates_wire_body_params_and_drops_surface_only_keys(self):
from litellm.types.llms.openai import ResponsesAPIResponse

View file

@ -5560,19 +5560,28 @@ _APPLICATION_INFERENCE_PROFILE: Final = (
@pytest.mark.asyncio
@pytest.mark.parametrize(
("thinking", "drop_params", "base_model", "forwards_effort"),
("thinking", "drop_params", "deployment_kwargs", "forwards_effort"),
[
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"),
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, True, {"base_model": _CONVERSE_EFFORT_MODEL}, True, id="no_thinking_drop_params_base_model"
),
pytest.param(
None,
True,
{"model_info": {"base_model": _CONVERSE_EFFORT_MODEL}},
True,
id="no_thinking_drop_params_model_info_base_model",
),
],
)
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,
deployment_kwargs: Mapping[str, object],
forwards_effort: bool,
) -> None:
await litellm.anthropic.messages.acreate(
@ -5582,7 +5591,7 @@ async def test_bedrock_application_inference_profile_loses_the_effort_only_when_
output_config={"effort": "high", "format": _CITY_FORMAT},
drop_params=drop_params,
**({"thinking": thinking} if thinking else {}),
**({"base_model": base_model} if base_model else {}),
**deployment_kwargs,
)
sent: Final = _sent_converse_fields(_converse_route)