# 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**:
```json
{
  "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**:
```json
{
  "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**:
```json
[
  {
    "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**:
```json
{
  "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:

```php
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()`:

```php
// 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.

## Related Files

- `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

- [FlowDrop Node Processor](./flowdrop-node-processor.md) - Node processor development guide
- [Gateway Nodes and Branching](./gateway-nodes.md) - Gateway node system with `branches` and `active_branches`
