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 = hybrid—pre_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_workflow — push сам по себе ничего не запускает и не активирует 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-stepstart_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=None → failed. У 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_failure ∈ skip/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_write → awaiting_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_requirement — Mode A (Stage 3): authoring декларирует именованный слот; reviewed binding profile связывает его с project-scoped connector instance;
- connector_instance_id — Mode 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_key — Mode 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 — Написать и опубликовать определение (engineer → manager+)¶
- (engineer, код) Создать
modules/workflows/<name>/сdefinition.py, экспортирующимdefinition: WorkflowSpec(шаги,connector_requirement[], trigger, config). Опц.:activities.py+__manifest__.pyдля local activities. - (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_keyMode C новые — reject) → immutable snapshot вworkflow_definitions.definition({execution, metadata}), pinneddefinition_id(wdef_<ulid>).pushНЕ создаётworkflowsrow и НЕ активирует trigger/schedule/ambient. - На первом publish, если в проекте уже есть ровно один usable connector instance под каждый требуемый logical тип → binding profile auto-create (
status=complete,auto_configured=true, баннер «Review» в Console). - Альтернатива (без кода):
Installreusable definition из Catalog (catalog:install, manager+) — latest-by-default; collision имени → 409 + rename.
Флоу 2 — Настроить binding profile (manager+)¶
- Console → Workflows →
<definition>→ Bindings. - UI показывает
ConnectorRequirement-слоты (имя + логический тип +required_actions). Auto-map(ConnectorMapper предлагает инстансы по типу: один кандидат → авто; несколько → выбор; нет → «требуется подключить») или вручную выбрать connector instance под каждый слот.- Сохранить →
set_workflow_bindings→ profilestatus=complete. Set-once-use-many.
Флоу 3 — Запустить workflow для кейса (operator+)¶
- Console → Workflows →
<definition>→ Run Wizard. - Выбрать
case(для case-aware), задатьinput_data; опционально override bindings на этот run (в т.ч. выбор concrete credential для Mode B-ref слотов). Create + Start→ канонический pathcreate_workflow(definition_id)→start_workflow(workflow_id)(pinneddefinition_id, без latest-key fallback) → pre-dispatch hook пиннитworkflow_run_bindings_snapshot(D36, system) → Temporal стартуетWorkflowRunner.- Исполнение: StepRunner идёт по
on_success/on_failure; на connector-step резолвит инстанс → берёт credential → policy gate / approval / audit / idempotency → side effect;model_call→ budget check;human_gate/external_write→awaiting_approval(signalapproval_decided). - Мониторинг — 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 указан pinnedworkflow_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_call — tool_name/tool_args + (опц.) один connector mode field (D27 XOR); для transform — type+параметры; для condition — expression/language; для subflow — definition_id; для human_gate — assignee_role/deadline_seconds/on_timeout/decisions; для wait — duration_seconds/wait_for_signal; для fan_out — source_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'а¶
running → paused (pause_workflow) / awaiting_approval (human_gate/external_write) / paused_budget (budget interrupt) → обратно running → completed / failed / cancelled. Definition при этом immutable (pinned definition_id); изменение определения не влияет на уже идущие run'ы.
7. Жизненный цикл и обслуживание¶
- Версии определений. Каждый
publish— новый immutable snapshot + новыйdefinition_id(wdef_<ulid>).definition_key— стабильный listing-id; pinneddefinition_id— то, что используется в runtime/replay (без latest-key fallback на runtime/replay boundary). Уже запущенные run'ы пиннят свойdefinition_id— изменение определения их не трогает. pushне активирует side effects. Trigger/schedule/ambient включаются отдельно;pushтолько сохраняет definition.- Run lifecycle.
pause→resume;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.md —
ConnectorRequirement[], connector mode fields, binding profiles, run snapshot. - Cases.md — case-aware workflows,
load_contextentry step, identity keys. - Undo-And-Compensation.md — compensation chain, отмена/откат run'а.
- Agents-And-Prompts.md —
agent_config, executor profiles,model_callvs agent execution. - Approvals.md —
human_gate/external_writeinterrupt 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).