Looking to hire Laravel developers? Try LaraJobs

laravel maintained by apartejs

Description
aparté for Laravel: an AI chat for Blade, Livewire and Filament, wired to the Laravel AI SDK.
Last update
2026/11/10 22:52 (dev-main)
License
Downloads
9

Comments
comments powered by Disqus

aparté for Laravel

An AI chat for Blade, Livewire and Filament pages, wired to the Laravel AI SDK. No React and no build step: replies stream with Markdown, tool calls show as they run, and a person can approve or refuse them.

The chat in a Filament panel, asking before a tool runs

It is built on aparté, a chat UI made of web components, and needs PHP 8.3+, Laravel 12 or 13 and laravel/ai 1.3+.

Install

composer require apartejs/laravel
php artisan vendor:publish --provider="Laravel\Ai\AiServiceProvider"
php artisan migrate

The last two are the SDK's own setup: its configuration and the tables that keep conversations.

Use it

An agent that keeps its conversations:

namespace App\Ai\Agents;

use Laravel\Ai\Concerns\RemembersConversations;
use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Contracts\Conversational;
use Laravel\Ai\Promptable;

class Assistant implements Agent, Conversational
{
    use Promptable, RemembersConversations;

    public function instructions(): string
    {
        return 'You are a helpful assistant.';
    }
}

A route, and the chat in a view. Give it a height:

// routes/web.php
Route::aparte('/chat', App\Ai\Agents\Assistant::class);
<x-aparte::chat endpoint="/chat" style="height: 32rem" />

Inside a Livewire component it works as is: it is excluded from Livewire's re-renders.

Protect the route. It spends your model budget and runs your tools, so give it the middleware your app needs:

Route::aparte('/chat', App\Ai\Agents\Assistant::class)->middleware(['auth', 'throttle:20,1']);

A button in the corner of the page

<x-aparte::launcher endpoint="/chat" label="Help" />

Filament

use Aparte\Laravel\Filament\ApartePlugin;

$panel->plugin(ApartePlugin::make()->agent(App\Ai\Agents\Assistant::class)->label('Assistant'));

Every page of the panel gets the button, for whoever is signed in to it. The route is added for you, behind the panel's authentication, and the chat follows the panel's light or dark mode.

Approving tool calls

A tool that needs a person uses the SDK's approvals:

public function tools(): iterable
{
    return [(new SendInvoice)->requireApproval('Sending an invoice.')];
}

The chat asks before the tool runs. The model answers a refusal, and reads what the person typed in its place. A pending question comes back after a reload.

Slots

<x-aparte::chat endpoint="/chat" style="height: 32rem">
    <x-slot:empty-state><p>How can I help?</p></x-slot:empty-state>
    <x-slot:above-composer><p>Answers may be wrong.</p></x-slot:above-composer>
    <x-slot:toolbar><button type="button" style="margin-inline-start: auto">Help</button></x-slot:toolbar>
</x-aparte::chat>

Good to know

  • The look is set with aparté's CSS variables. It follows the system's light or dark mode; follow-dark-class makes it follow Tailwind's dark class instead.
  • What is kept: the SDK keeps the conversation in your database, tied to the signed-in user, and the model's memory comes from there. What is on screen is kept for the tab: closing it starts a new conversation.
  • A conversation is identified by an id the browser creates, or by thread="..." on the component.
  • Guests can chat if your route allows them. Their conversations belong to nobody, so the id is all that protects one.
  • In production, replies stream through nginx and PHP-FPM with no configuration: the SDK tells nginx not to buffer them. Each reply in progress holds a PHP worker until it ends, so count them in pm.max_children.
  • The SDK's AG-UI stream, which this package reads, is not in its documentation yet, so a new laravel/ai version could change it.

Develop

composer install
vendor/bin/pest
npm install && npm run build   # rebuilds dist/, which is committed

MIT license.