Jump to content

Connect Leeroopedia MCP: Equip your AI agents to search best practices, build plans, verify code, diagnose failures, and look up hyperparameter defaults.

Principle:CrewAIInc CrewAI Conditional Routing

From Leeroopedia

Overview

Conditional Routing is a control flow mechanism that enables dynamic branching, fan-in, and fan-out in event-driven workflows through routing functions and boolean combinators (or_, and_).

Description

While @start and @listen provide linear execution chains, Conditional Routing adds the control flow primitives needed for real-world workflows:

Routing via @router

A @router method executes when its trigger condition is met (just like @listen), but its return value determines which downstream methods fire next. The return value is a string that matches against @listen conditions:

  • The router returns a string constant (e.g., "SUCCESS", "FAILURE")
  • Downstream listeners decorated with @listen("SUCCESS") or @listen("FAILURE") fire based on the router's return value
  • The router's return type annotation (e.g., -> Literal["SUCCESS", "FAILURE"]) is used by the framework to discover possible paths at class definition time

Fan-Out via or_()

The or_() combinator creates a condition that fires when any of the specified methods completes:

@listen(or_(method_a, method_b))
def handler(self):
    # Fires when EITHER method_a OR method_b completes
    pass

This enables fan-out patterns where a single producer triggers one of several possible consumers, or where multiple independent producers can each trigger the same consumer.

When used with parallel listeners, or_() implements first-wins semantics: if both method_a and method_b are running concurrently, only the first to complete triggers the handler. The framework tracks fired OR listeners to prevent duplicate execution.

Fan-In via and_()

The and_() combinator creates a condition that fires only when all specified methods have completed:

@listen(and_(method_a, method_b))
def handler(self):
    # Fires only when BOTH method_a AND method_b have completed
    pass

This enables fan-in (join) patterns where parallel branches must all complete before the next step proceeds. The framework tracks per-listener completion counts in _pending_and_listeners to know when all required methods have fired.

Nested Conditions

or_() and and_() can be nested arbitrarily:

@listen(or_(and_(step_1, step_2), step_3))
def handler(self):
    # Fires when (step_1 AND step_2) have both completed, OR when step_3 completes
    pass

Theoretical Basis

Conditional Routing draws from Petri Net control flow semantics:

Petri Net Concept CrewAI Flow Mapping
OR-Join (merge) or_(method_a, method_b) -- fires when any input place has a token
AND-Join (synchronization) and_(method_a, method_b) -- fires when all input places have tokens
Conditional transition @router return value selects which output place receives a token
Token Method completion event carrying the method's return value
Place Listener's pending condition state

The key properties inherited from Petri Net semantics:

  • OR-Join is non-blocking: the first token triggers the transition
  • AND-Join is blocking: all tokens must arrive before the transition fires
  • Conditional transitions consume exactly one token and produce exactly one output token (the router's return value)
  • Composability: OR and AND joins can be nested to express complex synchronization patterns

Usage

When to Use Routing

  • When execution should branch based on runtime values (data quality, classification results, user choices)
  • When different processing pipelines apply to different data categories
  • When a workflow has error/success/retry paths

When to Use or_()

  • When a handler should respond to whichever of several sources completes first
  • When implementing fallback patterns (primary source OR backup source)
  • When multiple independent paths converge to a single handler

When to Use and_()

  • When a handler requires results from multiple parallel branches
  • When implementing barrier synchronization before a final aggregation step
  • When ensuring all prerequisites complete before proceeding

Constraints

  • Router return values must be strings (or string-convertible); downstream listeners match on these strings
  • For visualization to work, routers should have return type annotations (Literal or Enum)
  • and_() listeners reset their completion tracking after firing, supporting cyclic flows
  • or_() listeners fire at most once per execution cycle (tracked via _fired_or_listeners)

Related Pages

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment