fix(responses): preserve forced-function tool_choice name in Responses to Chat transform (#29812)

The Responses API forces a specific function with a top-level name
({"type": "function", "name": "X"}), but _transform_tool_choice only handled the
nested Chat Completions shape and fell through to returning "required" for the flat
form, silently dropping the function name and degrading a forced function call to
force-any-tool. Map the flat Responses shape to the nested Chat shape, keeping the
"required" fallback when no name is present.
This commit is contained in:
abhay23-AI 2026-06-08 17:39:39 +05:30 committed by GitHub
parent a30801e083
commit 49600c67b4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 25 additions and 1 deletions

View file

@ -148,7 +148,9 @@ class LiteLLMCompletionResponsesConfig:
# which is equivalent to "required" in OpenAI format
return "required"
elif tool_choice_type == "function":
# function type without name - fall back to required
function_name = tool_choice.get("name")
if function_name:
return {"type": "function", "function": {"name": function_name}}
return "required"
# Return as-is for unknown formats

View file

@ -949,6 +949,28 @@ class TestToolChoiceTransformation:
result = LiteLLMCompletionResponsesConfig._transform_tool_choice(tool_choice)
assert result == tool_choice
def test_transform_tool_choice_responses_flat_function_name(self):
"""Responses-API forced-function with a top-level name maps to the nested Chat
Completions shape instead of degrading to required and dropping the name"""
result = LiteLLMCompletionResponsesConfig._transform_tool_choice(
{"type": "function", "name": "get_weather"}
)
assert result == {"type": "function", "function": {"name": "get_weather"}}
def test_transform_tool_choice_function_without_name_falls_back_to_required(self):
"""A function-type dict with no name still falls back to required"""
result = LiteLLMCompletionResponsesConfig._transform_tool_choice(
{"type": "function"}
)
assert result == "required"
def test_transform_tool_choice_function_empty_name_falls_back_to_required(self):
"""An empty top-level name is falsy and must not produce an empty function name"""
result = LiteLLMCompletionResponsesConfig._transform_tool_choice(
{"type": "function", "name": ""}
)
assert result == "required"
class TestContentTypeTransformation:
"""Test content type transformation from Responses API to Chat Completion format"""