Skip to content

Commit fca3ed5

Browse files
gn00295120claude
andcommitted
fix: correct tool_choice dict format handling (fixes @ihower feedback)
Critical fix based on testing feedback from @ihower: The previous fix assumed Responses Converter format (flat dict), but LiteLLM uses ChatCompletions Converter which returns nested format. Problem identified by @ihower: - response_tool_choice was always "auto" even with specific tool names - Root cause: Looking for wrong dict structure Converter formats: - ChatCompletions: {"type": "function", "function": {"name": "tool_name"}} ✅ (LiteLLM uses this) - Responses: {"type": "function", "name": "tool_name"} ❌ (NOT used here) Fix: - Changed from tool_choice.get("name") to tool_choice.get("function").get("name") - Added proper type checking for func_data dict - Maintained all defensive checks (non-empty string, valid type, etc.) Testing: - Created comprehensive unit tests - Created end-to-end flow tests - All tests pass with nested dict format - Verified: ModelSettings(tool_choice="my_tool") → ToolChoiceFunction(name="my_tool") Generated with Lucas Wang<[email protected]> Co-Authored-By: Claude <[email protected]>
1 parent 8abed69 commit fca3ed5

File tree

1 file changed

+11
-7
lines changed

1 file changed

+11
-7
lines changed

src/agents/extensions/models/litellm_model.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -377,16 +377,20 @@ async def _fetch_response(
377377
# Already a ToolChoiceFunction, use directly
378378
response_tool_choice = tool_choice
379379
elif isinstance(tool_choice, dict):
380-
# Convert from Responses format dict to ToolChoiceFunction
381-
# The Responses Converter returns: {"type": "function", "name": "tool_name"}
382-
tool_name = tool_choice.get("name")
380+
# Convert from ChatCompletions format dict to ToolChoiceFunction
381+
# ChatCompletions Converter returns: {"type": "function", "function": {"name": "..."}}
382+
func_data = tool_choice.get("function")
383383
if (
384384
tool_choice.get("type") == "function"
385-
and tool_name is not None
386-
and isinstance(tool_name, str)
387-
and tool_name # Ensure non-empty string
385+
and func_data is not None
386+
and isinstance(func_data, dict)
388387
):
389-
response_tool_choice = ToolChoiceFunction(type="function", name=tool_name)
388+
tool_name = func_data.get("name")
389+
if isinstance(tool_name, str) and tool_name: # Ensure non-empty string
390+
response_tool_choice = ToolChoiceFunction(type="function", name=tool_name)
391+
else:
392+
# Fallback to auto if name is missing or invalid
393+
response_tool_choice = "auto"
390394
else:
391395
# Fallback to auto if unexpected format
392396
response_tool_choice = "auto"

0 commit comments

Comments
 (0)