FLOW MASON

Build this pipeline yourself

Open in the interactive wizard to customize and export

Open in Wizard
07

Conditional Workflow Router

Dynamic routing based on customer status, request type, and priority

advanced Business Logic

Components Used

conditional router generator json_transform logger

The Problem

Business logic is rarely linear. Customer requests need different handling based on:

  • Who they are - VIP customers get priority treatment
  • What they want - Orders, refunds, and complaints need different teams
  • How urgent it is - Critical issues need escalation
  • Combinations - VIP + complaint + urgent = immediate manager attention

Hard-coding these rules leads to unmaintainable spaghetti logic.

Pain Points We’re Solving

  • Complex branching - Multiple nested if/else statements
  • Inconsistent routing - Different agents make different decisions
  • Missed escalations - Important cases fall through cracks
  • Hard to modify - Changing rules requires code changes

Thinking Process

Let’s model the business rules as a decision tree:

flowchart TD
    Start["Customer Request"]

    Start --> VIP{"Lifetime Value<br/>≥ $1000?"}

    VIP -->|Yes| VIPPath["VIP Treatment<br/>SLA: 4 hours"]
    VIP -->|No| StandardPath["Standard Treatment<br/>SLA: 24 hours"]

    VIPPath --> TypeRoute
    StandardPath --> TypeRoute

    TypeRoute{"Request Type?"}

    TypeRoute -->|order| OrderTeam["Orders Team"]
    TypeRoute -->|refund| FinanceTeam["Finance Team<br/>+ Approval Required"]
    TypeRoute -->|inquiry| SupportTeam["Support Team"]
    TypeRoute -->|complaint| EscalationTeam["Escalation Team"]

    EscalationTeam --> PriorityCheck{"Priority?"}

    PriorityCheck -->|urgent/high| NotifyManager["Notify Manager"]
    PriorityCheck -->|medium/low| Normal["Normal Processing"]

Two-Level Decision Making

  1. Conditional - Binary yes/no decisions (VIP check)
  2. Router - Multi-way branching (request type)

Solution Architecture

flowchart TB
    subgraph Input["📥 Customer Request"]
        I1["request_type"]
        I2["priority"]
        I3["customer_data"]
        I4["message"]
    end

    subgraph VIPCheck["⭐ VIP Classification"]
        V1{"lifetime_value >= 1000?"}
        V2["VIP Path<br/>SLA: 4h"]
        V3["Standard Path<br/>SLA: 24h"]
    end

    subgraph Router["🔀 Request Router"]
        R1{"request_type"}
        R2["process-order"]
        R3["process-refund"]
        R4["process-inquiry"]
        R5["process-complaint"]
    end

    subgraph Escalation["⚠️ Escalation Check"]
        E1{"urgent OR high?"}
        E2["notify-manager"]
    end

    subgraph Response["💬 Response"]
        RE1["Generate AI response"]
        RE2["Format output"]
    end

    Input --> VIPCheck
    V1 -->|Yes| V2
    V1 -->|No| V3
    V2 --> Router
    V3 --> Router

    R1 -->|order| R2
    R1 -->|refund| R3
    R1 -->|inquiry| R4
    R1 -->|complaint| R5

    R5 --> Escalation
    E1 -->|Yes| E2

    Router --> Response
    Escalation --> Response

Pipeline Stages

Stage 1: VIP Status Check

Binary conditional based on lifetime value:

{
  "id": "check-vip",
  "component": "conditional",
  "config": {
    "condition": "{{input.customer_data.lifetime_value}} >= 1000",
    "then_stages": ["set-vip-treatment"],
    "else_stages": ["set-standard-treatment"]
  }
}

Stage 2a: VIP Treatment

{
  "id": "set-vip-treatment",
  "component": "json_transform",
  "config": {
    "data": "{{input.customer_data}}",
    "expression": "merge(@, {treatment: 'vip', dedicated_support: `true`, sla_hours: `4`})"
  }
}

Stage 2b: Standard Treatment

{
  "id": "set-standard-treatment",
  "component": "json_transform",
  "config": {
    "data": "{{input.customer_data}}",
    "expression": "merge(@, {treatment: 'standard', dedicated_support: `false`, sla_hours: `24`})"
  }
}

Stage 3: Route by Request Type

Multi-way branching with the router:

{
  "id": "route-by-type",
  "component": "router",
  "depends_on": ["check-vip"],
  "config": {
    "expression": "{{input.request_type}}",
    "routes": {
      "order": ["process-order"],
      "refund": ["process-refund"],
      "inquiry": ["process-inquiry"],
      "complaint": ["process-complaint", "escalate-check"]
    }
  }
}

Note: Complaints trigger both processing AND escalation check!

Team Processing Stages

Each team has specific handling:

flowchart LR
    subgraph OrderTeam["Orders"]
        O1["team: orders_team"]
        O2["action: track_order"]
    end

    subgraph FinanceTeam["Finance"]
        F1["team: finance_team"]
        F2["requires_approval: true"]
    end

    subgraph SupportTeam["Support"]
        S1["team: support_team"]
        S2["action: answer_inquiry"]
    end

    subgraph EscalationTeam["Escalation"]
        E1["team: escalation_team"]
        E2["high_priority: true"]
    end
{
  "id": "process-refund",
  "component": "json_transform",
  "config": {
    "data": {
      "request_type": "{{input.request_type}}",
      "customer": "{{input.customer_data}}"
    },
    "expression": "{team: 'finance_team', action: 'process_refund', requires_approval: `true`, priority_boost: customer.lifetime_value >= `5000`}"
  }
}

Stage 4: Escalation Check (Complaints Only)

Nested conditional for urgent complaints:

{
  "id": "escalate-check",
  "component": "conditional",
  "config": {
    "condition": "{{input.priority}} == 'urgent' || {{input.priority}} == 'high'",
    "then_stages": ["notify-manager"]
  }
}

Stage 5: Manager Notification

{
  "id": "notify-manager",
  "component": "logger",
  "config": {
    "level": "warn",
    "message": "ESCALATION: {{input.customer_data.name}} - {{input.request_type}}",
    "data": {
      "priority": "{{input.priority}}",
      "lifetime_value": "{{input.customer_data.lifetime_value}}",
      "requires_immediate_attention": true
    }
  }
}

Stage 6: Generate Response

{
  "id": "generate-response",
  "component": "generator",
  "depends_on": ["route-by-type"],
  "config": {
    "system_prompt": "You are a customer service agent. Write brief, empathetic acknowledgments.",
    "prompt": "Write a 2-3 sentence acknowledgment for:\nCustomer: {{input.customer_data.name}}\nRequest: {{input.request_type}}\nMessage: {{input.message}}\n\nBe empathetic and set expectations.",
    "temperature": 0.7,
    "max_tokens": 150
  }
}

Routing Decision Table

flowchart LR
    subgraph Decision["Complete Routing Logic"]
        D1["VIP Check"] --> D2["Type Router"]
        D2 --> D3["Team Assignment"]
        D3 --> D4["Escalation Check"]
        D4 --> D5["Response Generation"]
    end
Request TypeTeamSpecial Handling
orderorders_teamTrack order status
refundfinance_teamRequires approval
inquirysupport_teamStandard response
complaintescalation_teamCheck for escalation
Priority + TypeAction
urgent + complaintNotify manager immediately
high + complaintNotify manager
any + enterpriseVIP treatment, 4h SLA

Sample Input: VIP Complaint

{
  "request_type": "complaint",
  "priority": "urgent",
  "customer_data": {
    "name": "Sarah Johnson",
    "email": "[email protected]",
    "account_type": "enterprise",
    "lifetime_value": 15000
  },
  "message": "I am extremely disappointed with the service outage that affected our entire team yesterday. We lost 4 hours of productivity and this is unacceptable for an enterprise customer paying premium rates."
}

Expected Output

{
  "workflow_path": "vip → complaint → escalation",
  "customer_treatment": {
    "treatment": "vip",
    "dedicated_support": true,
    "sla_hours": 4
  },
  "assigned_team": "escalation_team",
  "escalated": true,
  "manager_notified": true,
  "auto_response": "Dear Sarah, I sincerely apologize for the service disruption your team experienced. As a valued enterprise customer, this falls far below our standards. I've escalated this to our management team and you'll receive a detailed incident report within 4 hours, along with a discussion of compensation for the productivity loss."
}

Key Learnings

1. Conditional vs Router

flowchart LR
    subgraph Conditional["conditional"]
        C1["Binary choice"]
        C2["if/else"]
        C3["Boolean condition"]
    end

    subgraph Router["router"]
        R1["Multiple choices"]
        R2["switch/case"]
        R3["Expression matching"]
    end

2. Route to Multiple Stages

The router can trigger multiple stages for one route:

"complaint": ["process-complaint", "escalate-check"]

3. Nested Control Flow

You can nest conditionals inside routes for complex logic trees.

Try It Yourself

# VIP complaint (triggers escalation)
fm run pipelines/07-conditional-workflow.pipeline.json \
  --input inputs/07-workflow-complaint.json

# Standard order (simple routing)
fm run pipelines/07-conditional-workflow.pipeline.json \
  --input inputs/07-workflow-order.json