HumanReview Config

Consolidate all human-in-the-loop settings into a single config object.

HumanReview groups all HITL settings into a single object instead of passing them as separate parameters. Step, Loop, Router, Condition, and Steps accept human_review=HumanReview(...). Parallel rejects every requires_* field because parallel branches cannot be individually paused. Behavior fields set on Parallel have no effect.

from agno.workflow.step import Step
from agno.workflow.types import HumanReview
from agno.workflow import OnReject, OnTimeout

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,
    ),
)

Workflow primitives accept HITL settings only through human_review. Move former flat fields into HumanReview, renaming hitl_timeout to timeout and hitl_max_retries to max_retries. Step(max_retries=...) still controls executor-error retries separately.

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
allow_multiple_selectionsboolFalseLet a Router accept more than one selected route
user_input_schemaList[UserInputField]NoneSchema defining expected input fields
requires_output_reviewbool or Callable[[StepOutput], bool]FalsePause 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_errorOnErrorOnError.skipAction when a Step or Condition errors
max_retriesint3Max retries on rejection (when on_reject=OnReject.retry)
timeoutintNoneSeconds to wait for a Step confirmation or output review
on_timeoutOnTimeoutOnTimeout.cancelAction when timeout expires

Supported Fields by Component

Not every field works on every component. Passing an unsupported requires_* flag raises a ValueError at construction time. The behavior fields (on_reject, on_error, max_retries, timeout, on_timeout) are not validated; they only take effect on the components marked below.

FieldStepLoopRouterConditionStepsParallel
requires_confirmation-
requires_user_input----
requires_output_review----
requires_iteration_review-----
allow_multiple_selections-----
on_reject-
on_error----
max_retries----
timeout-----
on_timeout-----

Condition and Steps only support requires_confirmation. Parallel rejects any requires_* field. Passing an unsupported mode 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 a Step confirmation or output review. If the timeout expires, on_timeout determines what happens when continue_run() is called. Step user-input pauses and other components ignore timeout policies.

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.skipSkip the step and continue
OnTimeout.cancelCancel the workflow (default)

Serialization

Workflow primitives serialize HumanReview under a nested "human_review" key. Current deserialization drops legacy flat HITL keys with a warning; it does not restore their approval gates. Migrate persisted configurations to nested human_review before rehydrating them. For example, move requires_confirmation into that object and rename legacy hitl_timeout / hitl_max_retries to timeout / max_retries inside it.

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)

A callable requires_output_review predicate serializes as True. Reapply the callable after reconstructing a workflow if review should remain conditional.

Developer Resources