mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-05 02:41:56 +00:00
Fix Bedrock parallel tool choice type
Preserve explicit Bedrock tool_choice intent when moving parallel_tool_calls configuration into Anthropic's Bedrock extension.
This commit is contained in:
parent
cff3e0b75e
commit
84fbf3c1c1
2 changed files with 112 additions and 0 deletions
|
|
@ -606,6 +606,24 @@ class AmazonConverseConfig(BaseConfig):
|
|||
status_code=400,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _map_bedrock_tool_choice_to_anthropic_tool_choice(
|
||||
tool_choice: Optional[ToolChoiceValuesBlock],
|
||||
) -> dict:
|
||||
if tool_choice is None or "auto" in tool_choice:
|
||||
return {"type": "auto"}
|
||||
if "any" in tool_choice:
|
||||
return {"type": "any"}
|
||||
|
||||
specific_tool_choice = tool_choice.get("tool")
|
||||
if specific_tool_choice is not None:
|
||||
name = specific_tool_choice.get("name")
|
||||
if name:
|
||||
return {"type": "tool", "name": name}
|
||||
return {"type": "tool"}
|
||||
|
||||
return {"type": "auto"}
|
||||
|
||||
def get_supported_image_types(self) -> List[str]:
|
||||
return ["png", "jpeg", "gif", "webp"]
|
||||
|
||||
|
|
@ -1241,7 +1259,15 @@ class AmazonConverseConfig(BaseConfig):
|
|||
"_parallel_tool_use_config", None
|
||||
)
|
||||
if parallel_tool_use_config is not None and is_claude_4_5_on_bedrock(model):
|
||||
bedrock_tool_choice = inference_params.pop("tool_choice", None)
|
||||
anthropic_tool_choice = (
|
||||
self._map_bedrock_tool_choice_to_anthropic_tool_choice(
|
||||
tool_choice=bedrock_tool_choice,
|
||||
)
|
||||
)
|
||||
for key, value in parallel_tool_use_config.items():
|
||||
if key == "tool_choice" and isinstance(value, dict):
|
||||
value = {**anthropic_tool_choice, **value}
|
||||
if (
|
||||
key in additional_request_params
|
||||
and isinstance(additional_request_params[key], dict)
|
||||
|
|
|
|||
|
|
@ -3756,6 +3756,7 @@ def test_parallel_tool_calls_newer_model_adds_disable_flag():
|
|||
|
||||
assert "additionalModelRequestFields" in request_data
|
||||
assert "tool_choice" in request_data["additionalModelRequestFields"]
|
||||
assert request_data["additionalModelRequestFields"]["tool_choice"]["type"] == "auto"
|
||||
assert (
|
||||
request_data["additionalModelRequestFields"]["tool_choice"][
|
||||
"disable_parallel_tool_use"
|
||||
|
|
@ -3765,6 +3766,91 @@ def test_parallel_tool_calls_newer_model_adds_disable_flag():
|
|||
assert "parallel_tool_calls" not in request_data["additionalModelRequestFields"]
|
||||
|
||||
|
||||
def test_parallel_tool_calls_true_includes_type_field():
|
||||
"""parallel_tool_calls=True should include Anthropic's required tool_choice type."""
|
||||
config = AmazonConverseConfig()
|
||||
model = "anthropic.claude-sonnet-4-5-20250929-v1:0"
|
||||
messages = [{"role": "user", "content": "What's the weather in SF and NYC?"}]
|
||||
|
||||
optional_params = config.map_openai_params(
|
||||
non_default_params={"parallel_tool_calls": True, "tools": _TOOL_PARAM},
|
||||
optional_params={},
|
||||
model=model,
|
||||
drop_params=False,
|
||||
)
|
||||
|
||||
request_data = config.transform_request(
|
||||
model=model,
|
||||
messages=messages,
|
||||
optional_params=optional_params,
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
|
||||
assert "additionalModelRequestFields" in request_data
|
||||
tool_choice = request_data["additionalModelRequestFields"]["tool_choice"]
|
||||
assert tool_choice["type"] == "auto"
|
||||
assert tool_choice["disable_parallel_tool_use"] is False
|
||||
assert "parallel_tool_calls" not in request_data["additionalModelRequestFields"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("openai_tool_choice", "expected_anthropic_tool_choice"),
|
||||
[
|
||||
(
|
||||
"auto",
|
||||
{"type": "auto", "disable_parallel_tool_use": True},
|
||||
),
|
||||
(
|
||||
"required",
|
||||
{"type": "any", "disable_parallel_tool_use": True},
|
||||
),
|
||||
(
|
||||
{"type": "function", "function": {"name": "get_weather"}},
|
||||
{
|
||||
"type": "tool",
|
||||
"name": "get_weather",
|
||||
"disable_parallel_tool_use": True,
|
||||
},
|
||||
),
|
||||
],
|
||||
ids=["auto", "required", "named-tool"],
|
||||
)
|
||||
def test_parallel_tool_calls_moves_explicit_tool_choice_into_anthropic_extension(
|
||||
openai_tool_choice,
|
||||
expected_anthropic_tool_choice,
|
||||
):
|
||||
"""Explicit tool_choice should not conflict with Anthropic's parallel tool extension."""
|
||||
config = AmazonConverseConfig()
|
||||
model = "anthropic.claude-sonnet-4-5-20250929-v1:0"
|
||||
messages = [{"role": "user", "content": "What's the weather in SF and NYC?"}]
|
||||
|
||||
optional_params = config.map_openai_params(
|
||||
non_default_params={
|
||||
"tools": _TOOL_PARAM,
|
||||
"tool_choice": openai_tool_choice,
|
||||
"parallel_tool_calls": False,
|
||||
},
|
||||
optional_params={},
|
||||
model=model,
|
||||
drop_params=False,
|
||||
)
|
||||
|
||||
request_data = config.transform_request(
|
||||
model=model,
|
||||
messages=messages,
|
||||
optional_params=optional_params,
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
|
||||
assert (
|
||||
request_data["additionalModelRequestFields"]["tool_choice"]
|
||||
== expected_anthropic_tool_choice
|
||||
)
|
||||
assert "toolChoice" not in request_data["toolConfig"]
|
||||
|
||||
|
||||
def test_parallel_tool_calls_older_model_drops_disable_flag():
|
||||
"""Older Claude models (pre-4.5) must NOT receive disable_parallel_tool_use — Bedrock rejects it."""
|
||||
config = AmazonConverseConfig()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue