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

Le Chat Laravel Package

mmedia/le-chat

mmedia/le-chat is a Laravel package for integrating Mistral AI's Le Chat, giving PHP apps a simple way to send prompts, manage conversations, and configure models. It streamlines setup so you can add AI chat features without boilerplate.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and publish

composer require mmedia/le-chat
php artisan vendor:publish --tag=le-chat-config
php artisan vendor:publish --tag=le-chat-migrations
php artisan migrate

The service provider is auto-discovered; confirm the exact publish tags and provider FQCN in the package README or composer.json → extra.laravel.providers before scripting this into CI — publish tags are the single most common source of "nothing happened" on first install.

Where to look first

  1. config/le-chat.php — the whole surface area of the package lives here: user model binding, table names, route prefix/middleware, broadcasting driver, and attachment/upload settings. Read it top to bottom before writing a line of code; it tells you what you can configure instead of fork.
  2. src/Models/ — Conversation, Message, and the participant/pivot model. These are the objects you'll actually spend your day with.
  3. routes/ — whether the package ships HTTP routes (and under what middleware) or expects you to build your own controllers.
  4. database/migrations/ — foreign key types (unsignedBigInteger vs uuid) must match your users table or migrate will fail on day one.

First use case: a 1:1 direct message thread

Wire the package's trait onto your User model (per the README), then create a conversation, attach both users as participants, and post one message. Render the thread in whatever front end you already have — Blade, Livewire, or Inertia — and submit new messages to the package's send endpoint (or your own controller calling the model API). That single loop — create conversation → attach participants → list messages → create message — is 90% of what this package does; everything else is polish on top of it.

Get that loop working with polling before you touch broadcasting. A working 5-second setInterval refresh beats a half-configured WebSocket that silently drops messages in production.

Implementation Patterns

Wrap, don't reach in. Create a thin application-level service (App\Support\Chat) that owns conversation creation, participant resolution, and message dispatch. Your controllers and jobs call that service, never the package models directly. When (not if) you need to swap or fork the package, you change one file.

Participant resolution. The most common real-world need is "open a DM with user X, or return the existing one." Implement it explicitly:

public function direct(User $a, User $b): Conversation
{
    return Conversation::query()
        ->whereHas('participants', fn ($q) => $q->whereKey($a->id))
        ->whereHas('participants', fn ($q) => $q->whereKey($b->id))
        ->where('is_group', false)
        ->first()
        ?? tap(Conversation::create(['is_group' => false]), function ($c) use ($a, $b) {
            $c->participants()->attach([$a->id, $b->id]);
        });
}

Add a unique index or a transaction around this if you expect concurrent "message seller" clicks — two rows for the same pair is a classic race.

Authorization is yours, not the package's. Packages of this size rarely ship a policy that matches your tenancy model. Add ConversationPolicy::view() that checks participancy ($conversation->participants->contains($user)), and enforce it in every controller, channel authorization callback, and API resource. This is the single highest-risk gap: a chat package that trusts route model binding will happily serve someone else's thread.

Broadcasting alongside persistence. Pattern that holds up: persist the message synchronously, then dispatch a MessageSent broadcast event on a private channel named per conversation (private-chat.{conversationId}). Authorize that channel against participancy in routes/channels.php. Front end listens and appends; HTTP response and broadcast payload should be the same JSON resource so there's one shape to render.

Message lists and pagination. Always order descending with a cursor (latest()->cursorPaginate(30)) and reverse client-side. Offset pagination breaks the moment a new message arrives mid-scroll. Eager-load the sender and the latest message per conversation (with('latestMessage.sender')) — an inbox listing 20 conversations without eager loading is 20+ queries.

Read receipts / unread counts. If the package exposes them, treat the unread count as a derived, cacheable value. Compute it once per conversation list request with a single grouped query or a last_read_at column on the participant pivot, and store the count in cache keyed by user with a short TTL. Recomputing per conversation on every poll is where chat features quietly become your slowest endpoint.

Notifications. Chat is a delivery channel, not an inbox. Fan out an unread-message email or push notification only when the recipient is offline or has no active thread, with a debounce/ShouldBeUnique job — otherwise a five-message burst produces five emails.

Testing. Write a feature test for the loop above (create conversation, send message, assert participant authorization rejects a third user) before you build UI. Package-level factories are often absent; add your own ConversationFactory and reuse it in every test.

Gotchas and Tips

Adoption risk is the headline. 47 stars, zero dependents, and a single maintainer means this is a "vendor it and own it" dependency, not a "trust the ecosystem" one. Pin the exact version in composer.json, read the full diff before bumping, and be prepared to fork. Budget a day for a security read-through of the controllers and channel auth — you're the only reviewer this code will get.

Verify the Laravel version constraint. Small packages lag on framework majors. Check composer.json → require for illuminate/support before you plan the upgrade path; a package stuck on an older major can block your whole app's Laravel bump.

Foreign keys and key types. If your users table uses UUIDs or ULIDs (common with HasUuids), the package's user_id columns must match. Publish the migrations, edit them before running migrate (change to foreignUuid/foreignUlid), and never edit vendor migrations in place after they've run.

Config caching bites. php artisan config:cache in deploy means any env() called inside the package's config file resolves at cache time. Set chat config via config/le-chat.php constants or app-level env vars that exist at build time, and remember to config:clear locally when toggling broadcasting drivers.

Broadcasting failure is silent. If BROADCAST_CONNECTION=log, messages persist but never arrive in real time — and nothing errors. Debug in this order: php artisan route:list | grep -i chat, check the queue worker is running (php artisan queue:work — broadcast events are queued), inspect the browser's WS frames, then check routes/channels.php authorization returns true. A 403 on the channel is far more common than a broken socket.

Extension points beat edits. Prefer binding a subclass in a service provider over editing vendor/:

$this->app->bind(\MMedia\LeChat\Models\Message::class, \App\Models\ChatMessage::class);

Same for views (vendor:publish --tag=le-chat-views) and routes (disable the package's routes in config and register your own under your app's middleware stack — you almost certainly want auth:sanctum + tenancy middleware there, not the package defaults).

Sanitize before render. Chat messages are user input rendered as HTML in most front ends. Force plain-text rendering or run an HTML purifier; a chat package will not do this for you, and <script> in a support message is a live XSS.

Soft deletes and retention. Decide up front whether deleted messages vanish or tombstone, and add a scheduled prune job for retention/GDPR. Retrofitting deletion semantics onto a chat table with a million rows is unpleasant; a deleted_at column and a ->withTrashed() policy now costs nothing.

Plan the polling fallback and index for it. Even with broadcasting, add a cheap GET /conversations/{id}/messages?after={id} endpoint and index (conversation_id, id). It's your reconnect path, your load-test path, and your escape hatch when the socket server misbehaves at 2am.

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.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect