Skip to main content
Some tools you don’t want the model running unsupervised — sending email, executing code, charging cards. This pattern wires an Approver so the agent loop pauses before specified tools run, surfaces the pending call to a human, and only proceeds when they say yes.

What you’ll build

An agent with two tools — one safe (get_balance), one sensitive (transfer_funds). The safe tool runs without intervention; the sensitive one prompts for approval at a CLI before dispatching.

How it works

  • with_approver(...) plus the HumanInTheLoop middleware tap into the agent loop’s tool-dispatch step.
  • Your Approver decides per call. Approve, reject (with a reason the model sees), or edit (rewrite the args before running).
  • Rejection becomes a tool message. The agent sees “the tool was not approved” and can apologize, ask for clarification, or try a different approach.

The approver

The agent

How it works

  • The approver runs before dispatch. with_approver(...) wraps every registered tool in an ApprovalGatedTool. When the agent’s dispatcher tries to run the tool, the wrapper consults the approver first.
  • A Reject decision short-circuits the tool, returning the rejection reason as the tool’s output — the agent sees “rejected by operator” and can apologize, retry, or take a different path.
  • Edit lets the human fix the model’s args without rejecting. Useful when the model picked the right tool but the wrong amount or recipient.
  • Arc<dyn Approver> is the shape passed in — the builder takes ownership and uses the same instance for every gated tool, so the approver can hold state (a counter, a queue handle, an audit log) without divergence.

Production approver

A CLI approver is a starting point. In production you’d swap in: The trait is async, so you can wait on a long-lived signal. Just don’t block the agent’s hot path — if approval might take minutes, push to a queue and resume from a checkpoint.

Pair with checkpoints

For long-running approvals (the human is asleep), persist the agent’s state and resume later. Use a Checkpointer and rebuild the agent from state on the resume side. See Graph workflows → Checkpointing for the time-travel surface.

See also

Human-in-the-loop

Approver, Decision, graph interrupts.

Tools

Define the tools being gated.

Checkpointing

Pause across processes.