Skip to content

Task sub-agent attempts to execute the parent coordinator's delegation FunctionCall when resumability is enabled #6457

Description

@Yxnnxck

Task sub-agent attempts to execute the parent coordinator's delegation FunctionCall when resumability is enabled

Describe the bug

When an LLM coordinator delegates work to a sub-agent configured with mode="task", the task sub-agent attempts to execute the coordinator's delegation FunctionCall itself.

For example, after the coordinator delegates to the order_collector task agent, the order_collector appears to receive or observe the parent's delegation call named order_collector and attempts to execute it as one of its own tools.

This fails because order_collector is a delegation function exposed to the coordinator, not a tool registered on the child agent.

The resulting error is:

ValueError: Tool 'order_collector' not found.
Available tools: transfer_to_agent, confirmation, 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

The problem occurs when resumability is enabled on the application:

app = App(
name="test",
root_agent=root_agent,
resumability_config=ResumabilityConfig(
is_resumable=True,
),
)

Disabling resumability prevents the issue. The same agent setup works when using:

app = App(
name="test",
root_agent=root_agent,
)

or:

app = App(
name="test",
root_agent=root_agent,
resumability_config=ResumabilityConfig(
is_resumable=False,
),
)

This suggests that the issue is related to resumable task-agent dispatch or event isolation rather than the agent instructions or tool registration.

Steps to reproduce

  1. Create an order_collector agent using mode="task".

  2. Add the task agent to an LLM coordinator through sub_agents.

  3. Add a confirmation tool to the task agent.

  4. Enable resumability on the ADK App.

  5. Start the application using adk web.

  6. Ask the coordinator about the menu or place a food order.

  7. Let the coordinator delegate the request to order_collector.

Minimal reproduction



from future import annotations

from google.adk import Agent
from google.adk.agents.llm_agent import LlmAgent
from google.adk.models.lite_llm import LiteLlm
from google.adk.tools.function_tool import FunctionTool
from google.adk.apps.app import App, ResumabilityConfig
from pydantic import BaseModel
from pydantic import Field

from .adk_workaround import install_task_delegation_workaround

install_task_delegation_workaround()

class OrderItem(BaseModel):
name: str = Field(description="Name of the food item ordered")
quantity: int = Field(description="Quantity ordered")

class PaymentInfo(BaseModel):
"""Output schema for the payment collection task."""

credit_card_number: str
cvv: str

def place_order(orders: list[OrderItem], payment_info: PaymentInfo) -> str:
"""Mock an order placement operation."""
total_items = sum(item.quantity for item in orders)
return f"Successfully placed order for {total_items} items."

def confirmation() -> str:
"""Confirm proceeding with the order."""
return "Proceeding with order."

order_collector = Agent(
name="order_collector",
mode="task",
output_schema=list[OrderItem],
instruction=("""
You are an order collection assistant for a food delivery service.
Our menu today has exactly 3 items: 1. Pizza, 2. Burger, 3. Salad.
Ask the user what they would like to order and collect their choice and quantity.
Do not offer anything else.
If the combined quantity of items exceeds 5, you MUST use the confirmation tool to get user's confirmation before proceeding.
Do not ask for confirmation in natural language, always use the confirmation tool.
Once you have their final order and confirmation if needed, finish your task.
"""),
description="Collects the food order from the user.",
tools=[FunctionTool(confirmation, require_confirmation=True)],
)

payment_collector = Agent(
name="payment_collector",
mode="task",
output_schema=PaymentInfo,
instruction=("""
You are a payment collection assistant.
Ask the user for their credit card number and CVV.
Once you have both pieces of information, finish your task.
"""),
description="Collects credit card and CVV from the user.",
)

root_agent = LlmAgent(
model=LiteLlm("openai/gemma4unc:31b"),
name="coordinator",
sub_agents=[order_collector, payment_collector],
tools=[place_order],
instruction="""
You are a helpful coordinator for a food delivery service.
You need both order and payment information to place an order.
""",
)

app = App(
name="test",
root_agent=root_agent,
resumability_config=ResumabilityConfig(
is_resumable=True,
),
)

The model configuration has been omitted from this reproduction because the issue appears to be related to task dispatch and event isolation rather than a specific model provider.

Reproducing with ADK Web

The easiest way to reproduce the issue is to start the application with:

adk web

Then open the test application in the ADK Web UI and ask the coordinator about the available menu or place a simple food order, for example:

What is on the menu?

or:

I would like to order one pizza.

The coordinator delegates the request to the order_collector task agent.

Shortly after the delegation, the task agent attempts to execute the coordinator's delegation function call named order_collector, resulting in:

ValueError: Tool 'order_collector' not found.
Available tools: transfer_to_agent, confirmation, finish_task

The issue occurs consistently when is_resumable=True.

Repeating the same test after disabling resumability works as expected and does not produce the invalid tool call.

Expected behavior

The coordinator's delegation FunctionCall should remain part of the parent agent's execution context.

The child task agent should receive only:

  • its reconstructed task input;

  • relevant task-agent conversation events;

  • its own registered tools;

  • resumability information belonging to its task execution.

The child should not receive or attempt to execute the parent's delegation FunctionCall.

Enabling resumability should not change which function calls are visible to or executable by the child task agent.

Observed behavior

The coordinator correctly creates a delegation FunctionCall for the task agent.

After the task agent starts, it appears to receive the parent coordinator's delegation call in its own runner event list. It then attempts to execute the delegation call named order_collector.

Because the task agent only has access to its own tools, ADK raises:

Tool 'order_collector' not found.
Available tools: transfer_to_agent, confirmation, finish_task

The order_collector name is the task-agent delegation function exposed to the parent coordinator. It is not supposed to be executed by the child agent itself.

The behavior changes when resumability is disabled:

is_resumable=True -> Child attempts to execute order_collector and fails
is_resumable=False -> Delegation works as expected

Possible cause

The child task agent may be receiving the coordinator's delegation event as part of its own runner event list when resumability is enabled.

It appears that the parent delegation call is not sufficiently isolated from the child task-agent execution context. The child then interprets the parent's delegation FunctionCall as a pending function call that it must execute itself.

Environment details

  • ADK Library Version: 2.4.0

  • Desktop OS: Linux

  • Python Version: 3.14

  • Execution interface: adk web

  • Resumability enabled: Yes

  • Frequency: Always, 100%


Optional information

Regression

I have not verified whether this worked in an earlier ADK version.

Logs

ValueError: Tool 'order_collector' not found.
Available tools: transfer_to_agent, confirmation, 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

Workaround

Disabling resumability prevents the issue:

app = App(
name="test",
root_agent=root_agent,
resumability_config=ResumabilityConfig(
is_resumable=False,
),
)

A local workaround that forces task-agent dispatch into a separate sub-branch also prevents the parent delegation call from being executed by the child. However, that workaround modifies private ADK runtime APIs and is therefore not suitable as a permanent solution.

How often has this issue occurred?

  • Always, 100%

Metadata

Metadata

Assignees

Labels

agent engine[Component] This issue is related to Vertex AI Agent Engine

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions