Skip to main content

Human-in-the-Loop (HITL)

Human-in-the-loop lets you pause agent communication and require manual approval before a message is forwarded. This is critical for high-stakes operations where you need a human to verify what an agent is about to do.

How HITL Gets Triggered

There are two distinct ways a message can be held for human review:
These are fundamentally different flows. Policy escalation is triggered by a detection policy (regex, Presidio, Comprehend) at the relay level — before or after the message reaches the agent, depending on which leg matched. Agent-initiated INPUT_REQUIRED happens when the agent has processed the message and decided it needs human input. Both are automatically intercepted by the relay’s built-in HITL middleware.

Setting Up Policy-Based HITL

To escalate messages for human review, set the action to HUMAN_REVIEW_REQUIRED on any detection policy (regex, Presidio, or Comprehend). There is no separate “HITL policy type” — human review is an action you configure on your existing detection policies.
After creating your policy, remember to add it to a policy group and bind that group to a tenant, agent, or subscription. See the Policy Configuration tutorial for the full flow.

Reviewing Approvals

When a message is held for review, it appears as a pending approval.

List Pending Approvals

Response:
To see all approvals (including resolved ones):

Get a Specific Approval

Key Fields in an Approval


Resolving Approvals

Approve

Approving a request allows the message to continue through the relay to the target agent.
What happens next:
  • The held message is forwarded to the target agent
  • The task resumes from where it was paused — callers polling tasks/get will see completed state with the full agent response
  • The relay_reason metadata is no longer present in the resolved response
  • The approval, resolution, and reviewer are recorded in the audit log

Reject

Rejecting a request stops the message from being forwarded. The task is cancelled.
What happens next:
  • The message is not forwarded
  • The associated task is cancelled — callers polling tasks/get will see canceled state with relay_reason: "HITL_REJECTED" in the metadata (including policy_name, policy_version, and policy_level if the hold was policy-triggered)
  • The rejection reason is recorded in the audit log

Policy Escalation vs Agent INPUT_REQUIRED

It’s important to understand the difference between these two flows:
When an agent returns INPUT_REQUIRED, the agent has already seen the message and is asking for more input. The relay’s built-in HITL middleware automatically intercepts this and creates an approval request — you don’t need to configure a policy for this path. It happens by default.

Response Metadata — relay_reason

When the relay masks a response due to HITL (or a timeout), it sets a relay_reason field in the response metadata. This tells API consumers why the relay has taken ownership of the task. The response metadata is a strongly-typed discriminated union — the shape of the metadata depends on the relay_reason value. Policy fields (policy_name, policy_version, policy_level) are included for HITL_HELD and HITL_REJECTED to give consumers context about which policy triggered the hold. These fields are nullable on HITL_REJECTED — they will be null if the original hold was agent-initiated rather than policy-triggered. policy_level indicates the scope at which the policy is bound: TENANT, AGENT, or SUBSCRIPTION. Example metadata for a policy-held response:
Example metadata for an agent-initiated hold:
For a TypeScript integration, use the @swarmd/channel-client lifecycle events to react to working, hitl-held, completed, rejected, failed, and canceled without implementing polling yourself. The raw Conversation API frontend tutorial documents the underlying aggregateState / relay_reason protocol, and the older JSON-RPC flow is documented separately at Frontend Integration (JSON-RPC — legacy).

Auditing HITL Decisions

Every HITL event is recorded in the audit log with specific audit types: Query HITL-related events:
To see the complete flow — trigger, hold, and resolution — use the trace endpoint with the correlationId from the approval:

Required Permissions

To manage HITL approvals, users need the following permissions (granted through group membership): The default Editor group includes both of these permissions. See the User Management tutorial for how to manage groups and permissions.

Next Steps

TypeScript Channel Client

Handle HITL transitions through typed channel lifecycle events.

Monitoring & Audit

Track all agent activity and HITL decisions in the audit log.