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 / update / delete → create/edit/delete roles; list_permissions → can-show-permissions or create/edit roles.
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 flag vs similarity search
| Config | Env | Default |
|---|---|---|
ai.embeddings.enabled | AI_EMBEDDINGS_ENABLED | false |
Similarity is still a text scan
SearchSimilarCollectionItems does not read ai.embeddings.enabled. It always runs a semantic-lite pass: load up to 500 recent items, case-insensitive str_contains over the lowercased JSON of assembled field values, and return "mode": "semantic-lite". The embeddings flag is config-ready for a future vector provider; it does not change similarity behavior today.
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 (token-gated, CSRF-excepted) |