mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-07 08:26:10 +00:00
feat(bedrock): gate forced tool_choice on supports_forced_tool_use in converse
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
6513f5c539
commit
d816b75dd4
3 changed files with 85 additions and 12 deletions
|
|
@ -326,19 +326,13 @@ class AnthropicModelInfo(BaseLLMModelInfo):
|
|||
)
|
||||
|
||||
@staticmethod
|
||||
def _apply_forced_tool_choice(
|
||||
model: str,
|
||||
tool_choice: AnthropicMessagesToolChoice,
|
||||
drop_params: bool,
|
||||
) -> AnthropicMessagesToolChoice:
|
||||
"""Forward ``tool_choice`` unless the model map flags the model with
|
||||
def forced_tool_use_downgraded(model: str, drop_params: bool) -> bool:
|
||||
"""True when the model map flags the model with
|
||||
``supports_forced_tool_use: false`` (Fable 5.1 / Mythos 5.1 400 on
|
||||
``any``/``tool``), in which case downgrade to ``auto`` (with
|
||||
drop_params) or raise a clean client-side 400."""
|
||||
if tool_choice["type"] not in ("any", "tool"):
|
||||
return tool_choice
|
||||
``any``/``tool``) and ``drop_params`` asks for the ``auto`` downgrade;
|
||||
raises a clean client-side 400 for such models without ``drop_params``."""
|
||||
if AnthropicModelInfo._get_model_capability(model, "supports_forced_tool_use") is not False:
|
||||
return tool_choice
|
||||
return False
|
||||
if not (litellm.drop_params or drop_params):
|
||||
raise litellm.utils.UnsupportedParamsError(
|
||||
message=(
|
||||
|
|
@ -349,6 +343,18 @@ class AnthropicModelInfo(BaseLLMModelInfo):
|
|||
status_code=400,
|
||||
)
|
||||
litellm.verbose_logger.warning(DROP_FORCED_TOOL_CHOICE_WARNING, model)
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def _apply_forced_tool_choice(
|
||||
model: str,
|
||||
tool_choice: AnthropicMessagesToolChoice,
|
||||
drop_params: bool,
|
||||
) -> AnthropicMessagesToolChoice:
|
||||
if tool_choice["type"] not in ("any", "tool"):
|
||||
return tool_choice
|
||||
if not AnthropicModelInfo.forced_tool_use_downgraded(model, drop_params):
|
||||
return tool_choice
|
||||
disable_parallel: Final = tool_choice.get("disable_parallel_tool_use")
|
||||
if disable_parallel is None:
|
||||
return AnthropicMessagesToolChoice(type="auto")
|
||||
|
|
|
|||
|
|
@ -588,6 +588,10 @@ class AmazonConverseConfig(BaseConfig):
|
|||
supported_params.append("context_management")
|
||||
return supported_params
|
||||
|
||||
@staticmethod
|
||||
def _auto_tool_choice() -> ToolChoiceValuesBlock:
|
||||
return ToolChoiceValuesBlock(auto={})
|
||||
|
||||
def map_tool_choice_values(
|
||||
self, model: str, tool_choice: str | dict, drop_params: bool
|
||||
) -> ToolChoiceValuesBlock | None:
|
||||
|
|
@ -600,10 +604,14 @@ class AmazonConverseConfig(BaseConfig):
|
|||
status_code=400,
|
||||
)
|
||||
elif tool_choice == "required":
|
||||
if AnthropicModelInfo.forced_tool_use_downgraded(model, drop_params):
|
||||
return self._auto_tool_choice()
|
||||
return ToolChoiceValuesBlock(any={})
|
||||
elif tool_choice == "auto":
|
||||
return ToolChoiceValuesBlock(auto={})
|
||||
return self._auto_tool_choice()
|
||||
elif isinstance(tool_choice, dict):
|
||||
if AnthropicModelInfo.forced_tool_use_downgraded(model, drop_params):
|
||||
return self._auto_tool_choice()
|
||||
# only supported for anthropic + mistral models - https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ToolChoice.html
|
||||
specific_tool: Final = SpecificToolChoiceBlock(
|
||||
name=make_valid_bedrock_tool_name(tool_choice.get("function", {}).get("name", ""))
|
||||
|
|
|
|||
|
|
@ -6449,3 +6449,62 @@ def test_disabled_thinking_omitted_for_always_on_models_converse(
|
|||
assert "thinking" not in additional
|
||||
else:
|
||||
assert additional.get("thinking") == {"type": "disabled"}
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"model",
|
||||
["anthropic.claude-fable-5-1", "us.anthropic.claude-fable-5-1"],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"tool_choice",
|
||||
["required", {"type": "function", "function": {"name": "get_weather"}}],
|
||||
)
|
||||
def test_forced_tool_choice_downgraded_to_auto_on_fable_5_1_converse(
|
||||
local_model_cost_map, model, tool_choice
|
||||
):
|
||||
config = AmazonConverseConfig()
|
||||
|
||||
result = config.map_tool_choice_values(
|
||||
model=model, tool_choice=tool_choice, drop_params=True
|
||||
)
|
||||
|
||||
assert result == {"auto": {}}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"tool_choice",
|
||||
["required", {"type": "function", "function": {"name": "get_weather"}}],
|
||||
)
|
||||
def test_forced_tool_choice_raises_clean_error_on_fable_5_1_converse(
|
||||
local_model_cost_map, tool_choice, monkeypatch
|
||||
):
|
||||
monkeypatch.setattr(litellm, "drop_params", False)
|
||||
config = AmazonConverseConfig()
|
||||
|
||||
with pytest.raises(litellm.utils.UnsupportedParamsError, match="forced tool use"):
|
||||
config.map_tool_choice_values(
|
||||
model="anthropic.claude-fable-5-1", tool_choice=tool_choice, drop_params=False
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("tool_choice", ["auto", "none"])
|
||||
def test_unforced_tool_choice_unaffected_on_fable_5_1_converse(local_model_cost_map, tool_choice):
|
||||
config = AmazonConverseConfig()
|
||||
|
||||
result = config.map_tool_choice_values(
|
||||
model="anthropic.claude-fable-5-1", tool_choice=tool_choice, drop_params=True
|
||||
)
|
||||
|
||||
assert result == ({"auto": {}} if tool_choice == "auto" else None)
|
||||
|
||||
|
||||
def test_forced_tool_choice_forwarded_on_converse_models_that_support_it(
|
||||
local_model_cost_map, monkeypatch
|
||||
):
|
||||
monkeypatch.setattr(litellm, "drop_params", False)
|
||||
config = AmazonConverseConfig()
|
||||
|
||||
result = config.map_tool_choice_values(
|
||||
model="anthropic.claude-fable-5", tool_choice="required", drop_params=False
|
||||
)
|
||||
|
||||
assert result == {"any": {}}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue