Laravel AI SDK v0.10.0 Brings Human-in-the-Loop Control to Agents
Announced at Laracon US 2026 in Boston and shipped on July 21, Laravel AI SDK v0.10.0 introduces a human-in-the-loop (HITL) API for AI agents. Before this release, an agent that started executing tools ran straight through to completion with no way to intervene. That is acceptable for read-only operations, but it is a serious concern when a tool can delete a file, issue a refund, or send an email to a customer.
The new API lets you intercept specific tool calls, pause the agent, and require a human decision — approve, reject, or modify the arguments — before execution resumes.
Marking a Tool as Approvable
Approval is opt-in per tool. Implement the Approvable contract and add the InteractsWithApprovals trait:
use Laravel\Ai\Concerns\InteractsWithApprovals;
use Laravel\Ai\Contracts\Approvable;
use Laravel\Ai\Contracts\Tool;
class IssueRefund implements Approvable, Tool
{
use InteractsWithApprovals;
public function handle(Request $request): Stringable|string
{
$order = Order::findOrFail($request['order_id']);
$order->refund($request['amount']);
return "Refunded {$request['amount']} on order {$order->id}.";
}
}
When blanket approval is too broad, define a needsApproval method that inspects the incoming arguments and returns a boolean or an Approval instance with a reason:
use Laravel\Ai\Approvals\Approval;
protected function needsApproval(Request $request): Approval|bool
{
return $request['amount'] <= 2000
? false
: Approval::required('Refunds over $20 need a manager.');
}
You can also override approval requirements at the agent level using withoutApproval() and requireApproval().
Handling Pending Approvals
When the model calls an approvable tool, the agent pauses and surfaces the pending calls on the response object:
$response = (new SupportAgent)
->forUser($user)
->prompt('Refund the damaged headphones on order 4192.');
if ($response->hasPendingApprovals()) {
foreach ($response->pendingApprovals as $approval) {
// $approval->id, ->tool, ->arguments, ->reason
}
}
To resume, continue the conversation and pass a Decisions instance keyed by tool call ID:
use Laravel\Ai\Approvals\Decision;
use Laravel\Ai\Approvals\Decisions;
$response = (new SupportAgent)
->continue($conversationId, as: $user)
->prompt(Decisions::from([
'call_abc' => Decision::approve(),
'call_ghi' => Decision::reject('Outside the return window.'),
]));
Every pending call must receive a decision, or an ApprovalMismatchException is thrown. Use approveRemaining() or rejectRemaining() to set a bulk default for any calls not explicitly addressed.
Key Details to Know Before Upgrading
- The agent must implement
Conversationalwith persisted history (viaRemembersConversations) — there is nothing to resume otherwise. - HITL works with
prompt,stream,queue,broadcast,broadcastNow, andbroadcastOnQueue. - During streaming, a pause arrives as a
tool_approval_requestevent; queued agents dispatch aToolApprovalRequestedevent. - Pauses are per call, not per step — tools in the same step that do not require approval run immediately. Keep side effects idempotent using
$request->toolCallId(). - If generation fails after an approval result has already been stored, resume with a plain text prompt rather than resubmitting decisions.
Breaking Changes in v0.10.0
- A new nullable
approval_statecolumn is added to the conversation messages table. - Custom
ConversationStoreimplementations must add astoreApprovalResults()method.
Takeaways
- Approval is opt-in per tool via the
Approvablecontract andInteractsWithApprovalstrait. needsApproval()lets you apply conditional logic based on tool arguments.- Pending approvals are surfaced on the response and resumed via a
Decisionsinstance. - Streaming, broadcasting, and queued agents all support the HITL pause/resume flow.
- Upgrading requires a migration for the new
approval_statecolumn and astoreApprovalResults()method on custom stores.
Full documentation is available in the Laravel AI SDK docs. Source: Laravel News