Introduces two major capabilities: - Workflow runtime: graph-based execution engine for composing deterministic execution flows for agentic apps, with support for routing, fan-out/fan-in, loops, retry, state management, dynamic nodes, human-in-the-loop, and nested workflows - Task API: structured agent-to-agent delegation with multi-turn task mode, single-turn controlled output, mixed delegation patterns, human-in-the-loop, and task agents as workflow nodes Co-Authored-By: Bo Yang <ybo@google.com> Co-Authored-By: George Weale <gweale@google.com> Co-Authored-By: Sean Zhou <seanzhougoogle@google.com> Co-Authored-By: Shangjie Chen <deanchen@google.com> Co-Authored-By: Swapnil Agarwal <swapnilag@google.com> Co-Authored-By: Wei Sun <weisun@google.com> Co-Authored-By: Xuan Yang <xygoogle@google.com> Co-Authored-By: Yifan Wang <wanyif@google.com> Change-Id: I35932c50cfe29ff68559e3781713dbb5eb7b3382
ADK Workflow Request Input Rerun Sample
Overview
This sample demonstrates an alternative way to handle a Human-in-the-Loop workflow in ADK Workflows using the RequestInput event combined with the @node(rerun_on_resume=True) decorator.
Like the standard request_input sample, this workflow simulates a customer support scenario where an AI drafts an email and a human reviews it. The key difference lies in how the human input is processed when the workflow resumes.
request_input vs request_input_rerun
- Standard (
request_input): The workflow pauses after a node yieldsRequestInput. When the user provides input and execution resumes, the input is automatically passed as the argument to the next node in the edge definition. This requires two separate nodes: one to request the input and one to handle it. - Rerun (
request_input_rerun): The node yieldingRequestInputis decorated with@node(rerun_on_resume=True). When execution resumes, the workflow re-runs the exact same node that asked for the input. The node can then access the provided input via the executionContext.
This allows you to combine the requesting and handling of human input into a single, cohesive node.
Sample Inputs
The delivery was a week lateI received the wrong itemMy account was charged twice
Graph
[ START ]
|
v
[draft_email] <------------------+
| |
v |
[human_review] -- (revise) ------+
(reruns on resume)
/ \
/ \
v v
[send_email] [END (rejected)]
How To
-
Decorate the node that needs human input with
@node(rerun_on_resume=True). Ensure the function signature includes the workflowContext.from google.adk.workflow import node from google.adk import Context @node(rerun_on_resume=True) def human_review(draft: str, ctx: Context): # ... -
Inside the node, check if you are being resumed by looking for the
interrupt_idinctx.resume_inputs.resume_input = ctx.resume_inputs.get('human_review') -
If
resume_inputis missing (i.e., this is the first time the node is executing), yield theRequestInputevent to pause the workflow. Include an explicitinterrupt_id.if not resume_input: yield RequestInput( interrupt_id="human_review", message="Please review the draft...", ) return # Important: Stop execution of this node for now -
If
resume_inputis present (i.e., the workflow was resumed with user input), process the input and yield the appropriate routing events.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") -
The edge definition is much simpler because the single
human_reviewnode handles everything:Workflow( name="request_input", edges=[ ("START", process_input, draft_email, human_review), (human_review, {"revise": draft_email, "approved": send_email}), ], )