symfony/ai-cache-message-store
PSR-6 cache-backed message store for Symfony AI Chat. Persist and retrieve chat messages using any PSR-6 cache pool for lightweight conversation history across requests. Part of the Symfony AI ecosystem.
Install the Package Require the package in your Laravel project:
composer require symfony/ai-cache-message-store
Configure PSR-6 Cache
Ensure your Laravel cache driver (Redis, database, etc.) is properly set in .env:
CACHE_DRIVER=redis
Create a Laravel-Compatible Wrapper Since this package is Symfony-focused, create a Laravel service provider to bridge the gap:
// app/Providers/AiCacheServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Symfony\Component\AI\Chat\CacheMessageStore;
use Symfony\Component\AI\Chat\MessageStoreInterface;
use Symfony\Contracts\Cache\CacheInterface;
class AiCacheServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton(MessageStoreInterface::class, function ($app) {
return new CacheMessageStore(
$app->make(CacheInterface::class)
);
});
}
}
Register the provider in config/app.php.
First Use Case: Caching AI Chat Messages Use the message store to persist and retrieve chat messages:
use Symfony\Component\AI\Chat\Message;
use Symfony\Component\AI\Chat\MessageStoreInterface;
$messageStore = app(MessageStoreInterface::class);
// Save a message
$message = new Message('user', 'Hello, AI!');
$messageStore->save($message, 'chat_id_123');
// Retrieve messages
$messages = $messageStore->findAll('chat_id_123');
Hybrid Storage Integration Combine cache with a database for durability:
// app/Services/HybridMessageStore.php
use Symfony\Component\AI\Chat\CacheMessageStore;
use Symfony\Component\AI\Chat\MessageStoreInterface;
use Illuminate\Support\Facades\Cache;
class HybridMessageStore implements MessageStoreInterface
{
public function __construct(
private CacheMessageStore $cacheStore,
private \App\Models\ChatMessage $model
) {}
public function findAll(string $chatId): array
{
$cached = $this->cacheStore->findAll($chatId);
if ($cached) return $cached;
$messages = $this->model->where('chat_id', $chatId)->get();
$this->cacheStore->saveMany($messages, $chatId);
return $messages;
}
public function save(\Symfony\Component\AI\Chat\Message $message, string $chatId): void
{
$this->cacheStore->save($message, $chatId);
$this->model->create([
'chat_id' => $chatId,
'role' => $message->getRole(),
'content' => $message->getContent(),
]);
}
}
Cache Warming for Performance Preload frequently accessed chat histories:
// app/Console/Commands/WarmAiCache.php
use Illuminate\Console\Command;
use Symfony\Component\AI\Chat\MessageStoreInterface;
class WarmAiCache extends Command
{
protected $signature = 'ai:cache:warm';
protected $description = 'Preload active chat histories into cache';
public function handle(MessageStoreInterface $messageStore)
{
$activeChats = \App\Models\Chat::active()->pluck('id');
foreach ($activeChats as $chatId) {
$messageStore->findAll($chatId);
}
}
}
TTL-Based Message Expiration Dynamically set TTLs based on message age:
// app/Services/DynamicTtlMessageStore.php
use Symfony\Component\AI\Chat\CacheMessageStore;
class DynamicTtlMessageStore extends CacheMessageStore
{
public function save(\Symfony\Component\AI\Chat\Message $message, string $chatId, ?int $ttl = null): void
{
$defaultTtl = $this->calculateTtl($message);
parent::save($message, $chatId, $defaultTtl ?? 3600);
}
private function calculateTtl(\Symfony\Component\AI\Chat\Message $message): ?int
{
if ($message->getRole() === 'system') return 86400; // 24h for system messages
if (str_contains($message->getContent(), 'urgent')) return 300; // 5min for urgent
return null; // Use default
}
}
Cache Tagging for Invalidation Use Laravel's cache tags to invalidate related messages:
$cache = Cache::store('redis')->getAdapter();
$messageStore = new CacheMessageStore($cache);
// Save with tags
$messageStore->save($message, 'chat_id_123', 3600, ['chat:123', 'user:456']);
// Invalidate on user update
Cache::tags(['user:456'])->flush();
Event-Driven Cache Updates Listen to model events to keep cache in sync:
// app/Providers/EventServiceProvider.php
use App\Models\ChatMessage;
use Symfony\Component\AI\Chat\MessageStoreInterface;
protected $listen = [
ChatMessage::class => [
'deleted' => ['App\Listeners\InvalidateChatCache'],
],
];
Queue-Based Cache Population Offload cache population to queues for long-running operations:
// app/Jobs/PopulateChatCache.php
use Symfony\Component\AI\Chat\MessageStoreInterface;
class PopulateChatCache implements ShouldQueue
{
public function handle(MessageStoreInterface $messageStore)
{
$chat = \App\Models\Chat::find($this->chatId);
$messages = $chat->messages()->get();
$messageStore->saveMany($messages, $chat->id);
}
}
Serialization Issues
JsonSerializable or use a custom serializer:
class Message implements JsonSerializable
{
public function jsonSerialize(): array
{
return [
'role' => $this->role,
'content' => $this->content,
'timestamp' => $this->timestamp->getTimestamp(),
];
}
}
Cache Key Collisions
$messageStore = new CacheMessageStore($cache, 'ai_chat_');
TTL Misconfiguration
redis-cli info stats | grep keyspace_hits
Symfony Dependency Conflicts
composer.json:
"require": {
"symfony/ai": "^0.8",
"symfony/cache": "^6.0"
}
Cache Miss Analysis Use Laravel's cache debugging:
Cache::remember('debug:cache_stats', 60, function () {
return Cache::store('redis')->getAdapter()->getStats();
});
Message Store Logging Add debug logging to track cache operations:
$messageStore = new CacheMessageStore($cache);
$messageStore->setLogger(new \Monolog\Logger('ai_cache', [
new \Monolog\Handler\StreamHandler(storage_path('logs/ai_cache.log'))
]));
Redis Memory Monitoring Track memory usage to prevent evictions:
redis-cli info memory
Custom Cache Adapter Extend the message store to support custom cache logic:
class CustomCacheMessageStore extends CacheMessageStore
{
public function findAll(string $chatId): array
{
$key = $this->getKey($chatId);
$item = $this->cache->getItem($key);
if (!$item->isHit()) {
$messages = $this->fetchFromDatabase($chatId);
$item->set($messages);
$this->cache->save($item);
}
return $item->get();
}
}
Event Dispatching Trigger events for cache operations:
class EventfulMessageStore extends CacheMessageStore
{
public function save(\Symfony\Component\AI\Chat\Message $message, string $chatId, ?int $ttl = null):
How can I help you explore Laravel packages today?