Skip to main content

Human-in-the-Loop with USER_INPUT

Some processes require human approval, review, or sign-off. A USER_INPUT task suspends the running workflow, emits a Notification Service event, and holds the run in PAUSED state until a permitted user submits their input.

The Workflow#

The Weather_Alert_Human_Approval workflow fetches and analyses weather information and then pauses to request user approval.

fetch_weather (SCRIPT_EXECUTION)  → analyze_weather (SCRIPT_EXECUTION → severity)    → request_approval (USER_INPUT)   ← workflow PAUSES here      → act_on_decision (SCRIPT_EXECUTION)  ← reads the human's answer

The USER_INPUT Task#

Here's the configuration for the USER_INPUT task in the Weather_Alert_Human_Approval workflow. It specifies the notification type as well as the requried _userInput needed to continue.

{    _type: "USER_INPUT",    _name: "request_approval",    _sequenceno: 3,    _inputParams: {        _sendNotification: true,        _notificationId: "weather_alert_approval",        _userInputPermissions: [            { _userType: "user", _id: approverUserId }        ],        _userInput: {            approve: { type: "string", enum: ["yes", "no"] },            note:    { type: "string" }        }    }}

Key fields:

  • _userInput declares the shape of the answer expected from the human: here an approve enum and a free-text note.
  • _userInputPermissions lists who may provide the reqruied input. You can provide multiple individual users and user groups to the _userInputPermissions to allow users to provide the required input to the workflow. User groups are specified by configuring { _userType: 'usergroup', _id: <_id of the user group> } while individual users are specifed by { _userType: 'user', _id:<_id of a user> }. Your user _id was when you deployed the template package for the course. You can see it by right clicking Weather_Alert_Human_Approval and selecting 'View Definition JSON'.
  • _sendNotification / _notificationId cause the pause to emit a Notification Service event so a UI or subscriber can react. These live at the top of _inputParams, as siblings of _userInput.

Because the run may wait for a person, the definition sets a generous _timeoutSeconds: 3600.

Reading the Human's Input Downstream#

USER_INPUT output is addressed differently from a script output — the submitted fields live under {{task name}}._output._userInput.<field>:

{    _type: "SCRIPT_EXECUTION",    _name: "act_on_decision",    _sequenceno: 4,    _inputParams: {        _userType: "weather_workflow_demo_static",        _scriptName: "actOnApprovalDecision",        approve:  "${request_approval._output._userInput.approve}",        note:     "${request_approval._output._userInput.note}",        severity: "${analyze_weather._output.scriptOutput}"    }}

actOnApprovalDecision then dispatches on the answer. Sending the alert when approve === "yes" and suppressing it otherwise.

Running the Workflow#

  1. Run runWeatherWorkflow with input copying and pasting this value into the input field:

{ "workflowUserType": "weather_workflow_transformer_static" }

  1. Monitor with getLatestWorkflowRunByUserType.

The run advances to request_approval and then pauses (PAUSED).

  1. Submit the human decision by running updateWeatherUserInputRun with the following input:

    { "approve": "yes", "note": "Approved via the course" }

    With no workflowRunId, the updateWeatherUserInputRun script targets the latest run of the user-input workflow. It resolves the paused run and its USER_INPUT task, then calls the SDK:

    IafWorkflowSvc.updateUserInput(runId, userInputId, { _userInput: { approve, note } }, ctx)
  2. The run resumes, act_on_decision runs, and the workflow completes. Confirm with getLatestWorkflowRunByUserType or pollWorkflowUntilComplete.

Inspecting the Pause / Notification#

Two helpers exist to understand the paused state and its notification context:

  • resolveWeatherUserInputRun (internal helper) locates the run, its USER_INPUT task, the runtime userInputId, and the _notificationId.
  • sendWeatherUserInputNotification surfaces the notification context: it builds an event payload shaped like the live workflowsvc.UserInput event and lists the current user's Notification Service history and any matching triggers.

There is no API to re-fire the UserInput event after the fact — the workflow emits workflowsvc.UserInput once, when the task starts (because _sendNotification: true). To actually reach an approver by email or webhook, a Notification Service trigger must be configured to filter on event = UserInput and notificationId = weather_alert_approval. This is the bridge between a paused workflow and the outside world; the helper lets you verify that bridge is in place.

Human Input is an API Call#

Notice that completing a human task is an ordinary authenticated API call (updateUserInput). In a real application that call is made by a UI action, a chatbot, or another service. Anything that can present the decision to a permitted user and post their answer. The workflow does not care what the front end is; it only cares that a permitted user submitted an answer of the declared shape.