Understanding workflow structure, nodes, edges, and execution semantics
Workflows in AutoMFlows are represented as directed acyclic graphs (DAGs) where nodes represent operations and edges define execution flow and data dependencies.
Most interaction nodes share these common properties:
Wait Conditions
waitForSelector?: string; // Wait for element to appearwaitForSelectorType?: SelectorType;waitForSelectorModifiers?: SelectorModifiers;waitForSelectorTimeout?: number;waitForUrl?: string; // Wait for URL pattern (supports regex)waitForUrlTimeout?: number;waitForCondition?: string; // JavaScript expression to evaluatewaitForConditionTimeout?: number;waitStrategy?: 'sequential' | 'parallel'; // Execute waits sequentially or in parallelwaitAfterOperation?: boolean; // Wait before (false) or after (true) operation
Retry Configuration
retryEnabled?: boolean;retryStrategy?: 'count' | 'untilCondition';retryCount?: number | string; // Number of retries or variable reference// Retry until condition is metretryUntilCondition?: { type: 'selector' | 'url' | 'javascript'; value: string; selectorType?: SelectorType; visibility?: 'visible' | 'invisible'; timeout?: number | string;};retryDelay?: number | string; // Delay between retries (ms)retryDelayStrategy?: 'fixed' | 'exponential'; // Fixed delay or exponential backoffretryMaxDelay?: number | string; // Maximum delay for exponential strategy
Property Input Connections
_inputConnections?: { [propertyName: string]: { // e.g., "text", "url", "selector" sourceNodeId: string; // Node providing the value sourceHandleId: string; // Output handle from source node };};
Property input connections allow nodes to receive values dynamically from other nodes’ outputs, enabling data flow and reusable components.
Property input edges provide dynamic values to node properties. They create one-way data dependencies without affecting control flow.
// Example: Connect Int Value node output to Type node's text property{ "id": "e2", "source": "intValue-1", // Int Value node "target": "type-1", // Type node "sourceHandle": "output", "targetHandle": "text-input" // Property-specific handle}
Node properties support dynamic values using ${...} syntax:
Data Access
Variables
Complex Expressions
// Access context data"${data.username}" // From context.data.username"${data.config.apiKey}" // Nested property"${data.apiResponse.body.id}" // API response data
// backend/src/engine/parser.ts:10export interface ExecutionNode { node: BaseNode; dependencies: string[]; // Nodes that must execute first dependents: string[]; // Nodes that depend on this one}
The parser builds this graph during workflow loading:
// backend/src/engine/parser.ts:39private buildDependencyGraph(): void { for (const edge of this.edges) { const isPropertyInput = edge.targetHandle && edge.targetHandle !== 'driver' && edge.targetHandle !== 'input'; if (isPropertyInput) { // One-way dependency: target depends on source targetNode.dependencies.push(edge.source); } else { // Control flow: bidirectional relationship targetNode.dependencies.push(edge.source); sourceNode.dependents.push(edge.target); } }}