-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Description
Environment:
google-adk
Version:[1.1.1]
- Python Version:
[3.13]
- Models Used:
- Root Agent (
LlmAgent
, streaming, multimodal):gemini-2.0-flash-live-preview-04-09
- Wrapped Agent (
LlmAgent
, forAgentTool
): Initiallygemini-2.5-pro-preview-05-06
, later switched togemini-2.0-flash
for stability.
- Root Agent (
Problem Description:
When using an LlmAgent
(Root Agent) that is configured for streaming and multimodal input, and providing it with a tool that is an AgentTool
(wrapping another LlmAgent
, let's call it TaskExecutionAgent
), an AttributeError
occurs if the Root Agent's LLM attempts to call the TaskExecutionAgentTool
.
The error AttributeError: 'AgentTool' object has no attribute 'func'
originates from google/adk/flows/llm_flows/functions.py
during the processing of the tool call.
Steps to Reproduce / Code Context:
-
Define a
TaskExecutionAgent
(e.g., anLlmAgent
designed for specific multi-step logic).# From agent_config.py task_execution_agent = LlmAgent( model="gemini-2.0-flash", # Or any model name="TaskExecutionAgent", instruction="...", description="...", )
-
Wrap this
task_execution_agent
withAgentTool
:# From agent_config.py from google.adk.tools.agent_tool import AgentTool task_execution_agent_tool = AgentTool(agent=task_execution_agent)
-
Provide this
task_execution_agent_tool
in thetools
list of a RootLlmAgent
that is multimodal and streaming:# From agent_config.py all_root_agent_tools = [ # ... other tools (e.g., patched MCPTools) ... task_execution_agent_tool ] root_agent = LlmAgent( model="gemini-2.0-flash-live-preview-04-09", # Multimodal streaming model name="mcp_streaming_assistant", instruction="... instruction to sometimes call TaskExecutionAgentTool ...", tools=all_root_agent_tools, )
-
Initiate a scenario (e.g., via video stream input) where the
root_agent
's LLM decides to callTaskExecutionAgentTool
.
Observed Behavior (Error Traceback):
The application crashes with the following traceback when TaskExecutionAgentTool
is invoked:
Traceback (most recent call last):
File ".../main.py", line 369, in agent_to_client_messaging # Line in my WebSocket handling
async for event in live_events:
... (lines from adk/runners.py, adk/agents/base_agent.py, adk/agents/llm_agent.py) ...
File ".../google/adk/flows/llm_flows/base_llm_flow.py", line 378, in _postprocess_live
function_response_event = await functions.handle_function_calls_live(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
invocation_context, model_response_event, llm_request.tools_dict
)
File ".../google/adk/flows/llm_flows/functions.py", line 233, in handle_function_calls_live
function_response = await _process_function_live_helper(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
tool, tool_context, function_call, function_args, invocation_context
)
File ".../google/adk/flows/llm_flows/functions.py", line 313, in _process_function_live_helper
elif inspect.isasyncgenfunction(tool.func): # ERROR OCCURS HERE
^^^^^^^^^
AttributeError: 'AgentTool' object has no attribute 'func'
Workaround Applied:
Based on introspection and previous successful patching of MCPTool
instances (though MCPTools are now handled via MCPToolset in ADK 1.1.1, the patching principle for objects needing a .func attribute seemed relevant), we found that AgentTool
instances also:
- Are not directly callable (
callable(agent_tool_instance)
isFalse
). - Possess a
run_async
method that seems to be their intended execution entry point.
We patched the AgentTool
instance similarly to MCPTool
by adding a .func
attribute pointing to its run_async
method:
# In agent_config.py, after creating task_execution_agent_tool
if hasattr(task_execution_agent_tool, 'run_async') and callable(getattr(task_execution_agent_tool, 'run_async')):
task_execution_agent_tool.func = task_execution_agent_tool.run_async
logging.info(f"Patched AgentTool '{task_execution_agent_tool.name}' with .func attribute pointing to its run_async method.")
else:
logging.warning(f"Could not patch AgentTool ...")
This patch resolved the AttributeError: 'AgentTool' object has no attribute 'func'
and allowed the TaskExecutionAgentTool
to be called successfully.
The KeyError: 'request'
Issue and Solution (Related to AgentTool
Invocation):
After applying the .func
patch, a subsequent KeyError: 'request'
occurred within AgentTool.run_async
(at google/adk/tools/agent_tool.py
, line 101).
This was resolved by:
- Modifying the Root Agent's instructions to call
TaskExecutionAgentTool
with a single argument namedrequest
, the value of which is a JSON string containing all necessary parameters (e.g.,{"user_goal": "...", "seen_items": [...]}
). - Updating the
TaskExecutionAgent
's description and instructions to expect this single JSON string argument namedrequest
, which it then parses internally.
Expected Behavior / Suggestion:
It seems the ADK's function/tool handling mechanism in google.adk.flows.llm_flows.functions.py
might be too generally reliant on a .func
attribute for tools that are not caught by more specific type checks (like isinstance(tool, SomeSpecificADKToolType)
).
- Ideally, the ADK framework should natively recognize its own
AgentTool
instances and correctly invoke their intended execution method (presumablyrun_async
or an internal equivalent) without requiring a manual.func
patch. - If a
.func
patch is the intended way forAgentTool
(and potentially other tool types) to be made compatible with this execution flow, this requirement should be clearly documented. - Regarding the
KeyError: 'request'
,AgentTool
's expectation ofargs['request']
should also be clearly documented. IfAgentTool
is intended to support arbitrary named arguments (as derived from the wrapped agent's schema or description), thenAgentTool.run_async
would need to be more flexible in how it retrieves these arguments rather than hardcodingargs['request']
. Alternatively, the documentation should clearly state that any agent wrapped byAgentTool
will only receive its input via a singlerequest
argument from the calling LLM.
Clarifying these interaction patterns and ideally making AgentTool work more seamlessly out-of-the-box would significantly improve the developer experience when building complex, delegated multi-agent systems with ADK.