assistant-engine/filament-assistant
Integrates an AI assistant directly into Filament admin panels. Chat with an LLM, run tools, and automate workflows without leaving the dashboard. Configure providers and tools via simple PHP, with a clean chat UI built on Filament components. Ideal for Laravel teams adding in-panel AI help.
This package is pre-1.0 with no downstream dependents — treat every class name below as "verify against the repo README and
vendor/assistant-engine/filament-assistant/src" before you build on it.
1. Install and publish
composer require assistant-engine/filament-assistant
php artisan vendor:publish --tag="filament-assistant-config"
php artisan vendor:publish --tag="filament-assistant-migrations" # if conversations are persisted
php artisan migrate
Open the published config/filament-assistant.php immediately — that file is the real documentation. It will tell you which provider/model is wired up, where the API key comes from, and whether streaming or tool-calling is on by default.
2. Add the key
OPENAI_API_KEY=sk-... # or ANTHROPIC_API_KEY — check the config's default driver
Never put this key in a panel-visible config; confirm it is only read server-side.
3. Register the plugin on a panel
// app/Providers/Filament/AdminPanelProvider.php
use AssistantEngine\FilamentAssistant\FilamentAssistantPlugin;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->plugin(FilamentAssistantPlugin::make());
}
4. First use case: a "Draft with AI" button on one form field
Start narrower than a full chat sidebar. Pick a single high-friction field (a Textarea for a product description, a support reply body) and wire the assistant to it. That gives you an end-to-end path — auth, provider key, streaming, cost — in an afternoon, and it is the pattern most of your team will actually use daily.
Where to look first, in order:
config/filament-assistant.php — providers, models, features toggles.src/Actions or src/Concerns — the ready-made form/table actions.src/Tools — how app functions are exposed to the model.Panel-scoped rollout. Register the plugin on an internal/admin panel first, not the customer-facing one. You get real usage data and a cost baseline before it is user-visible.
->plugin(
FilamentAssistantPlugin::make()
->navigationGroup('Tools')
->visible(fn () => auth()->user()?->can('use-ai-assistant'))
)
Field-level generation. The highest-value, lowest-risk integration: an action on a form component that fills the field with a generated draft the user edits.
Textarea::make('description')
->suffixAction(
AssistantAction::make('draft')
->prompt(fn (Get $get) => "Write a 60-word product description for: {$get('name')}")
->target('description')
)
Keep the human in the loop. Never auto-save model output; make the action write into form state only.
Context from the schema, not from the DB dump. Feed the assistant the shape of your data (field labels, enum options, a couple of sample rows) rather than full records. Long table dumps are the fastest way to burn tokens and leak data across tenants.
->context(fn (Model $record) => [
'fields' => collect($record->getFillable()),
'status_options' => StatusEnum::values(),
])
Tool calling into your domain, with policies re-checked. If the package exposes tools/functions to the model, every tool should resolve the current user and call Gate::authorize() itself. Do not trust that the assistant was only shown permitted resources.
class LookupOrderTool implements AssistantTool
{
public function handle(array $args): array
{
Gate::authorize('view', Order::class);
return Order::where('number', $args['number'])
->where('team_id', auth()->user()->team_id) // tenancy is not implicit
->firstOrFail()
->only(['status', 'shipped_at']);
}
}
Streaming in Livewire. If responses stream, they arrive over the Livewire connection — confirm your queue driver and livewire.php config allow it, and that any reverse proxy isn't buffering. Behind nginx you may need proxy_buffering off; on the panel location, or streaming degrades to a single blocking response.
Swap providers behind config, not code. Keep the model name and driver in config/env so you can drop to a cheaper model for bulk operations and reserve the expensive one for interactive chat.
Testing. Mock the HTTP layer rather than the package, so you exercise the real request-building code:
Http::fake(['api.openai.com/*' => Http::response([...])]);
Assert on what your app does with the response (field populated, tool called, policy enforced), not on prompt strings — those will churn.
diff -r vendor/assistant-engine/filament-assistant between versions; assume minor bumps can break you."assistant-engine/filament-assistant": "0.x.y") until you have your own integration tests around it.config/filament-assistant.php, run php artisan config:clear. A surprising number of "the plugin does nothing" reports are cached config.composer.json constraints against your filament/filament version before installing; a v3-only plugin on a v4 panel will fail at registration with an unhelpful container error.can('use-ai-assistant') gate, scope every query by tenant inside tools, and log tool invocations. The panel's resource policies do not automatically apply to model-initiated calls.RateLimiter in front of the chat endpoint. Long resource tables plus streaming plus a frontier model can produce unpleasant invoices in a week. Trim context aggressively; cap max_tokens.Http::fake() for tests, Laravel Telescope or a logging HTTP client middleware for real requests. Log the request payload once at debug level — the most common bug is an empty or malformed context array, which the model answers around rather than erroring on.max_execution_time will 504. Move long jobs (summarise 500 rows) to a queued job and notify via Filament's database notifications.->view() override for the widget and a ->systemPrompt()/->prompt() setter. Reach for those before forking — but if the package is unmaintained, forking the handful of classes you use is a legitimate, cheap exit.FILAMENT_ASSISTANT_ENABLED=false) that removes the plugin, so an outage or a runaway bill is a one-line revert-and-deploy.How can I help you explore Laravel packages today?