google / google/adk-python

Parallel ungated tool results are lost across a tool-confirmation pause, yielding an empty model reply after approval

Đang mở
#6,732 2 bình luận 0 reaction 1 người được giao Được @sanketpatil06 nhận Xem trên GitHub
agent engine request clarification
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ả

**Describe the bug**

When a model turn contains a confirmation-gated function call (`FunctionTool(require_confirmation=True)`) **in parallel with** ungated function calls, the ungated siblings' results are lost across the confirmation pause. After the user approves, the resume processor (`flows/llm_flows/request_confirmation.py`) re-executes only the confirmed tool, leaving the sibling `function_call` in session history with no matching `function_response`. Gemini, given that dangling call, returns an **empty final message** — while the approved (destructive) tool HAS executed. The end user sees no answer and may retry an action that already succeeded.

**To Reproduce**

1. An `LlmAgent` with two tools: `delete_record` built with `require_confirmation=True`, and `list_records` (ungated).
2. Prompt so the model emits both calls in one turn, e.g. *"Delete record X, and after deleting, list the remaining records."* Gemini frequently parallelizes this into one response with both `function_call` parts.
3. The run pauses with `adk_request_confirmation`. Observations at this point:
- The ungated `list_records` **does execute** during the pause (its side effects are visible), but the merged function-response event — carrying the sibling's real result plus the gated tool's `"This tool call requires confirmation"` placeholder — is **never persisted to the session**. When the caller stops consuming the event stream at the confirmation event (the natural thing for a client that must wait for user input, e.g. any AG-UI/SSE bridge), the response event that `_postprocess_handle_function_calls_async` yields *after* `generate_request_confirmation_event` is never reached (`GeneratorExit`).
4. Resume with `ToolConfirmation(confirmed=True)`.
5. `_RequestConfirmationLlmRequestProcessor._resolve_confirmation_targets` re-executes only the confirmed `delete_record`. Session events now contain `function_call list_records` with no `function_response`.
6. The follow-up LLM call returns empty content (`{"text": ""}`).

Observed session event sequence (from a Postgres session service, ADK 2.7.0):

```
model: [text, function_call delete_record, thought_signature, function_call list_records, text]
model: [function_call adk_request_confirmation] (long_running_tool_ids set)
user: [function_response adk_request_confirmation {confirmed: true}]
model: [function_response delete_record {...success...}] <- only the confirmed tool
model: [text ""] <- empty final reply
```

**Expected behavior**

Either (a) the pause-time function-response event (sibling results + confirmation placeholder) is persisted before/with the confirmation-request event so history stays complete across the pause, or (b) the resume path re-executes (or synthesizes responses for) unresolved sibling calls from the same turn — so the post-approval continuation never sees a dangling `function_call`.

**Screenshots**

N/A (event sequence above).

**Desktop:**
- OS: macOS 26 / Linux (Docker python:3.12-slim)
- Python version: 3.12
- ADK version: 2.7.0 (also inspected 2.5.0 — same structure)

**Model Information:**
- Are you using LiteLLM: No
- Which model is being used: gemini via Vertex AI

**Additional context**

Single-call confirmation flows (pause → approve/reject → resume) work correctly in 2.7.0, including the 2.6.x fixes for consumed-confirmation re-validation. The failure is specific to the parallel gated+ungated combination. Downstream we mitigate with an `after_model_callback` that drops ungated siblings from mixed turns before execution (the model re-issues them after the decision), but a framework-level fix would let parallel calls keep their results.

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.