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.
The downstream agent returns task status INPUT_REQUIRED
Agent is uncertain, needs clarification, or is designed to ask for confirmation
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-initiatedINPUT_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.
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.
API
UI
curl -X POST https://api.swarmd.ai/relay/v1/policies \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $SWARMD_TOKEN" \ -d '{ "name": "Review Messages with SSNs", "description": "Escalate to human review when SSNs are detected", "config": { "type": "PRESIDIO_DETECTION", "enabledLegs": { "requestFromSource": true, "requestToSink": true, "responseFromSink": true, "responseToSource": true }, "entity": { "type": "US_SSN", "scoreThreshold": 0.7, "action": "HUMAN_REVIEW_REQUIRED" } } }'
Coming soon.
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.
Approving a request allows the message to continue through the relay to the target agent.
API
UI
curl -X POST https://api.swarmd.ai/relay/v1/approvals/APPROVAL_ID/resolve \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $SWARMD_TOKEN" \ -d '{ "action": "APPROVED", "message": "Verified — this is a test SSN for the demo environment" }'
Coming soon.
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
Rejecting a request stops the message from being forwarded. The task is cancelled.
API
UI
curl -X POST https://api.swarmd.ai/relay/v1/approvals/APPROVAL_ID/resolve \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $SWARMD_TOKEN" \ -d '{ "action": "REJECTED", "message": "Contains real PII — must not be sent to external agent" }'
Coming soon.
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)
It’s important to understand the difference between these two flows:
Policy Escalation
Agent INPUT_REQUIRED
Triggered by
A detection policy with HUMAN_REVIEW_REQUIRED action
Downstream agent returning INPUT_REQUIRED task status
When
During relay policy evaluation (on the matching leg)
After the agent has processed the message
Detection source
POLICY_ESCALATION
AGENT_INPUT_REQUIRED
Approval fields
policyName and matchedContent populated
policyName and matchedContent are null
Use case
Compliance, safety guardrails
Agent needs clarification or confirmation
On approve
Calls resumeTask() — the original held message is forwarded to the target agent
Calls resumeTask() — a confirmation response is sent to the agent
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.
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.
relay_reason
status.state
Meaning
Additional fields
TIMEOUT
working
Agent didn’t respond within the early-return timeout window
(none)
HITL_HELD
working
Held for human review by a detection policy
policy_name, policy_version, policy_level
HITL_HELD_AGENT_INPUT_REQUIRED
working
Agent explicitly requested human input (no policy involved)
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:
For full frontend integration details — including how to route UI behavior based on relay_reason, polling patterns, and decision flowcharts — see the Frontend Integration tutorial.