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