Тема
Воркфлоу агентов
Воркфлоу связывает агентов в цепочку: триггер, затем шаги, которые сервер выполняет сверху вниз, — шаги агентов (обычные задачи агентов), согласования, где решает человек там, где проверяют работу, детерминированные действия и вызовы других воркфлоу. Выполнение воркфлоу называется запуском.
Эндпоинты /api/workflows входят в модуль agents (тариф Pro). Запросы, кроме GET, подпадают под лимит ИИ-запросов — см. Ограничения частоты запросов.
Права и владелец
workflows:read— у всех ролей.workflows:write— уeditor,leadи администраторов.workflows:run— у них же; API-ключ со scopeworkflows:runможет запускать воркфлоу.
Запуск действует от имени владельца воркфлоу — того, кто последним сохранил или включил его, — с ролью владельца в проекте на момент старта запуска. Тот, кто запустил, записывается в startedBy и в журнал аудита вместе с входными данными. Сохранение отклоняет воркфлоу, шаги которого требуют прав, которых нет у сохраняющего (403 с missing). Если владельца удалили, деактивировали или он потерял право, воркфлоу помечается ownerProblem, и его запуски не стартуют, пока кто-нибудь не сохранит его заново.
Определение
definition: { name?, description?, trigger, limits?: { maxTokens?, maxItems? }, outputs?, steps[] }.
Триггер
trigger — один из вариантов:
{ type: "manual", inputs?: { <name>: { type: "string", pattern?, maxLength? (≤ 200) } | { type: "enum", values } | { type: "number", min?, max? } | { type: "boolean" } | { type: "array", items, maxItems } }, runRoles? }{ type: "schedule", cron, timezone? }{ type: "run.imported", branches? (globs), onlyWithFailures? (true), sources?, includeAutotestBranches? (false) }{ type: "requirement.changed", sourceKinds?, keyPrefix? }
runRoles ограничивает, кто может запускать ручной воркфлоу; API-ключ считается ролью ci_runner, поэтому укажите её для воркфлоу, который должен запускать CI.
Шаги
{ type: "agent", agent: agent0_coverage | agent1_generate | agent2_codegen | agent2_verify | agent3_triage | custom_agent, params }{ type: "approval", gate: agent1_drafts | merge_request | defect | confirm, of?, where?, show?, message?, auto? }{ type: "action", action: regression_suggest | create_run, params }{ type: "workflow", workflow: <slug>, inputs }{ type: "classify", question, show, choices: { <key>: what belongs to it } (2–10), minConfidence? (60) }
У любого шага может быть when, а у шагов agent, workflow и classify — forEach, maxItems (20; 5 для agent2_verify; не больше 50), overflow (fail | truncate), concurrency, onError (stop | continue).
Шаг classify
Шаг classify поручает модели отнести то, что содержит show, к одному из вариантов; на выходе — { choice, suggested, confidencePct, reason, input } (input — то, что классифицировалось). Ниже minConfidence или если модель не назвала ни один из вариантов, choice равно unsure, а suggested хранит, к чему она склонялась.
Последующие шаги ветвятся через when по steps.<id>.output.choice, а для шага classify, выполненного с forEach, — через forEach по steps.<id>.output и when по item.choice. Условие, сравнивающее поле со значением, которое оно никогда не принимает (вариант, которого шаг не предлагает, classification Агента 3, отличная от backend_defect, frontend_regression, flake или unknown), отклоняется при сохранении.
Согласование дефектов, черновиков или merge request может проверять работу через шаг classify, который прошёл по выходу своего агента, показывая каждый элемент (show: { "$ref": "item" }): его where читает item.choice (если туда входит unsure, сомнительные элементы тоже уходят человеку), и на ревью попадают элементы агента. Модель — classify в моделях агентов в настройках; шагу нужно право agents:write владельца, как и шагу агента.
Значения и условия
Значения — литералы или ссылки { "$ref": "trigger.<input>" | "steps.<id>.output.<field>" | "item.<field>", prefix?, suffix? }. Условия — { path, op: eq|neq|in|gt|gte|lt|lte|exists, value }, объединяются через { all: [...] } / { any: [...] }. Некоторые параметры задаются в определении и не могут быть ссылками (навыки, фреймворки, файлы воркфлоу CI, slug своего агента), поэтому тот, кто запускает воркфлоу, не может повлиять на то, с чем выполняются шаги владельца.
У выхода каждого типа шага фиксированные поля (например, agent1_generate → draftIds; согласование agent1_drafts → approvedCases: [{ id, title, priority }]; merge_request → artifactIds); POST /validate называет их, если ссылка неверна.
Воркфлоу проекта
GET /api/workflows— воркфлоу проекта с триггером, владельцем,ownerProblem,nextRunAtи последним запуском.POST /api/workflows{ slug, name, description?, definition, enabled? }(workflows:write) —400сerrorsдля определения, которое не проходит проверку, иdependencyProblems— чего не хватает проекту (своего агента нет или он не проверен: тогда воркфлоу сохраняется только выключенным).GET,PUT(сversion;409version_conflict) иDELETE/api/workflows/:slug.DELETEотвечает409, пока есть активные запуски или его вызывают другие воркфлоу.GET /api/workflows/:slug/callers(workflows:read) — эти другие воркфлоу; по ним и нужно разрешать409.PATCH /api/workflows/:slug{ enabled, version? }включает или выключает триггеры; включение заново проверяет воркфлоу и делает вызывающего его владельцем.
Slug runs, templates, validate, gates, events и chat зарезервированы.
POST /api/workflows/validate { definition, slug? } — проверка редактора, ничего не сохраняет: { valid, errors, warnings, dependencyProblems, permissions, estimate: { modelCalls, maxMinutes, note } }. Циклы вызовов (на любой глубине), вызовы глубже 3 уровней и входные данные, которые вызываемый воркфлоу не принимает, — ошибки.
Запуски
POST /api/workflows/:slug/runs{ inputs }(workflows:run) — ручной запуск; входные данные проверяются по типам триггера (400сdetails). Ответ —202с запуском.GET /api/workflows/:slug/runs,GET /api/workflows/runs?status=(active— ожидающие, выполняющиеся и ждущие) — запуски, сначала новые.GET /api/workflows/runs/:id— запуск с шагами (по строке на шаг и на каждый элемент forEach: статус, id задачи, выход, ошибка, попытки), элементами согласований, вызванными им запусками и токенами, потраченными всем деревом.GET /api/workflows/runs/:id/streamприсылает событияsnapshot, пока запуск идёт, иend, когда он завершается.POST /api/workflows/runs/:id/cancel(workflows:run) — останавливает запуск, его задачи и вызванные им запуски; созданные черновики и автотесты остаются.POST /api/workflows/runs/:id/steps/:stepRunId/retry(workflows:run) выполняет упавший шаг (или его упавшие элементы) заново в упавшем запуске.
Согласования
GET /api/workflows/gates — все согласования проекта, ждущие решения, с путём от корневого запуска («Requirement → autotest › Autotest for important cases › Open the merge requests») и правом, которое нужно для решения.
Согласования решаются там, где проверяют работу: одобрение и отбрасывание черновиков в очереди ревью Агента 1, открытие merge request (POST /api/repo/merge-request), заведение дефекта по результату. Запуск также принимает, с правом, которое нужно этому согласованию:
POST /api/workflows/runs/:id/steps/:stepRunId/finish{ remaining: "discard" | "detach" }— закрывает ревью с тем, что решено (остальные черновики отбрасываются или остаются в очереди сами по себе; неоткрытые merge requests просто отпускаются);.../items/:objectId/dismiss— откладывает один автотест или результат;.../confirm{ continue }— решает согласование confirm.
Согласование, ждущее 14 дней, закрывает запуск как expired.
Триггеры по событиям
Импорт из CI (POST /api/runs/import) и проверка изменившихся требований записывают событие один раз на сборку или версию источника; сервер запускает подходящие включённые воркфлоу в течение десяти секунд.
- Прогон, импортированный из ветки
autotest/, ничего не запускает, если триггер не говорит иначе. - Импорт пайплайна, который запустил запуск воркфлоу, не запускает этот воркфлоу снова.
- Воркфлоу запускается от событий и расписаний не больше 10 раз в час — то, что отклонено, видно в его запусках как
skippedс причиной. - Расписание срабатывает один раз на каждое время; время, пропущенное, пока сервер не работал, не навёрстывается.
Лимиты
- Задачи воркфлоу занимают не больше 2 из 3 мест проекта для задач агентов и не больше одной
agent2_verifyодновременно; шаг без свободного места ждёт (queued). limits.maxTokensзапуска распространяется на вызванные им запуски; токен, прочитанный из кеша промптов провайдера, считается как десятая часть, как он и тарифицируется (так же считается суточныйKVALLI_LLM_DAILY_TOKENS).- Завершённые запуски хранятся 90 дней.
KVALLI_MAX_WORKFLOWS_PER_PROJECT(50),KVALLI_MAX_WORKFLOW_TEMPLATES(100).
Шаблоны
GET /api/workflows/templates— встроенные шаблоны и шаблоны организации.POST /api/workflows/templates/:slug/instantiate(workflows:write) копирует шаблон в проект вместе с вызываемыми им воркфлоу, выключенным, и перечисляет, чего не хватает проекту.POST /api/workflows/:slug/publish-template{ templateSlug? }иDELETE /api/workflows/templates/:slug— для администраторов установки.
Копия — не ссылка: последующие изменения шаблона до неё не доходят.
Сборка воркфлоу в чате
POST /api/workflows/chat { messages: [{ role, content }], draft?, slug? } (workflows:write) составляет определение в беседе с моделью, которую настройки отводят чату воркфлоу (llm.agentModels.chat). Модель отвечает через инструменты (function calling в Gemini, OpenAI-совместимых провайдерах, Claude и Ollama): она может перечислить воркфлоу проекта, своих агентов и шаблоны и предлагает определение целиком, которое валидатор проверяет и возвращает ей на исправление. Ответ — { reply, proposal?: { definition, summary, validation }, steps }. Ничего не сохраняется.