> ## Documentation Index
> Fetch the complete documentation index at: https://agno-v2-agui.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Branching Workflow

> Complex decision trees requiring dynamic path selection based on content analysis

**Example Use-Cases**: Expert routing, content type detection, multi-path processing

Dynamic routing workflows provide intelligent path selection while maintaining predictable execution within each chosen branch.

<img className="block dark:hidden" src="https://mintcdn.com/agno-v2-agui/TRMTiAtCN7Ur5zRR/images/workflows-router-steps-light.png?fit=max&auto=format&n=TRMTiAtCN7Ur5zRR&q=85&s=2ff86d758b72815b5555e5562a79a524" alt="Workflows router steps diagram" width="2493" height="921" data-path="images/workflows-router-steps-light.png" />

<img className="hidden dark:block" src="https://mintcdn.com/agno-v2-agui/TRMTiAtCN7Ur5zRR/images/workflows-router-steps.png?fit=max&auto=format&n=TRMTiAtCN7Ur5zRR&q=85&s=e027945beddedd4e6a2286b999a67391" alt="Workflows router steps diagram" width="2493" height="921" data-path="images/workflows-router-steps.png" />

## Selector Flexibility

The Router selector function supports multiple return types:

* **String**: Return step name - Router resolves it from choices
* **Step**: Return Step object directly
* **List\[Step]**: Return list of steps for chaining

The selector can also receive `step_choices` as an optional second parameter for dynamic selection.

## Example: String-based Selector

The simplest approach - return the step name as a string:

```python branching_workflow.py theme={null}
from typing import Union, List

from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.workflow.router import Router
from agno.workflow.step import Step
from agno.workflow.types import StepInput
from agno.workflow.workflow import Workflow

tech_expert = Agent(
    name="tech_expert",
    model=OpenAIChat(id="gpt-4o-mini"),
    instructions="You are a tech expert. Provide technical analysis.",
)

biz_expert = Agent(
    name="biz_expert",
    model=OpenAIChat(id="gpt-4o-mini"),
    instructions="You are a business expert. Provide business insights.",
)

generalist = Agent(
    name="generalist",
    model=OpenAIChat(id="gpt-4o-mini"),
    instructions="You are a generalist. Provide general information.",
)

tech_step = Step(name="Tech Research", agent=tech_expert)
business_step = Step(name="Business Research", agent=biz_expert)
general_step = Step(name="General Research", agent=generalist)


def route_by_topic(step_input: StepInput) -> Union[str, Step, List[Step]]:
    """Selector can return step name as string - Router resolves it."""
    topic = step_input.input.lower()

    if "tech" in topic or "ai" in topic or "software" in topic:
        return "Tech Research"  # Return name as string
    elif "business" in topic or "market" in topic or "finance" in topic:
        return "Business Research"
    else:
        return "General Research"


workflow = Workflow(
    name="Expert Routing",
    steps=[
        Router(
            name="Topic Router",
            selector=route_by_topic,
            choices=[tech_step, business_step, general_step],
        ),
    ],
)

workflow.print_response("Latest developments in artificial intelligence", markdown=True)
```

## Example: Using step\_choices Parameter

Access available choices dynamically for more flexible routing:

```python dynamic_routing.py theme={null}
def dynamic_selector(step_input: StepInput, step_choices: list) -> Union[str, Step, List[Step]]:
    """
    Selector receives step_choices - can select by name or return Step directly.
    step_choices contains the prepared Step objects from Router.choices.
    """
    user_input = step_input.input.lower()

    # Build name map from step_choices
    step_map = {s.name: s for s in step_choices if hasattr(s, "name") and s.name}

    # Can return step name as string
    if "research" in user_input:
        return "researcher"

    # Can return Step object directly
    if "write" in user_input:
        return step_map.get("writer", step_choices[0])

    # Can return list of Steps for chaining
    if "full" in user_input:
        return [step_map["researcher"], step_map["writer"], step_map["reviewer"]]

    # Default
    return step_choices[0]


workflow = Workflow(
    name="Dynamic Routing",
    steps=[
        Router(
            name="Dynamic Router",
            selector=dynamic_selector,
            choices=[researcher, writer, reviewer],
        ),
    ],
)
```

## Example: Nested Choices

Nested lists in choices become Steps containers for sequential execution:

```python nested_routing.py theme={null}
def nested_selector(step_input: StepInput, step_choices: list) -> Union[str, Step, List[Step]]:
    """
    When choices contains nested lists like [step_a, [step_b, step_c]],
    the nested list becomes a Steps container in step_choices.
    """
    user_input = step_input.input.lower()

    # step_choices[0] = Step for step_a
    # step_choices[1] = Steps container with [step_b, step_c]

    if "single" in user_input:
        return step_choices[0]  # Just step_a
    else:
        return step_choices[1]  # Steps container: step_b -> step_c


workflow = Workflow(
    name="Nested Choices Routing",
    steps=[
        Router(
            name="Nested Router",
            selector=nested_selector,
            choices=[step_a, [step_b, step_c]],  # Nested list becomes Steps container
        ),
    ],
)
```

## Developer Resources

* [Router Steps Workflow](/workflows/usage/router-steps-workflow)
* [Router with step\_choices](/workflows/usage/router-with-step-choices)

## Reference

For complete API documentation, see [Router Steps Reference](/reference/workflows/router-steps).
