Variables & Conditions
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:
// 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:
{
"type": "llm_call",
"data": {
"prompt": "Classify: {{message}}",
"outputVariable": "classification"
}
}After execution, classification contains:
{
"text": "billing",
"tokensInput": 45,
"tokensOutput": 3
}Via the set_variable Action
Use the action node with actionType: "set_variable":
{
"type": "action",
"data": {
"actionType": "set_variable",
"variable": "greeting",
"value": "Welcome back, {{user_name}}!"
}
}Via Code Blocks
Code blocks can directly modify the variables context:
{
"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:
{
"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
{
"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
{
"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
{
"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.