Skip to content

Commit 09cb128

Browse files
seanzhougooglecopybara-github
authored andcommitted
fix: fix function tool name parsing
to fix #824 PiperOrigin-RevId: 761703269
1 parent b2a2b11 commit 09cb128

File tree

2 files changed

+28
-7
lines changed

2 files changed

+28
-7
lines changed

src/google/adk/tools/function_tool.py

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,27 @@ class FunctionTool(BaseTool):
3434

3535
def __init__(self, func: Callable[..., Any]):
3636
"""Extract metadata from a callable object."""
37-
if inspect.isfunction(func) or inspect.ismethod(func):
38-
# Handle regular functions and methods
37+
name = ''
38+
doc = ''
39+
# Handle different types of callables
40+
if hasattr(func, '__name__'):
41+
# Regular functions, unbound methods, etc.
3942
name = func.__name__
40-
doc = func.__doc__ or ''
41-
else:
42-
# Handle objects with __call__ method
43-
call_method = func.__call__
43+
elif hasattr(func, '__class__'):
44+
# Callable objects, bound methods, etc.
4445
name = func.__class__.__name__
45-
doc = call_method.__doc__ or func.__doc__ or ''
46+
47+
# Get documentation (prioritize direct __doc__ if available)
48+
if hasattr(func, '__doc__') and func.__doc__:
49+
doc = func.__doc__
50+
elif (
51+
hasattr(func, '__call__')
52+
and hasattr(func.__call__, '__doc__')
53+
and func.__call__.__doc__
54+
):
55+
# For callable objects, try to get docstring from __call__ method
56+
doc = func.__call__.__doc__
57+
4658
super().__init__(name=name, description=doc)
4759
self.func = func
4860

tests/unittests/tools/test_function_tool.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ async def async_function_for_testing_with_2_arg_and_no_tool_context(arg1, arg2):
4141

4242
class AsyncCallableWith2ArgsAndNoToolContext:
4343

44+
def __init__(self):
45+
self.__name__ = "Async callable name"
46+
self.__doc__ = "Async callable doc"
47+
4448
async def __call__(self, arg1, arg2):
4549
assert arg1
4650
assert arg2
@@ -57,6 +61,7 @@ def function_for_testing_with_1_arg_and_tool_context(arg1, tool_context):
5761
class AsyncCallableWith1ArgAndToolContext:
5862

5963
async def __call__(self, arg1, tool_context):
64+
"""Async call doc"""
6065
assert arg1
6166
assert tool_context
6267
return arg1
@@ -107,6 +112,8 @@ async def test_run_async_with_tool_context_async_callable():
107112
args = {"arg1": "test_value_1"}
108113
result = await tool.run_async(args=args, tool_context=MagicMock())
109114
assert result == "test_value_1"
115+
assert tool.name == "AsyncCallableWith1ArgAndToolContext"
116+
assert tool.description == "Async call doc"
110117

111118

112119
@pytest.mark.asyncio
@@ -125,6 +132,8 @@ async def test_run_async_without_tool_context_async_callable():
125132
args = {"arg1": "test_value_1", "arg2": "test_value_2"}
126133
result = await tool.run_async(args=args, tool_context=MagicMock())
127134
assert result == "test_value_1"
135+
assert tool.name == "Async callable name"
136+
assert tool.description == "Async callable doc"
128137

129138

130139
@pytest.mark.asyncio

0 commit comments

Comments
 (0)