airflow.providers.common.ai.mixins.approval

Attributes

log

Classes

DeferForApprovalProtocol

Protocol for defer for approval mixin.

LLMApprovalMixin

Mixin that pauses an operator for human review before returning output.

Functions

normalize_assigned_users(value, *, param)

Return value as a list of {'id': str, 'name': str} users.

Module Contents

airflow.providers.common.ai.mixins.approval.log[source]
airflow.providers.common.ai.mixins.approval.normalize_assigned_users(value, *, param)[source]

Return value as a list of {'id': str, 'name': str} users.

Accepts None, a single user dict, or an iterable of them, and raises TypeError naming param for anything else, so a malformed list fails when the Dag is parsed rather than when the task first asks for a review.

class airflow.providers.common.ai.mixins.approval.DeferForApprovalProtocol[source]

Bases: Protocol

Protocol for defer for approval mixin.

approval_timeout: datetime.timedelta | None[source]
allow_modifications: bool[source]
on_approval_timeout: Literal['fail', 'approve', 'reject'][source]
approval_notifiers: collections.abc.Sequence[airflow.providers.common.compat.notifier.BaseNotifier][source]
approval_assigned_users: list[airflow.sdk.execution_time.hitl.HITLUser][source]
prompt: str[source]
task_id: str[source]
defer: Any[source]
validate_approval_prompt()[source]
class airflow.providers.common.ai.mixins.approval.LLMApprovalMixin[source]

Mixin that pauses an operator for human review before returning output.

When require_approval=True on the operator, the generated output is presented to a human reviewer via the Airflow Human-in-the-Loop (HITL) interface. The task waits (awaiting_input on Airflow 3.3+, deferred on older versions) until the reviewer approves or rejects.

If allow_modifications=True, the reviewer can also edit the output before approving. The (possibly modified) output is then returned as the task result.

on_approval_timeout decides what happens when approval_timeout expires without a response: "fail" raises HITLTimeoutError, while "approve" and "reject" answer the review with that option so the task resumes as if a reviewer had chosen it. The chosen option is also pre-highlighted for the reviewer in the HITL form.

approval_notifiers are called once the review is open, so a reviewer learns about it without watching the Required Actions page, the way HITLOperator does with notifiers. The review subject and body are exposed as {{ task.subject }} and {{ task.body }} in notifier templates. A notifier whose delivery raises is logged without failing the task, while a template error fails the task. A retry re-runs the LLM and re-notifies with the regenerated output. On Airflow 3.4+ the reopened review shows the regenerated output too; on Airflow 3.1 to 3.3 it keeps the original subject, body and editable output, so approving it unedited returns the first attempt’s output.

approval_assigned_users restricts the review to the named users, the way HITLOperator does with assigned_users. Leaving it empty lets any user with the permission respond. On Airflow 3.1 to 3.3 the list is stored when the review is first created, so clearing the task after changing it does not take effect; on 3.4+ a cleared or retried task replaces it.

Operators that use this mixin must set the following attributes:

  • require_approval (bool)

  • allow_modifications (bool)

  • approval_timeout (timedelta | None)

  • on_approval_timeout (Literal["fail", "approve", "reject"])

  • approval_notifiers (Sequence[BaseNotifier])

  • approval_assigned_users (list[HITLUser])

  • prompt (str)

APPROVE = 'Approve'[source]
REJECT = 'Reject'[source]
TIMEOUT_DEFAULTS: ClassVar[dict[str, list[str]]][source]
validate_approval_prompt()[source]

Fail fast when the prompt cannot be rendered as text in the approval review body.

defer_for_approval(context, output, *, subject=None, body=None, modification_schema=None, decision=None)[source]

Write HITL detail, then pause the task for human review.

On Airflow 3.3+ the task parks in the awaiting_input state (no trigger or triggerer involved); on older versions it defers to HITLTrigger. Either way it resumes in execute_complete once a response (or timeout default) arrives. on_approval_timeout supplies that timeout default; "fail" supplies none, so the review times out as an error.

Parameters:
  • context (airflow.sdk.Context) – Airflow task context.

  • output (Any) – The generated output to present for review.

  • subject (str | None) – Headline shown on the Required Actions page. Defaults to "Review output for task `<task_id>`".

  • body (str | None) – Markdown body shown below the headline. Defaults to the prompt and output wrapped in a code block.

  • modification_schema (dict[str, Any] | None) – JSON schema for the editable output param when allow_modifications=True. Defaults to {"type": "string"}. Pass e.g. {"type": "string", "enum": [...]} to render a dropdown of valid values in the review form, or {"type": "array", "items": {"type": "string", "enum": [...]}, "examples": [...]} to render a multi-select (JSON Schema forbids enum at the array level, so the options come from examples); a list submitted by the reviewer is returned from execute_complete re-serialized as a compact JSON string.

  • decision (dict[str, Any] | None) – The pending decision record, when the operator wrote one. It is carried in the continuation the task resumes from, next to generated_output, so execute_complete finalizes the record from what was checkpointed with the pause and not from a copy a reader could have edited or deleted in the meantime.

execute_complete(context, generated_output, event, decision=None)[source]

Resume after human review.

Called automatically by Airflow when the HITL trigger fires. Returns the original or reviewer-modified output on approval.

Parameters:
  • context (airflow.sdk.Context) – Airflow task context.

  • generated_output (str) – The output that was deferred for review.

  • event (dict[str, Any]) – Trigger event payload containing chosen_options, params_input, responded_by_user, and timedout.

  • decision (dict[str, Any] | None) – The pending decision record passed to defer_for_approval, if any. The mixin does not read it; an operator that writes a record finalizes it.

Raises:
  • HITLRejectException – If the reviewer, or the on_approval_timeout="reject" default, rejected the output.

  • HITLTriggerEventError – If the trigger reported an error.

  • HITLTimeoutError – If the approval timed out.

Was this entry helpful?