Human-in-the-loop (HITL) allow you to require human approval before certain actions are executed. This is useful for:

  • Reviewing and approving high-risk operations
  • Validating model outputs before taking action

Inferable provides a simple API for creating approval requests and approving them. It accomplishes this by returning a special result type.

If you would like to send a notification without pausing the workflow, see notifications.

The notification input defined here is the same as what is passed to ctx.notify().

Usage

The following example shows how to use the Interrupt.approval() function to pause a workflow and wait for human approval.

import { Interrupt } from "inferable";

deleteUserWorkflow.version(1).define(async (ctx, input) => {
  // ... existing workflow code ...

  if (!ctx.approved) {
    return Interrupt.approval();
  }

  await db.customers.delete({
    userId: input.userId,
  });
});

Approval Notifications

By default, the approval request will be created in the Inferable app. Unless a human explicitly approves or rejects the request, the workflow will be indefinitely paused.

Notifications

Approval requests can also provide a notification destination to send the request to.

Email

Emails will be delivered from [email protected]
deleteUserWorkflow.version(1).define(async (ctx, input) => {
  if (!ctx.approved) {
    return Interrupt.approval({
      message: `I need your approval to delete the user ${input.userId}. Is this ok?`,
      destination: {
        type: "email",
        // The email address to notify
        email: "[email protected]",
      },
    });
  }
  //...
});

Slack

If enabled, the Slack integration can also be used to notify users / channels of approval requests.

deleteUserWorkflow.version(1).define(async (ctx, input) => {
  if (!ctx.approved) {
    return Interrupt.approval({
      message: `I need your approval to delete the user ${input.userId}. Is this ok?`,
      destination: {
        type: "slack",
        // The email address of the Slack user to notify
        email: "[email protected]",
        // Or Slack user ID
        userId: "U0123456789",
        // Or Slack channel ID
        channelId: "C0123456789",
      },
    });
  }
  //...
});

Semantics

Approval Flow

When Interrupt.approval() is returned from a Workflow:

  1. The Workflow or Run is paused.

  2. The approval request is created.

  3. An authorized user must approve or reject the request using the API or the App UI.

  4. If the approval is successful,

    4.1 The workflow will resume execution, and will call the handler again with the same input.

    4.2 At this point, since the context.approved is true, the handler will continue without entering the return Interrupt.approval() block.

  5. If the approval is rejected

    5.1 The tool / workflow will be rejected. If this is a tool, the agent will be notified that the tool call was rejected.

Pausing a Workflow

When a Workflow is paused, Inferable’s durable execution engine will save the state and resume when the approval is resolved.

Since humans can take a long time to approve, the run or workflow can be paused for an indefinite amount of time. There’s no theoretical upper limit on how long a run can be paused for.