Laravel Magazine
Laravel AI SDK Ships a Human-in-the-Loop API for Approving Agent Tool Calls

Laravel AI SDK Ships a Human-in-the-Loop API for Approving Agent Tool Calls

Eric Van Johnson ·

One of the framework updates announced at Laracon US 2026 addresses a problem anyone who has shipped an AI agent in production already knows about: once an agent starts calling tools, there's traditionally been no way to step in before it acts. The Laravel AI SDK's new human-in-the-loop (HITL) API changes that by letting you intercept specific tool calls and require a human decision before the agent proceeds.

The problem it solves

An agent that can, say, issue refunds, delete records, or send emails on a user's behalf is genuinely useful, and genuinely risky if it's running unattended. Until now, the only way to add a safety net was to build your own approval layer around the SDK by hand: intercepting tool execution, persisting pending calls somewhere, and wiring up a UI to approve them. The new HITL API moves that pattern into the framework itself.

How it works

You mark a tool as requiring approval, and the agent pauses instead of executing it directly:

use Laravel\Ai\Agent;
use Laravel\Ai\Attributes\RequiresApproval;

class IssueRefundTool
{
    #[RequiresApproval]
    public function __invoke(string $orderId, float $amount): string
    {
        Order::findOrFail($orderId)->refund($amount);

        return "Refunded {$amount} for order {$orderId}.";
    }
}

When the agent decides to call a tool marked with #[RequiresApproval], execution pauses and the pending call is handed back to your application instead of running immediately:

$run = $agent->run($conversation);

if ($run->isPendingApproval()) {
    foreach ($run->pendingToolCalls() as $call) {
        // Surface $call->tool, $call->arguments to a human reviewer
    }
}

Approve, deny, or modify

A reviewer isn't limited to a binary yes or no. The API supports adjusting the arguments before the tool actually runs, which matters for something like a refund amount a human might want to reduce rather than reject outright:

// Approve as-is
$run->approve($call->id);

// Deny, with a reason the agent can see and react to
$run->deny($call->id, reason: 'Refund exceeds policy limit for this order.');

// Approve with modified arguments
$run->approve($call->id, arguments: ['orderId' => $call->arguments['orderId'], 'amount' => 25.00]);

Once resolved, the agent's run continues from where it left off, incorporating the reviewer's decision into its next step rather than starting over.

Why this matters for teams shipping agents

Plenty of teams building on the Laravel AI SDK have been rolling their own approval layer already, usually as a queued job with a database flag and a custom admin panel. Having this as a first-party API means that pattern is now consistent across the ecosystem, and packages built on top of the AI SDK can rely on the same approval mechanics instead of each inventing their own.

If you're building anything that lets an agent act on customer data, billing, or infrastructure, this is worth adopting even if your current approval flow works fine, since it puts you on a supported path as the SDK continues to evolve rather than maintaining a parallel implementation yourself.

Stay Updated

Subscribe to our newsletter

Get latest news, tutorials, community articles and podcast episodes delivered to your inbox.

Weekly articles
We send a new issue of the newsletter every week on Friday.
No spam
We'll never share your email address and you can opt out at any time.