Concepts

Markdown

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

AppAssistant

ItemDetail
ClassApp\Ai\Agents\AppAssistant
Pathapp/Ai/Agents/AppAssistant.php
ContractsAgent, Conversational, HasSkills, HasTools
Provider attribute#[Provider('local')]
TraitsPromptable, RemembersConversations
StepsmaxSteps() = count(FieldTypeEnum::cases()) + 16
Timeout300 seconds
EntryAiChatController → new AppAssistant($user)
Route gatepermission:can-use-ai on routes/ai.php

From externa-core 1.4.0, AppAssistant::tools() returns AiToolRegistryService::chatToolsFor($user): the shared registry that also backs the MCP server (#202). A tool is listed only when the user holds the required permission(s) via EffectivePermissionResolverService and it passes the config gates (AI_TOOLS_*, write gate). Each tool then re-checks action-level permissions through ChecksAiPermissions::requirePermission().

Write tools are off by default (1.4.0)

With AI_WRITE_TOOLS=false (default), chat keeps the read actions of the Manage* tools (list, get, search, …) and refuses their write and destructive actions. Pure write tools (ImportCollectionCsv, ImportRemoteJson) and RollbackLastAiTurn are not offered. Enable them per tool class and approve each write in the chat — AI tool approvals & audit.

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/js ship English literals (admin UI i18n elsewhere is unchanged).

Field-type knowledge

PieceDetail
CookbookApp\Ai\Support\FieldTypeCookbook — curated purpose / required keys / settings_json examples / nested rules (aligned with Field types + BlocksFieldSchema)
ToolDescribeFieldTypes — input types = list, all, or complex
GateRegistered with collection tools; needs show/create/edit collections
Prompt ruleBefore create_field / update_field on complex types, MUST call DescribeFieldTypes; treat ManageCollections get as source of truth for existing schema
Validationcreate_field / update_field run CollectionFieldSettingsPipeline (same normalize + rules as HTTP Store/Update field)
MCPdescribe_collection on the MCP server exposes the same schema to external agents; the cookbook stays chat-only

Permission-gated tools

Registration (tool available in the agent)

Permission needed for the tool to be listed (before the write gate):

Tool classRegistered when the user has
ManageCollectionsAny of: show / create / edit / delete / restore / force-delete collections
ManageCollectionItemsSame collection permission set
DescribeFieldTypesSame collection permission set (action also accepts show or create or edit)
QueryCollectionItemscan-show-collections
ExportCollectioncan-show-collections
SearchSimilarCollectionItemscan-show-collections
ImportCollectionCsvcan-create-collections
ImportRemoteJsoncan-create-collections
ExtractPdfTextcan-create-collections
GetImportJobStatuscan-create-collections
ManageAiSyncSourcescan-create-collections
RollbackLastAiTurncan-delete-collections
ManageFilesAny of: show / create / edit / delete / restore / force-delete files
ManageUsersAny of: show / create / edit / delete / restore / force-delete users
ManageRolesAny of: show / create / edit / delete roles
ManageGroupsAny of: show / create / edit / delete / restore / force-delete groups
QueryActivityLogscan-show-activity-logs

Paths: app/Ai/Tools/{ToolName}.php.

Action-level gates (high level)

ManageCollections

ActionsPermission
list, get, list_field_packscan-show-collections
create, duplicatecan-create-collections
update, create_field, update_field, delete_field, apply_field_packcan-edit-collections
deletecan-delete-collections
restorecan-restore-collections
force_deletecan-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

ActionsPermission
list, get, list_relation_optionscan-show-collections
createcan-create-collections
update, bulk_update, publishcan-edit-collections
delete, bulk_deletecan-delete-collections
restorecan-restore-collections
force_deletecan-force-delete-collections

Single-permission tools

ToolPermission
QueryCollectionItemscan-show-collections
ExportCollectioncan-show-collections
SearchSimilarCollectionItemscan-show-collections
ImportCollectionCsvcan-create-collections
ImportRemoteJsoncan-create-collections
ExtractPdfTextcan-create-collections
GetImportJobStatuscan-create-collections
RollbackLastAiTurncan-delete-collections
QueryActivityLogscan-show-activity-logs

ManageAiSyncSources

ActionsPermission
list, createcan-create-collections
update, enable, disable, deletecan-edit-collections

ManageFiles

ActionsPermission
list, searchcan-show-files
create / create_folder, save_attachmentcan-create-files
rename, move, move_many, tagcan-edit-files
deletecan-delete-files
restorecan-restore-files
force_deletecan-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:

KeyValue
Tablesagent_conversations, agent_conversation_messages
generate_titlefalse (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}.

Since 1.4.0 each assistant message keeps what the stream showed, so a reload loses nothing (core #572):

Column on agent_conversation_messagesContent
stepsThe steps in order: reasoning, text, tool calls (arguments, result, error, denial) and provider tools
usageInput, output, reasoning and cache tokens
metaProvider, model, the cited sources (citations) and the error, if any
statusHow the turn ended

AiConversationMessagePresenterService turns a stored message into the payload the Assistant page and the conversation API send, with each tool call's final state. What the user sees: AI chat — What an answer shows.

Attachments

PieceDetail
ModelApp\Models\AiChatAttachment
Disklocal (AiChatAttachment::DISK)
Max size5 MiB
TTL24 hours
Extensionscsv, txt, xlsx, pdf
Upload routePOST /ai/attachments (throttle 30/min)
Chat usageUp to 5 attachment_ids on POST /ai/chat

Items, files, and saved prompts can also be attached as conversation context (1.4.0) — AI chat — Context attachments. | Cleanup | ai:cleanup-attachments (daily schedule) |

Daily prompt limit

ConfigEnvDefault
ai.daily_prompt_limitAI_DAILY_PROMPT_LIMIT0 (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.

ConfigEnvDefault
ai.embeddings.enabledAI_EMBEDDINGS_ENABLEDfalse

SearchSimilarCollectionItems (can-show-collections) respects the flag:

ModeWhenResponse mode
EmbeddingsFlag true, query embedding succeeds, and stored CollectionItemEmbedding rows exist for the collection"embeddings"
Semantic-liteFlag 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.

Agent Skills

From externa-core 1.4.0 (#181), AppAssistant implements laravel/ai HasSkills. Playbooks live under resources/skills/*/SKILL.md and the model loads one on demand (LoadSkill) instead of carrying every rule in the system prompt.

SkillUsed when
collection-operationsCreating, updating, querying, packing, exporting, or deleting collections, fields, or items
collection-importCSV/XLSX attachments, remote JSON/API URLs, PDF extraction, queued import status, scheduled sync sources
approvalsA write or destructive action needs confirmation, or an approval was rejected or abandoned

Skills only add instructions. They do not grant tools or permissions; the registry and write gate still decide what can run. The playbook texts are marked as drafts for maintainer review in core.

MCP server

ai.mcp.enabled (AI_MCP_ENABLED, default false) turns on a real MCP endpoint at /mcp (externa-core 1.4.0) that reuses this registry for external AI clients, with owned API keys and mcp:read / mcp:write scopes. See MCP server.

Surrounding jobs and schedule

PieceRole
ImportCollectionJobCSV / Excel / remote JSON imports; status in cache
ai:run-sync-sourcesEvery minute — due AiSyncSource rows enqueue imports
ai:cleanup-attachmentsDaily — purge expired chat attachments
WebhookPOST /ai/webhooks/collection-import (HMAC-signed, CSRF-excepted)