Actions
Actions transform attribute values and push results back into the simulation. Each action is a component that reads inputs (for example $in(...), $attr(...), $ext(...)), performs logic, and writes to one or more outputs. Use the actions container inside a model to declare the steps that run every simulation tick.
Defining actions in YAML
The actions container expects a list of mappings. The first key in each mapping selects the action class (for example set, function, or a custom name). The value of that key points to the target attribute(s). Additional keys configure parameters.
actions:
- function: $in(apparent_power)
call: $in(voltage) * $in(current)
params:
alarm_threshold: 100.0
- set:
- $in(status)
- $in(alarm_active)
value: "RUNNING"
{
"actions": [
{
"function": "$in(apparent_power)",
"call": "$in(voltage) * $in(current)",
"params": {
"alarm_threshold": 100.0
}
},
{
"set": [
"$in(status)",
"$in(alarm_active)"
],
"value": "RUNNING"
}
]
}
During loading the SDK turns this into action components named function and set. If you reuse the same action name multiple times, the container suffices by appending counters (set_1, set_2).
Attribute references use the <prefix>(<path>) form. In actions, prefer $in(...) (internal value) and $out(...) (external value), plus $attr(...)/$ext(...) for non-attribute component paths. The SDK also understands the same prefixes with # or @ markers, but spx-examples uses $... consistently.
The actions container
Class: spx_sdk.actions.actions.Actions
Registered as
actions/Actionsso you can embed it anywhere a container is allowed.Validates the list structure via
@definition_schema, catching typos like integers in place of mappings (tests/test_actions/test_actions_validation.py).Automatically instantiates subclasses of
Actionregistered in the component registry; if no specific class is registered for a name the baseActiontype is used.Creates unique child names per action (
dup,dup_1, ...) and preserves the original mapping asaction.definition.
Class: spx_sdk.actions.set_action.SetAction
Use set to assign a literal value to one or more attributes. The schema enforces the presence of set and value.
Behaviour highlights:
SetAction.run()writes the literal to every resolved output wrapper; if anyset()call fails, diagnostics raise aSpxFaultwithaction="actions.set.output"(tests/test_actions/test_set_action.py).Definitions can move the literal into a
paramsblock (valueis lifted automatically).
Built-in function action
function actionClass: spx_sdk.actions.function_action.FunctionAction
function evaluates an expression and writes the result to the configured outputs. The call string is executed with Python's eval, so stick to safe expressions and control inputs through the registry.
Features covered by tests/test_actions/test_function_action.py:
Supports multiple outputs (same result written to each).
paramsentries become resolvable attributes on the action, so you can reference them directly incall.Attribute references inside
callare resolved at runtime, afterprepare()gathers wrappers.
Function call: imports + params (spx-examples convention)
call: imports + params (spx-examples convention)The function action in spx-examples relies on a few extra fields to keep expressions readable and deterministic:
params: define constants, attribute references, or derived values that you reuse incall.imports: expose modules/symbols inside the expression context (either a list like[random]or a mapping like{np: numpy}; noimport ...statements in YAML).
Example: imports list (deterministic RNG)
Example: imports mapping (module alias)
Example: derived params + nested-chain references
Parameters can reference other params and runtime values. call can also be a multi-line YAML block (|) as long as it forms a valid Python expression.
Example: local helper import (extensions/)
extensions/)You can import a local helper function and call it from a multi-line expression. In spx-examples, helpers live under extensions/ and are mounted into the server container.
For the canonical DSL contract used by spx-examples, see:
https://github.com/HammerHeads-Engineers/spx-examples/blob/main/docs/MODEL_LANGUAGE.md
Base action class
Class: spx_sdk.actions.action.Action
Parses the raw mapping into
function,output, and parameter fields.Resolves outputs lazily during
_populateand exposes them viaself.outputs.prepare()gathers wrappers for parameters that contain attribute references;run()callsapply_wrappers()thenwrite_outputs(result).Custom actions can inherit from
Actionand override_populate,run, or helper methods. Remember to register the class (@register_class(name="ramp")) so the container uses it.
Creating a custom action
With the registration in place you can declare:
Validation workflow
The actions container schema (
Actions) ensures each entry is an object and the first key targets a recognised attribute reference pattern (tests/test_actions/test_actions_validation.py).SetActionandFunctionActionadd their own schemas (tests/test_actions/test_set_action_validation.py,tests/test_actions/test_function_action_validation.py), so missing required keys produceValidationErrorinstances before runtime.Custom actions can attach
@definition_schemaand@definition_validatorto enforce additional constraints, just like any other component.
Best practices
Prototype new behaviour with
setandfunctionbefore creating custom actions; this keeps early experiments easy to debug.Name actions after intent (
sync_apparent_power) so diagnostics and logs read like a story.Keep expressions short. If they grow complex, calculate intermediate values in attributes and reference them from actions.
Add unit tests that load your YAML with
Model(...)and callrun()to confirm each action writes the expected values.When collaborating with QA, document parameters (for example in comments or adjacent tables) so teammates know which knobs are safe to tweak.
Last updated

