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
188 lines
9.8 KiB
Plaintext
188 lines
9.8 KiB
Plaintext
---
|
|
title: Habilidades y agentes
|
|
description: Define habilidades y agentes de IA para tu aplicación.
|
|
icon: robot
|
|
---
|
|
|
|
<Warning>
|
|
Las habilidades y los agentes están actualmente en pruebas alfa. La funcionalidad es operativa, pero sigue evolucionando.
|
|
</Warning>
|
|
|
|
Las aplicaciones pueden definir capacidades de IA que residen dentro del espacio de trabajo — instrucciones de habilidades reutilizables y agentes con prompts de sistema personalizados.
|
|
|
|
<AccordionGroup>
|
|
<Accordion title="defineSkill" description="Define habilidades para agentes de IA">
|
|
|
|
Las habilidades definen instrucciones y capacidades reutilizables que los agentes de IA pueden usar dentro de tu espacio de trabajo. Usa `defineSkill()` para definir habilidades con validación incorporada:
|
|
|
|
```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`,
|
|
});
|
|
```
|
|
|
|
Puntos clave:
|
|
* `name` es una cadena identificadora única de la habilidad (se recomienda kebab-case).
|
|
* `label` es el nombre para mostrar, legible para humanos, que aparece en la interfaz de usuario.
|
|
* `content` contiene las instrucciones de la habilidad — este es el texto que usa el agente de IA.
|
|
* `icon` (opcional) establece el icono mostrado en la interfaz de usuario.
|
|
* `description` (opcional) proporciona contexto adicional sobre el propósito de la habilidad.
|
|
|
|
</Accordion>
|
|
<Accordion title="defineAgent" description="Define agentes de IA con prompts personalizados">
|
|
|
|
Los agentes son asistentes de IA que viven dentro de tu espacio de trabajo. Usa `defineAgent()` para crear agentes con un prompt de sistema personalizado:
|
|
|
|
```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.',
|
|
});
|
|
```
|
|
|
|
Puntos clave:
|
|
* `name` es una cadena identificadora única del agente (se recomienda kebab-case).
|
|
* `label` es el nombre para mostrar que aparece en la interfaz de usuario.
|
|
* `prompt` es el mensaje del sistema que define el comportamiento del agente.
|
|
* `description` (opcional) proporciona contexto sobre lo que hace el agente.
|
|
* `icon` (opcional) establece el icono mostrado en la interfaz de usuario.
|
|
* `modelId` (opcional) reemplaza el modelo de IA predeterminado usado por el agente.
|
|
* `responseFormat` (opcional) controla la forma de la salida del agente. De forma predeterminada es `{ type: 'text' }` para texto de formato libre. Usa `{ type: 'json', schema }` para forzar una salida JSON estructurada.
|
|
|
|
De forma predeterminada, un agente devuelve texto de formato libre. Para obtener una salida estructurada, establece `responseFormat` en `{ type: 'json' }` y proporciona un `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,
|
|
},
|
|
},
|
|
});
|
|
```
|
|
|
|
Notas sobre el esquema:
|
|
* El esquema es un objeto plano: el `type` de cada propiedad debe ser un tipo primitivo (`string`, `number` o `boolean`). Los objetos anidados y los arrays no son compatibles.
|
|
* `description` (opcional) en cada propiedad guía al modelo sobre qué debe poner allí.
|
|
* `required` (opcional) enumera las propiedades que el modelo siempre debe devolver.
|
|
* `additionalProperties: false` (opcional) prohíbe cualquier propiedad que no esté declarada en `properties`.
|
|
|
|
</Accordion>
|
|
<Accordion title="runAgent" description="Ejecutar un agente desde una función de lógica">
|
|
|
|
`runAgent()` permite que una función de lógica ejecute uno de los agentes de tu app (con sus skills y tools). Identifica el agente mediante el `universalIdentifier` que pasaste a `defineAgent()`. Pasa una cadena `prompt` o un historial de la conversación
|
|
en `messages`, pero no ambos:
|
|
|
|
```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.',
|
|
});
|
|
```
|
|
|
|
Para bots de múltiples turnos (Slack, Discord, Teams, …), pasa el historial del hilo como `messages` en lugar de un solo `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?' },
|
|
],
|
|
});
|
|
```
|
|
|
|
Puntos clave:
|
|
* Proporciona **exactamente uno** de `prompt` (cadena) o `messages` (de 1 a 100 entradas
|
|
de `{ role: 'user' | 'assistant', content: string }`).
|
|
* El agente se ejecuta **sincrónicamente** y puede leer/actualizar registros por sí mismo mediante sus propias tools; `runAgent()` se resuelve una vez que la ejecución finaliza.
|
|
* Una app solo puede ejecutar sus propios agentes.
|
|
* El [rol predeterminado](/l/es/developers/extend/apps/config/roles) de la app debe conceder el indicador de permiso `AI`; agrega `SystemPermissionFlag.AI` a sus `permissionFlagUniversalIdentifiers` (o establece `canAccessAllTools: true`).
|
|
Sin esto, `runAgent()` falla con un error de permisos.
|
|
* Establece un valor generoso de `timeoutSeconds` en la función de lógica: las ejecuciones de agentes pueden tardar varios segundos.
|
|
* `success` es `true` y `result` es no nulo cuando la ejecución finaliza; en caso de fallo `success` es `false`, `result` es `null`, y `error` contiene el motivo (por ejemplo, cuando el espacio de trabajo se queda sin créditos de AI en mitad de la ejecución).
|
|
|
|
```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 los bucles:** si llamas a `runAgent()` desde un trigger de evento de base de datos `*.updated` y el agente actualiza el mismo registro, limita el alcance del trigger con `updatedFields` a un campo que el agente nunca escriba (por ejemplo, la URL de origen), o comprueba si algún campo de destino sigue vacío antes de llamar a `runAgent()`.
|
|
</Warning>
|
|
|
|
### Ejecución en nombre de un miembro del espacio de trabajo
|
|
|
|
Pasa `runAsWorkspaceMemberId` cuando la ejecución es activada por una persona — por ejemplo, un bot de chat que responde a un mensaje — para que el agente actúe como ese miembro en lugar de como la aplicación:
|
|
|
|
```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',
|
|
});
|
|
```
|
|
|
|
La ejecución entonces actúa con **el propio rol del miembro**: puede hacer todo lo que ese miembro puede hacer y nada más, los registros que crea se le atribuyen a él, y se aplican sus permisos a nivel de fila. El rol del agente no participa: es el valor predeterminado de la aplicación para ejecuciones sin nadie detrás de ellas. Omite el campo para ejecuciones autónomas (trabajos programados, disparadores de eventos de base de datos): esos conservan el rol propio del agente. La aplicación que actúa permanece asociada al contexto de la ejecución para fines de trazabilidad, sin restringir los permisos del miembro.
|
|
|
|
Tu aplicación es responsable de asociar a la persona que activó la ejecución con un miembro del espacio de trabajo. Para poder designar uno se requiere un token de acceso de la aplicación, y a quién puede
|
|
designar un token depende de si lleva asociado un usuario:
|
|
|
|
* Un token **sin usuario asociado** puede designar a cualquier miembro. Una función lógica se ejecuta
|
|
con uno, y lo mismo ocurre con los tokens generados mediante `client_credentials` o a partir de una clave de API.
|
|
* Un token emitido **en nombre de un usuario**, como el que recibe un componente de interfaz, solo puede
|
|
designar al miembro propio de ese usuario.
|
|
|
|
Cualquier otro caso — una sesión de usuario simple, una clave de API sin un token de la aplicación — no puede
|
|
designar a ningún miembro.
|
|
|
|
<Warning>
|
|
`runAgent()` produce un error cuando no se puede resolver el miembro del espacio de trabajo — un
|
|
miembro desconocido o eliminado, o uno sin rol. Nunca recurre al
|
|
rol propio del agente, ya que eso otorgaría más acceso del que solicitó quien llama.
|
|
</Warning>
|
|
|
|
</Accordion>
|
|
</AccordionGroup>
|