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

Ai Meilisearch Message Store Laravel Package

symfony/ai-meilisearch-message-store

Meilisearch message store integration for Symfony AI Chat, using Meilisearch indexes and documents to persist and search conversation messages with async task support.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Install the Package

    composer require symfony/ai-meilisearch-message-store meilisearch/meilisearch-php
    

    For Laravel compatibility, ensure symfony/http-client is replaced with Laravel’s Http facade or Guzzle via a custom adapter (see Implementation Patterns).

  2. Configure Meilisearch Add to .env:

    MEILISEARCH_HOST=http://localhost:7700
    MEILISEARCH_API_KEY=your-api-key
    MEILISEARCH_INDEX=chat_messages  # Default index name
    
  3. Register the Message Store In AppServiceProvider or a dedicated service provider:

    use Symfony\Component\Ai\Chat\MessageStore\MeilisearchMessageStore;
    use Meilisearch\Client;
    
    public function register()
    {
        $this->app->singleton(\Symfony\Component\Ai\Chat\MessageStore\MessageStoreInterface::class, function ($app) {
            $client = new Client(
                env('MEILISEARCH_HOST'),
                env('MEILISEARCH_API_KEY')
            );
            return new MeilisearchMessageStore($client, env('MEILISEARCH_INDEX'));
        });
    }
    
  4. First Use Case: Store and Retrieve Messages

    use Symfony\Component\Ai\Chat\Message;
    use Symfony\Component\Ai\Chat\MessageStore\MessageStoreInterface;
    
    // Store a message
    $message = new Message(
        'conv-123',
        'user-456',
        'What is Laravel?',
        'user',
        'Laravel is a PHP framework...',
        ['timestamp' => now()->toDateTimeString()]
    );
    
    $store = app(MessageStoreInterface::class);
    $store->save($message);
    
    // Retrieve messages
    $messages = $store->findByConversationId('conv-123');
    
  5. Verify with Tinker

    php artisan tinker
    
    >>> $store = app(\Symfony\Component\Ai\Chat\MessageStore\MessageStoreInterface::class);
    >>> $messages = $store->findByConversationId('conv-123');
    >>> dd($messages);
    

Implementation Patterns

1. Adapter Layer for Laravel

Since the package is Symfony-focused, create a Laravel-compatible adapter:

// app/Providers/MeilisearchServiceProvider.php
namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Meilisearch\Client;
use Symfony\Component\Ai\Chat\MessageStore\MeilisearchMessageStore;

class MeilisearchServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->singleton(\Symfony\Component\Ai\Chat\MessageStore\MessageStoreInterface::class, function ($app) {
            $client = new Client(
                config('meilisearch.host'),
                config('meilisearch.api_key')
            );
            return new MeilisearchMessageStore($client, config('meilisearch.index'));
        });
    }
}

Configure in config/meilisearch.php:

return [
    'host' => env('MEILISEARCH_HOST', 'http://localhost:7700'),
    'api_key' => env('MEILISEARCH_API_KEY'),
    'index' => env('MEILISEARCH_INDEX', 'chat_messages'),
];

2. Message Serialization

Customize how messages are serialized/deserialized for Meilisearch:

// app/Services/MeilisearchMessageMapper.php
namespace App\Services;

use Symfony\Component\Ai\Chat\Message;
use Symfony\Component\Ai\Chat\MessageStore\MessageStoreInterface;

class MeilisearchMessageMapper
{
    public function toArray(Message $message): array
    {
        return [
            'id' => $message->getId(),
            'conversationId' => $message->getConversationId(),
            'role' => $message->getRole(),
            'content' => $message->getContent(),
            'createdAt' => $message->getCreatedAt()?->format('Y-m-d\TH:i:sP'),
            'metadata' => $message->getMetadata() ?? [],
        ];
    }

    public function toMessage(array $data): Message
    {
        return new Message(
            $data['conversationId'],
            $data['role'] === 'user' ? 'user' : 'assistant',
            $data['content'],
            $data['role'],
            null,
            $data['metadata'] ?? []
        );
    }
}

Inject the mapper into MeilisearchMessageStore via constructor or setter.

3. Async Operations

Handle Meilisearch’s async tasks (e.g., index updates) with Laravel queues:

// app/Services/MeilisearchAsyncHandler.php
namespace App\Services;

use Illuminate\Support\Facades\Queue;
use Meilisearch\Client;
use Meilisearch\Tasks\Task;

class MeilisearchAsyncHandler
{
    public function handleTask(Client $client, string $taskUid): void
    {
        Queue::dispatch(function () use ($client, $taskUid) {
            $task = $client->waitForTask($taskUid);
            if (!$task->getStatusData()['completed_at']) {
                $this->handleTask($client, $taskUid); // Retry
            }
        });
    }
}

Use in MeilisearchMessageStore:

public function save(Message $message)
{
    $data = $this->mapper->toArray($message);
    $task = $this->client->index($this->index)->addDocuments([$data]);
    $this->asyncHandler->handleTask($this->client, $task->getTaskUid());
}

4. Search Optimization

Customize search queries for Laravel use cases:

// app/Services/MeilisearchSearcher.php
namespace App\Services;

use Symfony\Component\Ai\Chat\MessageStore\MeilisearchMessageStore;

class MeilisearchSearcher
{
    public function searchByQuery(MeilisearchMessageStore $store, string $query, int $limit = 10)
    {
        return $store->client->index($store->index)->search($query, [
            'limit' => $limit,
            'attributesToRetrieve' => ['content', 'role', 'createdAt'],
            'filter' => ['role = user'], // Example: Only search user messages
        ]);
    }
}

5. Multi-Tenancy Support

Isolate message stores per tenant:

// app/Services/TenantAwareMeilisearchStore.php
namespace App\Services;

use Illuminate\Support\Facades\Auth;
use Symfony\Component\Ai\Chat\MessageStore\MeilisearchMessageStore;

class TenantAwareMeilisearchStore extends MeilisearchMessageStore
{
    public function __construct(MeilisearchMessageStore $store)
    {
        $tenantId = Auth::guard('tenant')->id();
        parent::__construct($store->client, "tenant_{$tenantId}_{$store->index}");
    }
}

Register in AppServiceProvider:

$this->app->singleton(MessageStoreInterface::class, function ($app) {
    return new TenantAwareMeilisearchStore(
        $app->make(MeilisearchMessageStore::class)
    );
});

6. Hybrid Search (Keyword + Semantic)

Combine Meilisearch’s keyword search with vector similarity:

// app/Services/HybridSearcher.php
namespace App\Services;

use Symfony\Component\Ai\Chat\MessageStore\MeilisearchMessageStore;

class HybridSearcher
{
    public function search(MeilisearchMessageStore $store, string $query, array $vector)
    {
        // Keyword search
        $keywordResults = $store->client->index($store->index)->search($query, [
            'limit' => 5,
        ]);

        // Vector search (requires Meilisearch with vector module)
        $vectorResults = $store->client->index($store->index)->search($vector, [
            'limit' => 5,
            'using' => 'vector', // Requires Meilisearch 1.0+
        ]);

        // Merge results (custom logic)
        return array_merge($keywordResults['hits'], $vectorResults['hits']);
    }
}

Gotchas and Tips

Pitfalls

  1. Async Task Timeouts

    • Meilisearch tasks may take seconds to complete. Always handle async operations with retries or callbacks.
    • Fix: Use Laravel queues with exponential backoff (e.g., laravel-queue-retries package).
  2. Index Schema Mismatches

    • Meilisearch requires consistent schemas. Changing message structures mid-flight can corrupt data.
    • Fix: Version your indexes (e.g., chat_messages_v1, `chat_messages_v2
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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings