Перейти к содержанию

Workflow — определения, публикация, запуск, привязки

Workflow — атом системы Axon: универсальный контейнер без типов («Magic Box»). Этот мануал: как программист пишет определение, как оно публикуется, как менеджер привязывает коннекторы, как оператор запускает процесс и управляет run'ом. Источник истины — WORKFLOW-ARCHITECTURE.md + ARCHITECTURE-V6.md + код; при расхождении — каноны/код главнее.


1. Что это и зачем

Workflow — атом (VISION инвариант 2): всё в Axon — workflow, любого масштаба, фрактально вложимый (SubFlows). Magic Box: workflow — универсальный контейнер; типов workflow нет — execution strategy выводится из формы config'а, а execution_mode определяет, есть ли children:

  • execution_mode = leaf — нет children; исполняет свои steps / agent_config / planner_config (одна из трёх leaf-стратегий, по форме config'а);
  • execution_mode = graph — только children; оркеструет дочерние workflow по DAG;
  • execution_mode = hybridpre_steps → children graph → post_steps.

Authoring vs Runtime (жёстко разделены): разработчик пишет WorkflowSpec (authoring-Pydantic, IDE-autocomplete) в modules/workflows/<name>/definition.py; axon push (= команда publish_definition) разбивает файл на execution payload + metadata и сохраняет immutable snapshot в workflow_definitions.definition. Runtime (Temporal-воркеры, Console, API) не знает о файловой системе — читает только PostgreSQL. Workflow row (запущенный экземпляр) создаётся позже отдельным create_workflow / start_workflowpush сам по себе ничего не запускает и не активирует trigger/schedule/ambient.

PostgreSQL = source of truth, Temporal = orchestration. Воркерам запрещено сканировать папки.

Три понятия не путать:

Понятие Что это Где живёт Таблица
Definition чертёж бизнес-процесса (его пишет разработчик) modules/workflows/ → БД workflow_definitions
Workflow запущенный экземпляр по чертежу (обработка конкретного письма) БД + Temporal workflows
Template обезличенный слепок для маркетплейса (без приватных ключей) БД module_catalog
Catalog Entry глобальная карточка reusable definition для поиска/install (не SoT для runtime) БД workflow_definition_catalog

2. Роли и доступ

Из core/models/auth.py. Полная матрица — Roles-And-Permissions.md.

Действие Permission owner admin manager operator reviewer read_only system
Создать / редактировать workflow create_workflow / edit_workflow
Опубликовать определение (axon push) publish_definition
Запустить workflow (Run Wizard) start_workflow
Pause / resume / cancel run pause_workflow / resume_workflow / cancel_workflow
Retry / replan run retry_workflow / replan_workflow
Настроить binding profile workflow:configure_bindings
Collections / labels (UI-навигация) manage_workflow_classification
Catalog: install в проект catalog:install
Catalog: publish/archive catalog:manage
Replay replay
Approve / reject шаг (human_gate, external_write) approve / reject_approval
Пиннинг binding snapshot run'а workflow_run:pin_bindings ✅*

* pin_workflow_run_bindings — system-only, исполняется как sub-step start_workflow (актор workflow_start_dispatcher); workflow_binding:invalidate зарезервирован (команды нет). manager имеет workflow CRUD/lifecycle кроме retry_workflow/replan_workflow (это owner/admin) и manage_workflow_classification/replay (тоже owner/admin).

Граница «код ↔ Console» (engineer): WorkflowDefinition/WorkflowSpec, agent/prompt definitions, кастомные activities пишутся в коде (modules/workflows/, git) и деплоятся; публикация (publish_definition) — через Console/API ролью manager+; привязки/запуск/управление run'ами — Console. engineer — не RBAC-роль (см. Roles-And-Permissions.md §1).


3. Где это в Console

Раздел сайдбара Workflows (+ Catalog под Administration).

Экран Что на нём
Список определений опубликованные WorkflowDefinition (имя, definition_key, версия/definition_id, статус, collections/labels-фильтры)
Определение (detail) шаги/граф (визуализация через React Flow), ConnectorRequirement[], trigger, версии; кнопки: открыть Bindings, Run Wizard
Bindings (binding profile) список ConnectorRequirement-слотов определения → выбор connector instance под каждый (Auto-map / вручную); статус профиля (incomplete / complete / auto_configured)
Run Wizard выбрать case (для case-aware) → input_data → опционально override bindings (в т.ч. multi-credential выбор) → Create + Start
Список runs запущенные workflows (status, definition, case, прогресс по шагам, стоимость)
Run (detail) шаги (timeline: status, длительность, tokens, cost), артефакты, текущий шаг, pending approvals; действия: Pause / Resume / Cancel / Retry / Replan
Catalog instance-wide карточки reusable definitions; Install в проект (latest-by-default); для admin/owner — Publish / Archive

Console читает только read.* проекции и пишет через CommandEnvelope; в app.* напрямую не ходит. Collections/labels — только UI-навигация (не влияют на семантику исполнения).


4. Концепции (mental model)

4.1 Step model

Каждый шаг — модель Step (core/models/workflow_definitions.py) с уникальным step_key (строка). Ветвление — через on_success / on_failure (ссылки по ключу), не по числовым индексам. Terminal routing: on_success=None → workflow completed; on_failure=Nonefailed. У condition: on_success = путь при True, on_failure = при False.

Каноническая таксономия step_type (13):

step_type Назначение side_effect где исполняется
load_context загрузка контекста workflow/task из БД none activity-side
retrieve_knowledge запрос к knowledge base none activity-side
model_call LLM-вызов со structured output (Instructor) none activity-side
tool_call вызов зарегистрированного tool/activity (или connector — см. §4.3) varies activity-side
transform трансформация данных: extract / merge / format / map (реализованы); compute — planned future none activity-side
validate валидация (schema / semantic) none activity-side
human_gate точка утверждения человеком (assignee_role, deadline_seconds, on_timeout, decisions) none activity-side
external_write запись во внешнюю систему через policy gate external_high activity-side
finalize финализация, подготовка результата internal activity-side
condition if/else: on_success (true) / on_failure (false) none workflow-side
wait Temporal sleep (duration_seconds) и/или ожидание signal (wait_for_signal); ноль ресурсов при ожидании none workflow-side
subflow запуск дочернего workflow (фрактальная вложенность); runtime валидирует pinned definition_id, depth limit, propagates budget + cancel cascade none workflow-side
fan_out обработка коллекции: N параллельных child workflows на каждый item (source_key, child_definition, max_parallel, on_item_failureskip/fail_all/retry) none workflow-side

Runtime partition (core/workflows/step_runner/types.py): 9 activity-side step types исполняются через Temporal activity execute_workflow_step; 4 workflow-side — внутри WorkflowRunner._run_steps() через Temporal primitives. subflowпервоклассный step type, не hack через tool_call.

Как StepRunner исполняет шаг: stagnation check (>N переходов → StagnationError; лимит из ExecutorProfile.max_steps, default 50) → step-type validation (executor profile) → tool allowlist check (для tool_call) → policy gate (если side_effect_class ∈ {external_low, external_high}) → budget check (если model_call) → execute handler → handle interrupts (human_gate/external_writeawaiting_approval) → record result (timing, tokens, cost).

Interrupt lifecycle (human_gate / external_write): handler → StepResult(interrupt_type="awaiting_approval") → run в статусе awaiting_approval → ждёт Temporal signal approval_decided → при resume StepRunner продолжает с текущего шага (не on_success) → после approve handler re-execute → completed → routing по on_success. Approvals — см. Approvals.md.

4.2 Магия execution_mode + leaf strategy

WorkflowDefinition
  ├─ execution_mode = leaf   →  одна leaf-стратегия (по форме config'а):
  │       steps:  list[Step]            — предопределённые шаги (sequential/branching)
  │       agent_config: AgentConfig     — AI-агент (model profile, tools, system prompt)  → см. Agents-And-Prompts.md
  │       planner_config: PlannerConfig — planner строит DAG (+ опц. reviewer_config)
  │     (ambiguous комбинации steps+agent_config / steps+planner_config / agent_config+planner_config → reject на materialization)
  ├─ execution_mode = graph  →  children: list[ChildWorkflowSpec] + child_dependencies + graph_config
  └─ execution_mode = hybrid →  graph_config.pre_steps → children graph → post_steps
  +  connector_requirements: list[ConnectorRequirement]   — именованные слоты (что нужно: email/crm/...)

Magic Box — 10 паттернов, один WorkflowRunner: Sequential · AI-enhanced (model_call) · Parallel/DAG (graph children) · Plan-based (planner + reviewer) · Ambient/Daemon (continue_as_new — observer shell + отдельный reaction workflow) · Wait+Signal (sleep+signal — дни/месяцы) · Schedule (Temporal Schedule) · Batch/Fan-out (child workflows + semaphore) · Saga/Compensation (compensation chain — см. Undo-And-Compensation.md) · Human Pipeline (signals+timers per gate). Никаких спец-типов workflow — только комбинации step_type в универсальном контейнере.

4.3 Connector binding в step.config (Mode A/B/B-ref/C, D27 XOR)

Connector-backed tool_call ссылается на binding через одно top-level поле в config (sibling рядом с tool_name/tool_args), D27 XOR — ровно один из: - connector_requirementMode A (Stage 3): authoring декларирует именованный слот; reviewed binding profile связывает его с project-scoped connector instance; - connector_instance_idMode B / B-ref (Stage 1/2): литерал cred_<ulid> (Stage 1: connector_instance_id == credential_id) ИЛИ typed ConnectorInstanceBinding = {"$credential_ref": "input_data.<field>"} (Stage 2 Run Wizard light для multi-credential — concrete credential выбирается на start_workflow); - connector_keyMode C (legacy grandfathered; новые publishes отвергаются — D31 quarantine).

external_write с connector mode пока fail-closed (connector_mode_not_supported_for_external_write). Секреты никогда не в config; runtime resolver разрешает credential через (project_id, credential_id) и расшифровывает payload в worker memory — до policy/approval/audit/dispatch/side effect. Подробно — Connectors-Credentials.md §4.

4.4 Binding layer (D17/D36)

ConnectorRequirement[] (в definition, пишет инженер) → WorkflowBindingProfile (app.workflow_binding_profiles; admin/manager один раз: слот → connector instance; review state) → при create/start_workflow хендлер пиннит app.workflow_run_bindings_snapshot (D36, system). Definition при старте не мутируется; runtime читает snapshot, materialize'ит concrete instance/credential. Три слоя override при запуске (D17): profile.bindings ← case.connector_overrides ← run.binding_overrides. См. Connectors-Credentials.md §4.

4.5 Case-aware workflows

Case-aware workflow привязан к case (носитель бизнес-кейса). Entry step — load_context с bounded projection invariant; publish_definition отвергает case_aware=True без него. Детали — Cases.md, CONCEPT-CASE-WORKFLOWS.md.


5. Флоу: пошаговые сценарии

Флоу 1 — Написать и опубликовать определение (engineermanager+)

  1. (engineer, код) Создать modules/workflows/<name>/ с definition.py, экспортирующим definition: WorkflowSpec (шаги, connector_requirement[], trigger, config). Опц.: activities.py + __manifest__.py для local activities.
  2. (engineer/CI) axon push → CLI шлёт HTTP POST к app-api → router строит CommandEnvelope типа publish_definition → handler валидирует (Mode XOR D27, case_aware invariant, connector mode fields только для tool_call, connector_key Mode C новые — reject) → immutable snapshot в workflow_definitions.definition ({execution, metadata}), pinned definition_id (wdef_<ulid>). push НЕ создаёт workflows row и НЕ активирует trigger/schedule/ambient.
  3. На первом publish, если в проекте уже есть ровно один usable connector instance под каждый требуемый logical тип → binding profile auto-create (status=complete, auto_configured=true, баннер «Review» в Console).
  4. Альтернатива (без кода): Install reusable definition из Catalog (catalog:install, manager+) — latest-by-default; collision имени → 409 + rename.

Флоу 2 — Настроить binding profile (manager+)

  1. Console → Workflows → <definition>Bindings.
  2. UI показывает ConnectorRequirement-слоты (имя + логический тип + required_actions).
  3. Auto-map (ConnectorMapper предлагает инстансы по типу: один кандидат → авто; несколько → выбор; нет → «требуется подключить») или вручную выбрать connector instance под каждый слот.
  4. Сохранить → set_workflow_bindings → profile status=complete. Set-once-use-many.

Флоу 3 — Запустить workflow для кейса (operator+)

  1. Console → Workflows → <definition>Run Wizard.
  2. Выбрать case (для case-aware), задать input_data; опционально override bindings на этот run (в т.ч. выбор concrete credential для Mode B-ref слотов).
  3. Create + Start → канонический path create_workflow(definition_id)start_workflow(workflow_id) (pinned definition_id, без latest-key fallback) → pre-dispatch hook пиннит workflow_run_bindings_snapshot (D36, system) → Temporal стартует WorkflowRunner.
  4. Исполнение: StepRunner идёт по on_success/on_failure; на connector-step резолвит инстанс → берёт credential → policy gate / approval / audit / idempotency → side effect; model_call → budget check; human_gate/external_writeawaiting_approval (signal approval_decided).
  5. Мониторинг — Run (detail): timeline шагов, tokens/cost, текущий шаг, pending approvals.

Флоу 4 — Управление run'ом

Действие Команда Permission Эффект
Pause pause_workflow manager+ run приостановлен; ресурсы не тратятся (Temporal)
Resume resume_workflow manager+ продолжить с места остановки
Cancel cancel_workflow manager+ остановить run; для уже выполненных side-effect'ов — compensation (если определена) или ручной runbook (Undo-And-Compensation.md)
Retry retry_workflow owner/admin перезапустить упавший шаг/run
Replan replan_workflow owner/admin для plan-based: перестроить DAG (planner + reviewer заново)
Replay replay owner/admin детерминированный реплей (отладка/восстановление)

Флоу 5 — Запустить через event/schedule/ambient

  • event — коннектор (gmail/webhook/telegram) → app-api ingress → канонический create_workflow/start_workflow (reaction workflow указан pinned workflow_definition_id) → Temporal.
  • schedule — Temporal Schedule запускает определение периодически (паттерн 5.8).
  • ambient — observer-shell непрерывно мониторит источник; при срабатывании условия dispatch'ит reaction workflow по pinned ID (паттерн 5.6). Trigger/schedule/ambient активируются не при push, а отдельно.

Флоу 6 — Опубликовать определение в Catalog (admin/owner)

Console → Catalog → Publish (catalog:manage) — instance-wide карточка reusable definition; Archive снимает. Managers видят и могут Install в свои проекты. См. Templates-And-Catalog.md.


6. Справочник опций

6.1 WorkflowDefinition / WorkflowSpec (ключевые поля)

Поле Что делает
execution_mode leaf / graph / hybrid
steps list[Step] — для leaf step-стратегии
agent_config AgentConfig — для leaf agent-стратегии (model profile, tools, system prompt)
planner_config (+ reviewer_config) для leaf plan-стратегии (planner строит DAG, reviewer ревьюит)
children / child_dependencies / graph_config для graph/hybrid (DAG дочерних workflow; graph_config.pre_steps/post_steps для hybrid)
connector_requirements list[ConnectorRequirement] — именованные слоты (логический тип + required_actions); default []
case_aware bool; если True — entry step обязан быть load_context с bounded projection
metadata (WorkflowSpec): name, trigger, definition_key, project_id hint, config definition_key — authoring/listing identity (не scope authority); если не задан — выводится из ASCII-имени; non-ASCII → fail-closed

6.2 Step (поля)

Поле Что делает
step_key уникальный строковый id; routing через ключи
step_type один из 13 (см. §4.1)
config dict; для tool_calltool_name/tool_args + (опц.) один connector mode field (D27 XOR); для transformtype+параметры; для conditionexpression/language; для subflowdefinition_id; для human_gateassignee_role/deadline_seconds/on_timeout/decisions; для waitduration_seconds/wait_for_signal; для fan_outsource_key/child_definition/max_parallel/on_item_failure
side_effect_class none / internal / external_low / external_high — гейтит policy/budget
model_profile для model_call (например haiku)
timeout_seconds таймаут шага
on_success / on_failure ссылки на step_key; None → terminal (completed / failed)
compensation activity для отката при Saga-compensation (вызывается в обратном порядке для completed шагов с side effects)
fan_out конфиг fan-out (см. §4.1)

6.3 Transform sub-types

extract (выбрать поля из dict), merge (объединить несколько dict-источников), format (шаблон + данные), map (field→field) — реализованы. compute (safe expression evaluator) — planned future, сейчас неизвестный subtype = passthrough; для вычислений используй condition/ConditionEvaluator или явно зарегистрированный activity.

6.4 Состояния run'а

runningpaused (pause_workflow) / awaiting_approval (human_gate/external_write) / paused_budget (budget interrupt) → обратно runningcompleted / failed / cancelled. Definition при этом immutable (pinned definition_id); изменение определения не влияет на уже идущие run'ы.


7. Жизненный цикл и обслуживание

  • Версии определений. Каждый publish — новый immutable snapshot + новый definition_id (wdef_<ulid>). definition_key — стабильный listing-id; pinned definition_id — то, что используется в runtime/replay (без latest-key fallback на runtime/replay boundary). Уже запущенные run'ы пиннят свой definition_id — изменение определения их не трогает.
  • push не активирует side effects. Trigger/schedule/ambient включаются отдельно; push только сохраняет definition.
  • Run lifecycle. pauseresume; cancel (+ compensation/runbook); retry/replan/replay — owner/admin.
  • Catalog. Install — latest-by-default; collision имени → 409 + rename; Archive — снять карточку; install создаёт project-level пригодный к запуску definition.
  • Stagnation guard. >N переходов (ExecutorProfile.max_steps, default 50) → StagnationError (защита от циклов).

8. Траблшутинг

Симптом Причина Что делать
Workflow не запускается — «binding profile incomplete» не все ConnectorRequirement-слоты замаплены на usable инстансы Bindings → Auto-map / выбрать инстансы; проверить, что инстансы usable (D42) и коннекторы в allowlist ON (Connectors-Credentials.md §8)
publish_definition 422 нарушен Mode XOR (D27) в connector-backed tool_call; либо connector_key Mode C в новом publish (D31 quarantine); либо connector_mode_not_supported_for_external_write; либо case_aware=True без load_context entry step Оставить ровно один connector mode field; для нового кода — Mode A (connector_requirement) или Mode B (connector_instance_id); вынести connector-вызов в tool_call; добавить entry load_context для case-aware
Run завис в awaiting_approval ждёт approve, нет approver'а с доступом назначить/найти approver (approve-роль с доступом к проекту) — Approvals.md
Run в paused_budget budget interrupt на model_call поднять/задать бюджет проекта (Budgets-And-Cost.md) → resume
StagnationError цикл переходов A→B→A дольше max_steps пересмотреть routing / увеличить max_steps в executor profile (осознанно)
subflow падает «definition not found» config.definition_id не pinned / не существует указать pinned wdef_* (не definition_key) — runtime не резолвит latest-key
Catalog Install → 409 имя определения уже занято в проекте rename при install
tool '<name>' not found in registry tool_name не разрешён ни через registry / generic dispatch / connector / sandbox проверить регистрацию tool/activity либо корректность connector mode field

9. Ограничения и инварианты

  • Workflow — атом (инвариант 2): типов workflow нет (Magic Box); execution strategy — по форме config'а, не по «типу».
  • Undo — фундаментальное право (инвариант 3): каждый process имеет inverse flow; для отката side-effect'ов — compensation chain / runbook (Undo-And-Compensation.md).
  • PostgreSQL = SoT, Temporal = orchestration. Воркеры не сканируют файловую систему; определения попадают в runtime только через publish_definition.
  • Authoring ≠ scope authority. project_id в authoring-файле — лишь hint; канонический scope приходит из CLI/API (CommandEnvelope.project_id); mismatch отклоняется.
  • Pinned definition_id на runtime/replay boundary — без latest-key fallback (детерминизм replay).
  • Безопасность и бюджет — до выполнения (инварианты 4, 5): policy gate (external_* шаги) + budget check (model_call) — до side effect.
  • Все мутации — через CommandEnvelope (publish_definition, create/start/pause/resume/cancel/retry/replan_workflow, binding-команды, catalog-команды); RBAC server-side.
  • Секреты не в definition / profile / run snapshot — только в зашифрованном credential payload; runtime materialize'ит до side effect.
  • subflow — первоклассный step type (не hack через tool_call): budget propagation, cancel cascade, depth check.
  • Collections / labels — только UI-навигация — не влияют на семантику исполнения, RBAC или routing.

10. Связанные мануалы и каноны

  • Connectors-Credentials.mdConnectorRequirement[], connector mode fields, binding profiles, run snapshot.
  • Cases.md — case-aware workflows, load_context entry step, identity keys.
  • Undo-And-Compensation.md — compensation chain, отмена/откат run'а.
  • Agents-And-Prompts.mdagent_config, executor profiles, model_call vs agent execution.
  • Approvals.mdhuman_gate/external_write interrupt lifecycle, кто approve'ит.
  • Templates-And-Catalog.md — Catalog publish/install, шаблоны.
  • Roles-And-Permissions.md — полная RBAC-матрица; First-Project-Walkthrough.md — где publish/run в общем флоу.
  • Каноны: WORKFLOW-ARCHITECTURE.md §1-§5 (authoring/runtime, Step model, 10 паттернов); ARCHITECTURE-V6.md §5-§6 (исполнение, граф), §11-§12 (connectors, Step Runner); CONCEPT-CASE-WORKFLOWS.md, CONCEPT-WORKFLOW-LABELS.md, CONCEPT-COMPENSATION-V2.md; core/models/workflow_definitions.py (Step), core/models/auth.py (RBAC).