Skip to content

Internal Parameters

This document describes the internal parameter system used in FlowDrop for system-level state management and orchestration.

Overview

Internal parameters are special parameters used for internal state management within the FlowDrop runtime. They follow a naming convention and receive special treatment by the ParameterResolver.

Quick Reference

Parameter Type Description Used By
__iterator__ object Iterator state for loops ForEachNode, IteratorNextNode, IteratorCollectNode, LoopControlNode
__current_item__ mixed Current item in iteration Nodes needing loop item
__state__ object Complete graph state ApprovalGateNode
__messages__ array Message history Nodes needing chat history
__data__ object Workflow data store StateStorageNode
__node_id__ string Current node instance ID ChatOutput
__execution_id__ string Current execution ID ChatOutput

Naming Convention

Internal parameters are identified by their name prefix:

  • Prefix: __ (double underscore)
  • Examples: __iterator__, __context__, __state__

This convention follows the common practice in many programming languages where double underscores indicate internal/private/magic variables.

Special Handling

Internal parameters receive special treatment in the ParameterResolver:

  1. Bypass Connectable Check: Internal parameters always accept runtime inputs, regardless of whether connectable: TRUE is set in the node type configuration.

  2. Bypass Configurable Check: Internal parameters cannot be configured by users. Even if configurable: TRUE is set, workflow values from users are ignored for internal parameters. This prevents users from tampering with system state.

  3. Automatic Injection: The orchestrator can inject internal parameters into nodes without requiring UI configuration.

  4. Not User-Facing: Internal parameters should not be exposed to end users in the workflow editor UI (i.e., "Show Port" and "Config" should typically be unchecked).

Resolution Priority

For internal parameters: 1. Runtime input (always accepted) 2. Entity default 3. Schema default

Note: Workflow values (user configuration) are never used for internal parameters.

For regular parameters: 1. Runtime input (only if connectable: TRUE) 2. Workflow value (if configurable: TRUE) 3. Entity default 4. Schema default

Currently Defined Internal Parameters

__iterator__

Used by: ForEachNode, IteratorNextNode, IteratorCollectNode, LoopControlNode

Type: object

Description: Contains the iterator state for loop iteration. Injected by the StateGraphOrchestrator when executing loop-related nodes.

Structure:

{
  "items": ["a", "b", "c"],
  "currentIndex": 0,
  "currentItem": "a",
  "hasMore": true,
  "results": []
}

Fields: | Field | Type | Description | |-------|------|-------------| | items | array | The array being iterated over | | currentIndex | integer | Current position in the array (0-based) | | currentItem | mixed | The current item at currentIndex | | hasMore | boolean | Whether there are more items after the current one | | results | array | Collected results from each iteration |

Injection Point: StateGraphOrchestrator::buildRuntimeInputData()

Source: GraphState.iterator (of type IteratorState)


__current_item__

Used by: Nodes that need access to the current loop item

Type: mixed

Description: A convenience parameter containing just the current item from the iterator. This is a shorthand for accessing __iterator__.currentItem.

Injection Point: StateGraphOrchestrator::buildRuntimeInputData()

Source: GraphState.iterator.currentItem


__state__

Used by: ApprovalGateNode, and nodes that need full state access

Type: object

Description: Contains the complete graph state as an array. Used by nodes that need to inspect or manipulate the full execution state.

Structure:

{
  "messages": [...],
  "data": {...},
  "iterator": {...},
  "status": "running",
  "error": null
}

Injection Point: StateGraphOrchestrator::buildRuntimeInputData()

Source: GraphState.toArray()


__messages__

Used by: Nodes that need access to the message history

Type: array

Description: Contains all messages in the current execution as an array. Each message is serialized using toArray().

Structure:

[
  {
    "role": "user",
    "content": "Hello",
    "timestamp": "2026-01-19T00:00:00Z"
  },
  {
    "role": "assistant",
    "content": "Hi there!",
    "timestamp": "2026-01-19T00:00:01Z"
  }
]

Injection Point: StateGraphOrchestrator::buildRuntimeInputData()

Source: GraphState.messages (mapped to arrays)


__data__

Used by: StateStorageNode, and nodes that need access to workflow data

Type: object

Description: Contains the workflow's data store - a key-value store for persisting data across nodes during execution.

Structure:

{
  "user_name": "John",
  "counter": 5,
  "items": ["a", "b", "c"]
}

Injection Point: StateGraphOrchestrator::buildRuntimeInputData()

Source: GraphState.data


__node_id__

Used by: ChatOutput, and nodes that need to identify themselves

Type: string

Description: Contains the unique node instance ID within the workflow (e.g., chat_output.1).

Injection Point: Varies by context

Source: Job metadata or execution context


__execution_id__

Used by: ChatOutput, and nodes that need the execution context

Type: string

Description: Contains the unique execution ID for the current workflow run.

Injection Point: Varies by context

Source: Execution context


Adding New Internal Parameters

When creating a new internal parameter, follow these guidelines:

1. Naming

  • Use the __name__ format (double underscores on both sides)
  • Choose a descriptive name that indicates the parameter's purpose
  • Keep names lowercase with underscores for multi-word names

2. Define in Plugin Schema

Add the parameter to your plugin's getParameterSchema() method:

public function getParameterSchema(): array {
  return [
    "type" => "object",
    "properties" => [
      "__my_internal__" => [
        "type" => "object",
        "description" => "Internal state for [purpose]. Automatically injected by orchestrator.",
      ],
      // ... other parameters
    ],
  ];
}

3. Document the Parameter

Add documentation for your internal parameter in this file, including: - Name and type - Which processor(s) use it - Structure/schema - Where it's injected from - Purpose and behavior

4. Inject from Orchestrator

If your internal parameter needs to be injected by the orchestrator, add the injection logic to StateGraphOrchestrator::buildRuntimeInputData():

// Inject __my_internal__ for MyNode nodes.
$nodeTypeId = $metadata["node_type_id"] ?? "";
if ($nodeTypeId === "my_node" && $state->myInternalState !== NULL) {
  $runtimeData["__my_internal__"] = $state->myInternalState->toArray();
}

5. Node Type Configuration

In the node type configuration: - Show Port: Typically unchecked (internal parameters shouldn't be visible as ports) - Config: Typically unchecked (users shouldn't configure internal parameters) - Required: Typically unchecked (the parameter may be NULL on first execution)

Best Practices

  1. Don't Expose to Users: Internal parameters are for system use. Keep "Show Port" and "Config" unchecked in node type configuration.

  2. Handle NULL Gracefully: Internal parameters may be NULL on first execution or in certain contexts. Always check for NULL before using.

  3. Use DTOs: For complex internal state, create a DTO class (like IteratorState) with proper serialization methods (toArray(), fromArray()).

  4. Document Thoroughly: Internal parameters can be confusing for developers. Always document their purpose, structure, and injection points.

  5. Keep State Minimal: Only include necessary data in internal parameters. Large state objects can impact performance.

  • modules/flowdrop_runtime/src/Service/ParameterResolver.php - Handles internal parameter resolution
  • modules/flowdrop_stategraph/src/Service/StateGraphOrchestrator.php - Injects internal parameters
  • modules/flowdrop_stategraph/src/DTO/IteratorState.php - DTO for __iterator__ state
  • modules/flowdrop_stategraph/src/DTO/GraphState.php - Contains iterator state for injection

See Also