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

# Conditional routes

> Add an "Only when…" condition to a route, so the router can choose an actor only for the right people or once the right details are known.

A route's [activation prompt](/conversation-flows/build/routing-edges.md) tells the router *when* the route fits. It guides the choice, but the router can still pick that actor. A **condition** decides whether the route is open at all. While a route's condition isn't met, the router can't choose the actor it leads to, however well the conversation fits it.

| | Activation prompt | Condition (**Only when…**) |
| - | - | - |
| What you write | When the route fits, in plain language | Rules on an Initial Parameter or a slot, or an [AI condition](#ai-conditions) in plain language |
| How it's used | The router weighs it against the conversation | Checked on every message before the router chooses: rules exactly, an AI condition by an AI |
| Effect | Guides which actor the router picks | While it isn't met, the actor isn't an option |

## When to use one

* **Only for some people.** A Refunds actor only for managers, an onboarding actor only for the Enterprise plan. The condition reads an [Initial Parameter](/conversation-flows/build/flow-settings.md#initial-parameters) such as `user_role` or `plan`.
* **Only once something is known.** An Order tracking actor only after the visitor has given an order number. The condition reads a slot that an **Ask Question** step fills ([Slots](/conversation-flows/build/step-builder.md#slots-the-data-backbone)).
* **Only once the visitor has said something.** An Account help actor only after the visitor says they're already a customer. No parameter or slot holds that, so an [AI condition](#ai-conditions) checks the conversation.

To choose between topics, keep using activation prompts. Use a condition when the answer must be a firm no.

## Add a condition

**1. Open the route**

Click the route's label on the canvas, or **When?** on a route that has no label yet. The **Route to** panel opens (titled with the actor it leads to), with the activation prompt under **When should this route be taken?**

**2. Click Add a condition**

The **Only when…** card opens on **Rules**, with one empty rule. To describe the condition in words instead, click **AI** next to **Check with** (see [AI conditions](#ai-conditions)). Conditions work on routes into an actor; other routes don't offer them.

**3. Pick what to check**

In **Choose a parameter or slot**, pick from **Parameters** (the agent's Initial Parameters) or **Slots** (values that Ask Question steps collect).

**4. Pick a comparison and a value**

Choose a comparison from the table below, then enter the value it needs.

**5. Add more rules (optional)**

Click **Add rule** for up to 10 rules. With two or more, choose **All of these** or **Any of these** next to **Match**.

**6. Let it save**

The condition saves on its own once every rule is complete. Until then, the panel says what's missing, for example *Rule 1: Enter a value*, and *Not saved yet: the route keeps its saved condition until this one is complete.* If you close the panel then, it asks whether to discard the unfinished condition. Clicking the canvas or another route keeps it for the next time you open this route.

A condition you didn't change keeps working as it is. If it has a problem, the note ends with *"Saving keeps this condition as it is."* On a route that doesn't lead to an actor, the panel says *"Remove the condition: this route does not lead to an actor"*.

> [!NOTE]
>
> An agent that went live before versions existed keeps a **Save** button in the route panel, and the reason shows under it. See [Agents that went live before versions](/conversation-flows/operate/deploy.md#agents-that-went-live-before-versions).

| Comparison | The rule is met when the value… | You enter |
| - | - | - |
| **is** | equals your value | one value |
| **is not** | is set and differs from your value | one value |
| **is one of** | equals any value in your list | a list: type a value and press Enter |
| **is not one of** | is set and equals none of the values in your list | a list |
| **contains** | includes your text, or has it as an item when the value is a list | one value |
| **is set** | has any value | nothing |
| **is not set** | is empty or missing | nothing |
| **is greater than** | is a number above yours | a number |
| **is less than** | is a number below yours | a number |

The value box follows the parameter: a parameter with options shows them to pick from, a Yes/No parameter shows **Yes** and **No**, and a number parameter takes a number. A Yes/No parameter offers only **is**, **is not**, **is set** and **is not set**; a number parameter offers everything except **contains**.

If the list of parameters and slots is empty, the agent has neither yet. Add Initial Parameters in **Agent settings**, or an Ask Question step that saves a slot.

To take a condition off, open the route and click **Remove condition**. The change saves on its own.

### On the canvas

A route with a condition is drawn as a dashed line, and its label shows an icon: a filter for rules, a sparkle for an AI condition. Hover the label to read the condition:

* *Only when user\_role is manager*
* *Only when plan is one of pro, enterprise and order\_id is set*
* *Only when any of: user\_role is manager; plan is enterprise*
* *Only when (AI): The visitor says they're already a customer, for example by…*

An AI condition's tooltip shows the first 60 characters of what you wrote, with mentions shortened to their name: `@param.plan` reads as `@plan`.

A red icon means the condition can't be read: *"This condition can't be read, so the router never takes this route."* Open the route and fix or remove it. If the editor can't show the condition at all, the panel says *"This route has a condition the editor can't show. Saving keeps it unchanged. Remove condition deletes it, so the router can always choose this route."*

## Example: refunds only for managers

A support agent runs inside your company's back office. Anyone can ask about orders; only managers may issue refunds.

```mermaid theme={null}
flowchart LR
    S((Start)) -->|Orders| O[Order help]
    S -->|"Refunds · only when user_role is manager"| R[Refunds]
```

**1. Add the parameter**

In **Agent settings → Initial Parameters**, add `user_role`: a string with the options `staff` and `manager`.

**2. Add the condition**

Open the Start → Refunds route, click **Add a condition**, and set the rule to `user_role` · **is** · `manager`. It saves on its own.

**3. Pass the role safely**

Your back office creates a [widget link](/conversation-flows/channels/widget-links.md) for each signed-in user, with their role. On the widget channel, set **Who can pass parameters** to **Only widget links**. See [Conditions are not access control](#conditions-are-not-access-control).

When a staff member asks for a refund, the router can't choose Refunds, so the request goes to Order help. Tell Order help in its instructions what to say about refunds, for example who to ask.

## Example: order tracking once the order number is known

Triage collects the order number with an Ask Question step whose **Slot name** is `order_id`. The route from Start to Order tracking has the rule `order_id` · **is set**.

Until the visitor gives the number, the router can't send them to Order tracking, so Triage keeps the conversation and asks for it. Conditions are checked on every message, so the route opens as soon as the slot is filled.

## How values are compared

* **Case and surrounding spaces don't matter.** `Manager` and `MANAGER` match `manager`, and spaces before or after a value are ignored.
* **Numbers compare as numbers.** `10` matches `10.0`. **is greater than** and **is less than** are met only when the value is a number.
* **A missing value matches only "is not set".** When a parameter wasn't passed or a slot isn't filled yet, every other comparison is not met, including **is not** and **is not one of**. To include visitors without a value, add an **is not set** rule and choose **Any of these**.

> [!NOTE]
>
> On a Inbound agent, only the website widget passes Initial Parameters. On other channels they're empty, so a route that needs a parameter value stays closed there.

## AI conditions

An AI condition says in your own words when the route is open, for example *The visitor says they're already a customer*. On each message, an AI reads it against the conversation and answers yes or no. While the answer is no, the router can't choose the actor.

An activation prompt can describe the same thing, but it only guides the router. An AI condition is a separate yes-or-no check that keeps the route closed until it's met.

**1. Switch to AI**

Open the route and click **Add a condition**. Next to **Check with**, click **AI** (the other choice is **Rules**).

**2. Describe when the route is open**

Write a sentence or two about the conversation or the visitor. Write it as the condition to meet, not as an instruction.

**3. Mention values (optional)**

To use a value, type `@` and pick from **Flow Parameters** or **Slot values**. It's inserted as `@param.<name>` or `@slot.<name>`, and the AI sees the value in its place. For example: *The visitor says order @slot.order\_id arrived damaged or incomplete.*

**4. Let it save**

It saves on its own once there's something to check. While the box is empty, the panel says *Describe the condition, or remove it*, and nothing is saved.

Under the box, a **How AI conditions work** note sums it up:

> * An AI checks this each time the visitor writes.
> * If it can't decide, or something goes wrong, the route stays closed.
> * For anything about roles or permissions, use Rules. They're exact.
> * Each check adds a little time to every message.

If you switch between **Rules** and **AI**, the panel keeps what you wrote in the other one until you close it, but saves only the one on screen: *"Your rules are kept while this panel is open, but only the AI condition is saved."*

### How it's checked

* **Each time the visitor writes.** The AI checks only the routes the router is about to choose between on that message. A route the router doesn't need on that message isn't checked, and stays closed.
* **One answer per message.** Once the AI answers yes or no, that answer holds for the rest of the visitor's message. If a step fills a slot the condition mentions, the route is checked again before the router next uses it.
* **With the recent conversation.** The AI reads your condition, with each mention replaced by its value, and the last few messages. A value that isn't set yet reads as not captured.
* **Closed unless it's a clear yes.** If the AI can't decide, or anything fails or takes too long, the route stays closed. A check that fails gives no answer, so it isn't kept: the route may be checked again later on the same message.

### AI or rules?

Use **Rules** whenever a parameter or a slot holds the answer. They're exact, add no time, and work in live voice. Use **AI** when the answer is in what the visitor says and no slot captures it, such as whether they're already a customer or whether a delivery arrived damaged.

| Use Rules for | Use AI for |
| - | - |
| Roles, plans and permissions | What the visitor has told the agent |
| Values passed in Initial Parameters | Situations that are hard to put in a single value |
| Slots an Ask Question step fills | Things no step asks about |

### Example: account help only for existing customers

A shop's website agent has a Triage actor for everyone and an Account help actor for logins, orders and subscriptions. Account help should come in only once the visitor says they're already a customer.

```mermaid theme={null}
flowchart LR
    S((Start)) -->|Questions| T[Triage]
    S -->|"Account · only when (AI): already a customer"| A[Account help]
```

**1. Add the condition**

Open the Start → Account help route, click **Add a condition**, and click **AI** next to **Check with**.

**2. Describe it**

Write *The visitor says they're already a customer, for example by mentioning their account or a past order.* It saves on its own.

**3. Try it**

Open **Test flow** and ask *"Do you ship to Canada?"*. Triage answers, and the summary under the reply counts *1 route hidden*. Open it to see Account help as hidden, with the AI's reason. Then write *"I can't log in to my account"*. The condition is met, so the router can choose Account help.

Leave Triage without a condition, so a visitor who isn't a customer still gets an answer.

### Limits

* **2000 characters** per AI condition. The counter under the box turns red past that, with *Shorten it to 2000 characters to save.*
* **Up to 10 AI checks per message.** If the router needs more than 10 AI checks on one message, the routes left over stay closed for that message.
* **A little time per message.** The checks run side by side, but the reply waits for them. If they take too long in total, the routes still waiting stay closed for that message.
* **The last few messages.** The AI doesn't read the whole conversation. For something the visitor said much earlier, have an Ask Question step save it to a slot, then mention the slot or use a rule.

> [!NOTE]
>
> **Live voice: AI conditions keep the route closed for now.** Live voice doesn't check AI conditions yet, so in live voice conversations a route with an AI condition stays closed. Use Rules there. On an agent that uses live voice, the panel says so: *"This agent uses live voice, which doesn't check AI conditions yet. In live voice conversations this route stays closed. Use Rules if it has to work there."*

> [!WARNING]
>
> **AI conditions are advisory, not access control.**
>
> The visitor writes the conversation the AI reads, so they can talk it into a yes. Never use an AI condition for roles or permissions, or to protect what an actor can see or do. Use a rule condition on a parameter passed through a [widget link](/conversation-flows/channels/widget-links.md), with **Who can pass parameters** set to **Only widget links**. See [Conditions are not access control](#conditions-are-not-access-control).

## What still reaches a hidden actor

A condition limits only what the router may choose. These still reach the actor:

* **A Transfer step** that hands the conversation to it. The panel reminds you: *"A transfer step can still go there."*
* **A conversation that starts directly on that actor**, instead of going through the router first.
* **The actor already in progress.** It finishes its job even if a slot its condition reads changes. Initial Parameters never change during a conversation.
* **An actor the conversation stepped away from** in the middle of its job. The router can bring the conversation back to it.
* **Another open route into the same actor.** Each route has its own condition. To hide an actor everywhere, add the same condition to every route into it.

A change to a condition applies to tests you start after making it, and to real conversations that start after you [deploy](/conversation-flows/operate/deploy.md) it.

## When no actor is available

If every route from Start has a condition and a visitor matches none of them, the router has nobody to choose. The visitor gets this reply:

> Sorry — I can't help with that here.

The panel warns you when you add the last one: *"Every route from Start now has a condition. A visitor who matches none of them gets a short "can't help with that here" reply. Leave one actor without a condition."* Keep a general actor, such as Triage, open to everyone.

## Conditions are not access control

> [!WARNING]
>
> **Visitors can change parameter values.**
>
> Your website widget accepts parameters from the page (the [embed code or the page address](/conversation-flows/channels/widget-parameters.md)), and anyone can edit those. Don't rely on a condition that reads them to decide what someone is allowed to do. To gate by role, pass the role in a [widget link](/conversation-flows/channels/widget-links.md) and set the widget's [**Who can pass parameters**](/conversation-flows/channels/widget-links.md#who-can-pass-parameters) to **Only widget links**.

The panel shows the same warning when a rule reads a parameter, or an AI condition mentions one, and the agent's widget accepts values from the page. **Open channels** takes you to the setting.

* Values from the **Start Conversation** form, a workflow, or a widget link can't be changed by the visitor.
* Slots hold what the visitor told the agent, so they don't prove anything either.
* An AI condition is never access control, whatever it mentions: the visitor can talk it into a yes ([AI conditions](#ai-conditions)).
* A condition decides which actors the agent offers. The systems the actor works with should still check permissions for what it does there.

## Test a condition

When the agent has Initial Parameters, the test drawer (**Test flow** in the toolbar) opens on an **Initial parameters** form: *"The values this test starts with, as a widget or a link would pass them. Leave a field empty to test without it."*

1. Fill in the values, then click **Start test**. Fields you leave empty aren't sent, so you can try **is not set** rules. Required parameters aren't enforced in a test.
2. Send messages as usual. A bar above the chat shows the values, for example *Parameters: user\_role = staff*.
3. To try other values, click **Change**, edit them, and click **Restart test**. Restarting ends the test conversation and starts a new one, which also picks up conditions you've changed since.

Under each reply, the summary counts the routes a condition closed (*1 route hidden*). Open it, and a line names every actor the router couldn't choose, with the reason:

```text theme={null}
Hidden this turn: Refunds — user_role is not "manager"
Hidden this turn: Order tracking — order_id is not set
```

A rule's reason names your rule and the value you expected, never the visitor's value. If the slot values can't be read on a message, every rule on a slot shows `slot values unavailable`, and its route stays closed. When every actor is hidden, a **no eligible actor** line says the visitor got the fallback reply. Only you see these lines; visitors never do.

For an AI condition, the reason is what the AI decided, or why there's no answer:

```text theme={null}
Hidden this turn: Account help — AI: The visitor hasn't said they are a customer
Hidden this turn: Account help — AI: not met
Hidden this turn: Account help — judge timed out
```

| Reason | Why the route was closed |
| - | - |
| `AI:` and a short explanation | The AI decided the condition isn't met. The explanation is the AI's own, up to 60 characters, so it can paraphrase what the visitor said. |
| `AI: not met` | The AI decided the condition isn't met, without an explanation. |
| `judge timed out`, `judge failed`, and other reasons that start with `judge` | The check gave no answer: it ran out of time, failed or was stopped, the AI model wasn't available, or its answer couldn't be read. A failed check isn't kept, so the route may be checked again later on the same message. |
| `AI judgement unavailable` | The condition couldn't be checked on this message, for example because the slot values it mentions couldn't be read. |
| `AI check took too long` | The AI checks for this message took too long in total. |
| `over the limit of 10 AI conditions per turn` | The router needed more than 10 AI checks on this message. |

An AI-checked route the router didn't need on that message isn't listed.

## Deploy checks

When you click **Deploy**, conditions are checked along with the channels.

| Problem | Deploy | What you see |
| - | - | - |
| A rule reads a parameter the agent doesn't have | Blocked | *"Cannot deploy — fix configuration first"*, with: *The route to Refunds checks the parameter "user\_role", which this agent doesn't define. Add it under Initial Parameters or change the condition.* |
| An AI condition mentions a parameter the agent doesn't have | Blocked | *The AI condition on the route to Account help mentions the parameter "plan", which this agent doesn't define. Add it under Initial Parameters or change the condition.* |
| A condition on a route that doesn't lead to an actor | Blocked | *The route to Collect email has a condition, but conditions only work on routes into an actor. Remove the condition, or connect the route to an actor.* |
| A condition that can't be read | Blocked | A sentence that says what's wrong and what to do, for example: *The condition on the route to Refunds isn't in a form the editor understands, so this route is never taken. Open the route, remove the condition and add it again.* See the examples below. |
| A rule reads a slot no Ask Question step collects | Goes ahead | A warning in the route's panel: *Unknown slot: no Ask question step collects order\_id, so it stays not set unless something else fills it.* |
| An AI condition mentions a slot no Ask Question step collects | Goes ahead | A warning under the AI condition: *Unknown slot: no Ask question step collects order\_id, so @slot.order\_id stays empty unless something else fills it.* |
| An AI condition on an agent that uses live voice | Goes ahead | A note under the AI condition (see [Limits](#limits)). In live voice conversations the route stays closed. |
| Every route from Start has a condition | Goes ahead | A warning in the route's panel (see [When no actor is available](#when-no-actor-is-available)). |

More sentences you can see for a condition that can't be read:

* *Rule 2 of the condition on the route to Refunds has no value to compare with, so this route is never taken. Open the route and enter a value, or remove the condition.*
* *The AI condition on the route to Account help is longer than 2000 characters, so this route is never taken. Open the route, remove the condition and add it again.*

Other problems get the same kind of sentence, for example a list with too many values, a value that isn't a number, or more than 10 rules.

In the panel, a missing parameter shows as **(unknown)** in the rule, with *"Unknown parameter: … Deploy is blocked until you add it or pick another."* In an AI condition, each unknown mention gets its own line under the box, for example *"Unknown parameter: this agent has no Initial Parameter named plan, so @param.plan is always empty. Deploy is blocked until you add it or change the mention."*

Building with an AI assistant? The same conditions can be set through [MCP](/mcp-server.md#conditions-on-routes).

## Next

> **[Routes](/conversation-flows/build/routing-edges.md)**
>
> Draw routes and write activation prompts.

> **[Widget links](/conversation-flows/channels/widget-links.md)**
>
> Pass values visitors can't change.

> **[Pass details to the widget](/conversation-flows/channels/widget-parameters.md)**
>
> Initial Parameters from the embed code or the page address.

> **[Test an agent](/conversation-flows/operate/test-flow.md)**
>
> Try routes and read the routing trace before you deploy.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.