Skip to content

AI decision routing

One SWITCH asks a fixed choice question and routes to the selected branch. The choices live in the definition, so the model can only pick a branch you declared.

The shape

route_request (SWITCH, evaluatorType: decision)  ──>  billing   ──> selected_result (INLINE)
                                                  └──>  technical ──┘

Prerequisites

conductor.integrations.ai.enabled=true and DECISION_API_KEY set on the server.

Runnable definition

Save this as ai-decision-routing.json:

{
  "name": "ai_decision_routing",
  "version": 1,
  "schemaVersion": 2,
  "enforceSchema": false,
  "failureWorkflow": "",
  "timeoutSeconds": 60,
  "timeoutPolicy": "ALERT_ONLY",
  "tasks": [
    {
      "name": "route_request",
      "taskReferenceName": "route_request",
      "type": "SWITCH",
      "evaluatorType": "decision",
      "expression": "route",
      "inputParameters": {
        "model": "jev-1.13",
        "state": "${workflow.input.request}",
        "questions": {
          "route": {
            "type": "choice",
            "instructions": "Choose the team best suited to handle this request.",
            "choices": {
              "billing": "Payments, invoices, refunds, or subscriptions.",
              "technical": "Errors, outages, or product troubleshooting."
            }
          }
        }
      },
      "decisionCases": {
        "billing": [
          {
            "name": "handle_billing",
            "taskReferenceName": "handle_billing",
            "type": "INLINE",
            "inputParameters": {
              "evaluatorType": "graaljs",
              "expression": "({team: \"billing\", nextAction: \"review_invoice\", message: \"Check invoice line items and payment records.\", request: $.request})",
              "request": "${workflow.input.request}"
            }
          }
        ],
        "technical": [
          {
            "name": "handle_technical",
            "taskReferenceName": "handle_technical",
            "type": "INLINE",
            "inputParameters": {
              "evaluatorType": "graaljs",
              "expression": "({team: \"technical\", nextAction: \"collect_diagnostics\", message: \"Collect error logs and steps to reproduce.\", request: $.request})",
              "request": "${workflow.input.request}"
            }
          }
        ]
      },
      "defaultCase": []
    },
    {
      "name": "selected_result",
      "taskReferenceName": "selected_result",
      "type": "INLINE",
      "inputParameters": {
        "evaluatorType": "graaljs",
        "expression": "$.billing || $.technical",
        "billing": "${handle_billing.output.result}",
        "technical": "${handle_technical.output.result}"
      }
    }
  ],
  "outputParameters": {
    "selectedCase": "${route_request.output.selectedCase}",
    "answers": "${route_request.output.answers}",
    "usage": "${route_request.output.usage}",
    "cost": "${route_request.output.usage.cost}",
    "latencyMs": "${route_request.output.latencyMs}",
    "result": "${selected_result.output.result}"
  }
}

Register and run

CONDUCTOR_API="${CONDUCTOR_SERVER_URL:-http://localhost:8080/api}"
curl --fail-with-body -X POST "$CONDUCTOR_API/metadata/workflow?overwrite=true" \
  -H 'Content-Type: application/json' --data-binary @ai-decision-routing.json
curl --fail-with-body -X POST "$CONDUCTOR_API/workflow/ai_decision_routing?version=1" \
  -H 'Content-Type: application/json' \
  -d '{"request":"I was charged twice on my latest invoice."}'

Open Executions in your Conductor UI and select the new execution. route_request.output.selectedCase and the workflow's selectedCase output are billing, only handle_billing ran, and result.nextAction is review_invoice. The workflow also exposes answers, usage, cost, and latencyMs from the decision.