eznix86 / laravel-ai-memory
AI memory for Laravel AI SDK with semantic search and reranking
Requires
- php: ^8.4
- illuminate/database: ^12.62|^13.15
- illuminate/view: ^12.62|^13.15
- laravel/ai: ^1.3
Requires (Dev)
- ext-pdo_pgsql: *
- larastan/larastan: ^3.9
- laravel/pint: ^1.27
- orchestra/testbench: ^11.0
- pestphp/pest: ^5.3
- pestphp/pest-plugin-evals: ^5.1
- pestphp/pest-plugin-laravel: ^5.0
- phpstan/phpstan: ^2.1
- rector/rector: ^2.3
- testcontainers/testcontainers: ^1.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
- dev-main
- v2.1.1
- v2.1.0
- v2.0.1
- v2.0.0
- v1.0.2
- v1.0.1
- 1.0.0
- dev-feat/drop-fulltext-index
- dev-feat/meaning-only-recall
- dev-docs/user-owner-rule
- dev-docs/simpler-context-and-schedule
- dev-docs/getting-started
- dev-docs/requirements-models
- dev-docs/models-needed
- dev-docs/inject-and-languages
- dev-docs/what-memory-keeps
- dev-docs/simplified-english
- dev-docs/memory-context-link
- dev-docs/how-it-works
- dev-feat/2.0
This package is auto-updated.
Last update: 2026-10-26 12:00:21 UTC
README
Long-term memory for agents of the Laravel AI SDK, in one PostgreSQL table.
The agent keeps what users tell it about themselves and their work: who they are, what they like, what they work on and how their team works.
- Requirements
- Getting started
- The memory context
- Injecting memory
- Languages
- Testing
- Extending the package
- Migrating from 1.x to 2.x
Requirements
- PHP 8.4+, Laravel 12.62+ or 13.15+
- Laravel AI SDK 1.3+
- PostgreSQL with pgvector. The migration adds the extension, so the database user must have that permission
- A queue worker
- An LLM (text model) with structured output, required
- extracts the facts after each turn
- decides on duplicates
- merges memories each week
- An embedding model, required
- stores a vector for each fact
- finds the memories for each prompt
- searches with
RecallMemory
- A classification model, optional
- only with
AI_MEMORY_DECIDER=classificationorAI_MEMORY_PERMISSION_GUARD=classification
- only with
- An LLM (text model) or a TypeSafe System One model, for evals only
- judges the answers in your Pest evals
See Models.
Getting started
1. Install and migrate. If you use Ollama, set AI_MEMORY_DIMENSIONS first.
composer require eznix86/laravel-ai-memory php artisan migrate
2. Run a queue worker. After each turn, a job extracts the facts.
3. Set the temperature of the memory model to 0. If you do not, some models return no facts.
AI_MEMORY_PROVIDER_OPTIONS='{"openrouter": {"temperature": 0}}'
4. Add memory to your agent. Keep your own tools and middleware:
use Eznix86\AI\Memory\Contracts\HasMemory; use Eznix86\AI\Memory\MemoryContext; use Eznix86\AI\Memory\Middleware\WithMemory; use Eznix86\AI\Memory\Tools\Forget; use Eznix86\AI\Memory\Tools\RecallMemory; use Eznix86\AI\Memory\Tools\Remember; class SupportAgent implements Agent, HasMemory, HasMiddleware, HasTools { use Promptable; public function __construct( protected MemoryContext $context, ) {} public function memory(): MemoryContext { return $this->context; } public function tools(): iterable { return [ // your tools... new Remember($this->context), new Forget($this->context), new RecallMemory($this->context), ]; } public function middleware(): array { return [ // your middleware... new WithMemory($this->context), ]; } }
5. Prompt the agent with a context for the current user:
$context = new MemoryContext(user: $request->user()); (new SupportAgent($context))->prompt($request->input('message'));
Each user gets their own memories. To share memories with a team, add owner: $team. See The memory context.
6. Schedule the weekly clean-up in routes/console.php. It merges memories on the same subject and archives the ones that faded:
Schedule::command('memory:consolidate')->sundays()->at('02:00');
Injecting memory
Your app can also give facts to the agent, for example from a settings page or an app event:
use Eznix86\AI\Memory\Facades\Memories; use Eznix86\AI\Memory\MemoryContext; class RememberTravelMode { public function handle(TravelModeEnabled $event): void { Memories::add(new MemoryContext(user: $event->user), [ 'kind' => 'context', 'content' => "The user is travelling in {$event->country} until {$event->until->format('j F')}.", 'source' => 'travel-mode', 'expires_at' => $event->until, ]); } }
The memory ends at expires_at. Add creator: $admin when a person writes it. See Adding memories from your application.
Languages
Facts stay in the language of the user. For other languages, use a multilingual embedding model, and translate the short messages that the agent reads:
php artisan vendor:publish --tag=memory-lang
Then copy lang/vendor/memory/en to a folder for your language, and translate the lines. See Languages.
Testing
| Level | Checks | Model calls |
|---|---|---|
| Unit | Your code for memory, such as your policy | No |
| Feature | The connection of your agent to memory, with Memories::fake() |
No |
| Eval | Your agent with your real model, with Pest evals | Yes |
// feature test test('the agent stores a preference with Remember', function () { Memories::fake(); $context = new MemoryContext(user: User::factory()->create()); SupportAgent::fake([ new ToolCall('call-1', 'Remember', ['kind' => 'preference', 'content' => 'The user wants the weekly report as PDF.']), 'Noted.', ]); (new SupportAgent($context))->prompt('From now on, send me the weekly report as PDF.'); expect(Memories::list($context)->pluck('content'))->toContain('The user wants the weekly report as PDF.'); }); // eval test, run with ./vendor/bin/pest --evals test('a fact told in one conversation is known in the next one', function () { $context = new MemoryContext(user: User::factory()->create()); (new SupportAgent($context))->prompt('I live in Mauritius. What is a nice place for a weekend walk?'); expect(new SupportAgent($context)) ->prompt('Which country do I live in?') ->toContain('Mauritius'); });
For all the examples, see docs/testing.md.
Extending the package
- How it works: one turn, and the path of a fact through the writer
- The memory context
- Safety, duplicates and decay
- Managing memories
- Languages
- Customizing
- Testing your application
- Migrating from 1.x to 2.x
- Contributing
License
MIT. See LICENSE.
