alidaaer / laravel-ai-agent
Give your Laravel app a brain, safely. Build AI Agents that can execute real actions in your application.
Requires
- php: ^8.2
- illuminate/cache: ^10.0|^11.0|^12.0
- illuminate/http: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
- illuminate/validation: ^10.0|^11.0|^12.0
Requires (Dev)
- orchestra/testbench: ^8.0|^9.0|^10.0
- phpunit/phpunit: ^10.0|^11.0
This package is auto-updated.
Last update: 2026-03-22 23:01:56 UTC
README
Laravel AI Agent
π§ Give your Laravel app a brain, safely.
Build AI Agents that execute real actions in your Laravel application with minimal code.
Laravel AI Agent is the ultimate Laravel AI package for building intelligent automation. Transform your Laravel app with AI-powered agents that can understand natural language and execute PHP methods directly. Perfect for Laravel GPT integration, AI automation, and function calling. This Laravel AI solution works with OpenAI, Anthropic Claude, Gemini, and more - making it the most flexible AI assistant for Laravel.
β¨ Why Laravel AI Agent?
| Feature | Description |
|---|---|
| π Zero Boilerplate | Turn any method into an AI tool with a single attribute |
| π§ Smart Auto-Inference | Auto-generates descriptions and infers types from parameter names |
| π¬ Chat Widget | Beautiful, customizable Web Component - just drop it in! |
| π Multi-Provider | OpenAI, Anthropic Claude, Google Gemini, DeepSeek, OpenRouter |
| πΎ Memory | AI-powered summarization with smart pointer tracking β session or database |
| π Markdown Responses | Tables, formatting, and rich text in chat |
| β‘ Smart Returns | view(), redirect(), Model β AI understands them all |
| π€ Multi-Agent | Class-based agents with per-method access control |
| π‘οΈ Security Built-in | Prompt injection detection, XSS prevention, secret redaction |
| π― Laravel Native | Feels like part of the framework |
π¦ Installation
composer require alidaaer/laravel-ai-agent php artisan vendor:publish --tag=ai-agent-config
Add to your .env:
# AI Driver (openai, anthropic, gemini, deepseek, openrouter) AI_AGENT_DRIVER=openai AI_AGENT_API_KEY=sk-... AI_AGENT_MODEL=gpt-4o-mini
Run migrations for conversation history:
php artisan migrate
π Quick Start
1. Add the Chat Widget β‘
Drop it into any Blade view β routes are auto-registered!
@aiAgentWidget <script src="/ai-agent/widget.js"></script>
Open the page, click the bubble, start talking. You already have a working AI chatbot! π
All widget settings (theme, language, position, etc.) are read from config/ai-agent.php:
'widget' => [ 'theme' => 'dark', 'rtl' => false, 'primary_color' => '#6366f1', 'position' => 'bottom-right', 'system_prompt' => 'You are a helpful shop assistant.', ],
π‘ The
system_promptis set in config (not HTML) so it stays hidden from the client.
2. Give AI Your Tools (Zero-Config!)
use LaravelAIAgent\Attributes\AsAITool; class ProductService { #[AsAITool] // Description auto-generated: "List products" β¨ public function listProducts(): array { return Product::all()->toArray(); } #[AsAITool] // Types inferred: $priceβnumber, $stockβinteger public function addProduct(string $name, float $price, int $stock = 0): array { return Product::create(compact('name', 'price', 'stock'))->toArray(); } }
Place it anywhere in app/ β the package auto-discovers all #[AsAITool] methods. Now say "Add a product called iPhone for $999" and it actually does it! π
π€ Need custom agents? Create dedicated agents with
php artisan make:agentβ see Multi-Agent System.
π¬ Chat Widget Component
A beautiful, drop-in Web Component for AI chat β with conversations, i18n, and stop button built-in.
Full-Featured Example
{{-- Reads all settings from config/ai-agent.php --}} @aiAgentWidget <script src="/ai-agent/widget.js"></script>
Or use the PHP helper directly with overrides:
{!! \LaravelAIAgent\Widget::render(['theme' => 'light', 'lang' => 'ar']) !!} <script src="/ai-agent/widget.js"></script>
All Options
| Attribute | Description | Default |
|---|---|---|
endpoint |
Chat API URL | Required |
stream |
Enable SSE streaming (boolean) | β |
history-endpoint |
Load conversation history + conversations sidebar | β |
persist-messages |
Keep messages across page reloads (boolean) | β |
theme |
light or dark |
dark |
lang |
Language: en, ar, fr, es, zh |
en |
rtl |
Right-to-left mode (boolean) | Auto for ar |
title |
Header title | AI Assistant |
subtitle |
Header subtitle | β |
welcome-message |
First bot message | β |
placeholder |
Input placeholder | Type your message... |
primary-color |
Theme color | #6366f1 |
position |
bottom-right, bottom-left, top-right, top-left |
bottom-right |
width |
Widget width | 400px |
height |
Widget height | 600px |
button-icon |
Floating button icon (URL or emoji) | π¬ |
button-size |
Floating button size | 56px |
Features
- β SSE Streaming β Real-time streaming with tool execution progress
- β Markdown Support β Tables, bold, code blocks with copy button, lists
- β Voice Input β Built-in Web Speech API microphone button
- β i18n β 5 languages built-in (EN, AR, FR, ES, ZH)
- β RTL Support β Auto-detected for Arabic, Hebrew, Farsi
- β Stop Button β Cancel AI responses mid-generation
- β Conversations Sidebar β Switch between past conversations (isolated per agent)
- β Keyboard Shortcuts β Escape to close, Enter to send, Shift+Enter for new line
- β Mobile Responsive β Full-screen on mobile
- β No Dependencies β Pure Web Component
π§ Chat API
Routes are auto-registered β no setup needed! The widget works out of the box with:
POST /ai-agent/chat β General chat
GET /ai-agent/history β Conversation history
GET /ai-agent/conversations β List conversations
Need a custom endpoint? Easy:
// routes/api.php Route::post('/my-chat', function () { $response = Agent::conversation(request('conversation_id')) ->system('You are a helpful shop assistant') ->tools([ProductService::class]) ->chat(request('message')); return response()->json(['response' => $response]); });
π οΈ Creating Tools
Zero-Config (Recommended)
#[AsAITool] // Description: "List Products" (from method name) public function listProducts(): array { } #[AsAITool] // Description: "Add Product" public function addProduct(string $name, float $price): array { }
With Custom Description
#[AsAITool('Search for products by name or category')] public function search(string $query): array { }
With Custom Parameters
The package auto-discovers parameters from type hints. But if your method uses Request or you want more control, define them manually with name:type syntax:
#[AsAITool(
description: 'Update product details',
params: [
'id:integer' => 'Product ID to update',
'name' => 'New product name', // type auto-inferred as string
'price:number' => 'New price in USD',
]
)]
public function updateProduct(Request $request): array
{
$product = Product::findOrFail($request->input('id'));
$product->update($request->only(['name', 'price']));
return ['success' => true, 'product' => $product->toArray()];
}
Supported types: string, integer, number, boolean, array. Without :type, the type is inferred from the parameter name (id β integer, price β number).
π‘ When to use
params? Only when auto-discovery isn't enough β e.g., dynamicRequestinputs, or when you want custom descriptions for the AI.
Smart Type Inference
No type hints? We infer from names:
| Parameter Name | Inferred Type |
|---|---|
$id, $productId, $userId |
integer |
$price, $total, $amount |
number |
$isActive, $hasItems, $enabled |
boolean |
$items, $products, $users |
array |
| Other | string |
β‘ Smart Return Handling
Use your existing methods as AI tools β no refactoring needed.
The agent automatically understands any return type: view(), redirect(), Model, Collection, JsonResponse, and even catches exceptions and validation errors gracefully.
Zero-Config β It Just Works
#[AsAITool] public function showProduct(int $id) { return view('product.show', ['product' => Product::findOrFail($id)]); // AI receives: {"product": {"id": 1, "name": "iPhone", "price": 999}} β¨ } #[AsAITool] public function activateProduct(int $id) { Product::findOrFail($id)->update(['is_active' => true]); return redirect()->back()->with('message', 'Product activated!'); // AI receives: {"message": "Product activated!"} β¨ }
Exceptions & Validation β Handled Automatically
#[AsAITool] public function createProduct(string $name, float $price) { $validator = Validator::make(compact('name', 'price'), [ 'name' => 'required|min:3', 'price' => 'required|numeric|min:0.01', ]); if ($validator->fails()) throw new ValidationException($validator); // AI tells the user: "Product name must be at least 3 characters" π‘οΈ return Product::create(compact('name', 'price'))->toArray(); }
isAICall() β Full Control When You Need It
Customize responses for AI vs Web with a single helper:
#[AsAITool] public function listProducts() { $products = Product::all(); if (isAICall()) { return ['count' => $products->count(), 'products' => $products->toArray()]; } return view('products.index', compact('products')); }
One method, two audiences. Web users get a Blade view, AI gets structured data.
| Return Type | What AI Receives |
|---|---|
view('...', $data) |
The $data variables directly |
redirect()->with('message', '...') |
{"message": "..."} |
Eloquent Model |
model->toArray() |
Collection |
collection->toArray() |
JsonResponse |
The JSON data |
ValidationException |
Error messages in user's language |
Any Exception |
Error message for AI to report |
π Providers
// OpenAI (default) Agent::driver('openai')->chat("Hello"); // Google Gemini Agent::driver('gemini')->chat("Hello"); // Anthropic Claude Agent::driver('anthropic')->chat("Hello"); // OpenRouter (100+ models via single API) Agent::driver('openrouter')->model('anthropic/claude-3.5-sonnet')->chat("Hello"); // Specific model override Agent::driver('openai')->model('gpt-4o')->chat("Hello");
π€ Multi-Agent System
Create dedicated agent classes with isolated tools, permissions, and conversations.
1. Create an Agent
php artisan make:agent ShopAgent php artisan make:agent AdminAgent
This generates a class in app/AI/Agents/ and auto-registers it in config/ai-agent.php.
// app/AI/Agents/ShopAgent.php class ShopAgent extends BaseAgent { public function instructions(): string { return 'You are a friendly shop assistant. Help customers browse and order.'; } public function tools(): array { return [\App\Services\ShopService::class]; } // Optional: customize driver, model, middleware, widget... // public function driver(): ?string { return 'openai'; } // public function model(): ?string { return 'gpt-4o-mini'; } // public function routeMiddleware(): array { return ['web', 'auth']; } }
2. Scope Tools Per Agent
Use class references for IDE autocompletion and refactor safety:
use App\AI\Agents\AdminAgent; class OrderService { #[AsAITool] // π All agents see this public function listOrders(): array { /* ... */ } #[AsAITool(agents: [AdminAgent::class])] // π Admin only public function deleteOrder(int $id) { /* ... */ } #[AsAITool(agents: [AdminAgent::class])] // π Admin only public function advancedStats() { /* ... */ } }
Rule: No agents param = available to all agents. Explicit list = restricted.
3. Auto-Generated Endpoints
Each agent gets its own isolated routes β automatically:
POST /ai-agent/shop/chat β Chat with ShopAgent
POST /ai-agent/shop/chat-stream β SSE streaming chat
GET /ai-agent/shop/conversations β List ShopAgent conversations only
GET /ai-agent/shop/history β Conversation history
DELETE /ai-agent/shop/history β Clear conversation
POST /ai-agent/admin/chat β Chat with AdminAgent (sees deleteOrder, advancedStats)
GET /ai-agent/admin/conversations β List AdminAgent conversations only
Conversations are isolated per agent β each agent sees only its own conversation history.
4. Add Widget to Blade
Each agent renders its own fully-configured widget:
// In any Blade view {!! \App\AI\Agents\ShopAgent::widget() !!} {!! \App\AI\Agents\AdminAgent::widget() !!} <script src="/ai-agent/widget.js"></script>
Each widget automatically uses the correct endpoints, theme, language, and position defined in the agent's widgetConfig().
5. Customize Widget Appearance
class AdminAgent extends BaseAgent { public function widgetConfig(): array { return [ 'title' => 'Admin AI', 'theme' => 'light', 'lang' => 'ar', 'primary_color' => '#ef4444', 'position' => 'bottom-left', ]; } }
6. Mobile / API Usage
// Flutter example final response = await http.post( Uri.parse('https://yourapp.com/ai-agent/shop/chat'), body: {'message': 'Show my orders', 'conversation_id': conversationId}, );
No agents? Everything works without agents β use the generic
/ai-agent/chatendpoint with the widget directly.
πΎ Conversation Memory
// Conversations are remembered! Agent::conversation('user-123') ->tools([OrderService::class]) ->chat("Show my orders"); // Later... Agent::conversation('user-123') ->chat("Cancel the last one"); // AI remembers the context!
Smart Memory Management:
- After every
summarize_aftermessages, the AI generates a concise summary of older messages - Messages are never deleted until reaching
max_messageshard limit - The LLM receives:
[summary of old context]+[last N recent messages]+[new message] - Falls back to manual summarization if AI summarization fails
- Disable AI summarization with
AI_AGENT_AI_SUMMARY=falsein.env
βοΈ Configuration
// config/ai-agent.php return [ 'default' => env('AI_AGENT_DRIVER', 'openai'), 'verify_ssl' => env('AI_AGENT_VERIFY_SSL', false), 'drivers' => [ 'openai' => [ 'api_key' => env('OPENAI_API_KEY'), 'model' => env('OPENAI_MODEL',env('AI_AGENT_MODEL','gpt-4o-mini')), ], 'anthropic' => [ /* ... */ ], 'gemini' => [ /* ... */ ], 'deepseek' => [ /* ... */ ], 'openrouter' => [ /* ... */ ], ], 'discovery' => [ 'paths' => [app_path()], // Scans all app/ by default 'cache' => true, // Cache discovered tools ], 'memory' => [ 'driver' => env('AI_AGENT_MEMORY', 'session'), 'summarize_after' => 10, // AI-summarize every N messages 'max_messages' => 100, // Hard limit β delete oldest beyond this 'recent_messages' => 4, // Send last N messages to LLM 'ai_summarization' => true, // Use AI for smart summaries ], 'agents' => [ \App\AI\Agents\ShopAgent::class, \App\AI\Agents\AdminAgent::class, ], 'security' => [ 'enabled' => true, // All security on by default 'max_tool_calls_per_request' => 10, 'max_iterations' => 10, ], ];
π See Full Documentation for all configuration options.
π‘ Events
use LaravelAIAgent\Events\ToolCalled; use LaravelAIAgent\Events\ToolExecuted; Event::listen(ToolCalled::class, function ($event) { Log::info("AI called: " . $event->tool['name']); }); Event::listen(ToolExecuted::class, function ($event) { Log::info("Result: " . json_encode($event->result)); });
π Full Example
// 1οΈβ£ Service with tools β place anywhere in app/ class ShopService { #[AsAITool] public function listProducts(): array { return Product::all()->toArray(); } #[AsAITool] public function addProduct(string $name, float $price): array { return Product::create(compact('name', 'price'))->toArray(); } }
# 2οΈβ£ Create an agent
php artisan make:agent ShopAgent
// 3οΈβ£ Drop the widget in Blade β routes are auto-registered! {!! \App\AI\Agents\ShopAgent::widget() !!} <script src="/ai-agent/widget.js"></script>
That's it. Tools are auto-discovered, routes are auto-registered, conversations are isolated per agent, memory is auto-managed. π
π Documentation
For the full detailed documentation β including all configuration options, security features, event system, streaming, and more β see documentation.md.
π€ Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
π License
The MIT License (MIT). See License File for more information.
Made with β€οΈ for Laravel developers
