Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laragent Laravel Package

maestroerror/laragent

LarAgent is an AI agent development framework for Laravel. Build and maintain agents with an Eloquent-style API, first-class tools and MCP server support, pluggable memory and context, multi-agent workflows, and structured output for reliable results.

View on GitHub
Deep Wiki
Context7

Getting Started

LarAgent is an agent framework, not just an LLM wrapper. The mental model to adopt on day one is: an agent is a class like an Eloquent model, and a chat is a keyed session like a cache entry. Once that clicks, the rest of the package is discoverable.

Minimum viable setup

composer require maestroerror/laragent
php artisan vendor:publish --tag="laragent-config"

Requirements are stricter than most Laravel packages: PHP 8.3+ and Laravel 10+. Check your CI matrix before committing — this is the most common first blocker on legacy projects.

Set OPENAI_API_KEY (or your provider key) in .env, then scaffold your first agent:

php artisan make:agent SupportAgent

That generates a class extending LarAgent\Agent with $model, $history, $provider, $tools, plus instructions() and prompt(). The two methods matter:

  • instructions() — the system prompt. Treat it as your primary lever for behavior.
  • prompt($message) — transforms the user message before it hits the provider. Useful for injecting context, formatting, or guardrails.

First use case: build a single-turn assistant with no tools and no persistence to prove the wiring, then add one trait at a time. A good starter is a "docs Q&A" or "internal ops helper" agent — low stakes, easy to eyeball output quality.

SupportAgent::forUser(auth()->user())->respond('How do I reset my password?');

Where to look first, in order:

  1. config/laragent.php after publishing — this is the source of truth for providers and defaults.
  2. The generated agent class — every provider-level config can be overridden per agent.
  3. The docs at docs.laragent.ai — the README is intentionally thin and points outward.
  4. The v0.7 → v0.8 and v1.0 changelogs before you copy code from a blog post. There are real breaking changes in the tool-execution event signatures.

Implementation Patterns

The agent class is your configuration surface

Providers supply defaults; the agent class overrides them. Keep provider configs generic and push behavior into the agent. This is the pattern the package is designed around and it keeps agents portable across providers.

class AnalystAgent extends Agent
{
    protected $provider = 'default';
    protected $model = 'gpt-4';
    protected $temperature = 0.2;          // low temp for analysis
    protected $parallelToolCalls = false;  // deterministic ordering
    protected $history = \LarAgent\History\CacheChatHistory::class;

    public function instructions() { /* ... */ }
    public function prompt($message) { return $message; }
}

Conversation scoping: for() and forUser()

This is the pattern you will use every single day. The history key determines which conversation the agent continues.

// Per-user, per-agent default thread
SupportAgent::forUser($user)->respond($message);

// Explicit named thread — great for multi-tab or multi-topic chats
SupportAgent::for("support:{$user->id}:billing")->respond($message);

Choose your key strategy early and standardize it. A common convention: "{agent}:{user_id}:{channel}". Getting this wrong late means migrating conversation storage or silently orphaning history.

History backends — pick deliberately

Backend Use when
InMemoryChatHistory Tests, single-request jobs, stateless one-shots
CacheChatHistory Default for real chat UIs; fast, TTL-managed
JSON / custom Audit trails, compliance, cross-service replay

The default is InMemoryChatHistory, which means history vanishes between HTTP requests. This surprises people constantly. If you're building a chat, you almost certainly want CacheChatHistory or a custom ChatHistory implementation wired to your DB.

Tools: three registration styles

LarAgent gives you attribute-based tools, class-based tools, and a Tool facade. Pick one convention per codebase.

#[Tool('Get the current weather in a given location')]
public function exampleWeatherTool($location, $unit = 'celsius')
{
    return "The weather in {$location} is 20 degrees {$unit}";
}

The attribute style is the lowest-friction and what most developers will reach for. Parameter names and types are inferred — document them in the description string because that text is what the model uses to decide when and how to call. Vague descriptions are the number-one cause of bad tool selection.

Disable parallelToolCalls when your tools have side effects (writes, emails, payments) and ordering matters. Leave it on for read-only fan-out.

Multi-provider fallback for resilience

Provider arrays are a genuinely useful production feature — not just a convenience:

// Ordered fallback
protected $provider = ['default', 'gemini', 'claude'];

// With per-provider overrides
protected $provider = [
    'default',
    'gemini' => ['model' => 'gemini-2.0-flash'],
    'claude',
];

Use this for uptime, but remember: capability is not identical across providers. A tool-calling workflow that works on OpenAI may degrade on a fallback. Test the fallback path explicitly, or restrict fallback chains to agents with simple, provider-agnostic prompts.

Reasoning models

For reasoning_effort-style models, use the OpenAiResponsesDriver and pass parameters through $extras:

protected $provider = 'openai_responses';
protected $model = 'gpt-5.4-mini';
protected $extras = ['reasoning_effort' => 'high'];

For third-party Responses-compatible endpoints, OpenAiResponsesCompatible plus an api_url handles it.

Events and hooks for observability

Nearly everything is hookable — this is the framework's strongest operational feature. Use it for logging, cost tracking, and redaction rather than polluting agent classes.

Event::listen(BeforeToolExecution::class, function ($event) {
    Log::info('Tool call', [
        'id'   => $event->toolCall->getId(),
        'tool' => $event->toolCall->getToolName(),
        'args' => json_decode($event->toolCall->getArguments(), true),
    ]);
});

Verify signatures against the changelog. In v0.8, beforeToolExecution() went from 2 to 3 parameters and afterToolExecution() from 3 to 4. Any callback written against v0.7 will silently receive the wrong arguments.

Async and long-running work

Agent turns are network-bound and can take seconds to minutes. Wrap them in jobs:

ProcessAgentMessage::dispatch($conversationId, $message);

The package provides multi-agent workflows with queues and chainable tasks — use those primitives rather than hand-rolling dispatch()->chain() with agent calls inside, so the framework's history and event plumbing stays consistent.

API exposure

The built-in OpenAI-compatible schema means you can front an agent with a chat-completions-shaped endpoint and point existing OpenAI SDK clients at it. Great for internal tooling and for drop-in replacing a provider during migration.

Gotchas and Tips

History is ephemeral until you change it. InMemoryChatHistory is the shipped default. If your agent "forgets" between requests, this is why — not a bug.

default_max_completion_tokens: 100 in the sample config is very low. The published config example shows 100 tokens. If your responses are getting cut off mid-sentence, this is the culprit. Raise it per provider and override per agent where needed.

Truncation is silent. default_truncation_threshold (50000 in the default provider) drops older context once exceeded. Combined with persistent history this can produce confident-but-wrong answers about things "discussed earlier." Log truncation events, and for long conversations prefer summarization or retrieval over a bigger threshold.

Model names drift. The README uses gpt-4 and gpt-5.4-mini in examples. Model identifiers change and get retired. Keep model strings in config or env, not hardcoded in agent classes, so a provider deprecation is a config change rather than a deploy.

Version the tool event contract. As above: v0.8 changed event and hook arities. If you have listeners in a long-lived app, pin the version or convert listeners to the new signatures in the same PR as the upgrade. There is no deprecation shim mentioned.

Anthropic strict tool use is on by default in v1.0. This improves structured output reliability but tightens the schema your tool definitions must satisfy. Tools with loose or nullable parameters may start failing validation.

Provider array order is the failover order, and the first is primary. The associative form ('gemini' => [...]) mixes keys and values — read it carefully; it's easy to accidentally make a provider primary when you meant it as a fallback.

Tool descriptions are prompt engineering, not documentation. Write them for the model: when to use, what each argument means, what it returns. Include negative guidance ("do not use for X") where tools overlap — overlapping tools with thin descriptions cause erratic selection.

Test without burning tokens. The package's own test suite uses testsManual/*.gitignore files holding API keys. Mirror that pattern: fake drivers or recorded fixtures for CI, real-key tests only locally or on a nightly job. Nothing drains a budget faster than a green CI run that hits a live API on every commit.

Extension points worth knowing before you fork anything: custom drivers (LarAgent\Drivers\...), custom chat history classes implementing the history interface, custom Tool classes for tools with dependencies, and the event system for anything cross-cutting. In this order, you can almost always avoid touching vendor code.

Standalone usage exists. The framework supports non-Laravel usage, which is useful for a CLI worker or a separate service sharing the same agent definitions — but you lose the artisan scaffolding and config helpers, so budget for that.

Pick a conversation-key convention on day one. Retrofitting for()/forUser() naming after users have live threads is a data migration, not a refactor.

MCP is a separate package. Tool and resource management from MCP servers lives in RedberryProducts/mcp-client-laravel, not in core. If you're planning MCP integration, add it to your dependency review up front.

Community and support posture. 645 stars, MIT, actively released, Diamond-tier Laravel partner backing, Discord plus a real docs site — that's a healthy signal for a young package. But dependents are effectively zero, which means you are an early adopter: budget for reading source when docs are thin, and pin your version.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel