Skip to content

Agent with task execution mode fails with ValueError "Tool not found" if App is resumable #6509

Description

@n-a-sz

Describe the Bug:
A mode='task' sub-agent works fine when the App is not resumable, but breaks when resumability_config.is_resumable=True.

Steps to Reproduce:

  1. Activate an env with google-adk==2.5.0 available. Also make sure you can connect to an LLM (e.g. set env var GOOGLE_API_KEY=your-key-here or GOOGLE_GENAI_USE_VERTEXAI=1)
  2. Run the below script with python main.py --resumable

Expected Behavior:
The script (python main.py --resumable) should run without error like if called without options (python main.py)

Observed Behavior:
Stack trace and error printed:

Traceback (most recent call last):
  File "/home/nagyand/git/adk-task-resumable-bug/main.py", line 104, in <module>
    asyncio.run(main(args.resumable))
  File "REDACTED/lib/python3.11/asyncio/runners.py", line 190, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "REDACTED/lib/python3.11/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "REDACTED/lib/python3.11/asyncio/base_events.py", line 654, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "/home/nagyand/git/adk-task-resumable-bug/main.py", line 81, in main
    async for event in runner.run_async(
  File "REDACTED/lib/python3.11/site-packages/google/adk/runners.py", line 1111, in run_async
    async for event in agen:
  File "REDACTED/lib/python3.11/site-packages/google/adk/runners.py", line 628, in _run_node_async
    await self._cleanup_root_task(task, self.agent.name)
  File "REDACTED/lib/python3.11/site-packages/google/adk/runners.py", line 906, in _cleanup_root_task
    await task
  File "REDACTED/lib/python3.11/site-packages/google/adk/runners.py", line 610, in _drive_root_node
    raise e.error
  File "REDACTED/lib/python3.11/site-packages/google/adk/workflow/_node_runner.py", line 136, in run
    await self._execute_node(ctx, node_input)
  File "REDACTED/lib/python3.11/site-packages/google/adk/workflow/_node_runner.py", line 274, in _execute_node
    await self._run_node_loop(ctx, node_input)
  File "REDACTED/lib/python3.11/site-packages/google/adk/workflow/_node_runner.py", line 288, in _run_node_loop
    async for event in agen:
  File "REDACTED/lib/python3.11/site-packages/google/adk/workflow/_base_node.py", line 166, in run
    async for item in agen:
  File "REDACTED/lib/python3.11/site-packages/google/adk/agents/llm_agent.py", line 601, in _run_impl
    async for event in agen:
  File "REDACTED/lib/python3.11/site-packages/google/adk/workflow/_llm_agent_wrapper.py", line 416, in run_llm_agent_as_node
    async for event in run_iter:
  File "REDACTED/lib/python3.11/site-packages/google/adk/agents/base_agent.py", line 306, in run_async
    async for event in agen:
  File "REDACTED/lib/python3.11/site-packages/google/adk/agents/llm_agent.py", line 550, in _run_async_impl
    async for event in agen:
  File "REDACTED/lib/python3.11/site-packages/google/adk/flows/llm_flows/base_llm_flow.py", line 932, in run_async
    async for event in agen:
  File "REDACTED/lib/python3.11/site-packages/google/adk/flows/llm_flows/base_llm_flow.py", line 994, in _run_one_step_async
    async for event in agen:
  File "REDACTED/lib/python3.11/site-packages/google/adk/flows/llm_flows/base_llm_flow.py", line 1281, in _postprocess_handle_function_calls_async
    if function_response_event := await functions.handle_function_calls_async(
                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "REDACTED/lib/python3.11/site-packages/google/adk/flows/llm_flows/functions.py", line 413, in handle_function_calls_async
    return await handle_function_call_list_async(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "REDACTED/lib/python3.11/site-packages/google/adk/flows/llm_flows/functions.py", line 459, in handle_function_call_list_async
    function_response_events = await asyncio.gather(*tasks)
                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "REDACTED/lib/python3.11/site-packages/google/adk/flows/llm_flows/functions.py", line 561, in _execute_single_function_call_async
    raise tool_error
  File "REDACTED/lib/python3.11/site-packages/google/adk/flows/llm_flows/functions.py", line 547, in _execute_single_function_call_async
    tool = _get_tool(function_call, tools_dict)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "REDACTED/lib/python3.11/site-packages/google/adk/flows/llm_flows/functions.py", line 1135, in _get_tool
      ValueError: Tool 'worker' not found.
Available tools: transfer_to_agent, finish_task

Possible causes:
1. LLM hallucinated the function name - review agent instruction clarity
2. Tool not registered - verify agent.tools list
3. Name mismatch - check for typos

Suggested fixes:
- Review agent instruction to ensure tool usage is clear
- Verify tool is included in agent.tools list
- Check for typos in function name

Environment Details:

  • ADK Library Version (pip show google-adk): 2.5.0
  • Desktop OS:** [e.g., macOS, Linux, Windows] Linux 6.18.33.2-microsoft-standard-WSL2 (Ubuntu 24.04 WSL)
  • Python Version (python -V): 3.11.15

Model Information:

  • Are you using LiteLLM: No
  • Which model is being used: default, probably gemini-3.5-flash, but doesn't matter

🟡 Optional Information

Minimal Reproduction Code:
Please provide a code snippet or a link to a Gist/repo that isolates the issue.

"""MVP repro for: a `mode='task'` sub-agent works fine when the App is NOT
resumable, but breaks when `resumability_config.is_resumable=True`.

Usage:
    activate an env with google-adk==2.5.0 available
    export GOOGLE_API_KEY=your-key-here
    (or GOOGLE_GENAI_USE_VERTEXAI=1 with appropriate Vertex AI credentials.)

    # Baseline (should work):
    python main.py

    # Reproduce the bug (should error, per the bug report):
    python main.py --resumable
    error:
            line 1135, in _get_tool
            raise ValueError(error_msg)
        ValueError: Tool 'worker' not found.
        Available tools: transfer_to_agent, finish_task

        Possible causes:
        1. LLM hallucinated the function name - review agent instruction clarity
        2. Tool not registered - verify agent.tools list
        3. Name mismatch - check for typos

        Suggested fixes:
        - Review agent instruction to ensure tool usage is clear
        - Verify tool is included in agent.tools list
        - Check for typos in function name
"""

import argparse
import asyncio
import uuid

from google.adk.agents.llm_agent import LlmAgent
from google.adk.apps.app import App
from google.adk.apps._configs import ResumabilityConfig
from google.adk.runners import Runner
from google.adk.sessions.in_memory_session_service import InMemorySessionService
from google.genai import types


def build_app(resumable: bool) -> App:
    # Sub-agent running in "task execution mode".
    worker = LlmAgent(
        name="worker",
        mode="task",
        instruction=(
            "You are a task worker. Solve the user's request, then you MUST "
            "call the `finish_task` tool with your final result."
        ),
    )

    # Root agent (chat mode, implicit) that delegates to the task sub-agent.
    coordinator = LlmAgent(
        name="coordinator",
        instruction=(
            "You are a coordinator. For any user request, delegate the work "
            "to the `worker` agent tool, then relay its result back to the "
            "user."
        ),
        sub_agents=[worker],
    )

    return App(
        name="task_resumable_repro",
        root_agent=coordinator,
        resumability_config=ResumabilityConfig(is_resumable=resumable),
    )


async def main(resumable: bool) -> None:
    app = build_app(resumable)
    session_service = InMemorySessionService()

    user_id = "repro-user"
    session_id = str(uuid.uuid4())

    await session_service.create_session(
        app_name=app.name,
        user_id=user_id,
        session_id=session_id,
    )

    runner = Runner(app=app, session_service=session_service)

    print(f"--- Running with resumability_config.is_resumable={resumable} ---")

    new_message = types.Content(
        role="user",
        parts=[types.Part(text="What is 12 * 7? Please give me the answer.")],
    )

    async for event in runner.run_async(
        user_id=user_id,
        session_id=session_id,
        new_message=new_message,
    ):
        author = getattr(event, "author", "?")
        text = None
        if event.content and event.content.parts:
            text = "".join(p.text or "" for p in event.content.parts if p.text)
        print(f"[event] author={author} text={text!r}")

    print("--- Done, no error raised ---")


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "--resumable",
        action="store_true",
        help="Enable App.resumability_config.is_resumable (reproduces the bug).",
    )
    args = parser.parse_args()

    asyncio.run(main(args.resumable))

How often has this issue occurred?:

  • Always (100%)

Metadata

Metadata

Assignees

Labels

core[Component] This issue is related to the core interface and implementationrequest clarification[Status] The maintainer need clarification or more information from the author

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions