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
Section titled “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
Section titled “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
Section titled “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
Section titled “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
Section titled “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
Section titled “Setting Variables”Via Node Output
Section titled “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
Section titled “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
Section titled “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
Section titled “Condition Syntax”Logic nodes (if_else type) use a simple condition syntax. The condition string is first interpolated (variables replaced), then evaluated.
Comparison Operators
Section titled “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
Section titled “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
Section titled “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
Section titled “Variable Scope”All variables share a single flat scope within a workflow execution. There is no block scoping or node-level isolation.
Variable Lifetime
Section titled “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
Section titled “Examples”Condition with Variable Interpolation
Section titled “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
Section titled “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
Section titled “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.