Adding human approval steps to agent workflows behind LiteLLM
Treat approval as an enforcement decision in the execution path, not a review after the fact. Gate actions by reversibility, hold the request outside the agent's own code, bind each approval to the actor and the exact tool call, deny by default on timeout or missing metadata, and record who requested, who approved, what was decided and what actually executed.
Design the approval flow
- 1
1. Trigger
Match the call against the declared approval class and the autonomous-action allowlist.
- 2
2. Hold
Pause the call and store a pending record keyed to the actor and the exact call and parameters.
- 3
3. Route with context
Send the request to the right authority with enough detail to decide, including the triggering condition and what the call will change.
- 4
4. Authenticate the approver
Identify the approver through your identity provider and confirm they hold authority for this action.
- 5
5. Check and consume
Validate the approval and consume it in one atomic step immediately before execution, so it cannot be reused.
- 6
6. Execute and record
Run the call, then write the outcome against the approval record.
Decide which actions need a human
Approving everything defeats the purpose. A useful starting point is an allowlist of actions the agent may take autonomously. Anything outside the allowlist requires explicit approval, as do high-impact or irreversible actions.
Reversibility is a practical gating criterion. Read-only inspection can run unattended. Externally reversible or irreversible changes, such as granting an IAM role or altering security-relevant configuration, should require approval. The class should be declared on the action itself by the team that owns the tool. If the agent infers its own risk class at run time, the control depends on the thing it is meant to constrain.
Content origin is a second trigger. Externally retrieved content should not be treated as instructions, so a high-impact action that follows untrusted tool output or retrieved text is a strong candidate for confirmation. Keep volume in mind. Frequent escalation leads to habitual approval, so set thresholds that reserve human attention for decisions that matter.
Classification is not permission. A label such as needs_human_approval says a person must be involved. It does not authorize the tool to run. Whether the actor may run the tool is a separate check, and both are enforced at execution.
Choose where the checkpoint sits
An agent behind a LiteLLM proxy produces two kinds of events worth intercepting: model requests and tool calls. A proxy is a natural chokepoint for model traffic, which makes it a reasonable place to catch high-risk requests. Tool calls are different. If an agent runtime invokes a tool directly, that call may never pass through the proxy. The checkpoint has to sit where the call is actually executed, or tool traffic has to be routed through it.
The principle is that authorization is enforced in an execution component outside the agent's context. A bare user_confirmed flag set by agent code proves nothing, because the same code that wants the action can set it. The component must verify that the approval belongs to the current actor and the exact tool call, is still valid, and has not already been consumed.
Before relying on proxy extension points such as callbacks, pre-call and post-call hooks or guardrail integrations, test one question directly: can the mechanism hold a request pending for minutes or hours, survive a restart, and resume or deny it correctly? If not, you must build the pending state yourself or put the checkpoint elsewhere.
Compare the three implementation patterns
Teams usually choose between approval code inside each agent, custom logic in proxy hooks and callbacks, and an external policy enforcement layer in the path. The comparison below describes design properties, not measured results. Latency in all three is dominated by the human wait, so the question is the overhead of the check itself and what happens when the check is unavailable.
- In-agent approval code: Bypass resistance: low, because the agent's own code decides whether approval happened. Consistency: varies by agent and team. Failure behaviour: set per implementation. Evidence: fragmented across applications, and rarely independent of the code being controlled.
- Proxy hooks and callbacks: Bypass resistance: good for traffic that crosses the proxy, none for calls that do not. Consistency: one implementation for all routed agents. Failure behaviour: you define pending state, timeouts and restart handling. Evidence: central, but you own the schema and its integrity.
- External enforcement in the path: Bypass resistance: strong when the checkpoint is where execution happens. Consistency: one policy applied across agents and tools. Failure behaviour: should fail closed by design and needs testing. Evidence: produced by the enforcement point itself, separate from agent code.
Define the evidence before you need it
An approval is only useful to an auditor if it shows what was approved and what executed, and whether the two match. A practical record contains the requester or acting agent identity, the approver identity, the decision, the timestamp, the exact tool call and parameters approved, and the action actually executed. The binding of approval to actor and exact call implies this set. It is a design inference, not a prescribed schema, so confirm the fields against your own control requirements.
Frameworks give direction rather than a template. As of November 2026, the EU AI Act text requires high-risk AI systems to be designed, including with appropriate human-machine interface tools, so that natural persons can effectively oversee them while in use. It says deployers shall assign oversight to people with the necessary competence, training and authority, and it requires a documented risk management system that addresses human oversight measures. Whether it applies to a given agent must be assessed separately. NIST guidance on human-in-the-loop triggers points the same way: define risk thresholds, route escalations to the correct authority, and supply enough information for review.
Treat approvers as controlled roles. Agents should operate under the same change-management controls applied to human administrators, with automated checks added.
Where Trussed fits, and what it does not cover
Trussed enforces policy in the execution path across models, agents, tools and MCP servers. Policy can allow, redact, block, rate limit or escalate an interaction or tool call for human approval, and enforcement generates audit-ready evidence that is mapped to frameworks including HIPAA, NYDFS, the EU AI Act and NIST. The decision is enforced at runtime, not reviewed after the fact. That corresponds to the third pattern above: one policy applied consistently, outside agent code, with evidence produced by the enforcement point.
The scope is individual interactions and tool calls. Trussed does not provide transaction-level governance across tasks and agents, and it does not trace an agentic workflow end to end. If you need to approve a business outcome that spans several agents, that decision has to be designed separately. The checkpoint described here governs each call within it.
The design in this guide stands on its own. Whether you build it in hooks or enforce it externally, test the same properties: no agent self-assertion, atomic consumption, default deny and complete evidence.
Approval checkpoint in the request path
Classify
Approval class is declared on the action, not inferred by the agent.
Hold
The call pauses in a component outside the agent's context.
Decide
An authenticated approver sees the exact call and decides.
Execute or deny
An approval is consumed once. Timeouts default to deny.
Record
Requester, approver, decision, time and executed action are retained.
Put the approval checkpoint in the execution path
See how policy enforcement escalates individual tool calls for human approval and produces audit-ready evidence for a regulated enterprise.
Request a Demo