inputs (a dict of upstream nodes’ outputs, keyed by input port name) and parameters (the run’s parameters, plus — inside a for_each body — the current item/index). Different node types expose two different ways to reference them in config.
llm_call and action_call templating
llm_call’s prompt/system_prompt and action_call’s string parameters values are plain Python str.format() templates, rendered against inputs/parameters:
- Nested dict/list access uses
[key]chains — no dots (e.g.{inputs[in][user][email]}, not{inputs.in.user.email}). action_callrenders every string value inparametersthis way, recursively through nested dicts/lists; non-string values (numbers, booleans) pass through unchanged.- If a referenced key is missing, the node fails with a clear error naming the field and the missing key — e.g.
llm_call 'prompt' references 'foo', which is missing from inputs/parameters on this run— rather than silently rendering an empty string.
if, for_each, and rest_call query values: Python expressions
if.config.left, for_each.config.items, and any rest_call.config.query value that mentions inputs or parameters are evaluated as a Python expression (via eval), with inputs and parameters as the only names in scope:
python node: full function body
The python node doesn’t template strings at all — it runs a complete Python module. Your handler(inputs, parameters) function receives both dicts directly and returns the node’s output:
Passing data across a branch
When anif node’s upstream input is a dict, its fields are merged through to the chosen branch alongside branch and value, so a node downstream of true (or false) still sees the original payload, not just the condition’s result:
Reference
See also: Node Reference, Overview.