Concepts
AI assistant model
The in-app assistant is App\Ai\Agents\AppAssistant: a conversational, tool-using agent (laravel/ai) whose tool list is filtered by the user’s effective permissions. Chat history, attachments, imports, and sync sources sit around that agent.
Related
Product guides: AI chat, AI imports & sync. Config: AI configuration. HTTP: AI API & webhooks.
AppAssistant
| Item | Detail |
|---|---|
| Class | App\Ai\Agents\AppAssistant |
| Path | app/Ai/Agents/AppAssistant.php |
| Contracts | Agent, Conversational, HasTools |
| Provider attribute | #[Provider('local')] |
| Traits | Promptable, RemembersConversations |
| Steps | maxSteps() = count(FieldTypeEnum::cases()) + 16 |
| Timeout | 300 seconds |
| Entry | AiChatController → new AppAssistant($user) |
| Route gate | permission:can-use-ai on routes/ai.php |
Tools are registered in AppAssistant::tools() only when the user holds the required permission(s) via EffectivePermissionResolver. Each tool then re-checks action-level permissions through ChecksAiPermissions::requirePermission().
Language policy
- The assistant replies in the same language as the user’s latest message. If it cannot confidently use that language, it uses English. It must never assume Italian.
- Tool errors, fallback turn summaries, and AI HTTP messages are English machine strings; the model translates them for the user.
- Prompt chips / AI UI chrome in
resources/jsship English literals (admin UI i18n elsewhere is unchanged).
Field-type knowledge (no MCP yet)
| Piece | Detail |
|---|---|
| Cookbook | App\Ai\Support\FieldTypeCookbook — curated purpose / required keys / settings_json examples / nested rules (aligned with Field types + BlocksFieldSchema) |
| Tool | DescribeFieldTypes — input types = list, all, or complex |
| Gate | Registered with collection tools; needs show/create/edit collections |
| Prompt rule | Before create_field / update_field on complex types, MUST call DescribeFieldTypes; treat ManageCollections get as source of truth for existing schema |
| Validation | create_field / update_field run CollectionFieldSettingsPipeline (same normalize + rules as HTTP Store/Update field) |
| MCP | ai.mcp.enabled stays off — custom tools are the knowledge plane for now |
Permission-gated tools
Registration (tool available in the agent)
| Tool class | Registered when the user has |
|---|---|
ManageCollections | Any of: show / create / edit / delete / restore / force-delete collections |
ManageCollectionItems | Same collection permission set |
DescribeFieldTypes | Same collection permission set (action also accepts show or create or edit) |
QueryCollectionItems | can-show-collections |
ExportCollection | can-show-collections |
SearchSimilarCollectionItems | can-show-collections |
ImportCollectionCsv | can-create-collections |
ImportRemoteJson | can-create-collections |
ExtractPdfText | can-create-collections |
GetImportJobStatus | can-create-collections |
ManageAiSyncSources | can-create-collections |
RollbackLastAiTurn | can-delete-collections |
ManageFiles | Any of: show / create / edit / delete / restore / force-delete files |
ManageUsers | Any of: show / create / edit / delete / restore / force-delete users |
ManageRoles | Any of: show / create / edit / delete roles |
ManageGroups | Any of: show / create / edit / delete / restore / force-delete groups |
QueryActivityLogs | can-show-activity-logs |
Paths: app/Ai/Tools/{ToolName}.php.
Action-level gates (high level)
ManageCollections
| Actions | Permission |
|---|---|
list, get, list_field_packs | can-show-collections |
create, duplicate | can-create-collections |
update, create_field, update_field, delete_field, apply_field_pack | can-edit-collections |
delete | can-delete-collections |
restore | can-restore-collections |
force_delete | can-force-delete-collections |
Collection packs: for SEO entity / Articles / Pages / Products / Categories, the assistant MUST call apply_collection_pack (pack, e.g. seo or articles). Dependencies auto-create. UI: Collections Create from pack…. Presets: “Apply SEO collection”, “Scaffold Articles”, “Scaffold Products”.
Field packs: for denormalized SEO (seo_inline) or publishing/contact/social on an existing collection, MUST call apply_field_pack (collection_id + pack). Use seo_inline only when the user wants inline seo_* fields. UI: Fields page Add field pack…. Registry: Field types — Field packs.
ManageCollectionItems
| Actions | Permission |
|---|---|
list, get, list_relation_options | can-show-collections |
create | can-create-collections |
update, bulk_update | can-edit-collections |
delete, bulk_delete | can-delete-collections |
restore | can-restore-collections |
force_delete | can-force-delete-collections |
Single-permission tools
| Tool | Permission |
|---|---|
QueryCollectionItems | can-show-collections |
ExportCollection | can-show-collections |
SearchSimilarCollectionItems | can-show-collections |
ImportCollectionCsv | can-create-collections |
ImportRemoteJson | can-create-collections |
ExtractPdfText | can-create-collections |
GetImportJobStatus | can-create-collections |
RollbackLastAiTurn | can-delete-collections |
QueryActivityLogs | can-show-activity-logs |
ManageAiSyncSources
| Actions | Permission |
|---|---|
list, create | can-create-collections |
update, enable, disable, delete | can-edit-collections |
ManageFiles
| Actions | Permission |
|---|---|
list, search | can-show-files |
create / create_folder, save_attachment | can-create-files |
rename, move, move_many | can-edit-files |
delete | can-delete-files |
restore | can-restore-files |
force_delete | can-force-delete-files |
ManageUsers / ManageGroups — show / create / edit / delete / restore / force-delete mapped to the matching can-*-users or can-*-groups permissions.
ManageRoles — list/get → can-show-roles; create / duplicate → can-create-roles (+ show for duplicate); update / delete → edit/delete roles; list_permissions → can-show-permissions or create/edit roles. Duplicate clones Spatie permissions and collection/file matrices into a new named role (no user/group memberships). Cannot duplicate super-admin or locked system roles (same as the UI).
Same gates as HTTP
Collections HTTP routes use Spatie permission:can-*-collections (and FormRequest checks on bulk). The assistant re-checks the same permission names per tool action, plus CollectionPermissionEnforcer for item ACL / item_filter. See Effective permissions · Collections API.
Conversations
Configured under config/ai.php → ai.conversations:
| Key | Value |
|---|---|
| Tables | agent_conversations, agent_conversation_messages |
generate_title | false (title derived from the first prompt without an extra LM call) |
Controllers: AiConversationController, AiPageController. Routes cover list/create/update/destroy, pin, truncate, bulk-destroy, and deep-link GET /ai/{conversation}.
Attachments
| Piece | Detail |
|---|---|
| Model | App\Models\AiChatAttachment |
| Disk | local (AiChatAttachment::DISK) |
| Max size | 5 MiB |
| TTL | 24 hours |
| Extensions | csv, txt, xlsx, pdf |
| Upload route | POST /ai/attachments (throttle 30/min) |
| Chat usage | Up to 5 attachment_ids on POST /ai/chat |
| Cleanup | ai:cleanup-attachments (daily schedule) |
Daily prompt limit
| Config | Env | Default |
|---|---|---|
ai.daily_prompt_limit | AI_DAILY_PROMPT_LIMIT | 0 (disabled) |
When the limit is greater than 0, AiChatController counts today’s Spatie activity rows (log_name = ai, event = ai_prompt, causer = user). At or above the limit the chat endpoint returns 429 with message Daily AI prompt limit reached.
Embeddings and similarity search
| Config | Env | Default |
|---|---|---|
ai.embeddings.enabled | AI_EMBEDDINGS_ENABLED | false |
SearchSimilarCollectionItems (can-show-collections) respects the flag:
| Mode | When | Response mode |
|---|---|---|
| Embeddings | Flag true, query embedding succeeds, and stored CollectionItemEmbedding rows exist for the collection | "embeddings" |
| Semantic-lite | Flag false, provider failure, or no stored vectors yet | "semantic-lite" |
Embeddings path: generate a query vector via Laravel AI Embeddings, score stored vectors (cosine over JSON float arrays; pgvector later), return scored items. Item saves queue GenerateCollectionItemEmbeddingJob. If the collection has zero stored embeddings, the tool dispatches generation for up to 50 recent items and falls back this request.
Semantic-lite path: load up to 500 recent items (permission-filtered), case-insensitive str_contains over lowercased JSON of assembled field values.
Tool description text also switches when the flag is on. Config details: AI configuration — Embeddings.
MCP flag
| Config | Env | Default |
|---|---|---|
ai.mcp.enabled | AI_MCP_ENABLED | false |
Referenced as an opt-in placeholder in AppAssistant::tools() comments. There is no active MCP wiring until laravel/ai exposes stable agent MCP integration. Leaving the flag false is correct for production today.
Surrounding jobs and schedule
| Piece | Role |
|---|---|
ImportCollectionJob | CSV / Excel / remote JSON imports; status in cache |
ai:run-sync-sources | Every minute — due AiSyncSource rows enqueue imports |
ai:cleanup-attachments | Daily — purge expired chat attachments |
| Webhook | POST /ai/webhooks/collection-import (HMAC-signed, CSRF-excepted) |