> ## Documentation Index
> Fetch the complete documentation index at: https://docs.syllable.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Example 5: Conditional Branching

> Implement smart routing based on user preferences with conditional transitions

Building on lifecycle actions, this example adds smart routing—different follow-up paths based on user preferences.

***

## Objective

In this example, you'll learn:

* How to use conditional `next` entries for branching logic
* How to write JMESPath expressions for conditions
* How to create parallel workflow paths with different endings
* The importance of fallback routes

***

## The Scenario

Your contact form collects the user's preferred contact time. Now you want to:

1. Route morning/afternoon preferences → schedule a phone call
2. Route evening/night preferences → send an email follow-up

This creates personalized experiences based on user input.

***

## Implementation

Here's the complete tool definition:

```json theme={null}
{
  "type": "context",
  "context": {
    "task": {
      "type": "steps",
      "version": "v1alpha",
      "id": "contact-form-with-branching",
      "tool": {
        "name": "submit_contact_info",
        "description": "Submit contact form information with conditional routing"
      },
      "steps": [
        {
          "id": "COLLECT_NAME",
          "goal": "Collect the user's name",
          "instructions": [
            "Ask the user for their name.",
            "Once you have their name, call the submit_contact_info tool with the user_name parameter."
          ],
          "inputs": [
            {
              "name": "user_name",
              "type": "string",
              "description": "The user's name",
              "required": true
            }
          ],
          "on": {
            "enter": [
              {"action": "say", "text": "Welcome! Let's collect your contact information. Step 1 of 3."},
              {"action": "set", "name": "local.steps_completed", "value": 0}
            ],
            "submit": [
              {"action": "save"},
              {"action": "inc", "name": "local.steps_completed"}
            ]
          },
          "next": [{"id": "COLLECT_EMAIL"}]
        },
        {
          "id": "COLLECT_EMAIL",
          "goal": "Collect the user's email address",
          "instructions": [
            "Ask the user for their email address.",
            "Once you have their email, call the submit_contact_info tool with the user_email parameter."
          ],
          "inputs": [
            {
              "name": "user_email",
              "type": "string",
              "description": "The user's email address",
              "required": true
            }
          ],
          "on": {
            "enter": [{"action": "say", "text": "Great! Step 2 of 3."}],
            "submit": [
              {"action": "save"},
              {"action": "inc", "name": "local.steps_completed"}
            ]
          },
          "next": [{"id": "COLLECT_TIME"}]
        },
        {
          "id": "COLLECT_TIME",
          "goal": "Collect the user's preferred contact time",
          "instructions": [
            "Ask the user for their preferred contact time.",
            "Once you have their preference, call the submit_contact_info tool with the contact_time parameter."
          ],
          "inputs": [
            {
              "name": "contact_time",
              "type": "string",
              "description": "The user's preferred contact time",
              "required": true,
              "enum": ["morning", "afternoon", "evening", "night"]
            }
          ],
          "on": {
            "enter": [{"action": "say", "text": "Almost done! Step 3 of 3."}],
            "submit": [
              {"action": "save"},
              {"action": "inc", "name": "local.steps_completed"}
            ]
          },
          "next": [
            {
              "if": "contact_time == 'morning' || contact_time == 'afternoon'",
              "id": "SCHEDULE_CALL"
            },
            {
              "if": "contact_time == 'evening' || contact_time == 'night'",
              "id": "SEND_EMAIL"
            },
            {
              "id": "SEND_EMAIL"
            }
          ]
        },
        {
          "id": "SCHEDULE_CALL",
          "goal": "Confirm phone follow-up for daytime contact preference",
          "instructions": [
            "Inform the user that we'll call them during business hours (morning or afternoon).",
            "Thank them for providing their information.",
            "Call the submit_contact_info tool to complete this step."
          ],
          "inputs": [],
          "next": []
        },
        {
          "id": "SEND_EMAIL",
          "goal": "Confirm email follow-up for evening/night contact preference",
          "instructions": [
            "Inform the user that we'll send them an email since they prefer evening or night contact.",
            "Thank them for providing their information.",
            "Call the submit_contact_info tool to complete this step."
          ],
          "inputs": [],
          "next": []
        }
      ]
    }
  },
  "tool": {
    "type": "function",
    "function": {
      "name": "contact_form_branching_workflow",
      "description": "Multi-step workflow with conditional branching",
      "parameters": {
        "type": "object",
        "properties": {},
        "required": []
      }
    }
  }
}
```

***

## Key Concepts

### Conditional `next` Entries

The `next` array can contain multiple entries with conditions:

```json theme={null}
"next": [
  {
    "if": "contact_time == 'morning' || contact_time == 'afternoon'",
    "id": "SCHEDULE_CALL"
  },
  {
    "if": "contact_time == 'evening' || contact_time == 'night'",
    "id": "SEND_EMAIL"
  },
  {
    "id": "SEND_EMAIL"
  }
]
```

**Evaluation rules:**

1. Entries are evaluated **in order** (top to bottom)
2. The **first** entry whose condition evaluates to true wins
3. An entry without `if` is a **fallback** (always matches)
4. If no entries match, the submission is treated as terminal and the workflow completes in place

### JMESPath Expressions

JMESPath is the default expression language for conditions. Common patterns:

```json theme={null}
// String comparison
"if": "contact_time == 'morning'"

// Logical OR
"if": "contact_time == 'morning' || contact_time == 'afternoon'"

// Logical AND
"if": "is_vip && has_consent"

// Negation
"if": "!opted_out"

// Numeric comparison (note backticks for literals)
"if": "local.attempts >= `3`"
```

**Important:** In JMESPath, boolean and numeric literals require backticks:

* `flag == \`true\``(not`flag == true\`)
* `count >= \`3\``(not`count >= 3\`)

### Variable Access in Conditions

After `on.submit` actions execute, you can access:

| Variable               | Access Pattern                    |
| ---------------------- | --------------------------------- |
| Saved global variables | `contact_time` (directly by name) |
| Task-local variables   | `local.steps_completed`           |
| Current step inputs    | `inputs.contact_time`             |

The `save` action runs before transition evaluation, so `contact_time` is available for routing decisions.

### Fallback Routes

Always include a fallback route (no `if` condition) as the last entry:

```json theme={null}
"next": [
  {"if": "condition1", "id": "STEP_A"},
  {"if": "condition2", "id": "STEP_B"},
  {"id": "DEFAULT_STEP"}  // Catches everything else
]
```

This prevents the workflow from getting stuck if none of the conditions match.

### Multiple Terminal Steps

This example has two terminal steps (`SCHEDULE_CALL` and `SEND_EMAIL`), each with:

* Unique instructions tailored to that path
* No inputs (confirmation only)
* Empty `next: []` (terminal)

The user's journey ends differently based on their preference:

```
User prefers morning → SCHEDULE_CALL → "We'll call you during business hours"
User prefers evening → SEND_EMAIL → "We'll send you an email"
```

***

## How It Works

### Path A: Morning/Afternoon Preference

```
User: "Hello"
Agent: "Welcome! Step 1 of 3. What is your name?"

User: "Alice"
Agent: "Great! Step 2 of 3. What is your email address?"

User: "alice@example.com"
Agent: "Almost done! Step 3 of 3. What is your preferred contact time?"

User: "morning"

[Agent calls submit_contact_info(contact_time="morning")]
  → on.submit: save contact_time
  → Evaluate next:
    - "morning == 'morning' || morning == 'afternoon'" → TRUE
  → Transition to SCHEDULE_CALL

Agent: "Thank you! We'll call you during business hours."

[Agent completes SCHEDULE_CALL]
  → Workflow ends
```

### Path B: Evening/Night Preference

```
... (same first 3 steps) ...

User: "evening"

[Agent calls submit_contact_info(contact_time="evening")]
  → on.submit: save contact_time
  → Evaluate next:
    - "evening == 'morning' || evening == 'afternoon'" → FALSE
    - "evening == 'evening' || evening == 'night'" → TRUE
  → Transition to SEND_EMAIL

Agent: "Thank you! We'll send you an email since you prefer evening contact."

[Agent completes SEND_EMAIL]
  → Workflow ends
```

### Workflow Structure

```
                    ┌─────────────────┐
                    │  COLLECT_NAME   │
                    └────────┬────────┘
                             │
                    ┌────────▼────────┐
                    │  COLLECT_EMAIL  │
                    └────────┬────────┘
                             │
                    ┌────────▼────────┐
                    │  COLLECT_TIME   │
                    └────────┬────────┘
                             │
           ┌─────────────────┴─────────────────┐
           │                                   │
    morning/afternoon                    evening/night
           │                                   │
    ┌──────▼──────┐                    ┌───────▼───────┐
    │ SCHEDULE_   │                    │  SEND_EMAIL   │
    │    CALL     │                    │               │
    └─────────────┘                    └───────────────┘
    (terminal)                          (terminal)
```

***

## Try It

To test this workflow in the Syllable Console:

1. Create a new tool with the JSON above
2. Assign it to an agent
3. Test both paths:
   * Say "morning" as your preferred time → expect phone call confirmation
   * Say "evening" as your preferred time → expect email confirmation

**Verify the routing:** Each path should deliver different confirmation messages based on the user's preference.

***

## What's Next

This example routes based on valid input, but what if the user provides invalid data? In [Example 6: Retry Loop](./example-06-retry), you'll learn how to:

* Validate email format before proceeding
* Allow retry attempts when validation fails
* Use counters to limit retries
* Loop back to the same step on failure
