Skip to main content

Overview

The hitl built-in member enables human-in-the-loop workflows with approval gates, using Durable Objects for state persistence.
- member: request-approval
  type: Function
  config:
    builtin: hitl
    operation: suspend
    prompt: "Review this content"
    fields:
      - name: approved
        type: boolean
        label: "Approve?"
      - name: comments
        type: string
        label: "Comments"

Operations

Suspend

Pause for human input:
- member: await-approval
  type: Function
  config:
    builtin: hitl
    operation: suspend
    prompt: ${input.reviewPrompt}
    fields: ${input.reviewFields}
    expiresIn: 86400000  # 24 hours
    notifyUrl: ${env.APPROVAL_WEBHOOK}

Resume

Resume with human input (API call):
curl -X POST /api/v1/executions/{id}/resume \
  -d '{"token": "hitl_token", "input": {"approved": true}}'

Approve

Auto-approve operation:
- member: auto-approve
  type: Function
  config:
    builtin: hitl
    operation: approve
    reason: "Meets auto-approval criteria"

Reject

Auto-reject operation:
- member: auto-reject
  type: Function
  config:
    builtin: hitl
    operation: reject
    reason: "Does not meet criteria"

Output

interface HITLOutput {
  status: 'suspended' | 'approved' | 'rejected';
  token?: string;
  input?: Record<string, any>;
  approvedBy?: string;
  approvedAt?: number;
}

Example Workflow

flow:
  - member: check-amount
    type: Function
    config:
      handler: (input) => ({ needsApproval: input.amount > 1000 })

  - member: request-approval
    condition: ${check-amount.output.needsApproval}
    type: Function
    config:
      builtin: hitl
      operation: suspend
      prompt: "Approve transaction of $${input.amount}"
      fields:
        - name: approved
          type: boolean
        - name: reason
          type: string

  - member: process-transaction
    condition: ${request-approval.output.approved || !check-amount.output.needsApproval}
    type: Function
    config:
      handler: () => ({ processed: true })