Description
Adds a ready-to-use HumanInTheLoop intervention handler that pauses agent execution before tool calls to request human approval, using the native interrupt system for pause/resume semantics.
This is the first vended intervention — a concrete, configurable InterventionHandler implementation shipped with the SDK, following the same pattern as vended plugins (ContextOffloader, Skills).
Motivation
Human-in-the-loop approval is one of the most common intervention use cases. Rather than requiring every user to implement their own handler, the SDK should provide a battle-tested implementation that covers the standard patterns (approve all, allowlist, denylist).
Dependencies
API
import { Agent, InterruptResponseContent } from '@strands-agents/sdk'
import { HumanInTheLoop } from '@strands-agents/sdk/vended-interventions/hitl'
// Mode 1: Require approval for ALL tool calls (default)
const agent = new Agent({
tools: [deleteTool, readTool, sendEmail],
interventions: [new HumanInTheLoop()],
})
// Mode 2: Allow specific safe tools, require approval for everything else
const agent = new Agent({
interventions: [new HumanInTheLoop({ allowedTools: ['readFile', 'listDir'] })],
})
// Mode 3: Only require approval for specific dangerous tools
const agent = new Agent({
interventions: [new HumanInTheLoop({ deniedTools: ['deleteFile', 'sendEmail'] })],
})
// Usage: agent pauses with stopReason: 'interrupt'
const result = await agent.invoke('Delete the production database')
// result.stopReason === 'interrupt'
// result.interrupts[0].reason includes tool name + input for display to user
// Resume with approval or denial
const finalResult = await agent.invoke([
new InterruptResponseContent({
interruptId: result.interrupts[0].id,
response: 'yes', // or true, 'approve', 'approved', { approved: true }
}),
])
Approval response format
The handler accepts any JSONValue response and interprets it as approved if it matches:
true
'yes', 'approve', 'approved' (case-insensitive)
{ approved: true }
Any other value (including false, 'no', null, arbitrary strings) is treated as denial.
Implementation details
- Lives at
strands-ts/src/vended-interventions/hitl/
- Exported via subpath:
@strands-agents/sdk/vended-interventions/hitl
- Overrides
beforeToolCall only — uses event.interrupt() for native pause/resume
- On denial, returns
deny() which sets event.cancel and prevents tool execution
- Interrupt reason includes the tool name and serialized input so the human has context
Testing
- 22 unit tests covering: config validation, all three modes, approval response parsing (10 response shapes), interrupt metadata, full agent integration (interrupt → resume → execute/deny)
Description
Adds a ready-to-use
HumanInTheLoopintervention handler that pauses agent execution before tool calls to request human approval, using the native interrupt system for pause/resume semantics.This is the first vended intervention — a concrete, configurable
InterventionHandlerimplementation shipped with the SDK, following the same pattern as vended plugins (ContextOffloader,Skills).Motivation
Human-in-the-loop approval is one of the most common intervention use cases. Rather than requiring every user to implement their own handler, the SDK should provide a battle-tested implementation that covers the standard patterns (approve all, allowlist, denylist).
Dependencies
API
Approval response format
The handler accepts any
JSONValueresponse and interprets it as approved if it matches:true'yes','approve','approved'(case-insensitive){ approved: true }Any other value (including
false,'no',null, arbitrary strings) is treated as denial.Implementation details
strands-ts/src/vended-interventions/hitl/@strands-agents/sdk/vended-interventions/hitlbeforeToolCallonly — usesevent.interrupt()for native pause/resumedeny()which setsevent.canceland prevents tool executionTesting