Laravel Magazine

Laravel AI: Configurable Conversation and Message Table Names

Eric Van Johnson · News
Laravel AI: Configurable Conversation and Message Table Names

@timmcleod merged PR #484 into laravel/ai, making the two database table names used by DatabaseConversationStore configurable via config/ai.php. The change resolves issue #483.


The Problem

DatabaseConversationStore hardcoded agent_conversations and agent_conversation_messages as string literals in five separate places. Any project that needed different names, to avoid collisions with another package, or to follow a naming convention like module_* or tenant_*, had to reimplement the entire ConversationStore interface from scratch. That meant inheriting none of the future improvements made to the built-in implementation.


The New Config Keys

A storage.tables array now lives in config/ai.php. Both keys fall back to the original literals, so no existing install needs any changes.

'storage' => [
    'tables' => [
        'conversations' => env('AI_TABLE_CONVERSATIONS', 'agent_conversations'),
        'messages'      => env('AI_TABLE_MESSAGES', 'agent_conversation_messages'),
    ],
],

Override via .env if the defaults conflict with anything on the same database:

AI_TABLE_CONVERSATIONS=acme_ai_conversations
AI_TABLE_MESSAGES=acme_ai_conversation_messages

How DatabaseConversationStore Reads Them

Two protected accessors replace the five scattered string literals inside DatabaseConversationStore:

protected function conversationsTable(): string
{
    return config('ai.storage.tables.conversations', 'agent_conversations');
}

protected function messagesTable(): string
{
    return config('ai.storage.tables.messages', 'agent_conversation_messages');
}

Every query method now calls one of those accessors rather than referencing a string directly:

public function storeConversation(string|int|null $userId, string $title): string
{
    // ...
    DB::table($this->conversationsTable())->insert([ /* ... */ ]);
    // ...
}

Migration Consistency

The published migration reads from the same config keys, so publishing both the config and the migration gives consistent table names with no manual edits required:

Schema::create(config('ai.storage.tables.conversations'), function (Blueprint $table) {
    // ...
});

Schema::create(config('ai.storage.tables.messages'), function (Blueprint $table) {
    // ...
});

Projects that have already run the original migration and want to rename their tables need to write a short rename migration alongside the config change. The package does not ship one automatically.


Test Coverage

@timmcleod added tests/Feature/Storage/DatabaseConversationStoreTest.php with four cases: default-config sanity, the default-tables write path, an overridden-tables write path that asserts the default table names are not created, and migration correctness under configured names. The full Pest suite passes 985 of 985 tests.


Who Should Care

Any project sharing a database with another package that also uses agent_conversations, or following strict internal table-naming conventions, can now set two environment variables and move on. No custom store implementation needed.

Stay Updated

Subscribe to our newsletter

Get latest news, tutorials, community articles and podcast episodes delivered to your inbox.

Weekly articles
We send a new issue of the newsletter every week on Friday.
No spam
We'll never share your email address and you can opt out at any time.