google / google/adk-python

LongRunningFunctionTool + A2A Protocol Task Completion Issue

Đang mở
#4,145 4 bình luận 0 reaction 2 người được giao Được giao cho @seanzhou1023 Xem trên GitHub
a2a answered needs review
Ngôn ngữ chính
Python
Star
21.5k
Fork
4k
Merge trung bình
1 ngày 14 giờ
Pull request đã merge (30 ngày)
37

Mô tả

# 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)
```python
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)
```javascript
// 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):**
```javascript
// 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
```python
# 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.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.