Files
upstream-mirror e7da97194a
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
snapshot of https://github.com/twentyhq/twenty.git (main, 2026-09-17; blobs > 131072B omitted)
2026-09-17 23:28:13 +05:00

181 lines
14 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Навыки и агенты
description: Определите навыки и агентов ИИ для вашего приложения.
icon: robot
---
<Warning>
Навыки и агенты сейчас проходят альфа-тестирование. Функция работает, но продолжает развиваться.
</Warning>
Приложения могут определять возможности ИИ, которые находятся внутри рабочего пространства — повторно используемые инструкции для навыков и агенты с настраиваемыми системными подсказками.
<AccordionGroup>
<Accordion title="defineSkill" description="Определяйте навыки ИИ-агентов">
Навыки определяют многократно используемые инструкции и возможности, которые агенты ИИ могут использовать в вашем рабочем пространстве. Используйте `defineSkill()` для определения навыков со встроенной валидацией:
```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`,
});
```
Основные моменты:
* `name` — уникальная строка-идентификатор навыка (рекомендуется kebab-case).
* `label` — читаемое человеком отображаемое имя, показываемое в UI.
* `content` содержит инструкции навыка — это текст, который использует агент ИИ.
* `icon` (необязательно) задаёт значок, отображаемый в UI.
* `description` (необязательно) предоставляет дополнительный контекст о назначении навыка.
</Accordion>
<Accordion title="defineAgent" description="Определяйте ИИ-агентов с пользовательскими промптами">
Агенты — это ИИ-помощники, работающие в вашем рабочем пространстве. Используйте `defineAgent()` для создания агентов с пользовательским системным промптом:
```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.',
});
```
Основные моменты:
* `name` — уникальная строка-идентификатор агента (рекомендуется kebab-case).
* `label` — отображаемое имя, показываемое в UI.
* `prompt` — это системный промпт, определяющий поведение агента.
* `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()`. Передайте либо строку `prompt`, либо историю диалога `messages` — но не оба варианта одновременно:
```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.',
});
```
Для многошаговых ботов (Slack, Discord, Teams, …) передавайте историю треда как `messages` вместо одного `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?' },
],
});
```
Основные моменты:
* Укажите **ровно один** из `prompt` (строка) или `messages` (от 1 до 100 элементов
вида `{ role: 'user' | 'assistant', content: string }`).
* Агент выполняется **синхронно** и может самостоятельно читать и обновлять записи с помощью собственных инструментов — `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>
### Запуск от имени участника рабочего пространства
Передавайте `runAsWorkspaceMemberId`, когда запуск инициирован человеком — например, чат-ботом, отвечающим на сообщение, — чтобы агент действовал как этот участник, а не как приложение:
```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',
});
```
Затем запуск выполняется с **собственной ролью участника**: он может делать всё, что может делать этот участник, и не больше; созданные им записи приписываются этому участнику, и к ним применяются его разрешения на уровне строк. Роль агента в этом не участвует — это роль по умолчанию приложения для запусков, за которыми никто не стоит. Опускайте это поле для автономных запусков (плановые задания, триггеры событий базы данных): в таких случаях сохраняется собственная роль агента. Действующее приложение остаётся привязанным к контексту запуска для отслеживания происхождения, не сужая при этом полномочий участника.
Ваше приложение отвечает за сопоставление человека, который инициировал запуск, с участником рабочего пространства. Чтобы указать участника, требуется токен доступа приложения; то, кого можно указать с помощью токена, зависит от того, привязан ли к нему пользователь:
* Токен **без привязанного пользователя** может указать любого участника. Логическая функция выполняется с таким токеном; то же относится к токенам, выпущенным через `client_credentials` или на основе API‑ключа.
* Токен, выданный **от имени пользователя** (как у фронтенд‑компонента), может указывать только на участника самого этого пользователя.
Все остальное — обычная пользовательская сессия, API‑ключ без токена приложения — вообще не может указывать участника.
<Warning>
`runAgent()` генерирует исключение, если не удаётся определить участника рабочего пространства — неизвестного или удалённого участника, либо участника без роли. При этом никогда не используется роль самого агента, так как это предоставило бы больше прав доступа, чем запросил вызывающий код.
</Warning>
</Accordion>
</AccordionGroup>