strands.vended_interventions.hitl.hitl
Human-in-the-loop intervention handler.
Pauses agent execution before tool calls so a human can approve or deny them.
AskCallback
Section titled “AskCallback”@runtime_checkableclass AskCallback(Protocol)Defined in: src/strands/vended_interventions/hitl/hitl.py:22
Typed contract for an ask callback: prompt a human and return their response.
May be sync or async (an async impl lets the agent keep serving its event loop while waiting). Documents the expected signature for type-checkers/IDEs; it is intentionally not exported — customers just pass a function.
__call__
Section titled “__call__”def __call__(prompt: str, **kwargs: Any) -> Any | Awaitable[Any]Defined in: src/strands/vended_interventions/hitl/hitl.py:30
Prompt the human and return their response (directly or as an awaitable).
EvaluateCallback
Section titled “EvaluateCallback”@runtime_checkableclass EvaluateCallback(Protocol)Defined in: src/strands/vended_interventions/hitl/hitl.py:36
Typed contract for an evaluate/evaluate_trust callback.
Decides whether a response approves (or trusts) a tool call. Documents the expected signature for type-checkers/IDEs; intentionally not exported — customers just pass a function.
__call__
Section titled “__call__”def __call__(response: Any, **kwargs: Any) -> boolDefined in: src/strands/vended_interventions/hitl/hitl.py:44
Return whether the response approves (or trusts) the pending tool call.
HumanInTheLoop
Section titled “HumanInTheLoop”class HumanInTheLoop(InterventionHandler)Defined in: src/strands/vended_interventions/hitl/hitl.py:83
Human-in-the-loop intervention handler that pauses agent execution before tool calls.
By default, ALL tools require approval and the agent pauses via interrupt/resume.
Use allowed_tools to allow-list tools that run freely, and ask to provide
inline prompting (CLI, custom UI).
Example:
from strands import Agentfrom strands.vended_interventions.hitl import HumanInTheLoop
# All tools require approval, agent pauses via interrupt (default)agent = Agent(interventions=[HumanInTheLoop()])
# read_file runs freely, everything else pauses for approvalagent = Agent(interventions=[HumanInTheLoop(allowed_tools=["read_file"])])
# CLI mode - prompts in terminal inlineagent = Agent(interventions=[HumanInTheLoop(ask="stdio")])
# Custom UI - provide your own prompt functionasync def slack_ask(prompt: str) -> str: return await slack_dm(user_id, prompt)
agent = Agent(interventions=[HumanInTheLoop(ask=slack_ask)])__init__
Section titled “__init__”def __init__(*, allowed_tools: list[str] | None = None, enable_trust: bool = False, evaluate_trust: EvaluateCallback | None = None, evaluate: EvaluateCallback | None = None, ask: AskCallback | Literal["stdio"] | None = None) -> NoneDefined in: src/strands/vended_interventions/hitl/hitl.py:114
Initialize the handler.
Arguments:
allowed_tools- Tools that can execute WITHOUT human approval. All other tools require approval. Use"*"to allow all tools. Prefix with!to exclude specific tools from"*"(they still require approval). For example,["read_file", "list_dir"]lets only those two run freely, while["*", "!delete_file"]lets everything run freely exceptdelete_file.enable_trust- When True, trust responses approve the tool AND remember it inagent.statefor the rest of the session (won’t ask again). Works in both interrupt/resume and inlineaskmodes. Negated tools (!tool) cannot be trusted. Defaults to False.evaluate_trust- Custom trust response validator. Defaults to accepting"t"/"trust"(case-insensitive). When this returns True, the tool is approved AND trusted for the session. Only evaluated whenenable_trustis True.evaluate- Custom approval response validator. Defaults to acceptingTrue,"y"/"yes"(case-insensitive).ask- Controls how the human’s response is collected. Omitted (default): uses interrupt/resume - agent pauses, caller resumes with response."stdio"- prompts via CLI stdin. Agent blocks inline until the human responds. Note that stdio mode runs a blockinginput()in a worker thread that cannot be cancelled, so it is intended for interactive CLI use rather than runs that may be cancelled mid-prompt. Custom callable: your own (optionally async) prompt logic (Slack, web UI, etc.). Agent blocks inline. A customaskshould return a concrete response; returningNone(e.g. a dismissed dialog) is treated as an explicit deny. If it raises, the exception propagates and aborts the run(fail-closed)- catch and return a deny value inside your callback if you prefer to proceed on error.
Notes:
name is a fixed class attribute, so at most one HumanInTheLoop can be
registered per agent; layering two policies requires subclassing to rename.
before_tool_call
Section titled “before_tool_call”async def before_tool_call(event: BeforeToolCallEvent, **kwargs: Any) -> InterventionActionDefined in: src/strands/vended_interventions/hitl/hitl.py:171
Request human approval before executing a tool that is not allow-listed or trusted.
Implemented as async so the inline ask path can await a human’s
response (e.g. an HTTP round-trip to a Slack/web UI) without blocking the
agent’s event loop. When no ask is configured this returns a Confirm
that pauses the agent via interrupt instead.
Arguments:
event- The tool call event under evaluation.**kwargs- Additional keyword arguments for future extensibility.
Returns:
Proceed if the tool is allow-listed, trusted, or approved inline;
otherwise a Confirm action (pausing via interrupt when no ask is set).