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 Doctrine Message Store Laravel Package

symfony/ai-doctrine-message-store

symfony/ai-doctrine-message-store integrates Doctrine DBAL with Symfony AI Chat to provide database-backed message storage. It lets AI chat applications persist conversation messages through Doctrine, with resources and contributions handled in the main Symfony AI repository.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony AI bridge, not a Laravel package. For a Laravel developer, the honest starting point is: use it only if you are already running symfony/ai Agent/Chat components inside a Laravel app and want DBAL-backed conversation persistence. If you are building on Laravel-native AI tooling or Eloquent, a small native repository will usually be simpler.

Minimal steps:

  1. Install DBAL and the bridge, pinned to the same Symfony AI minor version:

    composer require doctrine/dbal symfony/ai-doctrine-message-store
    
  2. Read the source before wiring anything:

    • vendor/symfony/ai-doctrine-message-store/src/DoctrineDBALMessageStore.php
    • The Symfony AI message-store interface it implements
    • The package composer.json for DBAL/Symfony AI version constraints
  3. Find the expected table shape. The README is intentionally thin; the source is the documentation. Check the table name, column names, ID strategy, and whether messages are serialized objects or plain arrays. Do not assume a schema.

  4. Create the table with a Laravel migration rather than letting DBAL create it in production. Keep the migration in your app so schema changes are reviewable.

  5. Build a DBAL connection from Laravel’s database config and bind the store as a singleton:

    use Doctrine\DBAL\DriverManager;
    use Symfony\AI\DoctrineMessageStore\DoctrineDBALMessageStore;
    
    $this->app->singleton(DoctrineDBALMessageStore::class, function () {
        $pdo = DB::connection()->getPdo();
    
        // Verify against your DBAL version; the 'pdo' parameter works on
        // common DBAL 3.x/4.x setups, but confirm in vendor code.
        $connection = DriverManager::getConnection(['pdo' => $pdo]);
    
        return new DoctrineDBALMessageStore($connection);
    });
    
  6. First use case: persist one short agent conversation, then reload it in a second request and assert the message order and content. Do this against SQLite in tests and MySQL/Postgres in staging before trusting it.

Where to look first: the store class constructor, the interface it implements, and the Symfony AI message DTOs. The package is small enough that reading it end-to-end is faster than searching for docs.

Implementation Patterns

Wrap the Symfony store behind an application interface. This is the most important Laravel pattern: do not let Symfony AI types leak through your app. Define a ConversationStore or MessageRepository contract, then adapt the bridge behind it.

interface ConversationStore
{
    public function append(string $conversationId, array $messages): void;
    public function load(string $conversationId, int $limit = 50): array;
}
final class DoctrineConversationStore implements ConversationStore
{
    public function __construct(
        private DoctrineDBALMessageStore $store,
    ) {}

    public function append(string $conversationId, array $messages): void
    {
        // Delegate to the package; transform app DTOs to Symfony AI messages
        // and back at this boundary.
    }

    public function load(string $conversationId, int $limit = 50): array
    {
        // Load and map to your own DTOs.
    }
}

This keeps the rest of the Laravel app swappable to Eloquent, Redis, or a fake in tests.

Reuse Laravel’s PDO where possible. A separate DBAL connection means separate transaction state, locks, and query visibility. Passing Laravel’s PDO into DBAL avoids duplicate credentials and surprises. Test transaction behavior explicitly; SQLite especially will complain about locks if two connections write concurrently.

Persist after each agent turn, load before prompting. A typical flow:

  1. Resolve the conversation ID from your controller/job.
  2. Load recent messages through your adapter.
  3. Pass them to the Symfony AI agent.
  4. Append the user message and assistant response in one write path.
  5. Keep the DBAL write inside a try/catch; decide whether a failed persistence should fail the request or only log.

Use jobs and console commands carefully. Queue payloads should contain conversation IDs and primitive data, never DBAL connections or serialized Symfony AI agent objects. Resolve the store inside handle().

Keep reporting queries separate from the write path. Laravel’s query builder or a read-only Eloquent model can query the same table for dashboards and analytics, provided your migration remains the source of truth. Do not let DBAL and Eloquent each try to own schema changes.

Test with in-memory SQLite, but do not rely on RefreshDatabase for DBAL writes. Run your migration, truncate the table between tests, and test reload ordering, empty conversations, and malformed stored payloads.

Use a decorator for cross-cutting behavior. Tenant scoping, PII redaction, encryption, caching, and audit logging belong in a decorator around the store, not in forked package code.

Gotchas and Tips

  • Maturity risk is real. One star, zero dependents, 0.x versions, and multiple “no significant changes” releases mean this is effectively infrastructure code you must audit. Pin exact versions and budget for upgrade testing.
  • It is not PSR-15. Some summaries describe it as a PSR-15 message store; that is misleading. It is a Symfony AI message-store bridge. Do not build an HTTP middleware bridge looking for PSR-15 interfaces.
  • No Laravel integration ships with it. There is no service provider, config file, facade, migration, model, or event integration. You own all wiring.
  • No Eloquent behavior. No casts, observers, soft deletes, or model events. If you need encrypted columns or accessors, implement them in your adapter or a read/write layer.
  • Schema ownership is your job. The README does not document migrations. Inspect the source for the expected table and create a Laravel migration. Prefix generic table names like messages or ai_messages to avoid collisions.
  • DBAL 3 vs DBAL 4 matters. Result APIs, logging, and connection parameters differ. Check composer why doctrine/dbal and test the exact combination Laravel resolves. A version conflict with package constraints is plausible.
  • Your Laravel and DBAL connections may not be the same connection. If they are separate, Laravel’s DB::transaction() will not cover DBAL writes, and DB::listen/Telescope may not show DBAL queries. Prefer sharing the PDO; otherwise enable DBAL logging locally and treat the database table as the debugging source.
  • Serialized Symfony AI messages can break on upgrade. If the store persists serialized message objects, a Symfony AI 0.x change may make old rows hard to hydrate. Keep upgrade tests with real stored rows. If possible, store your own stable JSON payload and use the package only as the low-level store.
  • Performance is relational, not real-time. Expect one or more inserts per turn and potentially large conversation payloads. Index conversation_id plus a timestamp/order column, paginate history loads, and archive old conversations. Use Redis for hot-path state if latency matters.
  • Chat logs are sensitive. DBAL bypasses Laravel’s encrypted casts. Decide what must be redacted before storage, encrypt at the application or column level if required, and add a retention/deletion command.
  • Extension point: decorate, don’t fork. Implement the same Symfony AI store interface or wrap DoctrineDBALMessageStore to add tenant filters, logging, redaction, or caching. A fork is justified only if the package becomes unmaintained and you need deep fixes.
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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core