Conditional Logic

Build dynamic workflows with branching logic, conditional execution, and complex decision trees.

Overview

Conditional logic enables workflows to make decisions based on data from previous steps. Use conditions to route execution, handle different scenarios, and create intelligent, adaptive workflows.

How Conditionals Work

Conditional execution uses a tagging system:

  1. CONDITION step evaluates - Tests a boolean expression against chain context
  2. Tag is activated - Either trueTag or falseTag based on result
  3. Tagged steps execute - Only steps with matching tag (or no tags) run
  4. Unmatched steps skip - Steps with non-matching tags are skipped
Simple Conditional Flow
json
[
  {
    "order": 0,
    "type": "PROMPT",
    "promptId": "sentiment-analyzer",
    "inputMapping": { "text": "{{userMessage}}" },
    "outputKey": "sentiment"
  },
  {
    "order": 1,
    "type": "CONDITION",
    "config": {
      "condition": "{{sentiment.sentiment}} == 'Negative'",
      "trueTag": "negative_path",
      "falseTag": "positive_path"
    }
  },
  {
    "order": 2,
    "type": "PROMPT",
    "promptId": "apology-response",
    "tags": ["negative_path"],
    "inputMapping": { "message": "{{userMessage}}" },
    "outputKey": "response"
  },
  {
    "order": 3,
    "type": "PROMPT",
    "promptId": "friendly-response",
    "tags": ["positive_path"],
    "inputMapping": { "message": "{{userMessage}}" },
    "outputKey": "response"
  }
]
In this example, only one of the two prompt steps will execute based on the sentiment. Both store their output in the same key ("response"), so the final output is always available.

Condition Syntax

Basic Comparisons

// Equality
"{{status}} == 'approved'"

// Inequality
"{{status}} != 'rejected'"

// Greater than
"{{confidence}} > 0.8"

// Less than or equal
"{{price}} <= 100"

// Greater than or equal
"{{score}} >= 75"

Logical Operators

// AND - Both conditions must be true
"{{sentiment}} == 'Negative' && {{confidence}} > 0.7"

// OR - Either condition can be true
"{{priority}} == 'high' || {{urgent}} == true"

// Complex combinations
"({{score}} > 80 && {{verified}} == true) || {{admin}} == true"

Nested Property Access

// Access nested object properties
"{{user.profile.verified}} == true"

// Access array elements (0-indexed)
"{{items[0].price}} > 50"

// Multiple levels deep
"{{response.data.status.code}} == 200"

Type Coercion

Values are automatically coerced to appropriate types for comparison:

// String to number
"{{quantity}} > 5"  // Works if quantity is "10" or 10

// String to boolean
"{{active}} == true"  // Works if active is "true" or true

// Case-sensitive strings
"{{status}} == 'Active'"  // "active" != "Active"
String comparisons are case-sensitive. Use toLowerCase() transform steps if you need case-insensitive matching.

Multiple Conditions

Chains can have multiple CONDITION steps to create complex decision trees:

Multi-Branch Workflow
json
[
  {
    "order": 0,
    "type": "PROMPT",
    "promptId": "classify-urgency",
    "inputMapping": { "text": "{{userMessage}}" },
    "outputKey": "urgency"
  },
  {
    "order": 1,
    "type": "CONDITION",
    "config": {
      "condition": "{{urgency.level}} == 'critical'",
      "trueTag": "critical",
      "falseTag": "not_critical"
    }
  },
  {
    "order": 2,
    "type": "PROMPT",
    "promptId": "analyze-sentiment",
    "tags": ["not_critical"],
    "inputMapping": { "text": "{{userMessage}}" },
    "outputKey": "sentiment"
  },
  {
    "order": 3,
    "type": "CONDITION",
    "tags": ["not_critical"],
    "config": {
      "condition": "{{sentiment.sentiment}} == 'Negative'",
      "trueTag": "negative_standard",
      "falseTag": "positive_standard"
    }
  },
  {
    "order": 10,
    "type": "API_CALL",
    "tags": ["critical"],
    "config": {
      "url": "https://api.example.com/urgent-alert",
      "method": "POST",
      "body": { "message": "{{userMessage}}" }
    },
    "outputKey": "alert_response"
  },
  {
    "order": 11,
    "type": "PROMPT",
    "promptId": "urgent-response",
    "tags": ["critical"],
    "inputMapping": { "message": "{{userMessage}}" },
    "outputKey": "response"
  },
  {
    "order": 20,
    "type": "PROMPT",
    "promptId": "empathetic-response",
    "tags": ["negative_standard"],
    "inputMapping": { "message": "{{userMessage}}" },
    "outputKey": "response"
  },
  {
    "order": 21,
    "type": "PROMPT",
    "promptId": "friendly-response",
    "tags": ["positive_standard"],
    "inputMapping": { "message": "{{userMessage}}" },
    "outputKey": "response"
  }
]

This creates three execution paths:

  • Critical path - Urgent alert API call + urgent response
  • Negative standard path - Sentiment analysis + empathetic response
  • Positive standard path - Sentiment analysis + friendly response

Tag Inheritance

CONDITION steps can themselves be tagged to create nested conditional logic:

{
  "order": 3,
  "type": "CONDITION",
  "tags": ["not_critical"],
  "config": {
    "condition": "{{sentiment.sentiment}} == 'Negative'",
    "trueTag": "negative_standard",
    "falseTag": "positive_standard"
  }
}
This CONDITION step only executes if the not_critical tag is active from a previous condition. This enables nested decision trees without complex nesting syntax.

Default Fallback

Steps without tags always execute regardless of condition results. Use this for setup steps or final fallbacks:

[
  {
    "order": 0,
    "type": "API_CALL",
    "config": {
      "url": "https://api.example.com/user/{{userId}}",
      "method": "GET"
    },
    "outputKey": "user_data"
  },
  {
    "order": 1,
    "type": "CONDITION",
    "config": {
      "condition": "{{user_data.premium}} == true",
      "trueTag": "premium",
      "falseTag": "free"
    }
  },
  {
    "order": 2,
    "type": "PROMPT",
    "promptId": "premium-response",
    "tags": ["premium"],
    "inputMapping": { "user": "{{user_data}}" },
    "outputKey": "response"
  },
  {
    "order": 3,
    "type": "PROMPT",
    "promptId": "free-response",
    "tags": ["free"],
    "inputMapping": { "user": "{{user_data}}" },
    "outputKey": "response"
  },
  {
    "order": 99,
    "type": "API_CALL",
    "config": {
      "url": "https://api.example.com/log",
      "method": "POST",
      "body": { "response": "{{response}}" }
    },
    "outputKey": "log_result"
  }
]

Step 0 (user data fetch) and step 99 (logging) always execute. Only one of steps 2 or 3 executes based on premium status.

Complex Scenarios

A/B Testing

Random A/B Split
json
[
  {
    "order": 0,
    "type": "TRANSFORM",
    "config": {
      "operation": "calculate",
      "expression": "Math.random() < 0.5"
    },
    "outputKey": "variant_a"
  },
  {
    "order": 1,
    "type": "CONDITION",
    "config": {
      "condition": "{{variant_a}} == true",
      "trueTag": "variant_a",
      "falseTag": "variant_b"
    }
  },
  {
    "order": 2,
    "type": "PROMPT",
    "promptId": "response-variant-a",
    "tags": ["variant_a"],
    "inputMapping": { "message": "{{userMessage}}" },
    "outputKey": "response"
  },
  {
    "order": 3,
    "type": "PROMPT",
    "promptId": "response-variant-b",
    "tags": ["variant_b"],
    "inputMapping": { "message": "{{userMessage}}" },
    "outputKey": "response"
  }
]

Tiered Pricing Logic

Multi-Tier Price Calculation
json
[
  {
    "order": 0,
    "type": "API_CALL",
    "config": {
      "url": "https://api.example.com/order/{{orderId}}",
      "method": "GET"
    },
    "outputKey": "order"
  },
  {
    "order": 1,
    "type": "CONDITION",
    "config": {
      "condition": "{{order.total}} >= 1000",
      "trueTag": "enterprise",
      "falseTag": "not_enterprise"
    }
  },
  {
    "order": 2,
    "type": "CONDITION",
    "tags": ["not_enterprise"],
    "config": {
      "condition": "{{order.total}} >= 100",
      "trueTag": "professional",
      "falseTag": "starter"
    }
  },
  {
    "order": 10,
    "type": "TRANSFORM",
    "tags": ["enterprise"],
    "config": {
      "operation": "calculate",
      "expression": "{{order.total}} * 0.80"
    },
    "outputKey": "final_price"
  },
  {
    "order": 11,
    "type": "TRANSFORM",
    "tags": ["professional"],
    "config": {
      "operation": "calculate",
      "expression": "{{order.total}} * 0.90"
    },
    "outputKey": "final_price"
  },
  {
    "order": 12,
    "type": "TRANSFORM",
    "tags": ["starter"],
    "config": {
      "operation": "calculate",
      "expression": "{{order.total}}"
    },
    "outputKey": "final_price"
  }
]

Error Handling with Fallbacks

Graceful Degradation
json
[
  {
    "order": 0,
    "type": "API_CALL",
    "config": {
      "url": "https://api.example.com/recommend",
      "method": "GET"
    },
    "outputKey": "recommendations"
  },
  {
    "order": 1,
    "type": "CONDITION",
    "config": {
      "condition": "{{recommendations}} != null",
      "trueTag": "has_recommendations",
      "falseTag": "no_recommendations"
    }
  },
  {
    "order": 2,
    "type": "PROMPT",
    "promptId": "personalized-response",
    "tags": ["has_recommendations"],
    "inputMapping": {
      "recommendations": "{{recommendations}}",
      "user": "{{user}}"
    },
    "outputKey": "response"
  },
  {
    "order": 3,
    "type": "PROMPT",
    "promptId": "generic-response",
    "tags": ["no_recommendations"],
    "inputMapping": {
      "user": "{{user}}"
    },
    "outputKey": "response"
  }
]

Performance Considerations

Minimize Conditional Depth - Deep nesting (3+ levels) can make workflows hard to debug. Consider splitting into multiple chains.
Use Early Exit Conditions - Place conditions that filter out most cases early in the workflow to skip unnecessary steps.
Skipped steps (due to tag mismatch) are not executed at all. They don't consume tokens, make API calls, or incur costs. This makes conditionals very efficient.

Debugging Conditionals

When debugging conditional workflows:

  • Check the execution response to see which steps ran vs skipped
  • Verify condition expressions evaluate correctly with test data
  • Ensure tag names match exactly (case-sensitive)
  • Use descriptive tag names that explain the condition (e.g., "high_priority" not "path1")
Execution Response Shows Step Status
json
{
  "data": {
    "executeChain": {
      "steps": [
        {
          "order": 0,
          "type": "PROMPT",
          "status": "success",
          "output": "{\"sentiment\": \"Negative\"}"
        },
        {
          "order": 1,
          "type": "CONDITION",
          "status": "success",
          "output": "negative_path"
        },
        {
          "order": 2,
          "type": "PROMPT",
          "status": "success",
          "output": "We apologize for the inconvenience..."
        },
        {
          "order": 3,
          "type": "PROMPT",
          "status": "skipped",
          "output": null
        }
      ]
    }
  }
}
The status: "skipped" indicates the step was not executed due to tag mismatch. This is normal behavior, not an error.

Best Practices

Use Descriptive Tags - Name tags clearly: "premium_user" is better than "path_a".
Document Decision Points - Add descriptions to chains explaining what each condition checks and why.
Test All Paths - Execute your workflow with test data that triggers each conditional path to ensure all branches work correctly.
Avoid Overlapping Tags - Don't use the same tag for multiple unrelated conditions. This can cause unexpected step execution.
Handle Edge Cases - Consider what happens if data is missing or null. Provide fallback paths for error scenarios.

Next Steps

Data Mapping

Learn how to pass data between conditional branches

Data Mapping →

Workflow Examples

See complete conditional workflows in action

View Examples →