Installation
composer require edulazaro/laragents
PHP 8.2 and Laravel 12. The one hard dependency beyond the framework is dragonmantank/cron-expression, which is what decides whether a scheduled agent is due.
The service provider registers itself. Publish the config and the migration:
php artisan vendor:publish --tag=laragents-config php artisan vendor:publish --tag=laragents-migrations php artisan migrate
That creates seven tables:
laragents_agents the standing instruction: persona, tools, trigger
laragents_agent_tasks one run of one agent
laragents_agent_logs what happened during it
laragents_chat_sessions one conversation
laragents_chat_messages its turns, tool calls included
laragents_memories what is remembered between conversations
laragents_rules what must be obeyed within them
One tag for all seven, not one per table. They were split for a while so that an app wanting only a chat would not get empty agent tables, and that saved nothing worth having: a session points at an agent, so the foreign key needs the agents table to exist whether you use agents or not.
The API key
OPENAI_API_KEY=sk-... ANTHROPIC_API_KEY=sk-ant-...
Only the provider you actually call needs one. There is no default model anywhere in the package: every call names the model it wants, because a default is how one renamed operation quietly moves to a more expensive tier and nobody finds out until the invoice.
The optional opt-out migration
php artisan vendor:publish --tag=laragents-optout-migration
Separate tag, and separate for a reason: it is the only migration in the package that touches a table the package does not own. It adds a share_memories boolean to your users table, so a person can keep their memories out of the pool everyone in the tenant reads. Skip it and everyone shares, which is a legitimate product decision and the default.
It asks which table rather than guessing, and it skips a column that is already there:
// config/laragents.php 'memory' => [ 'actor_table' => 'users', ],
Nothing else is required
Installed and migrated, the package talks to OpenAI, meters nothing, redacts nothing, and has the two memory tools registered. That is a working starting point, and everything past it is opt-in:
// app/Providers/AppServiceProvider.php use EduLazaro\Laragents\Laragents; public function boot(): void { Laragents::tools([ListProperties::class, ScheduleViewing::class]); Laragents::meterWith(LarameterRecorder::class); Laragents::redactWith(MyRedactor::class); }
Each of those is covered in its own chapter: Tools, Usage and credits, Privacy.
The scheduler, if you use agents
The package registers its own scheduled commands, so schedule:work or your cron entry is all that is needed:
laragents:run-due-agents every minute
laragents:cleanup-stale-tasks every five minutes
laragents:distil-inactive-sessions every thirty minutes
The first is what makes a scheduled agent actually fire. Turn the lot off with 'agents' => ['schedule' => false] and register them yourself.
And a worker
Agent runs and memory distillation both go to the queue, so something has to consume it. The failure mode when nothing does is the expensive one: no error, no exception, no log. The agent simply never runs, and you find out when somebody asks why the documents were never triaged.
Give agents a queue of their own if you also run a chat:
'agents' => [ 'queue' => 'agents', ],
An agent run is a loop of model calls and can take minutes. Sharing a queue with anything interactive means one run holds a worker while a person waits for a reply.