Back to Adk Python

ADK Workflow Request Input Rerun Sample

contributing/workflow_samples/request_input_rerun/README.md

2.0.0b13.3 KB
Original Source

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 yields RequestInput. 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 yielding RequestInput is 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 execution Context.

This allows you to combine the requesting and handling of human input into a single, cohesive node.

Sample Inputs

  • The delivery was a week late
  • I received the wrong item
  • My account was charged twice

Graph

text
       [ START ]
           |
           v
    [draft_email] <------------------+
           |                         |
           v                         |
    [human_review] -- (revise) ------+
    (reruns on resume)
        /    \
       /      \
      v        v
[send_email]  [END (rejected)]

How To

  1. Decorate the node that needs human input with @node(rerun_on_resume=True). Ensure the function signature includes the workflow Context.

    python
    from google.adk.workflow import node
    from google.adk import Context
    
    @node(rerun_on_resume=True)
    def human_review(draft: str, ctx: Context):
        # ...
    
  2. Inside the node, check if you are being resumed by looking for the interrupt_id in ctx.resume_inputs.

    python
    resume_input = ctx.resume_inputs.get('human_review')
    
  3. If resume_input is missing (i.e., this is the first time the node is executing), yield the RequestInput event to pause the workflow. Include an explicit interrupt_id.

    python
    if not resume_input:
        yield RequestInput(
            interrupt_id="human_review",
            message="Please review the draft...",
        )
        return # Important: Stop execution of this node for now
    
  4. If resume_input is present (i.e., the workflow was resumed with user input), process the input and yield the appropriate routing events.

    python
    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")
    
  5. The edge definition is much simpler because the single human_review node handles everything:

    python
    Workflow(
        name="request_input",
        edges=[
            ("START", process_input, draft_email, human_review),
            (human_review, {"revise": draft_email, "approved": send_email}),
        ],
    )