Event Entity
The Event entity is the entry point for workflow processing. It evaluates conditions against incoming messages and determines which path the workflow should take.
Purpose
Event entities serve as gatekeepers that:
- Filter messages based on conditions
- Extract and transform data via scripts
- Route to different branches based on logic
Configuration
Available Fields
| Field | Description |
|---|---|
| Name | Display name (e.g., "Check User Signup") |
| Description | Optional documentation |
| Condition | JSON condition tree for message matching |
| Script | JavaScript code executed after condition |
| Arguments | Variables injected before script execution |
| tfCondition | Branching mode: Single Path, True/False, Multi, Iterable |
| logicField | Variable name/path for Multi/Iterable branching |
| Logic Values | Branch values for Multi mode |
Condition Builder
The condition builder creates a JSON tree structure:
{
"type": "AND",
"conditions": [
{
"field": "message.type",
"operator": "equals",
"value": "user.signup"
},
{
"type": "OR",
"conditions": [
{
"field": "message.source",
"operator": "equals",
"value": "web"
},
{
"field": "message.source",
"operator": "equals",
"value": "mobile"
}
]
}
]
}
Supported Operators:
| Operator | Description | Example |
|---|---|---|
equals | Exact match | field === value |
not_equals | Not equal | field !== value |
contains | String contains | field.includes(value) |
not_contains | String doesn't contain | !field.includes(value) |
starts_with | String starts with | field.startsWith(value) |
ends_with | String ends with | field.endsWith(value) |
greater_than | Numeric greater | field > value |
less_than | Numeric less | field < value |
is_null | Is null/undefined | field == null |
is_not_null | Is not null | field != null |
Branching Modes
Single Path (Default)
The simplest mode — condition passes or workflow exits:
Event: Check User Type
Condition: message.type === 'signup'
├── Condition PASSES → Continue to children
└── Condition FAILS → Exit workflow (message ignored)
Configuration:
{
"tfCondition": "Single Path"
}
True/False Mode
Branch based on condition result:
Event: Is Premium User?
Condition: message.user.premium === true
├── true → Premium welcome flow
└── false → Basic welcome flow
Configuration:
{
"tfCondition": "True/False"
}
Canvas Representation:
The Event node displays two output ports:
- true port → connects to premium branch
- false port → connects to basic branch
Multi Mode
Branch based on a variable's value:
Event: Route by Role
Logic Field: userRole
Script sets: var userRole = message.user.role;
├── userRole === "admin" → Admin flow
├── userRole === "user" → User flow
├── userRole === "guest" → Guest flow
└── * (wildcard) → Default/catch-all flow
Configuration:
{
"tfCondition": "Multi",
"logicField": "userRole",
"logic": [
{ "name": "Admin", "value": "admin" },
{ "name": "User", "value": "user" },
{ "name": "Guest", "value": "guest" },
{ "name": "Other", "value": "*" }
]
}
Script Requirement:
The logicField variable must be set by the script:
// Extract role from message
var userRole = message.user.role || 'guest';
// Or compute it
if (message.user.admin) {
var userRole = 'admin';
} else if (message.user.id) {
var userRole = 'user';
} else {
var userRole = 'guest';
}
Wildcard Branch (*)
Use * as a branch value to create a catch-all that matches any value not matched by other branches:
Event: Route by Event Type
Logic Field: message.event.event_type
├── "touchdown" → Touchdown handler
├── "field_goal" → Field goal handler
├── "interception"→ Turnover handler
└── "*" → Default handler (catches all other event types)
How it works:
- Exact matches are evaluated first
- If no exact match, the
*wildcard branch is used - If no wildcard and no match, workflow exits
Use the wildcard branch to ensure your workflow always has a path forward, even for unexpected values. This is especially useful for logging or error handling of unknown cases.
Iterable Mode
Process each item in an array separately. The workflow executes once for each element in the specified array field.
Event: Process Each Recipient
Logic Field: message.recipients
If message.recipients = [user1, user2, user3]:
→ Execute children for user1 (___iterableItem___ = user1)
→ Execute children for user2 (___iterableItem___ = user2)
→ Execute children for user3 (___iterableItem___ = user3)
Configuration:
{
"tfCondition": "Iterable",
"logicField": "message.recipients"
}
Use Cases:
- Batch notifications (send to multiple recipients)
- Processing order items (multiple products)
- Multi-target publishing (post to multiple accounts)
- Parallel-style iteration over data arrays
Accessing Current Item:
In downstream scripts (Prompts, Actions), access the current iteration item:
// The current item being processed
const currentItem = ___iterableItem___;
// Example: if iterating over recipients array
const recipientEmail = currentItem.email;
const recipientName = currentItem.name;
print('Processing:', recipientName, recipientEmail);
Example Input:
{
"type": "notification",
"content": "Your order has shipped",
"recipients": [
{ "name": "Alice", "email": "alice@example.com" },
{ "name": "Bob", "email": "bob@example.com" }
]
}
With logicField: "message.recipients", the workflow executes twice - once for Alice, once for Bob.
If the logicField points to a non-array value, the workflow executes normally (single execution) with ___iterableItem___ set to that value.
Script Execution
Event scripts run after condition evaluation:
// Condition has already been evaluated
// ___result___ contains the condition result (true/false)
print('Condition result:', ___result___);
// Access the incoming message
const eventType = message.type;
const userId = message.user.id;
// Use environment variables
const debugMode = DEBUG_MODE;
// Transform data for downstream entities
var processedData = {
userId: userId,
timestamp: new Date().toISOString(),
source: message.source
};
// For Multi mode, set the logic field
var userRole = message.user.role;
Available in Script Context
| Variable | Description |
|---|---|
message | The incoming message payload |
___result___ | Condition evaluation result (boolean) |
__variables__ | Array of environment variables |
__variablesByName__ | Map of variable name → value |
{VARIABLE_NAME} | Each variable as top-level var |
| Arguments | Each argument as top-level var |
Execution Flow
The EventEvaluator processes Event entities:
┌─────────────────────────────────────────────────────────────┐
│ EventEvaluator.evaluate() │
├─────────────────────────────────────────────────────────────┤
│ 1. Inject message into V8 context │
│ 2. Evaluate condition tree using evaluateCondition() │
│ 3. Set ___result___ = condition result │
│ 4. Inject arguments (if any) │
│ 5. Run script (if any) │
│ 6. Determine branching: │
│ - Single Path: exit if false, continue if true │
│ - True/False: select branch by ___result___ │
│ - Multi: evaluate logicField, match to branch value │
│ 7. Return { action, children } │
└─────────────────────────────────────────────────────────────┘
Examples
Example 1: Simple Event Filter
Filter for signup events only:
{
"name": "Signup Events Only",
"condition": {
"field": "message.type",
"operator": "equals",
"value": "user.signup"
},
"tfCondition": "Single Path"
}
Example 2: Premium vs Basic Routing
Route based on subscription status:
{
"name": "Check Premium Status",
"condition": {
"field": "message.user.subscription",
"operator": "equals",
"value": "premium"
},
"tfCondition": "True/False"
}
Example 3: Multi-Region Routing
Route based on user region:
{
"name": "Route by Region",
"condition": {
"field": "message.type",
"operator": "equals",
"value": "order.created"
},
"script": "var region = message.shipping.country === 'US' ? 'us' : message.shipping.country === 'CA' ? 'ca' : 'intl';",
"tfCondition": "Multi",
"logicField": "region",
"logic": [
{ "name": "US Shipping", "value": "us" },
{ "name": "Canada Shipping", "value": "ca" },
{ "name": "International", "value": "intl" }
]
}
Example 4: Complex Condition with Script
Validate and transform before processing:
{
"name": "Validate Order",
"condition": {
"type": "AND",
"conditions": [
{ "field": "message.type", "operator": "equals", "value": "order" },
{ "field": "message.total", "operator": "greater_than", "value": 0 }
]
},
"script": "var orderData = { id: message.orderId, total: message.total, currency: message.currency || 'USD', validated: true };",
"tfCondition": "Single Path",
"arguments": [
{
"argumentName": "minOrderValue",
"argumentValue": "10",
"argumentDescription": "Minimum order value to process"
}
]
}
Example 5: Iterable Array Processing
Process each recipient in a notification:
{
"name": "Notify Each Recipient",
"condition": {
"type": "group",
"operator": "AND",
"conditions": [
{ "type": "rule", "field": "message.type", "comparison": "equals", "value": "notification.broadcast" }
]
},
"tfCondition": "Iterable",
"logicField": "message.recipients"
}
With this message input:
{
"type": "notification.broadcast",
"content": "Server maintenance at 3 AM",
"recipients": [
{ "name": "Alice", "email": "alice@example.com", "sms": "+1234567890" },
{ "name": "Bob", "email": "bob@example.com", "sms": "+0987654321" }
]
}
The workflow executes twice. In downstream Actions/Prompts:
// Access current recipient
const recipient = ___iterableItem___;
print('Sending to:', recipient.name, recipient.email);
Example 6: Multi-Branch with Wildcard Catch-All
Route sports events with a default handler:
{
"name": "Sports Event Router",
"condition": {
"type": "group",
"operator": "AND",
"conditions": [
{ "type": "rule", "field": "message.payload.metadata.league", "comparison": "equals", "value": "nfl" }
]
},
"tfCondition": "Multi",
"logicField": "playType",
"script": "var playType = message.payload.event?.play_type || 'unknown';",
"logic": [
{ "name": "Touchdown", "value": "touchdown" },
{ "name": "Field Goal", "value": "field_goal" },
{ "name": "Interception", "value": "interception" },
{ "name": "Other Plays", "value": "*" }
]
}
Best Practices
Condition Design
- Start simple — Add complexity only when needed
- Use AND for required conditions — All must pass
- Use OR for alternatives — Any can pass
- Test with sample messages — Verify logic before deployment
Script Guidelines
- Set variables early — Declare logic field variables at top
- Handle missing data — Use defaults for optional fields
- Log for debugging — Use
print()during development - Keep scripts focused — Transform data, don't add business logic
Branching Strategy
- Single Path — Use for simple filters
- True/False — Use for binary decisions
- Multi — Use for 3+ distinct paths (switch-like routing)
- Iterable — Use for array processing (loop over items)
Related Topics
- Workflow Canvas — Visual editor for Event nodes
- evaluateCondition — Condition evaluation function
- Consumer Evaluator — EventEvaluator implementation