Skip to content

LongRunningFunctionTool + A2A Protocol Task Completion Issue #4145

Closed as not planned

Description

@secprog

ADK Bug Report: LongRunningFunctionTool + A2A Protocol Task Completion Issue

Summary

Tasks using LongRunningFunctionTool in A2A protocol never transition to "completed" state, causing frontend clients to wait indefinitely despite the tool function completing successfully.

Environment

  • ADK Version: Latest from current branch
  • A2A SDK Version: >=0.3.11
  • Python Version: 3.12
  • LiteLLM Version: 1.80.16
  • Pydantic Version: 2.12.5

Problem Description

When agents use LongRunningFunctionTool for async operations, the A2A protocol task state machine gets stuck in "working" state. The tool function executes successfully and returns results, but the task never receives the completion signal, leaving clients waiting indefinitely.

Expected Behavior

  1. Client sends A2A request to agent
  2. Agent creates task with state "submitted"
  3. Agent calls LongRunningFunctionTool function, state changes to "working"
  4. Function completes and returns result
  5. Task state transitions to "completed"
  6. Client receives final response with task completion

Actual Behavior

  1. Client sends A2A request to agent ✅
  2. Agent creates task with state "submitted" ✅
  3. Agent calls LongRunningFunctionTool function, state changes to "working" ✅
  4. Function completes and returns result ✅
  5. Task state NEVER transitions to "completed" ❌
  6. Client never receives final response, waits indefinitely ❌

Reproduction Steps

1. Agent Setup (vision_agent.py)

from google.adk.tools.long_running_tool import LongRunningFunctionTool
from google.adk.agents import Agent

# Async function that takes ~10-30 seconds
async def run_core_analysis_parallel(user_id: str, session_id: str, filename: str) -> str:
    # Perform analysis with LLM calls
    result = await some_async_operation()
    return json.dumps(result)

visual_analysis_agent = Agent(
    name="visual_analyzer",
    model=LiteLlm(model="openai/gpt-5.1"),
    instruction="Analyze images using tools",
    tools=[
        LongRunningFunctionTool(func=run_core_analysis_parallel),
    ],
    planner=plan_re_act_planner.PlanReActPlanner(),
)

app = to_a2a(
    agent=root_agent,
    app=App(
        resumability_config=ResumabilityConfig(is_resumable=True),
        session_service=DatabaseSessionService(db_url=db_url),
        artifact_service=FileArtifactService(root_dir="./artifacts"),
    ),
    credential_service=InMemoryCredentialService(),
)

2. Client Request (A2A JSON-RPC)

// Frontend sends task request
const response = await fetch('http://localhost:8000/', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
        jsonrpc: '2.0',
        method: 'task/create',
        params: {
            message: {
                role: 'user',
                parts: [
                    { kind: 'text', text: 'analyze this diagram' },
                    { kind: 'data', data: { artifactRef: {...} } }
                ]
            }
        },
        id: 1
    })
});

3. Observed Behavior

Backend Logs (Vision Agent):

INFO:vision_analysis:Starting bundled core analysis for session_id=...
INFO:vision_analysis:Successfully loaded artifact: image.png (type: image/png)
INFO:LiteLLM: LiteLLM completion() model= gpt-5-mini; provider = openai
[Function executes successfully, returns JSON result]
INFO:     172.19.0.4:51552 - "POST / HTTP/1.1" 200 OK

Frontend Console (Status Updates):

// Repeated status updates, task never completes
Task 60c1186f-cdd7-4d5b-97e2-d82f691b048b status: {
    state: "working",
    message: {
        role: "agent",
        parts: [{
            kind: "data",
            data: {
                name: "run_core_analysis_parallel",
                id: "call_qo2vuDAqGcdmXgKJZ4C4ukrP"
            },
            metadata: {
                adk_type: "function_call",
                adk_is_long_running: true  // <-- Flag set correctly
            }
        }]
    },
    timestamp: "2026-01-13T22:34:37.524618+00:00"
}
// No "completed" state ever arrives

Network Activity:

  • Multiple POST requests to orchestrator: 200 OK ✅
  • Status-update events streaming correctly ✅
  • Final task completion event missing ❌

Root Cause Analysis

The LongRunningFunctionTool sets adk_is_long_running: true metadata correctly, but the A2A task result aggregation mechanism (TaskResultAggregator) doesn't properly handle the completion signal when the async function returns.

Suspected location: google.adk.a2a.executor.a2a_agent_executor.py lines 223-226 where TaskResultAggregator() is created but may not be waiting for long-running tool completion.

Impact

  • Severity: High - Blocks all async operations in production A2A agents
  • Affected Use Cases:
    • Image/diagram analysis with vision LLMs
    • Document processing pipelines
    • Any operation taking >5 seconds
    • Multi-step agent workflows with sub-agents

Additional Context

Related ADK Components

  • google.adk.tools.long_running_tool.LongRunningFunctionTool
  • google.adk.a2a.executor.a2a_agent_executor.A2aAgentExecutor
  • google.adk.a2a.executor.a2a_agent_executor.TaskResultAggregator
  • google.adk.a2a.converters.event_converter.convert_event_to_a2a_events

Expected Fix

The A2A task executor should:

  1. Wait for LongRunningFunctionTool async completion
  2. Capture the function return value
  3. Emit final status-update event with state: "completed"
  4. Include tool result in task artifacts or history
  5. Close the task properly

Test Case

# Should complete within timeout and return result
async def test_long_running_tool_completion():
    response = await client.send_task(message="analyze image")
    events = []
    async for event in response.stream():
        events.append(event)
        if event.state == "completed":
            break
    
    assert events[-1].state == "completed"  # Currently fails
    assert events[-1].artifacts is not None  # Tool result missing

Note: This issue prevents deployment of production A2A agents that require async operations.

Activity

  1. added
    a2a[Component] This issue is related a2a support inside ADK.
    on Jan 13, 2026
  2. added theissue type on Jan 13, 2026
  3. klateefa commented on Jan 16, 2026

    @klateefa

    @secprog Thanks for reporting!
    The issue is not with LongRunningFunctionTool. The tool executes correctly, completes the async work, and returns the result. The problem is in the A2A executor. After a long-running tool finishes, A2aAgentExecutor never emits a final task completion event. TaskResultAggregator only reacts to streamed events, and long-running tool completion happens outside that stream, so the task remains stuck in the working state.
    The executor must explicitly await long-running tool completion and then emit a terminal task update.
    What is missing
    future = asyncio.create_task(run_long_running_tool())

    Required fix in A2aAgentExecutor

    long_running_futures = []
    long_running_futures.append(tool_future)
    

    if long_running_futures

    results = await asyncio.gather(*long_running_futures)
    yield TaskStatusEvent(
       state="completed",
       artifacts=results,
    )
    

    With this change, the client receives the final response instead of waiting indefinitely.
    Thank you.

  4. self-assigned this
    on Jan 16, 2026
  5. added
    answered[Status] This issue has been answered by the maintainer
    on Jan 16, 2026
  6. secprog commented on Jan 20, 2026

    @secprog
    Author

    Thank you @klateefa i will try it :) any issue with that approach i open a new issue :).

  7. secprog commented on Jan 20, 2026

    @secprog
    Author

    Reopened for tracking by ADK team since this requires changes in ADK itself. :)

  8. DeanChensj commented on Jan 20, 2026

    @DeanChensj
    Collaborator

    Hi @seanzhou1023 , based on #4145 (comment), we might need some change in the A2AagentExecutor

  9. added
    needs review[Status] The PR/issue is awaiting review from the maintainer
    on Feb 6, 2026
  10. self-assigned this
    on Jun 16, 2026
  11. added
    spam[Status] Issues suspected of having comments which are spam
    on Jul 21, 2026
  12. removed
    spam[Status] Issues suspected of having comments which are spam
    on Jul 21, 2026
  13. deleted a comment from adk-bot on Jul 21, 2026
  14. GWeale commented on Oct 26, 2026

    @GWeale
    Collaborator

    hi @secprog, thanks for laying out the setup so clearly, and sorry it took a while to get back to you. when i ran this on main with LiteLlm, PlanReActPlanner, and DatabaseSessionService behind to_a2a, the task finished in input_required rather than working. that's expected for a LongRunningFunctionTool, which stays open waiting for the client to send back a function response before completing the task. since your function already returns the final result, passing it as a plain async tool instead will let the task finish as completed. if it still hangs after switching that over, please open a new issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

a2a[Component] This issue is related a2a support inside ADK.answered[Status] This issue has been answered by the maintainerneeds review[Status] The PR/issue is awaiting review from the maintainer

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions