fix(tool-choice): leave a malformed allowed_tools choice unrewritten in the interception hooks

This commit is contained in:
mateo-berri 2026-11-06 08:19:23 -08:00
parent 4755727276
commit cd076fb13a
2 changed files with 13 additions and 4 deletions

View file

@ -249,10 +249,9 @@ def _with_builtin_as(
def allowed_tools_tool_choice_with_builtin_as_function(
tool_choice: object, is_builtin: Callable[[Mapping[str, object]], bool], function_name: str
) -> object:
try:
parsed: Final = _ALLOWED_TOOLS_TOOL_CHOICE.validate_python(tool_choice)
except ValidationError:
if parse_allowed_tools_tool_choice(tool_choice) is None:
return tool_choice
parsed: Final = _ALLOWED_TOOLS_TOOL_CHOICE.validate_python(tool_choice)
match parsed:
case ChatAllowedToolsToolChoice():
nested: Final = {"type": "function", "function": {"name": function_name}}

View file

@ -375,6 +375,16 @@ def test_a_function_or_mcp_entry_is_never_taken_for_a_builtin():
assert parse_allowed_tools_tool_choice(rewritten) == parse_allowed_tools_tool_choice(tool_choice)
@pytest.mark.parametrize("tool_choice", ["auto", None, {"type": "allowed_tools", "mode": "auto", "tools": []}])
@pytest.mark.parametrize(
"tool_choice",
[
"auto",
None,
{"type": "allowed_tools", "mode": "auto", "tools": []},
{"type": "allowed_tools", "mode": "auto", "tools": [{"type": "web_search", "name": []}]},
{"type": "allowed_tools", "mode": "auto", "tools": [{"type": "web_search"}, {"type": "function", "name": 3}]},
{"type": "allowed_tools", "allowed_tools": {"mode": "auto", "tools": [{"type": "web_search", "name": {}}]}},
],
)
def test_any_other_or_malformed_choice_is_left_as_sent(tool_choice: object):
assert allowed_tools_tool_choice_with_builtin_as_function(tool_choice, _is_web_search, "litellm_web_search") is tool_choice