i18n - docs translations (#21237)

Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
This commit is contained in:
github-actions[bot]
2026-06-04 19:24:06 +02:00
committed by GitHub
parent 0877ba2ffd
commit f899660a40
18 changed files with 606 additions and 30 deletions
@@ -9,8 +9,8 @@ Eine **Rolle** ist ein Berechtigungssatz: welche Objekte eine App lesen oder sch
```ts src/roles/restricted-company-role.ts
import {
defineRole,
PermissionFlag,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
SystemPermissionFlag,
} from 'twenty-sdk/define';
export default defineRole({
@@ -46,7 +46,7 @@ export default defineRole({
canUpdateFieldValue: false,
},
],
permissionFlags: [PermissionFlag.APPLICATIONS],
permissionFlagUniversalIdentifiers: [SystemPermissionFlag.APPLICATIONS],
});
```
@@ -55,7 +55,7 @@ export default defineRole({
Wenn Sie eine neue App erzeugen, erstellt die CLI eine Datei für die Standardrolle, die mit `defineApplicationRole()` deklariert ist:
```ts src/roles/default-role.ts
import { defineApplicationRole, PermissionFlag } from 'twenty-sdk/define';
import { defineApplicationRole } from 'twenty-sdk/define';
export const DEFAULT_ROLE_UNIVERSAL_IDENTIFIER =
'b648f87b-1d26-4961-b974-0908fd991061';
@@ -74,7 +74,7 @@ export default defineApplicationRole({
canBeAssignedToApiKeys: false,
objectPermissions: [],
fieldPermissions: [],
permissionFlags: [],
permissionFlagUniversalIdentifiers: [],
});
```
@@ -90,5 +90,5 @@ Notizen:
* Beginnen Sie mit der vorgegebenen Rolle und schränken Sie sie dann schrittweise ein standardmäßig wird umfangreicher Lesezugriff gewährt, was selten das ist, was Sie in Produktionsumgebungen möchten.
* Ersetzen Sie `objectPermissions` und `fieldPermissions` durch die genauen Objekte und Felder, die Ihre Funktionen tatsächlich benötigen.
* `permissionFlags` steuern den Zugriff auf Funktionen auf Plattformebene. Halten Sie sie minimal.
* `permissionFlagUniversalIdentifiers` steuern den Zugriff auf Funktionen auf Plattformebene. Halten Sie sie minimal.
* Ein funktionierendes Beispiel finden Sie unter: [`hello-world/src/roles/function-role.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-apps/hello-world/src/roles/function-role.ts).
@@ -144,6 +144,33 @@ const handler = async (event: RoutePayload) => {
Header-Namen werden in Kleinbuchstaben normalisiert. Greifen Sie mit Schlüsseln in Kleinbuchstaben darauf zu (z. B. `event.headers['content-type']`).
</Note>
#### Benutzerdefinierte HTTP-Antwort
Standardmäßig sendet das Zurückgeben eines einfachen Werts aus Ihrem Handler diesen als `200`-Antwort zurück (JSON für Objekte, `text/plain` für Zeichenketten). Um den Statuscode und die Antwort-Header zu steuern, geben Sie eine `Response` aus `twenty-sdk/logic-function` zurück:
```ts
import { Response } from 'twenty-sdk/logic-function';
const handler = async (event: RoutePayload) => {
return new Response('<h1>Hello</h1>', {
status: 201,
headers: { 'content-type': 'text/html' },
});
};
```
Aus Sicherheitsgründen sind Antwort-Header auf eine Allowlist beschränkt. Jeder Header, der nicht auf der Liste steht (z. B. `Set-Cookie`, CORS-Header wie `Access-Control-Allow-Origin` oder benutzerdefinierte `X-*`-Header), wird stillschweigend verworfen, bevor die Antwort gesendet wird. Die erlaubten Antwort-Header sind:
* `content-type`
* `content-language`
* `content-disposition`
* `cache-control`
* `retry-after`
<Note>
Der Statuscode muss ein gültiger HTTP-Statuscode sein (zwischen 100 und 599). Antwort-Header-Namen werden ohne Beachtung der Groß-/Kleinschreibung verglichen.
</Note>
#### Datenbank-Event-Trigger-Payload
Wenn ein Datenbank-Event-Trigger Ihre Logic Function aufruft, erhält sie eine `DatabaseEventPayload` pro geändertem Datensatz. Die Payload kombiniert Metadaten über den Quell-Workspace und das Objekt mit dem Ereignis auf Datensatzebene.
@@ -64,6 +64,75 @@ Hauptpunkte:
* `description` (optional) liefert Kontext dazu, was der Agent tut.
* `icon` (optional) legt das in der UI angezeigte Symbol fest.
* `modelId` (optional) überschreibt das vom Agenten verwendete Standard-KI-Modell.
* `responseFormat` (optional) steuert die Form der Ausgabe des Agenten. Standardmäßig ist `{ type: 'text' }` für Freitext. Verwenden Sie `{ type: 'json', schema }`, um eine strukturierte JSON-Ausgabe zu erzwingen.
Standardmäßig gibt ein Agent freien Text zurück. Um eine strukturierte Ausgabe zu erhalten, setzen Sie `responseFormat` auf `{ type: 'json' }` und geben Sie ein `schema` an:
```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,
},
},
});
```
Schema-Hinweise:
* Das Schema ist ein flaches Objekt: Der `type` jeder Eigenschaft muss ein primitiver Typ sein (`string`, `number` oder `boolean`). Verschachtelte Objekte und Arrays werden nicht unterstützt.
* `description` (optional) an jeder Eigenschaft leitet das Modell an, was dort eingetragen werden soll.
* `required` (optional) listet die Eigenschaften auf, die das Modell immer zurückgeben muss.
* `additionalProperties: false` (optional) verbietet alle Eigenschaften, die nicht in `properties` deklariert sind.
</Accordion>
<Accordion title="runAgent" description="Einen Agenten aus einer Logikfunktion ausführen">
`runAgent()` ermöglicht es einer Logikfunktion, einen der Agenten Ihrer App auszuführen (mit seinen Fähigkeiten und Tools). Identifizieren Sie den Agenten über den `universalIdentifier`, den Sie an `defineAgent()` übergeben haben:
```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.',
});
```
Hauptpunkte:
* Der Agent wird **synchron** ausgeführt und kann selbst Datensätze über seine eigenen Tools lesen/aktualisieren — `runAgent()` wird aufgelöst, sobald die Ausführung abgeschlossen ist.
* Eine App kann nur ihre eigenen Agenten ausführen.
* Die [Standardrolle](/l/de/developers/extend/apps/config/roles) der App muss das Berechtigungsflag `AI` gewähren — fügen Sie `SystemPermissionFlag.AI` zu ihren `permissionFlagUniversalIdentifiers` hinzu (oder setzen Sie `canAccessAllTools: true`).
Ohne dieses Flag schlägt `runAgent()` mit einem Berechtigungsfehler fehl.
* Setzen Sie ein großzügiges `timeoutSeconds` für die Logikfunktion — Agentenläufe können mehrere Sekunden dauern.
* `success` ist `true` und `result` ist nicht null, wenn der Lauf abgeschlossen ist; bei einem Fehler ist `success` `false`, `result` ist `null` und `error` enthält den Grund (zum Beispiel, wenn dem Workspace während des Laufs die AI-Credits ausgehen).
```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>
**Vermeiden Sie Schleifen:** Wenn Sie `runAgent()` von einem `*.updated`-Datenbankereignis-Trigger aus aufrufen und der Agent denselben Datensatz aktualisiert, schränken Sie den Trigger mit `updatedFields` auf ein Feld ein, das der Agent niemals beschreibt (z. B. die Quell-URL), oder prüfen Sie, ob eines der Zielfelder noch leer ist, bevor Sie `runAgent()` aufrufen.
</Warning>
</Accordion>
</AccordionGroup>
@@ -9,8 +9,8 @@ Um **papel** é um conjunto de permissões: quais objetos um app pode ler ou gra
```ts src/roles/restricted-company-role.ts
import {
defineRole,
PermissionFlag,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
SystemPermissionFlag,
} from 'twenty-sdk/define';
export default defineRole({
@@ -46,7 +46,7 @@ export default defineRole({
canUpdateFieldValue: false,
},
],
permissionFlags: [PermissionFlag.APPLICATIONS],
permissionFlagUniversalIdentifiers: [SystemPermissionFlag.APPLICATIONS],
});
```
@@ -55,7 +55,7 @@ export default defineRole({
Ao criar um novo app com o scaffold, a CLI cria um arquivo de papel padrão declarado com `defineApplicationRole()`:
```ts src/roles/default-role.ts
import { defineApplicationRole, PermissionFlag } from 'twenty-sdk/define';
import { defineApplicationRole } from 'twenty-sdk/define';
export const DEFAULT_ROLE_UNIVERSAL_IDENTIFIER =
'b648f87b-1d26-4961-b974-0908fd991061';
@@ -74,7 +74,7 @@ export default defineApplicationRole({
canBeAssignedToApiKeys: false,
objectPermissions: [],
fieldPermissions: [],
permissionFlags: [],
permissionFlagUniversalIdentifiers: [],
});
```
@@ -90,5 +90,5 @@ Notas:
* Comece a partir do papel gerado pelo scaffold e, em seguida, restrinja-o progressivamente — o padrão concede amplo acesso de leitura, o que raramente é o que você quer em produção.
* Substitua `objectPermissions` e `fieldPermissions` pelos objetos e campos de que suas funções realmente precisam.
* `permissionFlags` controlam o acesso a recursos em nível de plataforma. Mantenha-os no mínimo necessário.
* `permissionFlagUniversalIdentifiers` controlam o acesso a recursos em nível de plataforma. Mantenha-os no mínimo necessário.
* Veja um exemplo funcional: [`hello-world/src/roles/function-role.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-apps/hello-world/src/roles/function-role.ts).
@@ -144,6 +144,33 @@ const handler = async (event: RoutePayload) => {
Os nomes dos cabeçalhos são normalizados para minúsculas. Acesse-os usando chaves em minúsculas (por exemplo, `event.headers['content-type']`).
</Note>
#### Resposta HTTP personalizada
Por padrão, retornar um valor simples do seu handler o envia de volta como uma resposta `200` (JSON para objetos, `text/plain` para strings). Para controlar o código de status e os cabeçalhos da resposta, retorne um `Response` de `twenty-sdk/logic-function`:
```ts
import { Response } from 'twenty-sdk/logic-function';
const handler = async (event: RoutePayload) => {
return new Response('<h1>Hello</h1>', {
status: 201,
headers: { 'content-type': 'text/html' },
});
};
```
Por motivos de segurança, os cabeçalhos de resposta são restringidos a uma lista de permissões. Qualquer cabeçalho que não esteja na lista (por exemplo, `Set-Cookie`, cabeçalhos CORS como `Access-Control-Allow-Origin` ou cabeçalhos personalizados `X-*`) é silenciosamente descartado antes de a resposta ser enviada. Os cabeçalhos de resposta permitidos são:
* `content-type`
* `content-language`
* `content-disposition`
* `cache-control`
* `retry-after`
<Note>
O código de status deve ser um código de status HTTP válido (entre 100 e 599). Os nomes dos cabeçalhos de resposta são comparados sem distinção entre maiúsculas e minúsculas.
</Note>
#### Payload do gatilho de evento do banco de dados
Quando um gatilho de evento do banco de dados invoca sua função lógica, ela recebe um `DatabaseEventPayload` por registro alterado. O payload combina metadados sobre o workspace e o objeto de origem com o evento em nível de registro.
@@ -64,6 +64,75 @@ Pontos-chave:
* `description` (opcional) fornece contexto sobre o que o agente faz.
* `icon` (opcional) define o ícone exibido na UI.
* `modelId` (opcional) substitui o modelo de IA padrão usado pelo agente.
* `responseFormat` (opcional) controla o formato da saída do agente. O padrão é `{ type: 'text' }` para texto em formato livre. Use `{ type: 'json', schema }` para forçar a saída em JSON estruturado.
Por padrão, um agente retorna texto em formato livre. Para obter saída estruturada, defina `responseFormat` como `{ type: 'json' }` e forneça um `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,
},
},
});
```
Observações sobre o esquema:
* O esquema é um objeto plano: o `type` de cada propriedade deve ser um primitivo (`string`, `number` ou `boolean`). Objetos aninhados e arrays não são suportados.
* `description` (opcional) em cada propriedade orienta o modelo sobre o que colocar ali.
* `required` (opcional) lista as propriedades que o modelo deve sempre retornar.
* `additionalProperties: false` (opcional) proíbe qualquer propriedade não declarada em `properties`.
</Accordion>
<Accordion title="runAgent" description="Executar um agente a partir de uma função de lógica">
`runAgent()` permite que uma função de lógica execute um dos agentes do seu app (com suas habilidades e ferramentas). Identifique o agente pelo `universalIdentifier` que você passou para `defineAgent()`:
```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.',
});
```
Pontos-chave:
* O agente é executado sincronamente e pode ler/atualizar registros por conta própria por meio de suas próprias ferramentas — `runAgent()` é resolvido quando a execução é concluída.
* Um app só pode executar os seus próprios agentes.
* O [papel padrão](/l/pt/developers/extend/apps/config/roles) do app deve conceder o sinalizador de permissão `AI` — adicione `SystemPermissionFlag.AI` ao seu `permissionFlagUniversalIdentifiers` (ou defina `canAccessAllTools: true`).
Sem isso, `runAgent()` falha com um erro de permissão.
* Defina um valor generoso de `timeoutSeconds` na função de lógica — execuções de agentes podem levar vários segundos.
* `success` é `true` e `result` é diferente de nulo quando a execução é concluída; em caso de falha `success` é `false`, `result` é nulo e `error` contém o motivo (por exemplo, quando o espaço de trabalho fica sem créditos de IA no meio da execução).
```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>
**Evite loops:** se você chamar `runAgent()` a partir de um gatilho de evento de banco de dados `*.updated` e o agente atualizar o mesmo registro, delimite o gatilho com `updatedFields` para um campo que o agente nunca escreve (por exemplo, a URL de origem) ou verifique se algum campo de destino ainda está vazio antes de chamar `runAgent()`.
</Warning>
</Accordion>
</AccordionGroup>
@@ -9,8 +9,8 @@ Un **rol** este un set de permisiuni: ce obiecte poate citi sau scrie o aplicaț
```ts src/roles/restricted-company-role.ts
import {
defineRole,
PermissionFlag,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
SystemPermissionFlag,
} from 'twenty-sdk/define';
export default defineRole({
@@ -46,7 +46,7 @@ export default defineRole({
canUpdateFieldValue: false,
},
],
permissionFlags: [PermissionFlag.APPLICATIONS],
permissionFlagUniversalIdentifiers: [SystemPermissionFlag.APPLICATIONS],
});
```
@@ -55,7 +55,7 @@ export default defineRole({
Când generați o aplicație nouă, CLI creează un fișier de rol implicit declarat cu `defineApplicationRole()`:
```ts src/roles/default-role.ts
import { defineApplicationRole, PermissionFlag } from 'twenty-sdk/define';
import { defineApplicationRole } from 'twenty-sdk/define';
export const DEFAULT_ROLE_UNIVERSAL_IDENTIFIER =
'b648f87b-1d26-4961-b974-0908fd991061';
@@ -74,7 +74,7 @@ export default defineApplicationRole({
canBeAssignedToApiKeys: false,
objectPermissions: [],
fieldPermissions: [],
permissionFlags: [],
permissionFlagUniversalIdentifiers: [],
});
```
@@ -90,5 +90,5 @@ Notițe:
* Porniți de la rolul generat de scaffolding, apoi restrângeți-l progresiv — rolul implicit acordă acces larg la citire, ceea ce rareori este de dorit în producție.
* Înlocuiți `objectPermissions` și `fieldPermissions` cu obiectele și câmpurile de care au nevoie efectiv funcțiile dvs.
* `permissionFlags` controlează accesul la capabilități la nivelul platformei. Mențineți-le la minimum.
* `permissionFlagUniversalIdentifiers` controlează accesul la capabilități la nivelul platformei. Mențineți-le la minimum.
* Vedeți un exemplu funcțional: [`hello-world/src/roles/function-role.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-apps/hello-world/src/roles/function-role.ts).
@@ -145,6 +145,33 @@ const handler = async (event: RoutePayload) => {
Numele anteturilor sunt normalizate la litere mici. Accesați-le folosind chei cu litere mici (de exemplu, `event.headers['content-type']`).
</Note>
#### Răspuns HTTP personalizat
În mod implicit, returnarea unei valori simple din handler trimite înapoi un răspuns `200` (JSON pentru obiecte, `text/plain` pentru șiruri). Pentru a controla codul de stare și antetele răspunsului, returnează un `Response` din `twenty-sdk/logic-function`:
```ts
import { Response } from 'twenty-sdk/logic-function';
const handler = async (event: RoutePayload) => {
return new Response('<h1>Hello</h1>', {
status: 201,
headers: { 'content-type': 'text/html' },
});
};
```
Din motive de securitate, anteturile de răspuns sunt limitate la o listă de antete permise. Orice antet care nu se află pe listă (de exemplu, `Set-Cookie`, anteturi CORS precum `Access-Control-Allow-Origin` sau anteturi personalizate `X-*`) este eliminat în mod silențios înainte ca răspunsul să fie trimis. Anteturile de răspuns permise sunt:
* `content-type`
* `content-language`
* `content-disposition`
* `cache-control`
* `retry-after`
<Note>
Codul de stare trebuie să fie un cod de stare HTTP valid (între 100 și 599). Numele anteturilor de răspuns sunt comparate fără a ține cont de majuscule și minuscule.
</Note>
#### Payload-ul declanșatorului de eveniment al bazei de date
Când un declanșator de eveniment al bazei de date apelează funcția dvs. logică, aceasta primește un `DatabaseEventPayload` pentru fiecare înregistrare modificată. Payload-ul combină metadatele despre spațiul de lucru și obiectul sursă cu evenimentul la nivel de înregistrare.
@@ -64,6 +64,75 @@ Puncte cheie:
* `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) controlează forma ieșirii agentului. Valoarea implicită este `{ type: 'text' }` pentru text liber. Folosește `{ type: 'json', schema }` pentru a impune ieșire JSON structurată.
În mod implicit, un agent returnează text liber. Pentru a obține o ieșire structurată, setează `responseFormat` la `{ type: 'json' }` și furnizează `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 despre schemă:
* Schema este un obiect plat: `type` al fiecărei proprietăți trebuie să fie un tip primitiv (`string`, `number` sau `boolean`). 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ă în `properties`.
</Accordion>
<Accordion title="runAgent" description="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()`:
```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.',
});
```
Puncte cheie:
* Agentul rulează **sincron** și poate citi/actualiza direct înregistrări prin propriile sale instrumente — `runAgent()` este rezolvat după ce rularea se încheie.
* O aplicație poate rula doar propriii săi agenți.
* [Rolul implicit](/l/ro/developers/extend/apps/config/roles) al aplicației trebuie să acorde indicatorul de permisiune `AI` — adaugă `SystemPermissionFlag.AI` la `permissionFlagUniversalIdentifiers` (sau setează `canAccessAllTools: true`).
Fără acesta, `runAgent()` eșuează cu o eroare de permisiune.
* Setează un `timeoutSeconds` generos pentru funcția logică — rulările agentului pot dura câteva secunde.
* `success` este `true` și `result` este nenul când rularea se încheie; în caz de eșec `success` este `false`, `result` este `null`, iar `error` conține motivul (de exemplu, când spațiul de lucru rămâne fără credite AI în timpul rulării).
```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>
**Evită buclele:** dacă apelezi `runAgent()` dintr-un declanșator de tip eveniment de bază de date `*.updated`, iar agentul actualizează aceeași înregistrare, restrânge declanșatorul cu `updatedFields` la un câmp pe care agentul nu îl scrie niciodată (de exemplu, URL-ul sursă) sau verifică dacă vreun câmp țintă este încă gol înainte de a apela `runAgent()`.
</Warning>
</Accordion>
</AccordionGroup>
@@ -9,8 +9,8 @@ icon: shield-halved
```ts src/roles/restricted-company-role.ts
import {
defineRole,
PermissionFlag,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
SystemPermissionFlag,
} from 'twenty-sdk/define';
export default defineRole({
@@ -46,7 +46,7 @@ export default defineRole({
canUpdateFieldValue: false,
},
],
permissionFlags: [PermissionFlag.APPLICATIONS],
permissionFlagUniversalIdentifiers: [SystemPermissionFlag.APPLICATIONS],
});
```
@@ -55,7 +55,7 @@ export default defineRole({
Когда вы создаёте новое приложение с помощью шаблона, CLI создаёт файл роли по умолчанию, объявленный с помощью `defineApplicationRole()`:
```ts src/roles/default-role.ts
import { defineApplicationRole, PermissionFlag } from 'twenty-sdk/define';
import { defineApplicationRole } from 'twenty-sdk/define';
export const DEFAULT_ROLE_UNIVERSAL_IDENTIFIER =
'b648f87b-1d26-4961-b974-0908fd991061';
@@ -74,7 +74,7 @@ export default defineApplicationRole({
canBeAssignedToApiKeys: false,
objectPermissions: [],
fieldPermissions: [],
permissionFlags: [],
permissionFlagUniversalIdentifiers: [],
});
```
@@ -90,5 +90,5 @@ export default defineApplicationRole({
* Начните с сгенерированной роли и постепенно ограничивайте её — роль по умолчанию предоставляет широкий доступ на чтение, что редко подходит для продакшена.
* Замените `objectPermissions` и `fieldPermissions` на точные объекты и поля, которые действительно нужны вашим функциям.
* `permissionFlags` управляют доступом к возможностям на уровне платформы. Сведите их к минимуму.
* `permissionFlagUniversalIdentifiers` управляют доступом к возможностям на уровне платформы. Сведите их к минимуму.
* См. рабочий пример: [`hello-world/src/roles/function-role.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-apps/hello-world/src/roles/function-role.ts).
@@ -144,6 +144,33 @@ const handler = async (event: RoutePayload) => {
Имена заголовков приводятся к нижнему регистру. Обращайтесь к ним, используя ключи в нижнем регистре (например, `event.headers['content-type']`).
</Note>
#### Пользовательский HTTP-ответ
По умолчанию возврат простого значения из обработчика отправляет его обратно как ответ `200` (JSON для объектов, `text/plain` для строк). Чтобы управлять статус-кодом и заголовками ответа, верните `Response` из `twenty-sdk/logic-function`:
```ts
import { Response } from 'twenty-sdk/logic-function';
const handler = async (event: RoutePayload) => {
return new Response('<h1>Hello</h1>', {
status: 201,
headers: { 'content-type': 'text/html' },
});
};
```
По соображениям безопасности заголовки ответа ограничены списком разрешенных заголовков. Любой заголовок, которого нет в этом списке (например, `Set-Cookie`, CORS-заголовки, такие как `Access-Control-Allow-Origin`, или пользовательские заголовки `X-*`), молчаливо удаляется перед отправкой ответа. Разрешенные заголовки ответа:
* `content-type`
* `content-language`
* `content-disposition`
* `cache-control`
* `retry-after`
<Note>
Код состояния должен быть допустимым кодом состояния HTTP (в диапазоне от 100 до 599). Имена заголовков ответа сравниваются без учета регистра.
</Note>
#### Полезная нагрузка триггера события базы данных
Когда триггер события базы данных вызывает вашу функцию логики, она получает по одному `DatabaseEventPayload` на каждую изменённую запись. Полезная нагрузка объединяет метаданные о рабочем пространстве-источнике и объекте с событием на уровне записи.
@@ -64,6 +64,75 @@ export default defineAgent({
* `description` (необязательно) предоставляет контекст о том, что делает агент.
* `icon` (необязательно) задаёт значок, отображаемый в UI.
* `modelId` (необязательно) переопределяет модель ИИ по умолчанию, используемую агентом.
* `responseFormat` (необязательно) определяет форму вывода агента. По умолчанию для свободного текста используется `{ type: 'text' }`. Используйте `{ type: 'json', schema }`, чтобы принудительно получать структурированный JSON-вывод.
По умолчанию агент возвращает свободный текст. Чтобы получить структурированный вывод, установите для `responseFormat` значение `{ type: 'json' }` и укажите `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,
},
},
});
```
Примечания к схеме:
* Схема — это плоский объект: `type` каждого свойства должен быть примитивом (`string`, `number` или `boolean`). Вложенные объекты и массивы не поддерживаются.
* `description` (необязательно) для каждого свойства подсказывает модели, что туда нужно поместить.
* `required` (необязательно) перечисляет свойства, которые модель всегда должна возвращать.
* `additionalProperties: false` (необязательно) запрещает любые свойства, не объявленные в `properties`.
</Accordion>
<Accordion title="runAgent" description="Запуск агента из логической функции">
`runAgent()` позволяет логической функции запустить одного из агентов вашего приложения (с его навыками и инструментами). Идентифицируйте агента по `universalIdentifier`, который вы передали в `defineAgent()`:
```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.',
});
```
Основные моменты:
* Агент выполняется **синхронно** и может самостоятельно читать и обновлять записи с помощью собственных инструментов — `runAgent()` возвращает результат после завершения выполнения.
* Приложение может запускать только собственных агентов.
* [Роль по умолчанию](/l/ru/developers/extend/apps/config/roles) приложения должна предоставлять флаг разрешения `AI` — добавьте `SystemPermissionFlag.AI` в `permissionFlagUniversalIdentifiers` (или установите `canAccessAllTools: true`).
Без этого `runAgent()` завершится с ошибкой прав доступа.
* Установите достаточно большое значение `timeoutSeconds` для логической функции — выполнение агента может занимать несколько секунд.
* `success` имеет значение `true`, а `result` — не `null`, когда запуск завершается; при ошибке `success` равно `false`, `result` равно `null`, а в `error` содержится причина (например, если в рабочем пространстве закончились AI-кредиты во время запуска).
```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>
**Избегайте циклов:** если вы вызываете `runAgent()` из триггера события базы данных `*.updated`, и агент обновляет ту же запись, ограничьте триггер, указав в `updatedFields` поле, которое агент никогда не изменяет (например, исходный URL), или добавьте проверку, что хотя бы одно целевое поле всё ещё пусто, прежде чем вызывать `runAgent()`.
</Warning>
</Accordion>
</AccordionGroup>
@@ -9,8 +9,8 @@ Bir **rol**, bir izin kümesidir: bir uygulamanın hangi nesneleri okuyup yazabi
```ts src/roles/restricted-company-role.ts
import {
defineRole,
PermissionFlag,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
SystemPermissionFlag,
} from 'twenty-sdk/define';
export default defineRole({
@@ -46,7 +46,7 @@ export default defineRole({
canUpdateFieldValue: false,
},
],
permissionFlags: [PermissionFlag.APPLICATIONS],
permissionFlagUniversalIdentifiers: [SystemPermissionFlag.APPLICATIONS],
});
```
@@ -55,7 +55,7 @@ export default defineRole({
Yeni bir uygulama iskeleti oluşturduğunuzda, CLI `defineApplicationRole()` ile bildirilen varsayılan bir rol dosyası oluşturur:
```ts src/roles/default-role.ts
import { defineApplicationRole, PermissionFlag } from 'twenty-sdk/define';
import { defineApplicationRole } from 'twenty-sdk/define';
export const DEFAULT_ROLE_UNIVERSAL_IDENTIFIER =
'b648f87b-1d26-4961-b974-0908fd991061';
@@ -74,7 +74,7 @@ export default defineApplicationRole({
canBeAssignedToApiKeys: false,
objectPermissions: [],
fieldPermissions: [],
permissionFlags: [],
permissionFlagUniversalIdentifiers: [],
});
```
@@ -90,5 +90,5 @@ Notlar:
* Oluşturulmuş (scaffolded) rolden başlayın ve ardından giderek kısıtlayın — varsayılan rol geniş okuma erişimi verir; bu ise üretim ortamında nadiren isteyeceğiniz bir şeydir.
* `objectPermissions` ve `fieldPermissions` değerlerini, fonksiyonlarınızın gerçekten ihtiyaç duyduğu nesne ve alanlarla değiştirin.
* `permissionFlags`, platform düzeyindeki yeteneklere erişimi kontrol eder. Bunları asgari düzeyde tutun.
* `permissionFlagUniversalIdentifiers`, platform düzeyindeki yeteneklere erişimi kontrol eder. Bunları asgari düzeyde tutun.
* Çalışan bir örnek için bkz.: [`hello-world/src/roles/function-role.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-apps/hello-world/src/roles/function-role.ts).
@@ -145,6 +145,33 @@ const handler = async (event: RoutePayload) => {
Başlık adları küçük harfe normalize edilir. Onlara küçük harfli anahtarlarla erişin (örneğin, `event.headers['content-type']`).
</Note>
#### Özel HTTP yanıtı
Varsayılan olarak, işleyicinizden düz bir değer döndürmek, onu `200` yanıtı olarak geri gönderir (nesneler için JSON, stringler için `text/plain`). Durum kodunu ve yanıt üstbilgilerini kontrol etmek için, `twenty-sdk/logic-function` içinden bir `Response` döndürün:
```ts
import { Response } from 'twenty-sdk/logic-function';
const handler = async (event: RoutePayload) => {
return new Response('<h1>Hello</h1>', {
status: 201,
headers: { 'content-type': 'text/html' },
});
};
```
Güvenlik nedenleriyle, yanıt üstbilgileri bir izin listesiyle sınırlandırılmıştır. Listede yer almayan herhangi bir üstbilgi (örneğin `Set-Cookie`, `Access-Control-Allow-Origin` gibi CORS üstbilgileri veya özel `X-*` üstbilgileri), yanıt gönderilmeden önce sessizce yok sayılır. İzin verilen yanıt üstbilgileri şunlardır:
* `content-type`
* `content-language`
* `content-disposition`
* `cache-control`
* `retry-after`
<Note>
Durum kodu geçerli bir HTTP durum kodu olmalıdır (100 ile 599 arasında). Yanıt üstbilgisi adları büyük/küçük harfe duyarsız olarak eşleştirilir.
</Note>
#### Veritabanı olay tetikleyicisi yükü
Bir veritabanı olay tetikleyicisi mantık fonksiyonunuzu çağırdığında, değişen her kayıt için bir `DatabaseEventPayload` alır. Yük, kaynak çalışma alanı ve nesne hakkındaki üstveriyi, kayıt düzeyindeki olayla birleştirir.
@@ -64,6 +64,75 @@ export default defineAgent({
* `description` (isteğe bağlı), ajanın ne yaptığı hakkında bağlam sağlar.
* `icon` (isteğe bağlı), UI'de gösterilen simgeyi ayarlar.
* `modelId` (isteğe bağlı), ajanın kullandığı varsayılan yapay zekâ modelini geçersiz kılar.
* `responseFormat` (isteğe bağlı), ajan çıktısının şeklini kontrol eder. Serbest biçimli metin için varsayılan olarak `{ type: 'text' }` kullanılır. Yapılandırılmış JSON çıktısını zorunlu kılmak için `{ type: 'json', schema }` kullanın.
Varsayılan olarak bir ajan serbest biçimli metin döndürür. Yapılandırılmış çıktı almak için, `responseFormat` değerini `{ type: 'json' }` yapın ve bir `schema` sağlayın:
```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,
},
},
});
```
Şema notları:
* Şema düz bir nesnedir: her özelliğin `type` değeri, ilkel bir tür (`string`, `number` veya `boolean`) olmalıdır. İç içe nesneler ve diziler desteklenmez.
* Her özellik üzerindeki `description` (isteğe bağlı), modele oraya ne koyması gerektiği konusunda yol gösterir.
* `required` (isteğe bağlı), modelin her zaman döndürmesi gereken özellikleri listeler.
* `additionalProperties: false` (isteğe bağlı), `properties` içinde tanımlanmamış herhangi bir özelliği yasaklar.
</Accordion>
<Accordion title="runAgent" description="Bir mantık işlevinden bir ajan çalıştırın">
`runAgent()`, bir mantık işlevinin uygulamanızın ajanlarından birini (kendi yetenekleri ve araçlarıyla) çalıştırmasına olanak tanır. Ajanı, `defineAgent()` işlevine ilettiğiniz `universalIdentifier` ile belirleyin:
```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.',
});
```
Önemli noktalar:
* Ajan **senkron** olarak çalışır ve kendi araçları aracılığıyla kayıtları kendisi okuyup/güncelleyebilir — işlem tamamlandığında `runAgent()` çözümlenir.
* Bir uygulama yalnızca kendi ajanlarını çalıştırabilir.
* Uygulamanın [varsayılan rolü](/l/tr/developers/extend/apps/config/roles), `AI` izin bayrağını vermelidir — `permissionFlagUniversalIdentifiers` içine `SystemPermissionFlag.AI` ekleyin (veya `canAccessAllTools: true` olarak ayarlayın).
Bu olmadan, `runAgent()` bir izin hatasıyla başarısız olur.
* Mantık işlevi için cömert bir `timeoutSeconds` değeri ayarlayın — ajan çalışmaları birkaç saniye sürebilir.
* Çalışma tamamlandığında `success` değeri `true` olur ve `result` boş olmayan bir değerdir; başarısızlık durumunda `success` değeri `false` olur, `result` değeri `null` olur ve `error` nedenini tutar (örneğin, çalışma ortasında çalışma alanının AI kredileri bittiğinde).
```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>
**Döngülerden kaçının:** Bir `*.updated` veritabanı olayı tetikleyicisinden `runAgent()` çağırırsanız ve ajan aynı kaydı güncelliyorsa, tetikleyiciyi, ajan tarafından asla yazılmayan bir alana (örneğin kaynak URL) göre `updatedFields` ile kapsamlandırın veya `runAgent()` çağırmadan önce herhangi bir hedef alanın hâlâ boş olup olmadığına göre koruma ekleyin.
</Warning>
</Accordion>
</AccordionGroup>
@@ -9,8 +9,8 @@ icon: shield-halved
```ts src/roles/restricted-company-role.ts
import {
defineRole,
PermissionFlag,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
SystemPermissionFlag,
} from 'twenty-sdk/define';
export default defineRole({
@@ -46,7 +46,7 @@ export default defineRole({
canUpdateFieldValue: false,
},
],
permissionFlags: [PermissionFlag.APPLICATIONS],
permissionFlagUniversalIdentifiers: [SystemPermissionFlag.APPLICATIONS],
});
```
@@ -55,7 +55,7 @@ export default defineRole({
当你使用脚手架创建新应用时,CLI 会创建一个使用 `defineApplicationRole()` 声明的默认角色文件:
```ts src/roles/default-role.ts
import { defineApplicationRole, PermissionFlag } from 'twenty-sdk/define';
import { defineApplicationRole } from 'twenty-sdk/define';
export const DEFAULT_ROLE_UNIVERSAL_IDENTIFIER =
'b648f87b-1d26-4961-b974-0908fd991061';
@@ -74,7 +74,7 @@ export default defineApplicationRole({
canBeAssignedToApiKeys: false,
objectPermissions: [],
fieldPermissions: [],
permissionFlags: [],
permissionFlagUniversalIdentifiers: [],
});
```
@@ -90,5 +90,5 @@ export default defineApplicationRole({
* 从脚手架生成的角色开始,然后逐步收紧它的权限——默认角色授予广泛的读取访问权限,而这在生产环境中很少是你想要的。
* 将 `objectPermissions` 和 `fieldPermissions` 替换为你的函数实际需要的精确对象和字段。
* `permissionFlags` 控制对平台级能力的访问。 尽量保持最小化。
* `permissionFlagUniversalIdentifiers` 控制对平台级能力的访问。 尽量保持最小化。
* 查看一个可运行示例:[`hello-world/src/roles/function-role.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-apps/hello-world/src/roles/function-role.ts)。
@@ -145,6 +145,33 @@ const handler = async (event: RoutePayload) => {
请求头名称会被规范化为小写。 请使用小写键访问它们(例如,`event.headers['content-type']`)。
</Note>
#### 自定义 HTTP 响应
默认情况下,从处理程序返回一个普通值会以 `200` 响应返回该值(对象为 JSON,字符串为 `text/plain`)。 要控制状态码和响应头,请从 `twenty-sdk/logic-function` 返回一个 `Response`
```ts
import { Response } from 'twenty-sdk/logic-function';
const handler = async (event: RoutePayload) => {
return new Response('<h1>Hello</h1>', {
status: 201,
headers: { 'content-type': 'text/html' },
});
};
```
出于安全原因,响应头被限制在一个允许列表中。 任何不在该列表中的响应头(例如 `Set-Cookie`、CORS 响应头(如 `Access-Control-Allow-Origin`),或自定义的 `X-*` 响应头)都会在发送响应之前被静默丢弃。 允许的响应头包括:
* `content-type`
* `content-language`
* `content-disposition`
* `cache-control`
* `retry-after`
<Note>
状态码必须是有效的 HTTP 状态码(介于 100 和 599 之间)。 响应头名称的匹配不区分大小写。
</Note>
#### 数据库事件触发器有效负载
当数据库事件触发器调用你的逻辑函数时,每条被更改的记录都会对应一个 `DatabaseEventPayload`。 该负载将关于源工作区和对象的元数据与记录级事件组合在一起。
@@ -64,6 +64,75 @@ export default defineAgent({
* `description`(可选)提供有关智能体功能的上下文。
* `icon`(可选)设置在 UI 中显示的图标。
* `modelId`(可选)会覆盖该智能体使用的默认 AI 模型。
* `responseFormat`(可选)控制代理输出的结构形式。 对于自由格式文本,默认值为 `{ type: 'text' }`。 使用 `{ type: 'json', schema }` 来强制生成结构化 JSON 输出。
默认情况下,代理返回自由格式文本。 要获取结构化输出,将 `responseFormat` 设置为 `{ type: 'json' }`,并提供一个 `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,
},
},
});
```
架构说明:
* 该架构是一个扁平对象:每个属性的 `type` 必须是原始类型(`string`、`number` 或 `boolean`)。 不支持嵌套对象和数组。
* 每个属性上的 `description`(可选)用于引导模型应在此处填入什么内容。
* `required`(可选)列出模型必须始终返回的属性。
* `additionalProperties: false`(可选)禁止任何未在 `properties` 中声明的属性。
</Accordion>
<Accordion title="runAgent" description="从逻辑函数中运行代理">
`runAgent()` 允许逻辑函数运行你的应用的某个代理(及其技能和工具)。 通过你传递给 `defineAgent()` 的 `universalIdentifier` 来标识该代理:
```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.',
});
```
关键点:
* 代理以**同步**方式运行,并且可以通过其自身的工具读取/更新记录 —— `runAgent()` 会在运行完成后才 resolve。
* 一个应用只能运行它自己的代理。
* 应用的[默认角色](/l/zh/developers/extend/apps/config/roles)必须授予 `AI` 权限标记 —— 在其 `permissionFlagUniversalIdentifiers` 中添加 `SystemPermissionFlag.AI`(或设置 `canAccessAllTools: true`)。
否则,`runAgent()` 会因权限错误而失败。
* 在逻辑函数上设置较大的 `timeoutSeconds` 值 —— 代理运行可能需要数秒时间。
* 当运行完成时,`success` 为 `true` 且 `result` 为非空;失败时,`success` 为 `false``result` 为 `null`,并且 `error` 保存失败原因(例如,当工作区在运行过程中耗尽 AI 额度时)。
```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>
\*\*避免循环:\*\*如果你从 `*.updated` 数据库事件触发器中调用 `runAgent()`,而代理又会更新同一条记录,请将触发器的 `updatedFields` 限定为代理永远不会写入的字段(例如来源 URL),或者在调用 `runAgent()` 之前检查任何目标字段是否仍为空。
</Warning>
</Accordion>
</AccordionGroup>