Skip to content

Commit

Permalink
[Bug Fix] Tool signature error for Anthropic #1091 (#1101)
Browse files Browse the repository at this point in the history
* [Bug Fix] Tool signature error for Anthropic #1091

* tests added

* updated tests to reflect test coverage

* pre-commit checks

---------

Co-authored-by: Davor Runje <[email protected]>
  • Loading branch information
marufaytekin and davorrunje authored Feb 25, 2025
1 parent bf48ec4 commit 24d6acc
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 6 deletions.
6 changes: 3 additions & 3 deletions .secrets.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -911,15 +911,15 @@
"filename": "test/oai/test_anthropic.py",
"hashed_secret": "9e712c7fd95990477f7c83991f86583883fa7260",
"is_verified": false,
"line_number": 51,
"line_number": 50,
"is_secret": false
},
{
"type": "Secret Keyword",
"filename": "test/oai/test_anthropic.py",
"hashed_secret": "1250ccf39e681decf5b51332888b7ccfc9a05227",
"is_verified": false,
"line_number": 71,
"line_number": 70,
"is_secret": false
}
],
Expand Down Expand Up @@ -1596,5 +1596,5 @@
}
]
},
"generated_at": "2025-02-24T18:10:39Z"
"generated_at": "2025-02-25T12:38:52Z"
}
35 changes: 33 additions & 2 deletions autogen/oai/anthropic.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,11 +365,42 @@ def get_usage(response: ChatCompletion) -> dict:

@staticmethod
def convert_tools_to_functions(tools: list) -> list:
"""
Convert tool definitions into Anthropic-compatible functions,
updating nested $ref paths in property schemas.
Args:
tools (list): List of tool definitions.
Returns:
list: List of functions with updated $ref paths.
"""

def update_refs(obj, defs_keys, prop_name):
"""Recursively update $ref values that start with "#/$defs/"."""
if isinstance(obj, dict):
for key, value in obj.items():
if key == "$ref" and isinstance(value, str) and value.startswith("#/$defs/"):
ref_key = value[len("#/$defs/") :]
if ref_key in defs_keys:
obj[key] = f"#/properties/{prop_name}/$defs/{ref_key}"
else:
update_refs(value, defs_keys, prop_name)
elif isinstance(obj, list):
for item in obj:
update_refs(item, defs_keys, prop_name)

functions = []
for tool in tools:
if tool.get("type") == "function" and "function" in tool:
functions.append(tool["function"])

function = tool["function"]
parameters = function.get("parameters", {})
properties = parameters.get("properties", {})
for prop_name, prop_schema in properties.items():
if "$defs" in prop_schema:
defs_keys = set(prop_schema["$defs"].keys())
update_refs(prop_schema, defs_keys, prop_name)
functions.append(function)
return functions

def _add_response_format_to_system(self, params: dict[str, Any]):
Expand Down
68 changes: 67 additions & 1 deletion test/oai/test_anthropic.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
# SPDX-License-Identifier: MIT
# !/usr/bin/env python3 -m pytest


import pytest

from autogen.import_utils import optional_import_block, skip_on_missing_imports
Expand Down Expand Up @@ -265,3 +264,70 @@ class MathReasoning(BaseModel):

with pytest.raises(ValueError, match="No valid JSON found in response for Structured Output."):
anthropic_client._extract_json_response(no_json_response)


@skip_on_missing_imports(["anthropic"], "anthropic")
def test_convert_tools_to_functions(anthropic_client):
tools = [
{
"type": "function",
"function": {
"description": "weather tool",
"name": "weather_tool",
"parameters": {
"type": "object",
"properties": {
"city_name": {"type": "string", "description": "city_name"},
"city_list": {
"$defs": {
"city_list_class": {
"properties": {
"item1": {"title": "Item1", "type": "string"},
"item2": {"title": "Item2", "type": "string"},
},
"required": ["item1", "item2"],
"title": "city_list_class",
"type": "object",
}
},
"items": {"$ref": "#/$defs/city_list_class"},
"type": "array",
"description": "city_list",
},
},
"required": ["city_name", "city_list"],
},
},
}
]
expected = [
{
"description": "weather tool",
"name": "weather_tool",
"parameters": {
"type": "object",
"properties": {
"city_name": {"type": "string", "description": "city_name"},
"city_list": {
"$defs": {
"city_list_class": {
"properties": {
"item1": {"title": "Item1", "type": "string"},
"item2": {"title": "Item2", "type": "string"},
},
"required": ["item1", "item2"],
"title": "city_list_class",
"type": "object",
}
},
"items": {"$ref": "#/properties/city_list/$defs/city_list_class"},
"type": "array",
"description": "city_list",
},
},
"required": ["city_name", "city_list"],
},
}
]
actual = anthropic_client.convert_tools_to_functions(tools=tools)
assert actual == expected

0 comments on commit 24d6acc

Please sign in to comment.