Как исполняется граф
Движок событийный. Он не выстраивает ноды в очередь заранее и не читает холст слева направо. Сам он запускает ровно одну ноду — entry (внутри тела composite — его входной порт). Всё остальное запускает входящее ребро.
Ребро — это триггер
Разные провода делают разное:
- exec — только порядок: запускает следующую ноду, не передавая значение;
- execute_data — запускает и передаёт значение одним ребром, самый частый случай;
- data — только значение: цель его прочитает, но ребро её не запустит;
- link_llm / link_memory / link_extension — ссылка на конфигурацию (модель, память, инструмент), к порядку исполнения отношения не имеет.
Отсюда главное следствие: нода, до которой не доходит ни одно exec- или
execute_data-ребро, не выполнится — сколько бы шаблонов на неё ни ссылалось.
Запись {{ nodes.<id>.output }} читает значение, но не запускает ноду.
Слияние веток: по умолчанию ждём всех
Нода с несколькими входящими зависимостями запускается, когда сработали все — это обычный AND-join. Так же ведут себя параллельные ветви: независимые цепочки исполняются одновременно, а количество одновременно работающих нод ограничено тарифом.
Ветвление убивает рёбра
if и switch выбирают ровно одну ногу. Невыбранные рёбра помечаются мёртвыми — по ним уже никогда ничего не придёт. Нода, у которой мертвы все входы, тоже становится мёртвой и передаёт это дальше: так пропускается целая ветка. Почему конкретная нода не выполнялась, видно в её карточке запуска — см. статусы и skip_reason.
OR-join: один вход сработал, остальные мертвы
Когда обе ветви if сходятся в одну ноду, ждать «всех» бессмысленно: второй
вход не придёт никогда. Такая нода запускается, как только сработал хотя бы один
вход, а все оставшиеся мертвы.
- Исполнение + данные
Нода выполняется один раз и получает значение той ветви, которая сработала;
значений остальных веток у неё нет. Валидатор говорит об этом предупреждением
wire.andjoin_partial_payload — это подсказка, а не ошибка: обычно именно такого
поведения и ждут.
Барьер: для веток, которые идут одновременно
Если ветви друг друга не исключают, а действительно работают параллельно, вести
их в один вход нельзя: они гонятся за него, и значение выигрывает та, что пришла
последней. Валидатор отбивает это ошибкой wire.fanin_needs_barrier.
Правильная форма — wait_all: каждая ветвь идёт в его вход
barrier_in, дальше граф продолжается с его выхода.
- Исполнение + данные
Барьер ждёт, пока каждый вход разрешится: либо сработает, либо окажется
мёртвым. Поэтому пропущенная ветка switch его не блокирует. Как объединить
значения, решает поле merge_mode (first, last, merge).
Чистая data-нога
Ребро data передаёт значение, но ноду не запускает. Из этого правила есть одно
исключение: если у цели нет никакой другой зависимости планировщика, а
источник сам управляем, движок поднимает такое ребро в планировщик — и цель
запускается вслед за источником. Именно поэтому работает самая естественная форма
раздельных портов: code_javascript[data] → exit.
Если же поднимать нечего и exit не достижим ни по одному exec-пути, запуск
закончился бы пустым результатом. Валидатор отбивает такой граф ошибкой
exec.exit_no_exec_trigger ещё до старта.
Ошибка в одной ветви
Упавшая нода не отменяет остальные ветви — они доигрывают до конца. Что будет с
её собственным продолжением, решает наличие ветки on_error; итоговый статус
запуска подводится после того, как все ветви остановились.