Features
AI imports & sync
Beyond chat, the assistant can import collection rows from attachments or remote JSON, export data, extract PDF text, schedule sync sources, and roll back the last AI mutation turn. Async work is tracked as import jobs; an external webhook can enqueue the same pipeline with AI_WEBHOOK_TOKEN.
Related
Chat UI & attachments: AI chat. Tool registration gates: AI assistant model. Env keys: AI configuration. Routes: AI API & webhooks.
Tools
Registered on App\Ai\Agents\AppAssistant when the user holds the matching permission (then re-checked inside the tool).
| Tool class | Gate | Role |
|---|---|---|
ImportCollectionCsv | can-create-collections | CSV/TXT/XLSX attachment → collection; max 500 rows sync; async if async or rows > 200 |
ImportRemoteJson | can-create-collections | Remote JSON URL via SafeRemoteUrlValidator; limit default 200, max 500; same async threshold |
ExportCollection | can-show-collections | Export up to 500 rows as csv or json |
ExtractPdfText | can-create-collections | PDF attachment text, max 20 000 characters |
RollbackLastAiTurn | can-delete-collections | Soft-delete creations from the last AI turn (ai_prompt → following ai_mutation) |
GetImportJobStatus | can-create-collections | Poll job status (mirror of HTTP status) |
ManageAiSyncSources | create vs edit collection perms | List/create/update/enable/disable/delete sync sources |
Paths: app/Ai/Tools/{ToolName}.php.
dry_run and upsert_key
Both ImportCollectionCsv and ImportRemoteJson accept:
| Option | Meaning |
|---|---|
dry_run | Preview inferred schema / sample; no writes |
upsert_key | Field name used to choose update vs create |
Also accepted on the collection-import webhook and stored on AiSyncSource for scheduled runs. ImportCollectionJob carries upsertKey and dryRun in its constructor.
Import job status
| Item | Detail |
|---|---|
| Job | App\Jobs\ImportCollectionJob |
| HTTP | GET /ai/import-jobs/{jobId} → ImportJobStatusController |
| Name | ai.import-jobs.show |
| Extra middleware | permission:can-create-collections (in addition to can-use-ai on the group) |
| Status source | ImportCollectionJob::status($jobId) — cache key ai:import-job:{uuid}, TTL 24h |
Status payload includes job_id, status (queued | running | done | failed), processed, total, message, and result (user id stripped for the response).
Webhook
| Item | Detail |
|---|---|
| Route | POST /ai/webhooks/collection-import |
| Controller | App\Http\Controllers\Ai\CollectionImportWebhookController |
| Name | ai.webhooks.collection-import |
| Middleware | Only throttle:30,1 (no session auth) |
| Token config | config('ai.webhook_token') ← AI_WEBHOOK_TOKEN |
Auth: Bearer token or header X-AI-Webhook-Token, compared with hash_equals. Empty configured token → 403.
Body (CollectionImportWebhookRequest):
| Field | Rules |
|---|---|
collection_id | Required |
records | Array, 1–500 |
upsert_key | Optional |
Uses ImportsCollectionRecords; webhook path does not write AI mutation logs (logAiMutation no-op).
Scheduled sync (AiSyncSource)
| Item | Detail |
|---|---|
| Model | App\Models\AiSyncSource |
| Fillable | user_id, collection_id, url, upsert_key, interval_minutes, auth_bearer (encrypted), last_run_at, last_status, enabled |
| Command | ai:run-sync-sources → App\Console\Commands\RunAiSyncSourcesCommand |
| Schedule | Schedule::command('ai:run-sync-sources')->everyMinute() in routes/console.php |
Eligible sources enqueue ImportCollectionJob with sourceType: 'remote_json' and syncSourceId.
Remote URL safety
| Item | Detail |
|---|---|
| Validator | App\Ai\Support\SafeRemoteUrlValidator |
| Used by | ImportRemoteJson, ManageAiSyncSources |
| Rules | http/https only; no URL credentials; block localhost / metadata / private IPs; DNS resolve check |
| Allowlist | config('ai.remote_import_hosts') ← AI_REMOTE_IMPORT_HOSTS (comma-separated) |
If the allowlist is non-empty, the host must be listed. If empty, any non-blocked host is allowed.
Related env vars
| Env | Config key |
|---|---|
AI_REMOTE_IMPORT_HOSTS | ai.remote_import_hosts |
AI_WEBHOOK_TOKEN | ai.webhook_token |
AI_DAILY_PROMPT_LIMIT | ai.daily_prompt_limit |
(Plus provider keys documented under AI configuration.)
Source map
| Concern | Location |
|---|---|
| Tools | app/Ai/Tools/ImportCollectionCsv.php, ImportRemoteJson.php, ExportCollection.php, ExtractPdfText.php, RollbackLastAiTurn.php, … |
| Job | app/Jobs/ImportCollectionJob.php |
| Webhook | app/Http/Controllers/Ai/CollectionImportWebhookController.php |
| Job status | app/Http/Controllers/Ai/ImportJobStatusController.php |
| Sync command | app/Console/Commands/RunAiSyncSourcesCommand.php |
| Validator | app/Ai/Support/SafeRemoteUrlValidator.php |
| Routes / schedule | routes/ai.php, routes/console.php |