Fix: Enable custom function tools with Anthropic models

This commit fixes three bugs that prevented custom function tools from working alongside the computer tool with Anthropic Claude models:

1. Tool format conversion: Convert OpenAI format to Anthropic format
- Changed from {type, function: {parameters}} to {name, description, input_schema}

2. Response handling (content format): Add custom tool detection
- Check tool name and handle custom tools separately from computer actions
- Prevents 'Unknown action type: None' errors

3. Response handling (tool_calls format): Add custom tool handling
- Parse JSON arguments and route custom tools correctly
- Ensures compatibility with litellm's normalized response format

These changes enable developers to use custom Python functions as tools alongside computer control tools without breaking existing functionality.

Fixes: Custom function tools now work correctly with Anthropic models.
This commit is contained in:
Luca Steingen
2025-11-06 15:26:40 +01:00
parent 1b71062589
commit 7b2ecb8a9a

View File

@@ -107,12 +107,9 @@ async def _prepare_tools_for_anthropic(tool_schemas: List[Dict[str, Any]], model
function_schema = schema["function"]
anthropic_tools.append(
{
"type": "function",
"function": {
"name": function_schema["name"],
"description": function_schema.get("description", ""),
"parameters": function_schema.get("parameters", {}),
},
"name": function_schema["name"],
"description": function_schema.get("description", ""),
"input_schema": function_schema.get("parameters", {}),
}
)
@@ -666,11 +663,24 @@ def _convert_completion_to_responses_items(response: Any) -> List[Dict[str, Any]
if content_item.get("type") == "text":
responses_items.append(make_output_text_item(content_item.get("text", "")))
elif content_item.get("type") == "tool_use":
# Convert tool use to computer call
# Check if this is a custom function tool or computer tool
tool_name = content_item.get("name", "computer")
tool_input = content_item.get("input", {})
action_type = tool_input.get("action")
call_id = content_item.get("id")
# Handle custom function tools (not computer tools)
if tool_name != "computer":
from ..responses import make_function_call_item
responses_items.append(make_function_call_item(
function_name=tool_name,
arguments=tool_input,
call_id=call_id
))
continue
# Computer tool - process actions
action_type = tool_input.get("action")
# Action reference:
# https://docs.anthropic.com/en/docs/agents-and-tools/tool-use/computer-use-tool#available-actions
@@ -868,6 +878,24 @@ def _convert_completion_to_responses_items(response: Any) -> List[Dict[str, Any]
# Handle tool calls (alternative format)
if hasattr(message, "tool_calls") and message.tool_calls:
for tool_call in message.tool_calls:
tool_name = tool_call.function.name
# Handle custom function tools
if tool_name != "computer":
from ..responses import make_function_call_item
# tool_call.function.arguments is a JSON string, need to parse it
try:
args_dict = json.loads(tool_call.function.arguments)
except json.JSONDecodeError:
args_dict = {}
responses_items.append(make_function_call_item(
function_name=tool_name,
arguments=args_dict,
call_id=tool_call.id
))
continue
# Handle computer tool
if tool_call.function.name == "computer":
try:
try: