# Workflow Parameters Feature

## Overview

Workflow parameters are user-provided input values that:
- Start with a letter (no `$` prefix)
- Can be used in expressions throughout the workflow
- Are **read-only** during workflow execution (cannot be modified)
- Are declared in the workflow registry with type information

## Example Workflow

```json
{
  "version": "3.6",
  "name": "UserDataProcessor",
  "registry": {
    "params": [
      "userId(STRING)",
      "maxRecords(INT)",
      "config(OBJECT)"
    ],
    "vars": [
      "$processedData(OBJECT)",
      "$recordCount(INT)"
    ]
  },
  "steps": [
    {
      "id": "Set_RecordCount",
      "target": "$recordCount",
      "value": "=maxRecords + 10",
      "next": "Set_Data"
    },
    {
      "id": "Set_Data",
      "target": "$processedData",
      "value": "{\"userId\": \"=userId\", \"limit\": \"=$recordCount\", \"host\": \"=config.host\"}",
      "next": "Stop_End"
    },
    {
      "id": "Stop_End"
    }
  ]
}
```

## Usage in Go

```go
// Define workflow with parameters
workflow := &workflow.Workflow{
    Version: "3.6",
    Name:    "UserDataProcessor",
    Registry: workflow.Registry{
        Params: []string{
            "userId(STRING)",
            "maxRecords(INT)",
            "config(OBJECT)",
        },
        Vars: []string{
            "$processedData(OBJECT)",
            "$recordCount(INT)",
        },
    },
    Steps: []workflow.Step{
        // ... steps as shown above
    },
}

// Create engine
engine, _ := workflow.NewEngine(workflow)

// Execute with parameter values
result, _ := engine.Execute(
    context.Background(),
    map[string]interface{}{
        "userId":     "user123",
        "maxRecords": 100,
        "config": map[string]interface{}{
            "host": "api.example.com",
            "port": 443,
        },
    },
    adapters,
)
```

## Key Features

### 1. Type Safety with Automatic Conversion
Parameters can have type declarations similar to variables:
- `userId(STRING)` - string parameter
- `maxRecords(INT)` - integer parameter
- `config(OBJECT)` - object parameter (automatically converts JSON strings to maps)
- `items([STRING])` - array parameter

**OBJECT Parameter Conversion**: When you declare a parameter as `OBJECT` type and pass a JSON string during workflow execution, it's automatically parsed and converted to a `map[string]interface{}`:

```go
// Workflow declares config(OBJECT)
engine.Execute(ctx, map[string]interface{}{
    "config": `{"host": "localhost", "port": 8080}`,  // String input
}, adapters)

// Inside workflow, config is accessible as a map:
// "=config.host" → "localhost"
// "=config.port" → 8080
```

### 2. Expression Support
Parameters can be used in any expression:
```javascript
// Direct reference
"=userId"

// Arithmetic
"=maxRecords + 10"

// String concatenation
"=userId + \"_processed\""

// Nested access
"=config.host"

// Comparisons
"=maxRecords > 100"
```

### 3. Read-Only Enforcement
Attempting to modify a parameter will result in an error:
```json
{
  "id": "Set_Param",
  "target": "userId",
  "value": "newValue"
}
```
This will fail with: `"cannot modify parameter: userId (parameters are read-only)"`

### 4. Distinction from Variables
- **Parameters**: No `$` prefix, read-only, passed at workflow execution
- **Variables**: `$` prefix, mutable, can be modified during execution

## Passing Parameters

When executing a workflow, parameters can be passed through `initialVars`:

```go
initialVars := map[string]interface{}{
    "userId":   "user123",      // Parameter (no $ prefix)
    "config":   configObject,   // Parameter
    "$result":  nil,            // Variable ($ prefix)
}

engine.Execute(ctx, initialVars, adapters)
```

The engine will automatically:
1. Check if a key is declared in `registry.params`
2. Store declared parameters in `ExecutionContext.Params`
3. Store variables (with `$` prefix) in `ExecutionContext.Variables`
4. Store undeclared keys as variables with `$` prefix added

## Error Handling

### Undefined Parameter
```javascript
// If "unknownParam" is not in Params
"=unknownParam"
// Error: "parameter not found: unknownParam"
```

### Attempting to Modify
```json
{
  "target": "userId",
  "value": "newValue"
}
// Error: "cannot modify parameter: userId (parameters are read-only)"
```

### Invalid JSON for OBJECT Parameter
```go
// If passing invalid JSON for OBJECT param
engine.Execute(ctx, map[string]interface{}{
    "config": "not valid json",  // Invalid JSON
}, adapters)
// Error: "failed to convert parameter config to OBJECT: ..."
```

## Best Practices

1. **Use Parameters for**:
   - User inputs
   - Configuration values
   - Read-only reference data
   - API keys and credentials

2. **Use Variables for**:
   - Intermediate computation results
   - Data that needs to be modified
   - Loop iteration values
   - Step output mappings

3. **Naming Conventions**:
   - Parameters: camelCase (e.g., `userId`, `maxRecords`)
   - Variables: camelCase with `$` prefix (e.g., `$result`, `$processedData`)
   - Local vars: camelCase with `_` prefix (e.g., `_item`, `_index`)
