Skip to main content

Entity Evaluators

All workflow entity types (Event, Prompt, Action, and others) are evaluated by a single UnifiedEntityEvaluator, built on BaseEntityEvaluator. Type-specific configuration (conditions, prompts, branching modes) still varies by entity type, but the execution pipeline is the same for every node.

Base Class

UnifiedEntityEvaluator extends BaseEntityEvaluator (rocketwave-stream-shared/src/execution/evaluators/BaseEntityEvaluator.ts), which owns injection helpers, condition helpers, prompt/model injection, handlebar processing, script execution, and context capture.

Shared Methods

MethodDescription
injectMessage(context, message)Inject incoming message fields as top-level globals in the V8 isolate
injectArguments(context, entity, executionContext)Inject entity arguments
injectPromptAndModel(context, entity, executionContext)Inject prompt/model data
processPromptHandlebars(context, entity, executionContext)Substitute {{...}} placeholders in prompt
runScript(...)Execute a preScript or postScript body inside an async wrapper
getResultVariable(context)Read ___result___ value
setResultVariable(context, value)Set ___result___ value
evaluateVariable(context, variableName)Read any variable value
captureContextVariables(context, executionContext)Capture all context vars

Argument Injection

Arguments support two modes:

Literal Values:

argumentValue: "Hello World"
// Becomes: var argName = "Hello World";

Handlebar References:

argumentValue: "{{user.id}}"
// Becomes: var argName = user.id;

UnifiedEntityEvaluator

File location

rocketwave-stream-shared/src/execution/evaluators/UnifiedEntityEvaluator.ts (Consumer workers use this shared implementation).

Unified pipeline (all entity types)

Every node runs the same ordered steps:

  1. Pre-Script — If entity.preScript is non-empty, run it in the isolate (failure → exit workflow with error).
  2. Inject arguments — Skipped when there are none; iterable parents may also inject item / index.
  3. Evaluate condition — If entity.condition is missing, result is true; otherwise evaluateCondition(tree, message) runs and ___result___ is set.
  4. Prompt + model — If a prompt and/or model is configured: inject prompt/model, handlebars, optional image resolution, then executePromptWithModel() when a model is present (failures can exit the workflow).
  5. Post-Script — If entity.postScript is non-empty, run it (failure → exit workflow with error).
  6. Capture context — Persist eligible globals into executionContext for downstream nodes.
  7. BranchingdetermineBranch(...) implements Single Path, True/False, Multi (including * wildcard), and Iterable modes using the condition result and tfCondition / logicField / logic configuration.
info

Older deployments used separate EventEvaluator, PromptEvaluator, and ActionEvaluator classes. Those have been replaced by this single evaluator; field names on entities are now preScript and postScript instead of one script field.

Branching modes (after the unified steps)

ModeConfigurationBehavior
Single PathtfCondition: "Single Path"Continue if condition true, exit if false
True/FalsetfCondition: "True/False"Match child by value: "true" / "false"
MultitfCondition: "Multi", logicFieldRead branch variable from context; match child value, else * wildcard
IterabletfCondition: "Iterable", logicFieldFan out children per array element

Multi / wildcard: Same as before — explicit branch values match first; a child with value: "*" is the catch-all.

Triggers

Messages produced by workflow triggers are not auto-passed through the root node. They go through the same pipeline as any other message (pre-script → … → branching).


Return Actions

UnifiedEntityEvaluator returns an action object:

ActionMeaningTypical case
exit_workflowStop this workflow path (condition failed, branch miss, or error)After condition or branching, or script/model failure
process_childrenContinue to selected child nodesCondition passed and branch resolved
workflow_completeWorkflow finished, stop processingOrchestrator (automatic)

Action Object Structure

interface EvaluatorResult {
action: 'exit_workflow' | 'process_children' | 'workflow_complete';
children?: WorkflowNode[]; // For process_children
}

Script Execution Details

Wrapping for Async

Pre and post snippets are wrapped the same way (pseudocode):

async runScript(context, entity, scriptBody, phase /* 'preScript' | 'postScript' */) {
const wrappedScript = `(async () => { ${scriptBody} })()`;

await context.eval(wrappedScript, {
timeout: this.scriptTimeout,
promise: true
});
}

Timeout Handling

await context.eval(wrappedScript, { 
timeout: this.scriptTimeout // Default 5000ms
});

// On timeout:
// Error: Script execution timed out

Error Recovery

Failures in preScript / postScript (or timeouts) are logged; the unified evaluator returns exit_workflow with error details instead of continuing when a script phase fails.


Context Variable Capture

After postScript (and prompt/model work), eligible globals are captured:

async captureContextVariables(context, executionContext) {
const varsJson = await context.eval(`JSON.stringify(
Object.keys(global).reduce((acc, key) => {
if (!key.startsWith('__') && typeof global[key] !== 'function') {
try {
acc[key] = global[key];
} catch (e) {}
}
return acc;
}, {})
)`);

const vars = JSON.parse(varsJson);
Object.assign(executionContext, vars);
}

This makes variables set by one entity available to downstream entities.