8000 Investigating unexpected AttributeError with AgentTool and argument handling discrepancy in streaming multimodal agents. · Issue #1084 · google/adk-python · GitHub
[go: up one dir, main page]

Skip to content
Investigating unexpected AttributeError with AgentTool and argument handling discrepancy in streaming multimodal agents. #1084
Open
@surfiniaburger

Description

@surfiniaburger

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, for AgentTool): Initially gemini-2.5-pro-preview-05-06, later switched to gemini-2.0-flash for stability.

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:

  1. Define a TaskExecutionAgent (e.g., an LlmAgent 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="...",
    )
  2. Wrap this task_execution_agent with AgentTool:

    # From agent_config.py
    from google.adk.tools.agent_tool import AgentTool
    task_execution_agent_tool = AgentTool(agent=task_execution_agent)
  3. Provide this task_execution_agent_tool in the tools list of a Root LlmAgent 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,
    )
  4. Initiate a scenario (e.g., via video stream input) where the root_agent's LLM decides to call TaskExecutionAgentTool.

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) is False).
  • 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:

  1. Modifying the Root Agent's instructions to call TaskExecutionAgentTool with a single argument named request, the value of which is a JSON string containing all necessary parameters (e.g., {"user_goal": "...", "seen_items": [...]}).
  2. Updating the TaskExecutionAgent's description and instructions to expect this single JSON string argument named request, 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)).

  1. Ideally, the ADK framework should natively recognize its own AgentTool instances and correctly invoke their intended execution method (presumably run_async or an internal equivalent) without requiring a manual .func patch.
  2. If a .func patch is the intended way for AgentTool (and potentially other tool types) to be made compatible with this execution flow, this requirement should be clearly documented.
  3. Regarding the KeyError: 'request', AgentTool's expectation of args['request'] should also be clearly documented. If AgentTool is intended to support arbitrary named arguments (as derived from the wrapped agent's schema or description), then AgentTool.run_async would need to be more flexible in how it retrieves these arguments rather than hardcoding args['request']. Alternatively, the documentation should clearly state that any agent wrapped by AgentTool will only receive its input via a single request 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.


Metadata

Metadata

Assignees

Labels

toolsIssues related to tools

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions

    0