> ## Documentation Index
> Fetch the complete documentation index at: https://developer.watson-orchestrate.ibm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Decisions node

A decisions node manages and executes a decision table composed of a set of rules. The system evaluates each rule in order from top to bottom and returns the result of the first successful rule as the final result.

## Rule

Each rule includes two parts:

* **conditions**: A set of conditions to evaluate.
* **actions**: The results to return when **all** conditions are satisfied.

### Condition

Each condition includes a variable reference and a value expression. To simplify condition building and ensure correct syntax, use the `DecisionsCondition` class.

<Note>
  **Variable Naming Convention:**
  Conditions can reference all upstream variables using fully qualified path formats:

  * **Agentic workflow inputs**: `flow.input.<variable_name>`. For example, to check the `grade` input variable, use `flow.input.grade`.
  * **Agentic workflow private variables**: `flow.private.<variable_name>`
  * **Upstream node outputs**: use the variable path emitted by the upstream node
</Note>

<Expandable title="supported types">
  * `number`: Integer or floating-point values.
  * `string`: Text values.
  * `boolean`: `true` or `false` values.
  * `date`: Locale-sensitive date strings. Supported formats include:
    * `3/14/2020`
    * `March 25, 2025`
    * `2020-10-20`
    * For the full list, see [any-date-parser](https://www.npmjs.com/package/any-date-parser)
      <Note>
        **Note:**
        The default format is 'YYYY-MM-DD', for example, '2025-07-31'.
      </Note>
  * `time`: Time-of-day values, for example, `14:30:00`.
  * `datetime`: Combined date and time values, for example, `2025-07-31T14:30:00`.
</Expandable>

<Expandable title="supported expressions">
  * **Range** (number and date): Set a range specifying the expression "min:max" enclosed by `( )` or `[ ]` or combination of `( [ ) ]`.
    * `(` and `)`: for exclusive range.
    * `[` and `]`: for inclusive range.
  * **Operators**: The following operators are supported.
    * `==`: equal (number, date and string), such as `== 5`
    * `!=`: not equal (number, date and string)
    * `>`: greater than (number, date)
    * `>=`: equal or greater than (number, date)
    * `<`: less than (number, date)
    * `<=`: equal or less than (number, date)
    * `contains` (string): checks if the key includes the value
    * `doesNotContain` (string): checks if the key excludes the value
    * `startsWith` (string): checks if the key starts with the value
    * `endsWith` (string): checks if the key ends with the value
</Expandable>

The following example checks whether the value of `revenue_quote_ratio` falls within the range from 0 (inclusive) to 50 (exclusive).

```py Python theme={null}
rule.condition("flow.input.revenue_quote_ratio", DecisionsCondition().in_range(0, 50, True, False))
```

### Action

An action defines the result when all conditions in a rule are satisfied. Actions can reference agentic workflow output variables using the fully qualified path format `flow.output.<variable_name>`, or any other agentic workflow variable, such as `flow.private.<variable_name>`. You can also define a default action to return when no rules match.

<Expandable title="supported action types">
  * `number`: Integer or floating-point values
  * `string`: Text values
  * `boolean`: True or False values
  * `date`: Date values, automatically formatted as "Month Day, Year"
</Expandable>

## Decision Table Columns

Decision table columns define the mapping between technical variable names and user-friendly display names in the agentic workflow Builder UI. Use the `DecisionTableColumn` class to specify columns for both conditions and actions.

```py Python theme={null}
from ibm_watsonx_orchestrate.flow_builder.types import DecisionTableColumn

decision_table_columns=[
    DecisionTableColumn(variable="flow.input.grade", display_name="Credit Grade"),
    DecisionTableColumn(variable="flow.input.loan_amount", display_name="Loan Amount"),
    DecisionTableColumn(variable="flow.output.insurance_required", display_name="Insurance Required"),
    DecisionTableColumn(variable="flow.output.insurance_rate", display_name="Insurance Rate"),
]
```

## Locale

You can specify a locale string, such as en-US, fr-FR, or es-MX, to control how dates are parsed. Currently, locale only affects date parsing.

## Example

In this example `get_insurance_rate`, you define a set of rules to calculate the insurance rate based on credit grade and loan amount:

```py Python [expandable] theme={null}
'''
Build a simple agentic workflow that will programmatically create a decisions table.
'''

from typing import Literal
from pydantic import BaseModel

from ibm_watsonx_orchestrate.flow_builder.flows import END, Flow, flow, START, DecisionsNode, DecisionsRule, DecisionsCondition
from ibm_watsonx_orchestrate.flow_builder.types import DecisionTableColumn


class Assessment(BaseModel):
    """
    This class represents the outcome of the assessment.
    """
    insurance_required: bool = False
    insurance_rate: float = 0.0
    assessment_error: str | None = None

class AssessmentData(BaseModel):
    """
    This class represents the data to be assessed.
    """
    loan_amount: float
    grade: Literal['A', 'B']

def build_decisions(aflow: Flow) -> DecisionsNode:
    """
    Build a Decisions Table programmatically as a node.

    For example, read from an Excel spreadsheet or CSV and populate the decision table.
    """

    rules = []

    ## We will be build the rules programmatically.
    rule1 = DecisionsRule()
    rule1.condition("flow.input.grade", DecisionsCondition().equal("A")).condition("flow.input.loan_amount", DecisionsCondition().less_than(100000))
    rule1.action("flow.output.insurance_required", False)
    rules.append(rule1)

    rule2 = DecisionsRule()
    rule2.condition("flow.input.grade", DecisionsCondition().equal("A")).condition("flow.input.loan_amount", DecisionsCondition().in_range(100000, 300000, True, False))
    rule2.action("flow.output.insurance_required", True).action("flow.output.insurance_rate", 0.001)
    rules.append(rule2)

    rule3 = DecisionsRule()
    rule3.condition("flow.input.grade", DecisionsCondition().equal("A")).condition("flow.input.loan_amount", DecisionsCondition().in_range(300000, 600000, True, False))
    rule3.action("flow.output.insurance_required", True).action("flow.output.insurance_rate", 0.003)
    rules.append(rule3)

    rule4 = DecisionsRule()
    rule4.condition("flow.input.grade", DecisionsCondition().equal("A")).condition("flow.input.loan_amount", DecisionsCondition().greater_than_or_equal(600000))
    rule4.action("flow.output.insurance_required", True).action("flow.output.insurance_rate", 0.005)
    rules.append(rule4)

    ## We will be build the rules programmatically.
    rule5 = DecisionsRule()
    rule5.condition("flow.input.grade", DecisionsCondition().equal("B")).condition("flow.input.loan_amount", DecisionsCondition().less_than(100000))
    rule5.action("flow.output.insurance_required", False)
    rules.append(rule5)

    rule6 = DecisionsRule()
    rule6.condition("flow.input.grade", DecisionsCondition().equal("B")).condition("flow.input.loan_amount", DecisionsCondition().in_range(100000, 300000, True, False))
    rule6.action("flow.output.insurance_required", True).action("flow.output.insurance_rate", 0.0025)
    rules.append(rule6)

    rule7 = DecisionsRule()
    rule7.condition("flow.input.grade", DecisionsCondition().equal("B")).condition("flow.input.loan_amount", DecisionsCondition().in_range(300000, 600000, True, False))
    rule7.action("flow.output.insurance_required", True).action("flow.output.insurance_rate", 0.005)
    rules.append(rule7)

    rule8 = DecisionsRule()
    rule8.condition("flow.input.grade", DecisionsCondition().equal("B")).condition("flow.input.loan_amount", DecisionsCondition().greater_than_or_equal(600000))
    rule8.action("flow.output.insurance_required", True).action("flow.output.insurance_rate", 0.0075)
    rules.append(rule8)

    node = aflow.decisions(
        name="assess_insurance_rate",
        display_name="Assess insurance rate.",
        description="Based on credit rate and loan amount, assess insurance rate.",
        rules=rules,
        default_actions={
            "flow.output.assessment_error": "Not assessed. Incorrect data submitted."
        },
        decision_table_columns=[
            DecisionTableColumn(variable="flow.input.grade", display_name="Grade"),
            DecisionTableColumn(variable="flow.input.loan_amount", display_name="Loan Amount"),
            DecisionTableColumn(variable="flow.output.insurance_required", display_name="Insurance Required"),
            DecisionTableColumn(variable="flow.output.insurance_rate", display_name="Insurance Rate"),
            DecisionTableColumn(variable="flow.output.assessment_error", display_name="Assessment Error"),
        ]
    )
    return node


@flow(
    name="get_insurance_rate",
    input_schema=AssessmentData,
    output_schema=Assessment
    )
def build_get_insurance_rate(aflow: Flow = None) -> Flow:
    """
    Creates an agentic workflow to calculate the insurance rate based on provided information.
    """
    decisions_node = build_decisions(aflow)

    aflow.sequence(START, decisions_node, END)

    return aflow
```

<Note>
  **Note:**

  * The `decision_table_columns` parameter is required for proper UI integration in agentic workflow Builder.
</Note>
