Skip to main content

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:

  1. Filter messages based on conditions
  2. Extract and transform data via scripts
  3. Route to different branches based on logic

Configuration

Available Fields

FieldDescription
NameDisplay name (e.g., "Check User Signup")
DescriptionOptional documentation
ConditionJSON condition tree for message matching
ScriptJavaScript code executed after condition
ArgumentsVariables injected before script execution
tfConditionBranching mode: Single Path, True/False, Multi, Iterable
logicFieldVariable name/path for Multi/Iterable branching
Logic ValuesBranch 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:

OperatorDescriptionExample
equalsExact matchfield === value
not_equalsNot equalfield !== value
containsString containsfield.includes(value)
not_containsString doesn't contain!field.includes(value)
starts_withString starts withfield.startsWith(value)
ends_withString ends withfield.endsWith(value)
greater_thanNumeric greaterfield > value
less_thanNumeric lessfield < value
is_nullIs null/undefinedfield == null
is_not_nullIs not nullfield != 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:

  1. Exact matches are evaluated first
  2. If no exact match, the * wildcard branch is used
  3. If no wildcard and no match, workflow exits
tip

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.

info

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

VariableDescription
messageThe 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
ArgumentsEach 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

  1. Start simple — Add complexity only when needed
  2. Use AND for required conditions — All must pass
  3. Use OR for alternatives — Any can pass
  4. Test with sample messages — Verify logic before deployment

Script Guidelines

  1. Set variables early — Declare logic field variables at top
  2. Handle missing data — Use defaults for optional fields
  3. Log for debugging — Use print() during development
  4. Keep scripts focused — Transform data, don't add business logic

Branching Strategy

  1. Single Path — Use for simple filters
  2. True/False — Use for binary decisions
  3. Multi — Use for 3+ distinct paths (switch-like routing)
  4. Iterable — Use for array processing (loop over items)