google / google/adk-python

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

Offen
#5,617 6 Kommentare 0 Reaktionen 2 zugewiesene Personen Beansprucht von @wyf7107 Auf GitHub ansehen
needs review request clarification v2 web
Vorherrschende Sprache
Python
Sterne
21.5k
Forks
4k
Ø Merge
1 T. 14 Std.
Gemergte PRs (30 T.)
37

Beschreibung

## 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.

Beitragsleitfaden

Beitragsleitfaden öffnen

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.