Skip to main content
HumanReview groups all HITL settings into a single object instead of passing them as separate parameters. All workflow primitives accept human_review=HumanReview(...): Step, Loop, Router, Condition, Steps, and Parallel.
from agno.workflow.step import Step
from agno.workflow.types import HumanReview
from agno.workflow import OnReject

Step(
    name="draft_email",
    agent=draft_agent,
    human_review=HumanReview(
        requires_output_review=True,
        output_review_message="Review the draft before sending.",
        on_reject=OnReject.retry,
        max_retries=3,
        timeout=300,
        on_timeout=OnTimeout.approve,
    ),
)
Flat parameters still work for backward compatibility:
# Equivalent to the above
Step(
    name="draft_email",
    agent=draft_agent,
    requires_output_review=True,
    output_review_message="Review the draft before sending.",
    on_reject=OnReject.retry,
    hitl_max_retries=3,
    hitl_timeout=300,
    on_timeout=OnTimeout.approve,
)
If both human_review and flat parameters are provided, human_review takes priority.

All Fields

FieldTypeDefaultDescription
requires_confirmationboolFalsePause for user confirmation before execution
confirmation_messagestrNoneMessage shown during confirmation
requires_user_inputboolFalsePause to collect user input before execution
user_input_messagestrNoneMessage shown when collecting input
user_input_schemaList[UserInputField]NoneSchema defining expected input fields
requires_output_reviewboolFalsePause after execution for output review
output_review_messagestrNoneMessage shown during output review
requires_iteration_reviewboolFalsePause after each loop iteration for review
iteration_review_messagestrNoneMessage shown during iteration review
on_rejectOnRejectOnReject.skipAction when user rejects
on_errorOnErrorNoneAction when step errors
max_retriesint3Max retries on rejection (when on_reject=OnReject.retry)
timeoutintNoneSeconds to wait for user response
on_timeoutOnTimeoutNoneAction when timeout expires

Supported Fields by Component

Not every field works on every component. Passing an unsupported field raises a ValueError at construction time.
FieldStepLoopRouterConditionStepsParallel
requires_confirmation
requires_user_input----
requires_output_review----
requires_iteration_review-----
on_reject
on_error-----
max_retries
timeout
on_timeout
Condition, Steps, and Parallel only support requires_confirmation. Passing unsupported fields raises a clear error:
from agno.workflow.condition import Condition
from agno.workflow.types import HumanReview

# This raises ValueError: requires_output_review is not supported on Condition.
# Supported: requires_confirmation.
Condition(
    name="my_condition",
    steps=[...],
    human_review=HumanReview(requires_output_review=True),
)

Validation Rules

  • requires_output_review and requires_iteration_review cannot both be True in the same config.
  • Each component validates at construction time. You get a clear error if a field is unsupported.

HITL Modes

Pre-execution: Confirmation

Pause before a step runs. The user approves or rejects.
HumanReview(
    requires_confirmation=True,
    confirmation_message="Delete 1000 records?",
    on_reject=OnReject.cancel,
)

Pre-execution: User Input

Collect parameters from the user before execution.
from agno.workflow.types import HumanReview, UserInputField

HumanReview(
    requires_user_input=True,
    user_input_message="Configure report settings:",
    user_input_schema=[
        UserInputField(name="format", field_type="str", required=True),
        UserInputField(name="include_charts", field_type="bool", required=False),
    ],
)

Post-execution: Output Review

Pause after a step completes so the user can review the output. Supported on Step and Router.
HumanReview(
    requires_output_review=True,
    output_review_message="Review the generated report.",
    on_reject=OnReject.retry,
    max_retries=3,
)

Per-iteration: Iteration Review

Pause after each loop iteration for review. Supported on Loop only.
HumanReview(
    requires_iteration_review=True,
    iteration_review_message="Review this iteration's output.",
    on_reject=OnReject.retry,
)

Timeout

Set a timeout for how long to wait for a user response. If the timeout expires, on_timeout determines what happens.
from agno.workflow import OnTimeout

HumanReview(
    requires_confirmation=True,
    confirmation_message="Approve deployment?",
    timeout=300,  # 5 minutes
    on_timeout=OnTimeout.approve,  # Auto-approve after timeout
)
OnTimeout ValueBehavior
OnTimeout.approveAutomatically approve and continue
OnTimeout.rejectAutomatically reject
OnTimeout.cancelCancel the workflow

Serialization

HumanReview serializes to a single "human_review" key in the workflow state. Deserialization reads "human_review" first, then falls back to flat keys for backward compatibility with existing persisted data.
config = HumanReview(
    requires_confirmation=True,
    confirmation_message="Proceed?",
    timeout=60,
)

data = config.to_dict()
# {"requires_confirmation": True, "confirmation_message": "Proceed?", "timeout": 60, ...}

restored = HumanReview.from_dict(data)

Developer Resources