Документация Triggo
Интеграция с агентами

Публикация workflow как действий

Превратите workflow в вызываемое действие, которое AI-агент может запустить через REST или MCP.

Автоперевод — в процессе проверки

Публикация workflow как действий

Triggo предоставляет внешним вызывающим две поверхности: REST API по адресу /api/v1/runtime/ и MCP-сервер по POST /mcp. Обе показывают один и тот же ресурс — опубликованное действие — и обе отказываются видеть всё, что не опубликовано. Эта страница описывает полный путь от «у меня есть workflow, который работает на холсте» до «мой агент может вызвать его по slug с Bearer-токеном».

Callable и event-driven workflow

У каждого workflow в Triggo есть type, который определяет, как он запускается. Тип хранится в таблице workflows и принимает одно из двух значений:

  • event_driven — запускается платформой. Срабатывает вебхук, отсчитывается расписание, триггер коннектора эмитирует событие — и workflow исполняется с тем полезным грузом, который доставила платформа. Event-driven workflow нельзя вызвать напрямую от агента. У них ровно один узел trigger; попытка опубликовать такой через runtime API отклоняется.
  • callable — запускается явным вызовом агента. Это та форма, которую вы публикуете как действие. Callable workflow должен иметь ровно один узел action_input (который определяет схему ввода, заполняемую вызывающим) и хотя бы один узел return_output (который определяет, что возвращает вызов). Валидатор следит за обоими правилами: «Callable workflow must have exactly 1 Action Input node» / «Callable workflow must have at least 1 Return Output node».

Тип выводится в момент создания из формы определения: если на холсте есть плейсхолдеры Action Input и Return Output — workflow callable; если есть trigger-узел — event-driven. Сегодня это плейсхолдерные типы узлов (action_input, return_output) — спецификация system-nodes-overhaul редизайнит их в полноценные узлы Manual Trigger и Return, но поведение, описанное здесь, соответствует текущему коду.

Форма callable workflow

Callable workflow — это три вещи, сшитые вместе:

  1. Узел Action Input в начале. Его массив data.properties (name, type, required) становится публичной схемой ввода действия. В момент деплоя схема выводится deriveInputSchemaFromDefinition() в объект, похожий на JSON Schema: { type: "object", properties: { <name>: { type: <type> } }, required: [...] }.
  2. Один или несколько узлов Return Output в конце. Их data.properties становятся схемой вывода через deriveOutputSchemaFromDefinition(){ type: "object", properties: {... } }, или null, если свойства вывода не заданы.
  3. Любые узлы между ними делают основную работу — действия коннекторов, условия, трансформации, code-узлы, циклы, вызовы LLM. Сопоставление полей {{action_input.field}} пробрасывает ввод вызывающего в узлы ниже по графу.

Схема ввода — это публичный контракт действия. Её изменение — breaking change для каждого вызывающего. Добавить новое необязательное поле безопасно; переименовать существующее поле, сделать поле обязательным или изменить его тип — нет. Вызывающие валидируются против этой схемы ещё до того, как запуск попадает в очередь (см. «Ошибки» ниже).

Публикация

На холсте основная кнопка в панели инструментов для callable workflow — Activate при первом деплое и Publish Action при каждом последующем (вторичная кнопка Run manually находится рядом). Полное описание состояния первичного действия с учётом триггеров см. в разделе Активация и версии (event-driven workflow проходят ту же транзакцию, но надпись на кнопке — Activate/Stop). Клик по первичной кнопке выполняет три действия одной транзакцией:

  1. Валидирует текущий черновик против правил callable (1 action_input, >=1 return_output) или правил event-driven (ровно 1 триггер), плюс лимиты сложности по узлам/связям.
  2. Архивирует предыдущую задеплоенную версию (статус меняется с deployed на archived) и повышает черновик до новой строки workflowVersions со статусом deployed.
  3. Для callable workflow выводит и фиксирует схемы ввода и вывода на новой версии.

После того как у workflow появилась версия deployed, можно создать публичное действие. Действие несёт slug — стабильный уникальный в рамках рабочего пространства идентификатор, который вызывающий использует вместо внутреннего UUID, — и ссылается на текущую задеплоенную версию через actionReleases. Slug выбирает публикующий, он не выводится из имени workflow: он явно передаётся в actionService.create(), проверяется на уникальность в рабочем пространстве и не может быть переиспользован другим workflow (в v1 действует инвариант «одно действие на workflow»).

После публикации действие видно на двух поверхностях:

  • REST: GET /api/v1/runtime/actions и GET /api/v1/runtime/actions/:slug.
  • MCP: list_actions (возвращает тот же список) и get_action (возвращает ту же детализацию).

Черновики и приостановленные действия не видны ни на одной из поверхностей — list по умолчанию фильтрует по status = "active", а попытка запуска против неактивного действия возвращает ACTION_UNAVAILABLE (409).

Вызов через REST

POST /api/v1/runtime/actions/:slug/run с Bearer API key, несущим область actions:run.

Тело запроса:

{
  "input": { "<field>": "<value>" },
  "dry_run": false
}
  • input — объект, соответствующий inputSchema действия. Значения, не являющиеся объектом, приводятся к {}.
  • dry_run — опциональное булево. Когда true, запуск записывается с source: "dry_run" и сразу помечается succeeded; задание BullMQ не ставится в очередь, побочные эффекты коннекторов не происходят, проверки пользовательского rate-limit и биллинговой квоты пропускаются.

Ответ (HTTP 202 Accepted, из executionService.createActionRun):

{
  "run_id": "6f3e...-uuid",
  "action_slug": "normalize-lead",
  "action_release_version": 3,
  "source": "action",
  "status": "accepted",
  "input": { "...": "..." },
  "output": null,
  "error": null,
  "steps": [],
  "approval": null,
  "dry_run": false,
  "started_at": null,
  "completed_at": null,
  "duration_ms": null,
  "created_at": "2026-04-12T10:15:30.000Z"
}

Полный пример curl — действие normalize-lead, которое принимает сырую запись из CRM и возвращает очищенную версию:

curl -sS -X POST https://api.triggo.dev/api/v1/runtime/actions/normalize-lead/run \
  -H "Authorization: Bearer trg_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "input": {
      "email": " Ivan@Example.COM ",
      "phone": "+7 (912) 345-67-89",
      "source": "webform"
    },
    "dry_run": false
  }'

В ответ вы получаете 202 с run_id. Финальный результат заберите через GET /api/v1/runtime/runs/:runId, когда запуск завершится (см. «Опрос статуса запуска» ниже).

Вызов через MCP

MCP-инструмент run_action принимает { slug, input, dry_run? }. Минимальный JSON-RPC-конверт:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "run_action",
    "arguments": {
      "slug": "normalize-lead",
      "input": {
        "email": " Ivan@Example.COM ",
        "phone": "+7 (912) 345-67-89",
        "source": "webform"
      },
      "dry_run": false
    }
  }
}

Ответ — это MCP tool result, в котором content[0].text содержит тот же JSON-объект, что и тело REST-ответа 202run_id, status: "accepted", action_release_version и так далее. В случае ошибки конверт переключает isError: true, а в text приходит { error, code, details? }. Сам MCP-транспорт остаётся 200 OK; ошибки инструмента выражаются внутри конверта, а не через HTTP-статус.

Синхронный или асинхронный режим

POST /runасинхронный. Эндпоинт валидирует ввод против схемы действия, проверяет пользовательский лимит скорости исполнения (100/час) и биллинговую квоту, вставляет строку в runs со status: "accepted", ставит задание BullMQ execution в очередь Redis и сразу возвращает 202 — он не ждёт завершения задания.

Возвращённый run_id — это идентификатор, который вы опрашиваете. Синхронного верхнего предела приводить не нужно, потому что эндпоинт никогда не блокируется на исполнении; таймауты 30 секунд на шаг и 300 секунд на пайплайн управляют самим фоновым запуском, а не первоначальным HTTP-вызовом.

Одно исключение: когда у действия approval_policy = "always", начальный статус — waiting_for_approval вместо accepted, создаётся строка approval_requests с истечением через 1 час, и задание исполнения не ставится в очередь, пока подтверждение не будет решено через POST /runs/:runId/approve или MCP-инструмент approve_run.

Опрос статуса запуска

Получите запуск по id с любой из поверхностей:

  • REST: GET /api/v1/runtime/runs/:runId (область runs:read).
  • MCP: get_run_status с { run_id } (область runs:read).

В ответе приходит актуальный status (accepted, running, waiting_for_approval, succeeded, failed, cancelled, timed_out), структурированный output (заполняется из узла Return Output при успехе) и таймлайн steps, выведенный из событий журнала. Полная форма таймлайна шагов и интерпретация каждого статуса — в разделе Отладка запусков.

Ошибки

Ошибки на REST-поверхности используют следующую карту кодов:

HTTPКодКогда
400INPUT_VALIDATION_FAILEDinput не соответствует схеме действия. Ответ включает details: [...] с ошибками по полям.
401UNAUTHORIZEDBearer-токен отсутствует, повреждён, отозван или просрочен.
403FORBIDDENКлюч валиден, но не несёт actions:run.
404ACTION_NOT_FOUNDSlug не существует в этом рабочем пространстве. Снаружи черновики выглядят идентично удалённым действиям.
409ACTION_UNAVAILABLEДействие существует, но его статус не active — обычно paused или archived, либо у него ещё нет текущего релиза.
429RATE_LIMIT_EXCEEDEDЛибо скользящее окно на ключ (зависит от тарифа), либо пользовательский лимит 100 запусков в час. В ответе есть заголовок retry-after в секундах; см. Ограничения скорости.
500что-либо ещёВнутренний сбой workflow при создании запуска — редко; сам запуск падает позже и проявляется на GET /runs/:runId.

Поверх MCP те же коды появляются внутри content[0].text с isError: true, а транспорт остаётся 200 OK.

Смотрите также

On this page