Prezentare generală
Aplicațiile pot defini capabilități AI care există în interiorul spațiului de lucru — instrucțiuni reutilizabile pentru abilități și agenți cu prompturi de sistem personalizate.defineSkill
Definiți abilități pentru agentul AI
defineSkill
Definiți abilități pentru agentul AI
Abilitățile definesc instrucțiuni și capabilități reutilizabile pe care agenții AI le pot folosi în spațiul dvs. de lucru. Folosiți Puncte cheie:
defineSkill() pentru a defini abilități cu validare încorporată:src/skills/example-skill.ts
nameeste un șir identificator unic pentru abilitate (se recomandă kebab-case).labeleste numele lizibil afișat în interfața cu utilizatorul (UI).contentconține instrucțiunile abilității — acesta este textul pe care agentul AI îl folosește.icon(opțional) setează pictograma afișată în UI.description(opțional) oferă context suplimentar despre scopul abilității.
defineAgent
Definiți agenți AI cu prompturi personalizate
defineAgent
Definiți agenți AI cu prompturi personalizate
Agenții sunt asistenți AI care există în interiorul spațiului dvs. de lucru. Utilizați Puncte cheie:Note despre schemă:
defineAgent() pentru a crea agenți cu un prompt de sistem personalizat:src/agents/example-agent.ts
nameeste un șir identificator unic pentru agent (se recomandă kebab-case).labeleste numele de afișare din interfața cu utilizatorul (UI).promptconține promptul de sistem — acesta este textul de instrucțiuni care definește comportamentul agentului.description(opțional) oferă context despre ce face agentul.icon(opțional) setează pictograma afișată în UI.modelId(opțional) suprascrie modelul AI implicit utilizat de agent.responseFormat(opțional) stabilește formatul implicit al ieșirii agentului. Valoarea implicită este{ type: 'text' }pentru text liber. Folosește{ type: 'json', schema }pentru a impune ieșire JSON structurată. Un apelrunAgent()sau un pas AI dintr-un flux de lucru poate solicita un format diferit, care are prioritate.roleUniversalIdentifier(opțional) leagă agentul de un rol definit de aplicația ta. Acel rol nu trebuie să acorde mai multe permisiuni decât rolul aplicației, altfel compilarea eșuează; consultați Roluri de agent.modelConfiguration(opțional) activează instrumentele native ale modelului, așa cum face pagina de setări a agentului:{ webSearch: { enabled: true }, twitterSearch: { enabled: true } }. Fiecare instrument funcționează numai pe modelele care îl acceptă. Omiteți-l pentru a le menține dezactivate.isSystem(opțional, are implicit valoareafalse) ascunde agentul din listele de agenți, la fel ca agenții pe care Twenty îi creează pentru pașii de IA din fluxurile de lucru. Schimbă doar ceea ce este afișat: agenții unei aplicații pot fi modificați numai prin intermediul aplicației, indiferent de valoarea acestei opțiuni.
responseFormat la { type: 'json' } și furnizează schema:src/agents/structured-agent.ts
- Schema este un obiect plat:
typeal fiecărei proprietăți trebuie să fie un tip primitiv (string,numbersauboolean). Obiectele îmbricate și tablourile nu sunt acceptate. description(opțional) pe fiecare proprietate ghidează modelul cu privire la ce să pună acolo.required(opțional) enumeră proprietățile pe care modelul trebuie să le returneze întotdeauna.additionalProperties: false(opțional) interzice orice proprietate care nu este declarată înproperties.
defineMcpServer
Expuneți un server MCP extern către IA spațiului de lucru (beta)
defineMcpServer
Expuneți un server MCP extern către IA spațiului de lucru (beta)
Utilizați Puncte cheie:
defineMcpServer() pentru a livra un server MCP la distanță (HTTP streaming) împreună cu aplicația dvs., astfel încât IA spațiului de lucru să îi poată utiliza instrumentele fără a sincroniza datele respective în Twenty:src/mcp-servers/github.ts
nameeste în snake_case (litere mici, cifre și caractere de subliniere, începe cu o literă, maximum 32 de caractere) și este unic în spațiul de lucru. Acesta este prefixul numelor instrumentelor serverului.urltrebuie să fie un URL HTTP sau HTTPS.connectionProvider(opțional) face referire la un furnizor de conexiune declarat de aceeași aplicație. Apelurile trimit tokenul de acces al conexiunii respective ca token Bearer. Omiteți-l pentru un server public.- URL-ul nu se poate modifica într-o versiune ulterioară cât timp este asociat un furnizor de conexiune, astfel încât tokenurile să nu fie trimise niciodată către o altă gazdă.
- Spațiile de lucru pot dezactiva serverul; o versiune ulterioară a aplicației păstrează această opțiune.
- Necesită
"engines": { "twenty": ">=2.53.0" }.
runAgent
Rulează un agent dintr-o funcție logică
runAgent
Rulează un agent dintr-o funcție logică
runAgent() permite unei funcții logice să ruleze unul dintre agenții aplicației tale (cu abilitățile și instrumentele sale). Identifică agentul prin universalIdentifier pe care l-ai transmis
către defineAgent() și transmite ca input ceea ce vrei să proceseze:src/logic-functions/run-enricher.ts
inputeste un șir sau o listă de 1 până la 100 de mesaje ({ role: 'user' | 'assistant', content: string }). Un mesajuserpoate include și atașamente de fișiere (vezi mai jos). Pentru a menține o conversație, transmiteți unthreadîn loc să reluați dvs. rândurile anterioare.- În mod implicit, apelul așteaptă agentul, care poate citi/actualiza înregistrări
direct prin propriile sale instrumente —
runAgent()se finalizează după ce execuția se încheie. TransmitețiwaitForCompletion: falsepentru a se finaliza de îndată ce începe execuția:statuseste apoiRUNNINGșiresult: null, iar răspunsul ajunge în conversațiathreadId. O execuție care depășește 15 minute se finalizează, de asemenea, caRUNNING. - Agentul poate, de asemenea, să se întrerupă până când se modifică o înregistrare sau a trecut un anumit timp.
runAgent()se rezolvă apoi cusuccess: true,status: 'SUSPENDED'șiresult: null; agentul continuă singur mai târziu, iar răspunsul său ajunge în conversațiathreadId. Un apel către unthreadal cărui agent încă așteaptă eșuează până când acesta se finalizează. - Fiecare apel este stocat împreună cu intrarea și starea sa, precum și cu răspunsul și utilizarea sa
atunci când se finalizează, astfel încât să apară în execuțiile agentului. Fără un
thread, un apel primește o conversație proprie:threadIdo denumește, iar un apel ulterior nu o vede niciodată. - O aplicație poate rula doar propriii săi agenți.
- Rolul implicit al aplicației trebuie să acorde indicatorul de permisiune
AI— adaugăSystemPermissionFlag.AIlapermissionFlagUniversalIdentifiers(sau seteazăcanAccessAllTools: true). Fără acesta,runAgent()eșuează cu o eroare de permisiune. - Setează un
timeoutSecondsgeneros pentru funcția logică — rulările agentului pot dura câteva secunde. statusesteCOMPLETEDcu unresultcare nu este null atunci când execuția se finalizează fără a aștepta;SUSPENDEDcusuccess: trueșiresult: nullcât timp așteaptă;RUNNINGcusuccess: trueșiresult: nullatunci când apelul nu a așteptat execuția;FAILEDcusuccess: falseșierrorcare conține motivul (de exemplu, când spațiul de lucru rămâne fără credite AI în timpul execuției).
src/roles/default-role.ts
Trimiterea fișierelor cu un mesaj
Un mesajuser poate include attachments, astfel încât agentul vede o captură de ecran sau un
PDF în loc să vadă doar numele acestuia. Fiecare intrare face referire la un fișier pe care aplicația dvs. l-a
încărcat deja în folderul agent-chat:src/logic-functions/describe-screenshot.ts
UPLOAD_FILE în rolul implicit al aplicației,
alături de AI. filename este opțional și doar etichetează fișierul pentru model.- Doar mesajele
userpot include atașamente. Acestea nu pot fi reprezentate într-un tur al asistentului, astfel încâtrunAgent()le respinge acolo, în loc să le elimine. - Cel mult 10 atașamente per mesaj.
fileIdtrebuie să indice un fișier încărcat complet în același spațiu de lucru, în folderulagent-chat. Orice altceva face ca apelul să eșueze, în loc să răspundă în mod discret fără fișier.
Solicitarea unui rezultat structurat
TransmitețiresponseFormat pentru a obține un format numai pentru acest apel. Are prioritate față de
propriul responseFormat al agentului, astfel încât un agent poate deservi apelanți care au nevoie de
ieșiri diferite. Folosește aceeași schemă ca defineAgent():src/logic-functions/score-lead.ts
Continuarea unei conversații
Transmiteți unthread, iar Twenty păstrează conversația pentru dvs.: fiecare apel trimite doar
noua intrare, iar agentul vede rândurile anterioare, inclusiv ceea ce au
returnat instrumentele sale. Utilizați ca cheie orice identificator stabil din partea dvs., cum ar fi un canal Slack
și marca temporală a firului de discuție:src/logic-functions/reply-in-thread.ts
- Cheile sunt limitate la aplicația și agentul dvs., astfel încât două aplicații nu partajează niciodată o
conversație. Numai tokenurile de acces ale aplicației pot transmite un
thread. inputpoate conține numai mesajeuser: conversația conține deja răspunsurile agentului.additionalInstructionssunt oferite modelului numai pentru acest apel și nu sunt stocate, ceea ce este potrivit pentru instrucțiuni per solicitare, cum ar fi reguli de formatare sau un termen-limită. Acestea funcționează și fără unthread.- Fiecare rulare este stocată ca un tur cu starea sa, inclusiv cele eșuate. Utilizarea sa este stocată când agentul revine, chiar dacă a rămas fără credite. O rulare eșuată nu face parte din conversație, astfel încât următorul apel nu o vede.
- Apelurile din același fir de discuție rulează pe rând: un al doilea apel așteaptă ca primul să se termine, astfel încât fiecare îl vede pe cel dinaintea sa.
- Când rândurile rulează ca membri diferiți (vedeți mai jos), fiecare vede numai textul rândurilor celorlalți, niciodată rezultatele instrumentelor lor, deoarece acestea au fost citite cu permisiunile altcuiva.
Rulare în numele unui membru al spațiului de lucru
TransmiterunAsWorkspaceMemberId atunci când rularea este declanșată de o persoană — de exemplu, un chatbot care răspunde la un mesaj — astfel încât agentul să acționeze ca acel membru în loc să acționeze ca aplicația:src/logic-functions/answer-question.ts
- Un token fără niciun utilizator atașat poate denumi orice membru. O funcție logică rulează cu unul, la fel și tokenurile emise prin
client_credentialssau dintr-o cheie API. - Un token emis în numele unui utilizator, așa cum primește un front component, poate denumi doar propriul membru al acelui utilizator.
În urma unei conversații
O aplicație citește conversațiile pe care le deține cu agenții săi prin intermediul aceluiași API ca și chat:listConversationMessages() returnează istoricul ei, și
streamConversation() generează evenimentele sale live, token by token. Numește conversația
de către agent și cheia thread pe care o treci la `runAgent()”; tu
îl poți urmări înainte ca prima execuție să ajungă la el.src/logic-functions/follow-conversation.ts
- Evenimentele sunt ale chatului:
stream-chunktransportă un AI SDKUIMessageChunkşi unseq, şi notificări precummesajpersistă(un mesaj a fost salvat: un membru sau răspunsul, care transportă contul săuturnId),credits-exhausted(răspunsul s-a oprit atunci când spațiul de lucru a expirat din credite),queue-updatedsaustream-error` spune când să citească din nou istoria. Un “keepalive” vine odată conectat, apoi la fiecare câteva secunde: citește istoria din primul, de când ce s-a întâmplat înainte de este acolo. - Pentru a transforma bucățile în mesaje cum face chatul, țineți-le în
readUIMessageStream()din pachetulai. listConversationMessages()returnează{ mesaje, streamCatchup }: mesajele salvate caUIMessages, pe măsură ce chat-ul le construiește, și bucățile de sunt încă în mișcare. Arată acele chunks, apoi sari peste chunkurile în direct careseqeste cel multstreamCatchup.maxSeq, din moment ce le repetă.runAgent()returneazărunId, apelul se deschis: mesajele care rulează îl poartă cametadata.turnId. O cursă care așteaptă să se îndrepte mai târziu de conversația de la .- Fluxul rămâne deschis până când renunțați la
semnalsaubreak, și aruncă dacă picăturile de conexiune: stream-ul pentru a relua. - O aplicație citește doar propriile sale conversații. Întoarce un membru deschis în altă parte,
cum ar fi în chat, arată doar textul în istorie, live și în următoarea rulare a agentului
: live, celelalte bucăți de joc sosesc sub formă de bucăți goale
‘mesagerie metadata’, astfel încât
seqrămâne nesigur. Transformă aplicația ta rulată ca membru (a se vedea mai sus) rămâne întreagă atunci când citește de unul singur. - Necesită
"motoare": { "twenty": ">=2.56.0" }.
ai.generate
Apelați un model dintr-o funcție logică, fără un agent
ai.generate
Apelați un model dintr-o funcție logică, fără un agent
ai.generate() apelează un model dintr-o funcţie logică. Spre deosebire de
runAgent(), nu are nevoie de defineAgent(): apelul are propriile instrucțiuni
și nu deschide nicio conversație. Folosiți-l pentru o singură împuşcătură, cum ar fi
clasificare, sumarizare sau extracție.inputeste un șir sau o listă de mesaje{ role: 'user' | 'assistant', content }.instrucțiuni(opțional) adaugă instrucțiunile sistemului apelantului.modelId(opţional) alege modelul. Fără el, apelul folosește modelul implicit al spațiului de lucru .responseFormat(opţional) funcţionează ca înrunAgent(). Cu{ type: 'json', schema }", schema merge pe cererea modelului în sine, prin urmare un răspuns JSON face o cerere (plus unealtă pași atunci când unscope` acordă instrumente ).scope(opţional) permite apelării să utilizeze baza de date, aşa cum este descrisă mai jos.
{ success, text, obiect, eroare, runId, usage }:texteste răspunsul unui text şinullpentru unul JSON.objecteste rezultatul unui răspuns JSON şinullaltfel.errorexplică o rulare eșuată, cândsuccesestefalse. O execuție care eșuează rezolvă în acest fel în loc să aruncați; un apel care nu poate începe o rulare, cum ar fi ca unul cu intrare nevalidă, aruncă.runIdidentifică rularea înregistrată, cu modelul, utilizarea şi creditele sale.usageeste{ inputTokens, outputTokens }: what the run cheltuit, including the steps that finished before a fail.
scope, apelul citeşte şi nu scrie nici o înregistrare. Pentru a o lăsa să folosească baza de date
pasează un scope, scris ca permisiunile unui rol:onChunk. Apelul încă se rezolvă cu
în acelaşi rezultat, odată ce ultimul chunk a fost înmânat lui onChunk. Dacă runda
nu soseşte niciodată, se opreşte să aştepte odată ce rezultatul este în şi 5 s
trece fără un nou chunk, și chiar mâini peste fiecare bucată primită până atunci:- Apelul se derulează prin același abonament ca
streamConversation(): se abonează mai întâi, așteaptă până când abonamentul este live, apoi începe rularea, astfel încât să nu piardă chunk. - Bucățile sunt ale chat-ului: țineți-le în
readUIMessageStream()din pachetul pentru a construi mesajul. semnalanulează apelul: acesta respinge cu eroarea de abortare și închide fluxul Drumul în sine continuă şi este înregistrat ca de obicei.- Odată ce fluxul este live, un eşec al acestuia opreşte doar bucăţile: apelul
încă se rezolvă cu rezultatul run-ului. care este facturat în ambele sensuri. Apelul
respinge atunci când abonamentul eșuează înainte de a trece în direct, astfel încât nu mai începe niciodată
sau când
onChunkarată. - O aplicație urmează doar propriile sale execuții, astfel încât
onChunkare nevoie de un token de aplicație. - Necesită
"motoare": { "twenty": ">=2.56.0" }.
ai.generate() necesită steagul de permisiune AI de pe rolul implicit al aplicației,
like runAgent().sendInboxMessage
Începeți sau continuați o conversație în chaturile membrilor
sendInboxMessage
Începeți sau continuați o conversație în chaturile membrilor
sendInboxMessage() postează un mesaj din aplicația dvs. în chaturile unuia sau mai multor
membri ai spațiului de lucru. Se poate încheia cu un apel de instrument la care membrul răspunde din chat,
după care conversația continuă cu asistentul Twenty. Consultați
Căsuța de intrare pentru opțiunile sale, funcțiile ajutătoare pentru mențiuni
și cum să publicați dintr-o componentă front.