maestroerror/laragent
LarAgent is an open-source AI agent framework for Laravel. Build and maintain agents with an Eloquent-style API, pluggable tools (incl. MCP server support), memory/context management, multi-agent workflows, queues, and structured output for reliable integrations.
Installation:
composer require maestroerror/laragent
php artisan vendor:publish --tag="laragent-config"
Configure config/laragent.php with your API keys (e.g., OPENAI_API_KEY).
Generate Your First Agent:
php artisan make:agent CustomerSupportAgent
This creates a new agent class in app/AiAgents/ with a familiar Eloquent-like structure.
Define Agent Behavior:
// app/AiAgents/CustomerSupportAgent.php
class CustomerSupportAgent extends Agent
{
protected $model = 'gpt-4';
protected $temperature = 0.3;
public function instructions()
{
return "You are a customer support agent. Be polite and concise.";
}
#[Tool('Fetch user order details')]
public function getOrderDetails($orderId)
{
return Order::find($orderId)->toArray();
}
}
Use the Agent:
$response = CustomerSupportAgent::forUser(auth()->user())
->respond("How can I track my order #12345?");
Test Locally:
Use the LarAgent\Testing\TestAgent facade to mock responses during development:
TestAgent::fake([
CustomerSupportAgent::class => fn($message) => "Order #12345 is in transit."
]);
Agent Lifecycle:
make:agent for boilerplate.$model, $temperature) or methods (instructions(), prompt()).forUser() or for("custom_history") before respond().Tool Integration:
#[Tool('description')].Tool::create() for dynamic tools:
$tool = Tool::create('SearchDatabase', fn($query) => DB::table('products')->where('name', 'like', "%$query%")->get());
$parallelToolCalls = true (default: false).Multi-Agent Workflows:
$agent1 = new FirstAgent();
$agent2 = new SecondAgent();
$result = $agent1->respond($message)->then($agent2);
AgentResponding events to trigger other agents.Memory Management:
CacheChatHistory (configured in config/laragent.php).ChatHistory and bind via service provider:
$this->app->bind(\LarAgent\History\ChatHistory::class, CustomChatHistory::class);
API Exposure:
LarAgent\OpenAi\OpenAiController for direct API access.#[Tool('ValidateUserInput', outputSchema: ['type' => 'object', 'properties' => ['valid' => ['type' => 'boolean']]])]
public function validateInput($input) { ... }
dispatch() for async processing:
dispatch(new ProcessAgentResponse($agent, $message));
AgentResponded to log or transform responses:
event(new AgentResponded($agent, $response));
TestAgent::fake() to mock responses in unit tests:
TestAgent::fake([
CustomerSupportAgent::class => fn($msg) => "Mocked: $msg"
]);
Tool Validation:
strict: false (default in some drivers like Anthropic).outputSchema with additionalProperties: false:
#[Tool(outputSchema: ['type' => 'object', 'properties' => ['id' => ['type' => 'string']], 'additionalProperties' => false])]
Token Limits:
default_truncation_threshold in config to auto-truncate.gpt-4 (32k context) or implement custom chunking via ChatHistory.Provider Fallbacks:
protected $provider = ['primary', 'fallback']) may not respect per-agent overrides.config(['laragent.providers.primary' => [...]]) dynamically.Event Order:
AgentResponding fires before tool execution, while AgentResponded fires after.AgentToolExecuting for tool-specific hooks.Memory Leaks:
InMemoryChatHistory retains all conversations in RAM.CacheChatHistory or implement TTL:
protected $history = \LarAgent\History\CacheChatHistory::class;
protected $historyTTL = 60 * 60 * 24; // 1 day
Enable Logging:
config(['laragent.log' => true]);
Check storage/logs/laragent.log for driver interactions.
Inspect Tools:
Use dd($agent->getTools()) to verify tool definitions before execution.
Streaming Debug:
For sendMessageStreamed(), log chunks:
$agent->sendMessageStreamed($message)->each(function ($chunk) {
Log::debug($chunk);
});
Custom Drivers:
LarAgent\Drivers\LlmDriver and bind in AppServiceProvider:
$this->app->bind(\LarAgent\Drivers\LlmDriver::class, CustomDriver::class);
Chat History:
LarAgent\History\ChatHistory and register:
$this->app->bind(\LarAgent\History\ChatHistory::class, function ($app, $params) {
return new DatabaseChatHistory($params['user_id']);
});
Events:
AgentResponding) or dispatch custom ones:
event(new CustomAgentEvent($agent, $response));
Artisan Commands:
LarAgent\Console\MakeAgentCommand to add custom agent templates.Provider Overrides:
Per-agent provider configs override global settings but ignore api_key (always uses global).
// Override model but keep global API key
protected $provider = 'custom';
protected $model = 'gemini-1.0';
Parallel Tools:
Disabling $parallelToolCalls improves reliability but may increase latency for sequential tools.
Extras Handling:
Driver-specific extras (e.g., reasoning_effort for OpenAI Responses API) must be set in $extras:
protected $extras = ['reasoning_effort' => 'high'];
How can I help you explore Laravel packages today?