Skip to content

feat(actuators): StandardActuator — sync/async base class#955

Open
michael-johnston wants to merge 8 commits into
mainfrom
maj_sync_actuator
Open

feat(actuators): StandardActuator — sync/async base class#955
michael-johnston wants to merge 8 commits into
mainfrom
maj_sync_actuator

Conversation

@michael-johnston
Copy link
Copy Markdown
Member

@michael-johnston michael-johnston commented May 18, 2026

Introduces StandardActuator, a flexible base class for actuator plugins that provides both synchronous (execute) and asynchronous (submit) execution paths without callers needing to manage Ray actors or MeasurementQueue instances.

Two customisation hooks:

  • _experiment_implementations() — simple path: subclasses override this to provide a map of experiment identifiers to plain python functions (**kwargs) -> dict.
  • _get_request_executor() — custom path: Subclasse can override to return any picklable zero-argument callable for full control over experiment execution.

Other changes:

  • NullQueue (was _NullQueue): a public no-op queue for execute()-only use
  • Registry skips abstract classes at discovery time so StandardActuator is not registered directly.
  • Example RoboticLab actuator refactored to use the new pattern; experiment_executor.py removed.
  • Test suite with 15 tests covering both execution paths, NullQueue, error paths (ValueError, DeprecatedExperimentError, KeyError), and a model round-trip lifecycle test.

TODO:

  • Update actuator documentation. Will wait on agree the final changes.

To use new StandardActuator pattern
- Make NullQueue public
- Update init of StandardActuatorBase so queue type is union
- Make all ray worker functions decorated (instead of two being dynamically decorated)
-
@michael-johnston
Copy link
Copy Markdown
Member Author

TBA: handling of ray helper actors for actuators - like cleanup and console queue that won't be available running outside ray.



@ray.remote
def _run_execute_fn(
Copy link
Copy Markdown
Member

@AlessandroPomponio AlessandroPomponio May 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name of this function seems a bit too generic

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a pretty generic function though.

try:
input_values = experiment.propertyValuesFromEntity(entity)
result_dict = fn(**input_values)
values = dict_to_measurements(result_dict, experiment)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method should probably be renamed to observed_property_values_from_dicts, since it doesn't return Measurements

Comment on lines +11 to +18
* _experiment_implementations() — simple path: return a mapping from experiment
identifier to a callable ``fn(**kwargs) -> dict[str, Any]``. The caller
supplies constitutive property values as kwargs; the callee returns a dict
whose keys are observed property identifiers.

* _get_request_executor() — custom path: override to return any zero-argument
callable that runs the batch and returns a completed MeasurementRequest.
Use functools.partial or a closure to capture any actuator state required.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These seem to be two separate options. If so, it could be worth to have this be an abstract class that can't be instantiated and have two separate subclasses where each implements one option and prevents the other from being used.

It would also be good to have descriptive names for them, although I wouldn't really know what to suggest

Comment on lines +11 to +14
* _experiment_implementations() — simple path: return a mapping from experiment
identifier to a callable ``fn(**kwargs) -> dict[str, Any]``. The caller
supplies constitutive property values as kwargs; the callee returns a dict
whose keys are observed property identifiers.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems sort of similar to custom_experiments, no?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(actuators): improve the process of using an actuator from within another actuator

2 participants