diff --git a/ai-sdk.md b/ai-sdk.md index 70cd2a8ee3..04d2887172 100644 --- a/ai-sdk.md +++ b/ai-sdk.md @@ -1,44 +1,58 @@ # Laravel AI SDK -- [Introduction](#introduction) -- [Installation](#installation) +- [Laravel AI SDK](#laravel-ai-sdk) + - [Introduction](#introduction) + - [Installation](#installation) - [Configuration](#configuration) - [Custom Base URLs](#custom-base-urls) - [Provider Support](#provider-support) -- [Agents](#agents) + - [Agents](#agents) - [Prompting](#prompting) - [Conversation Context](#conversation-context) + - [Remembering Conversations](#remembering-conversations) - [Structured Output](#structured-output) - [Attachments](#attachments) - [Streaming](#streaming) + - [Streaming Using the Vercel AI SDK Protocol](#streaming-using-the-vercel-ai-sdk-protocol) - [Broadcasting](#broadcasting) - [Queueing](#queueing) - [Tools](#tools) + - [Similarity Search](#similarity-search) + - [Tool Approval](#tool-approval) + - [Conditional Approval](#conditional-approval) + - [Handling Pending Approval Responses](#handling-pending-approval-responses) + - [Approving and Rejecting Tool Calls](#approving-and-rejecting-tool-calls) + - [Events](#events) - [Provider Tools](#provider-tools) + - [Web Search](#web-search) + - [Web Fetch](#web-fetch) + - [File Search](#file-search) - [Middleware](#middleware) - [Anonymous Agents](#anonymous-agents) - [Agent Configuration](#agent-configuration) -- [Images](#images) -- [Audio (TTS)](#audio) -- [Transcription (STT)](#transcription) -- [Embeddings](#embeddings) + - [Images](#images) + - [Audio](#audio) + - [Transcriptions](#transcriptions) + - [Embeddings](#embeddings) - [Querying Embeddings](#querying-embeddings) - [Caching Embeddings](#caching-embeddings) -- [Reranking](#reranking) -- [Files](#files) -- [Vector Stores](#vector-stores) + - [Reranking](#reranking) + - [Reranking Collections](#reranking-collections) + - [Files](#files) + - [Using Stored Files in Conversations](#using-stored-files-in-conversations) + - [Vector Stores](#vector-stores) - [Adding Files to Stores](#adding-files-to-stores) -- [Failover](#failover) -- [Testing](#testing) - - [Agents](#testing-agents) - - [Images](#testing-images) - - [Audio](#testing-audio) - - [Transcriptions](#testing-transcriptions) - - [Embeddings](#testing-embeddings) - - [Reranking](#testing-reranking) - - [Files](#testing-files) - - [Vector Stores](#testing-vector-stores) -- [Events](#events) + - [Failover](#failover) + - [Testing](#testing) + - [Agents](#agents-1) + - [Images](#images-1) + - [Audio](#audio-1) + - [Transcriptions](#transcriptions-1) + - [Embeddings](#embeddings-1) + - [Reranking](#reranking-1) + - [Files](#files-1) + - [Vector Stores](#vector-stores-1) + - [Events](#events-1) ## Introduction @@ -641,6 +655,169 @@ SimilaritySearch::usingModel(Document::class, 'embedding') ->withDescription('Search the knowledge base for relevant articles.'), ``` + +#### Tool Approval + +Sometimes tools perform actions with real-world consequences — deleting files, processing payments, or sending messages on behalf of a user. In these cases, you may want to require human approval before a tool is executed. To indicate that a tool requires approval, define a `requiresApproval` method on the tool that returns `true`: + +```php + $schema->integer()->description('The user ID')->required(), + ]; + } +} +``` + +When the AI model calls a tool that requires approval, the agent will not execute the tool. Instead, the `prompt` method will return a `PendingApprovalResponse` instance containing the pending tool call details. + + +##### Conditional Approval + +The `requiresApproval` method receives no arguments, but since it is a regular method on your tool class, you may use any application logic to determine whether approval is necessary: + +```php +/** + * Determine if the tool requires approval before execution. + */ +public function requiresApproval(): bool +{ + return ! auth()->user()->isAdmin(); +} +``` + + +##### Handling Pending Approval Responses + +To handle approval responses, your agent should use the `HasApprovalFlow` trait, which provides `approve` and `reject` methods: + +```php +prompt('Delete all files for user 42'); + +if ($response instanceof PendingApprovalResponse) { + $pendingToolCall = $response->pendingToolCalls->first(); + + // Store the pending tool call for later (session, cache, etc.)... + session(['pending_tool' => $pendingToolCall]); + + // Present the pending tool call to the user for approval... + return response()->json([ + 'status' => 'pending_approval', + 'tool' => $pendingToolCall->toolName(), + 'arguments' => $pendingToolCall->arguments, + ]); +} + +return response()->json(['message' => $response->text]); +``` + + +##### Approving and Rejecting Tool Calls + +Once the user has made a decision, you may approve or reject the pending tool call. The `approve` method will execute the tool and re-prompt the agent with the tool's result: + +```php +$pendingToolCall = session()->pull('pending_tool'); + +$response = (new FileManager)->approve($pendingToolCall); + +return response()->json(['message' => $response->text]); +``` + +The `reject` method accepts an optional reason that will be communicated to the agent: + +```php +$response = (new FileManager)->reject($pendingToolCall, 'User declined the operation'); +``` + +> **Note:** Both `approve` and `reject` re-prompt the agent, which results in an additional API call to the AI provider. The tool's result (or rejection reason) is provided as context in the new prompt. + + +##### Events + +The following events are dispatched during the tool approval lifecycle: + +- `ToolApprovalRequested`: Dispatched when a tool requiring approval is intercepted at prompt time. +- `ToolApproved`: Dispatched when a pending tool call is approved, before the tool is executed. +- `ToolRejected`: Dispatched when a pending tool call is rejected. + +These events may be used to log approval decisions, send notifications, or implement audit trails: + +```php +use Laravel\Ai\Events\ToolApprovalRequested; + +Event::listen(ToolApprovalRequested::class, function ($event) { + Log::info('Tool approval requested', [ + 'tool' => $event->pendingToolCall->toolName(), + 'arguments' => $event->arguments, + ]); +}); +``` + ### Provider Tools @@ -1995,7 +2172,10 @@ The Laravel AI SDK dispatches a variety of [events](/docs/{{version}}/events), i - `StoreCreated` - `StoringFile` - `StreamingAgent` +- `ToolApprovalRequested` +- `ToolApproved` - `ToolInvoked` +- `ToolRejected` - `TranscriptionGenerated` You can listen to any of these events to log or store AI SDK usage information.