Some checks failed
App Prod-Parity E2E Dispatch / dispatch (push) Failing after 10s
CD Storybook UI / build (push) Failing after 3m25s
CD Storybook UI / dispatch (push) Has been skipped
CD deploy main / website-changed-files (push) Successful in 18m8s
CI Agent Skills / changed-files-check (push) Successful in 18m9s
CI Create App E2E minimal / changed-files-check (push) Successful in 24s
CI Create App / changed-files-check (push) Successful in 26s
CI Docs / changed-files-check (push) Successful in 26s
CI Emails / changed-files-check (push) Successful in 28s
CI Example App Hello World / changed-files-check (push) Successful in 23s
CI Front / changed-files-check (push) Has been skipped
CI Example App Postcard / changed-files-check (push) Successful in 27s
CI UI / changed-files-check (push) Has been skipped
CI Utils Test / changed-files-check (push) Successful in 45s
CI Twenty Apps / discover (push) Successful in 1m3s
CD deploy main / deploy-main (push) Failing after 3s
CI Agent Skills / agent-skills-validate (push) Has been skipped
CI Create App / create-app-test (lint) (push) Has been skipped
CI Emails / emails-test (push) Has been skipped
CI Front / front-task (lingui:compile) (push) Has been skipped
CI Front / front-task (lint) (push) Has been skipped
CI Example App Postcard / example-app-postcard (push) Has been skipped
CI UI / ui-task (lint) (push) Has been skipped
CI UI / ui-task (pack-size) (push) Has been skipped
CI UI / ui-task (size) (push) Has been skipped
CI UI / ui-task (test) (push) Has been skipped
CI UI / ui-task (typecheck) (push) Has been skipped
CI Utils Test / utils-test (push) Has been skipped
CI Twenty Apps / ${{ matrix.app.name }} (push) Has been skipped
CI Emails / ci-emails-status-check (push) Successful in 2s
CI Example App Hello World / ci-example-app-hello-world-status-check (push) Successful in 2s
CI Example App Postcard / ci-example-app-postcard-status-check (push) Successful in 3s
CI UI / ui-sb-test (push) Has been skipped
CI Utils Test / ci-utils-test-status-check (push) Successful in 2s
CI Twenty Apps / ci-twenty-apps-status-check (push) Successful in 2s
CI UI / ci-ui-status-check (push) Successful in 2s
CI Desktop / desktop (push) Failing after 1m8s
Push docs to Crowdin / Push documentation to Crowdin (push) Failing after 55s
Push translations to Crowdin / Extract and upload translations (push) Failing after 5s
Push website translations to Crowdin / Extract and upload website translations (push) Failing after 5s
CI Create App / create-app-test (test) (push) Has been skipped
CI Create App / create-app-test (typecheck) (push) Has been skipped
CI Docs / docs-lint (push) Has been skipped
CI Example App Hello World / example-app-hello-world (push) Has been skipped
CI Front / front-task (lingui:extract) (push) Has been skipped
CI Front / front-task (test) (push) Has been skipped
CI Front / front-task (typecheck) (push) Has been skipped
CI UI / ui-sb-build (push) Failing after 1m32s
CI Twenty Apps / ${{ matrix.app.name }} (${{ matrix.server-source }}) (push) Has been skipped
CI Agent Skills / agent-skills-publish (push) Has been skipped
CI Create App / ci-create-app-status-check (push) Successful in 2s
CI Agent Skills / agent-skills-remote-source (push) Has been skipped
CI Create App E2E minimal / create-app-e2e-minimal (push) Has been cancelled
CI E2E Main / e2e-test (push) Has been cancelled
CI Front / front-sb-build (push) Has been cancelled
CI Front / front-build (push) Has been cancelled
CI Create App E2E minimal / ci-create-app-e2e-minimal-status-check (push) Has been cancelled
CI E2E Main / ci-e2e-main-status-check (push) Has been cancelled
CI E2E Main / notify-main-ci-failure (push) Has been cancelled
CI E2E Main / qa-scout-comment (push) Has been cancelled
CI Front / front-sb-test (push) Has been cancelled
CI Front / front-sb-screenshots (push) Has been cancelled
CI Front / ci-front-status-check (push) Has been cancelled
DPA Sub-Processor Sync / sync-subprocessors (push) Failing after 3s
AI Catalog Sync / sync-catalog (push) Failing after 2s
187 lines
9.6 KiB
Plaintext
187 lines
9.6 KiB
Plaintext
---
|
||
title: Skill e agenti
|
||
description: Definisci skill e agenti di IA per la tua app.
|
||
icon: robot
|
||
---
|
||
|
||
<Warning>
|
||
Le skill e gli agenti sono attualmente in fase alfa. La funzionalità funziona ma è ancora in evoluzione.
|
||
</Warning>
|
||
|
||
Le app possono definire capacità di IA che risiedono all'interno dello spazio di lavoro — istruzioni di skill riutilizzabili e agenti con prompt di sistema personalizzati.
|
||
|
||
<AccordionGroup>
|
||
<Accordion title="defineSkill" description="Definisci le skill degli agenti IA">
|
||
|
||
Le skill definiscono istruzioni e capacità riutilizzabili che gli agenti IA possono utilizzare all'interno del tuo spazio di lavoro. Usa `defineSkill()` per definire skill con convalida integrata:
|
||
|
||
```ts src/skills/example-skill.ts
|
||
import { defineSkill } from 'twenty-sdk/define';
|
||
|
||
export default defineSkill({
|
||
universalIdentifier: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
|
||
name: 'sales-outreach',
|
||
label: 'Sales Outreach',
|
||
description: 'Guides the AI agent through a structured sales outreach process',
|
||
icon: 'IconBrain',
|
||
content: `You are a sales outreach assistant. When reaching out to a prospect:
|
||
1. Research the company and recent news
|
||
2. Identify the prospect's role and likely pain points
|
||
3. Draft a personalized message referencing specific details
|
||
4. Keep the tone professional but conversational`,
|
||
});
|
||
```
|
||
|
||
Punti chiave:
|
||
* `name` è una stringa identificativa univoca per la skill (kebab-case consigliato).
|
||
* `label` è il nome di visualizzazione leggibile mostrato nell'UI.
|
||
* `content` contiene le istruzioni della skill — questo è il testo che l'agente IA utilizza.
|
||
* `icon` (opzionale) imposta l'icona visualizzata nell'UI.
|
||
* `description` (opzionale) fornisce contesto aggiuntivo sullo scopo della skill.
|
||
|
||
</Accordion>
|
||
<Accordion title="defineAgent" description="Definisci agenti IA con prompt personalizzati">
|
||
|
||
Gli agenti sono assistenti IA che vivono all'interno del tuo spazio di lavoro. Usa `defineAgent()` per creare agenti con un prompt di sistema personalizzato:
|
||
|
||
```ts src/agents/example-agent.ts
|
||
import { defineAgent } from 'twenty-sdk/define';
|
||
|
||
export default defineAgent({
|
||
universalIdentifier: 'b3c4d5e6-f7a8-9012-bcde-f34567890123',
|
||
name: 'sales-assistant',
|
||
label: 'Sales Assistant',
|
||
description: 'Helps the sales team draft outreach emails and research prospects',
|
||
icon: 'IconRobot',
|
||
prompt: 'You are a helpful sales assistant. Help users with their questions and tasks.',
|
||
});
|
||
```
|
||
|
||
Punti chiave:
|
||
* `name` è la stringa identificativa univoca dell'agente (kebab-case consigliato).
|
||
* `label` è il nome visualizzato nell'UI.
|
||
* `prompt` è il prompt di sistema che definisce il comportamento dell'agente.
|
||
* `description` (opzionale) fornisce contesto su ciò che fa l'agente.
|
||
* `icon` (opzionale) imposta l'icona visualizzata nell'UI.
|
||
* `modelId` (opzionale) sostituisce il modello di IA predefinito utilizzato dall'agente.
|
||
* `responseFormat` (facoltativo) controlla la forma dell'output dell'agente. Per il testo in formato libero, il valore predefinito è `{ type: 'text' }`. Usa `{ type: 'json', schema }` per forzare un output JSON strutturato.
|
||
|
||
Per impostazione predefinita, un agente restituisce testo in formato libero. Per ottenere un output strutturato, imposta `responseFormat` su `{ type: 'json' }` e fornisci uno `schema`:
|
||
|
||
```ts src/agents/structured-agent.ts
|
||
import { defineAgent } from 'twenty-sdk/define';
|
||
|
||
export default defineAgent({
|
||
universalIdentifier: 'c4d5e6f7-a8b9-0123-cdef-456789012345',
|
||
name: 'lead-scorer',
|
||
label: 'Lead Scorer',
|
||
prompt: 'Score the lead and explain your reasoning.',
|
||
responseFormat: {
|
||
type: 'json',
|
||
schema: {
|
||
type: 'object',
|
||
properties: {
|
||
score: { type: 'number', description: 'Lead score from 0 to 100' },
|
||
summary: { type: 'string', description: 'Short reasoning for the score' },
|
||
},
|
||
required: ['score', 'summary'],
|
||
additionalProperties: false,
|
||
},
|
||
},
|
||
});
|
||
```
|
||
|
||
Note sullo schema:
|
||
* Lo schema è un oggetto piatto: il `type` di ogni proprietà deve essere un primitivo (`string`, `number` o `boolean`). Gli oggetti annidati e gli array non sono supportati.
|
||
* `description` (facoltativo) su ogni proprietà guida il modello su cosa inserire lì.
|
||
* `required` (facoltativo) elenca le proprietà che il modello deve sempre restituire.
|
||
* `additionalProperties: false` (facoltativo) vieta qualsiasi proprietà non dichiarata in `properties`.
|
||
|
||
</Accordion>
|
||
<Accordion title="runAgent" description="Esegui un agente da una funzione di logica">
|
||
|
||
`runAgent()` permette a una funzione di logica di eseguire uno degli agenti della tua app (con le sue skill e i suoi strumenti). Identifica l'agente tramite l'`universalIdentifier` che hai passato a `defineAgent()`. Passa una stringa `prompt` oppure una cronologia di conversazione `messages`, ma non entrambe:
|
||
|
||
```ts src/logic-functions/run-enricher.ts
|
||
import { runAgent } from 'twenty-sdk/logic-function';
|
||
|
||
const { result, error, success } = await runAgent({
|
||
agentUniversalIdentifier: 'b3c4d5e6-f7a8-9012-bcde-f34567890123',
|
||
prompt: 'Enrich House Ad <recordId>: fill empty fields from its listing URL.',
|
||
});
|
||
```
|
||
|
||
Per bot multi-turno (Slack, Discord, Teams, …), passa la cronologia del thread come `messages` invece di un singolo `prompt`:
|
||
|
||
```ts src/logic-functions/reply-in-thread.ts
|
||
import { runAgent } from 'twenty-sdk/logic-function';
|
||
|
||
const { result, error, success } = await runAgent({
|
||
agentUniversalIdentifier: 'b3c4d5e6-f7a8-9012-bcde-f34567890123',
|
||
messages: [
|
||
{ role: 'user', content: 'Who owns Acme?' },
|
||
{ role: 'assistant', content: 'Sarah owns the Acme account.' },
|
||
{ role: 'user', content: 'What was the last touchpoint?' },
|
||
],
|
||
});
|
||
```
|
||
|
||
Punti chiave:
|
||
* Fornisci **esattamente uno** tra `prompt` (string) o `messages` (da 1 a 100 elementi
|
||
di `{ role: 'user' | 'assistant', content: string }`).
|
||
* L'agente viene eseguito in modo **sincrono** e può leggere/aggiornare direttamente i record tramite i propri strumenti — `runAgent()` viene risolta una volta completata l'esecuzione.
|
||
* Un'app può eseguire solo i propri agenti.
|
||
* Il [ruolo predefinito](/l/it/developers/extend/apps/config/roles) dell'app deve concedere il flag di autorizzazione `AI` — aggiungi `SystemPermissionFlag.AI` ai suoi `permissionFlagUniversalIdentifiers` (oppure imposta `canAccessAllTools: true`).
|
||
In mancanza di ciò, `runAgent()` non riesce con un errore di autorizzazione.
|
||
* Imposta un valore generoso per `timeoutSeconds` sulla funzione di logica — l'esecuzione degli agenti può richiedere diversi secondi.
|
||
* `success` è `true` e `result` è non nullo quando l'esecuzione viene completata; in caso di errore `success` è `false`, `result` è `null` ed `error` contiene il motivo (ad esempio, quando lo spazio di lavoro esaurisce i crediti AI durante l'esecuzione).
|
||
|
||
```ts src/roles/default-role.ts
|
||
import { defineApplicationRole, SystemPermissionFlag } from 'twenty-sdk/define';
|
||
|
||
export default defineApplicationRole({
|
||
universalIdentifier: 'b648f87b-1d26-4961-b974-0908fd991061',
|
||
label: 'Default function role',
|
||
// runAgent() requires the AI permission flag on the app's default role.
|
||
permissionFlagUniversalIdentifiers: [SystemPermissionFlag.AI],
|
||
});
|
||
```
|
||
|
||
<Warning>
|
||
**Evita i loop:** se chiami `runAgent()` da un trigger di evento del database `*.updated` e l'agente aggiorna lo stesso record, limita il trigger con `updatedFields` a un campo che l'agente non scrive mai (ad esempio l'URL di origine), oppure controlla che almeno uno dei campi di destinazione sia ancora vuoto prima di chiamare `runAgent()`.
|
||
</Warning>
|
||
|
||
### Esecuzione per conto di un membro dello spazio di lavoro
|
||
|
||
Passa `runAsWorkspaceMemberId` quando l'esecuzione viene attivata da una persona — ad esempio un chatbot che risponde a un messaggio — in modo che l'agente agisca come quel membro invece che come l'app:
|
||
|
||
```ts src/logic-functions/answer-question.ts
|
||
const { result } = await runAgent({
|
||
agentUniversalIdentifier: 'b3c4d5e6-f7a8-9012-bcde-f34567890123',
|
||
prompt: 'How many open opportunities do we have?',
|
||
runAsWorkspaceMemberId: '20202020-0687-4c41-b707-ed1bfca972a7',
|
||
});
|
||
```
|
||
|
||
L’esecuzione quindi agisce con **il ruolo proprio del membro**: può fare tutto ciò che
|
||
quel membro può fare e niente di più, i record che crea sono attribuiti a lui e
|
||
si applicano i suoi permessi a livello di riga. Il ruolo dell’agente non partecipa — è l’impostazione predefinita dell’app per le esecuzioni senza nessuno dietro. Ometti il campo per
|
||
le esecuzioni autonome (attività pianificate, trigger di eventi del database): queste mantengono il ruolo proprio dell’agente. L’applicazione che agisce rimane collegata al contesto dell’esecuzione
|
||
per la tracciabilità, senza restringere i permessi del membro.
|
||
|
||
La tua app è responsabile di mappare la persona che ha attivato l'esecuzione a un membro dello spazio di lavoro. Per specificarne uno è necessario un token di accesso dell'app e ciò che un token può specificare dipende dal fatto che sia o meno associato a un utente:
|
||
|
||
* Un token senza alcun utente associato può specificare qualsiasi membro. Una funzione logica viene eseguita con uno, e così anche i token generati tramite `client_credentials` o da una chiave API.
|
||
* Un token emesso per conto di un utente, come quello che riceve un front component, può specificare solo il membro dell'utente stesso.
|
||
|
||
Qualsiasi altra cosa — una semplice sessione utente, una chiave API senza un token dell'app — non può specificare affatto un membro.
|
||
|
||
<Warning>
|
||
`runAgent()` genera un errore quando il membro dello spazio di lavoro non può essere risolto — un
|
||
membro sconosciuto o rimosso, o uno senza ruolo. Non ricorre mai al
|
||
ruolo proprio dell'agente, poiché ciò concederebbe più accesso di quanto richiesto dal chiamante.
|
||
</Warning>
|
||
|
||
</Accordion>
|
||
</AccordionGroup>
|