google / google/adk-python

RequestInput with constant interrupt_id breaks dev-ui input prompt on @node(rerun_on_resume=True) loops

Đang mở
#5,617 6 bình luận 0 reaction 2 người được giao Được @wyf7107 nhận Xem trên GitHub
needs review request clarification v2 web
Ngôn ngữ chính
Python
Star
21.5k
Fork
4k
Merge trung bình
1 ngày 22 giờ
Pull request đã merge (30 ngày)
31

Mô tả

## Summary
When a `@node(rerun_on_resume=True)` node yields `RequestInput` more than once across rerun loops using the **same** `interrupt_id` (as shown in the official `request_input_rerun` sample), the dev-ui fails to render the input prompt for the second and subsequent requests. The workflow appears stuck even though the backend is correctly waiting for input.

## Environment
- `google-adk` `2.0.0b1`
- Python 3.14
- macOS, `adk web` (built-in dev-ui)

## Reproduction
Use the official sample `request_input_rerun/agent.py` verbatim:

```python
@node(rerun_on_resume=True)
def human_review(draft: str, ctx: Context):
resume_input = ctx.resume_inputs.get("human_review")
if not resume_input:
yield RequestInput(
interrupt_id="human_review",
message="Please review ... 'approve', 'reject', or feedback to revise.\n\n---\n{draft}\n---",
)
return

if resume_input == "reject":
yield Event(route="rejected")
elif resume_input == "approve":
yield Event(route="approved")
else:
yield Event(state={"feedback": resume_input}, route="revise")
```

Steps:
1. Start session with any complaint, e.g. `I received the wrong item`.
2. At the first `adk_request_input` prompt, type `Please add a more empathetic tone` (triggers `revise`).
3. Wait for the second draft + the second `adk_request_input` event.

## Expected
The dev-ui renders the inline `Enter your response...` input box for the second `adk_request_input`, allowing the user to submit `approve` / `reject` / more feedback.

## Actual
The second `adk_request_input` event shows up only as a collapsed badge — no message body, no input box. Typing into the main `Type a message...` box submits as a *new* user turn (#9) instead of resuming the interrupt, and the workflow restarts the graph from `process_input`.

## Root cause analysis
Both `RequestInput` events are persisted with the same `function_call.id == "human_review"`. The dev-ui treats a `function_call.id` as "already responded" once any matching `function_response` has been seen in the session, regardless of whether a *newer* `function_call` with the same id is now pending. So the second pending interrupt is silently classified as a historical/already-resolved request.

Notably, the framework itself does allow multiple interrupts from the same node when `rerun_on_resume=True` — `_node_runner.py` only raises when `not node.rerun_on_resume and node_interrupted`:
```python
if is_interrupt and (
data_event_count > 0
or (not node.rerun_on_resume and node_interrupted)
):
raise ValueError(...)
```
So the backend contract permits the loop, but the dev-ui contract does not.

## Workaround
Make `interrupt_id` unique per run by appending `ctx.run_id`:

```python
interrupt_id = f"human_review:{ctx.run_id}"
resume_input = ctx.resume_inputs.get(interrupt_id)
if not resume_input:
yield RequestInput(interrupt_id=interrupt_id, message=...)
return
```

With this change the full loop (`revise → approve → send_email`) works end-to-end.

## Suggested fixes (any one)
1. **Framework auto-disambiguation:** transparently append `run_id` / `attempt_count` to the user-supplied `interrupt_id` for `rerun_on_resume=True` nodes when persisting the event.
2. **Validation:** when `rerun_on_resume=True`, validate or warn that the `interrupt_id` was already used by a prior completed interrupt in the same node lineage.
3. **Dev-ui fix:** match `function_response` to the **most recent** `function_call` with that id, instead of marking the id as "responded forever".
4. **Docs/sample:** at minimum, update the `request_input_rerun` sample (and the "How To" code snippet) to use a unique `interrupt_id` per run, since the current sample reproduces the bug.

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.