# Variables & Conditions

> Variable interpolation syntax and condition operators for Aerostack bot workflows.

Workflow nodes communicate through a shared **variables context**. Nodes can read variables using `{{variableName}}` interpolation and write variables via their `outputVariable` field.

---

## Variable Interpolation

Use double curly braces to insert variable values into prompts, messages, tool arguments, and conditions:

```
Hello, {{user_name}}! Your order {{order_id}} is {{order_status}}.
```

### Dot Notation

Access nested properties using dot notation:

```
Your order total is ${{order_data.total}}
Shipped via {{order_data.shipping.carrier}}
```

The interpolation engine walks the object path:

```javascript
// If order_data = { total: 42.50, shipping: { carrier: "FedEx" } }
"{{order_data.total}}"            // → "42.50"
"{{order_data.shipping.carrier}}" // → "FedEx"
```

### Object Serialization

If a variable points to an object or array, it is serialized as JSON:

```
Order details: {{order_data}}
// → Order details: {"id":"12345","status":"shipped","total":42.50}
```

### Unresolved Variables

If a variable path does not resolve (the variable does not exist or a nested property is missing), the placeholder is left as-is:

```
Hello, {{unknown_var}}!
// → Hello, {{unknown_var}}!
```

---

## Built-In Variables

These variables are automatically set by the `trigger` node when a message arrives:

| Variable | Type | Description |
|----------|------|-------------|
| `message` | string | The user's message text |
| `user_id` | string | Platform-specific user identifier |
| `user_name` | string | User's display name (empty string if unavailable) |
| `channel_id` | string | Platform-specific channel/chat identifier |
| `platform` | string | `telegram`, `discord`, `whatsapp`, `slack`, or `custom` |

---

## Setting Variables

### Via Node Output

Most node types support an `outputVariable` field. The node's result is stored in this variable:

```json
{
  "type": "llm_call",
  "data": {
    "prompt": "Classify: {{message}}",
    "outputVariable": "classification"
  }
}
```

After execution, `classification` contains:
```json
{
  "text": "billing",
  "tokensInput": 45,
  "tokensOutput": 3
}
```

### Via the set_variable Action

Use the `action` node with `actionType: "set_variable"`:

```json
{
  "type": "action",
  "data": {
    "actionType": "set_variable",
    "variable": "greeting",
    "value": "Welcome back, {{user_name}}!"
  }
}
```

### Via Code Blocks

Code blocks can directly modify the variables context:

```json
{
  "type": "code_block",
  "data": {
    "code": "ctx.variables.full_name = ctx.variables.first_name + ' ' + ctx.variables.last_name;"
  }
}
```

---

## Condition Syntax

Logic nodes (`if_else` type) use a simple condition syntax. The condition string is first interpolated (variables replaced), then evaluated.

### Comparison Operators

| Operator | Description | Example |
|----------|-------------|---------|
| `==` | Equals | `{{intent}} == billing` |
| `!=` | Not equals | `{{status}} != closed` |
| `>` | Greater than (numeric) | `{{total}} > 100` |
| `<` | Less than (numeric) | `{{count}} < 5` |
| `>=` | Greater than or equal (numeric) | `{{score}} >= 0.8` |
| `<=` | Less than or equal (numeric) | `{{score}} <= 0.2` |
| `contains` | String contains | `{{message}} contains refund` |
| `startsWith` | String starts with | `{{message}} startsWith /help` |
| `endsWith` | String ends with | `{{email}} endsWith @acme.com` |

### Syntax Rules

- Operators must be surrounded by spaces: `{{x}} == y` (not `{{x}}==y`)
- Values on both sides are treated as strings unless using numeric operators (`>`, `<`, `>=`, `<=`)
- Quotes around values are optional and stripped: `{{x}} == "billing"` is the same as `{{x}} == billing`
- For numeric comparisons, values are parsed with `parseFloat()`

### Truthiness Fallback

If no operator is found, the condition falls back to a **truthiness check**:

| Value | Truthy? |
|-------|---------|
| Non-empty string | Yes |
| `"false"` | No |
| `"0"` | No |
| `"null"` | No |
| `"undefined"` | No |
| Empty string `""` | No |

Example:

```json
{
  "type": "logic",
  "data": {
    "logicType": "if_else",
    "condition": "{{has_account}}"
  }
}
```

This follows the `true` edge if `has_account` is set to any truthy value.

---

## Variable Scope

All variables share a single flat scope within a workflow execution. There is no block scoping or node-level isolation.

Be careful with variable names. If two nodes use the same `outputVariable`, the second one overwrites the first. Use descriptive, unique variable names like `order_lookup_result` instead of generic names like `result`.

### Variable Lifetime

Variables persist for the duration of a single workflow execution (one incoming message). They are not preserved across messages. Each new message starts a fresh execution with only the built-in variables.

---

## Examples

### Condition with Variable Interpolation

```json
{
  "type": "logic",
  "data": {
    "logicType": "if_else",
    "condition": "{{order_data.total}} > 500"
  }
}
```

If `order_data = { total: 750 }`, the condition resolves to `750 > 500`, which evaluates to `true`.

### String Matching

```json
{
  "type": "logic",
  "data": {
    "logicType": "if_else",
    "condition": "{{message}} contains cancel"
  }
}
```

If the user sends "I want to cancel my order", the condition resolves to `I want to cancel my order contains cancel`, which evaluates to `true`.

### Switch with Dynamic Variable

```json
{
  "type": "logic",
  "data": {
    "logicType": "switch",
    "variable": "platform",
    "cases": ["telegram", "discord", "slack"]
  }
}
```

This branches to `case_telegram`, `case_discord`, `case_slack`, or `case_default` based on which platform the message came from.
