UniteLabs

Step

A single action on one device, which completes or fails as a whole.

A step is a single action on one device. It completes or fails as a whole, so a step never leaves a partial result at the scientific level.

For example, a shaking step can lock a shaker, set its RPM, run it for a duration, and unlock it. The step succeeds only when the complete operation finishes.

Example

workflows/steps.py
from unitelabs.sdk.automate import step, phase

@step()
async def shake(shaker: ShakerDevice, rpm: int, duration: int):
    await shaker.elm_controller.lock(retry=3)
    await shaker.shake_controller.set_rpm(rpm)
    await shaker.shake_controller.shake(duration)
    await shaker.elm_controller.unlock()

Steps are called from inside a phase:

workflows/agitation.py
@phase()
async def agitation(target: Plate, shaker: ShakerDevice):
    await mix(target)
    await shake(shaker=shaker, rpm=300, duration=60)
    await shake(shaker=shaker, rpm=150, duration=30)

Key properties

  • No partial results: raise and handle errors inside the step so it returns a clear success or failure.
  • One device per step: a step drives a single device. Coordinating two or more devices belongs in a phase.
  • Automatically retryable: the workflow engine retries technical errors (device timeouts, transient communication failures) automatically before propagating the error upward
  • Sequenced within a phase: steps within a phase always run sequentially, in the order they are called

Retries

The workflow engine retries steps on technical failures automatically. You can configure retry behavior per step:

workflows/steps.py
@step(retries=5, retry_delay_seconds=2)
async def aspirate(liquid_handler: LiquidHandler, volume: float):
    await liquid_handler.pipettes.aspirate(volume)

A technical error is a transient device-level failure: a timeout, a lost connection, a device that did not acknowledge a command. These are retried automatically.

A scientific error: a sample gone missing, a volume that cannot be aspirated — is propagated to the phase for user-defined recovery. Steps do not handle scientific errors; phases do (see Error Handling).

Steps are always sequential within a phase. If you need parallelism, split your work into multiple phases — the workflow engine will run independent phases concurrently and evaluate constraints and transitions.

Device typing

Steps declare the device type they require as a function parameter. The workflow engine resolves the actual hardware instance at run time based on availability and capability — the step code never hardcodes a specific instrument:

workflows/steps.py
@step()
async def centrifuge_samples(centrifuge: CentrifugeDevice, rpm: int, duration: int):
    await centrifuge.centrifugation_controller.spin(rpm=rpm, duration=duration)

This means the same step can run on any compatible centrifuge in the lab.

  • Phase: the group of steps that ends in a stable state a run can resume from
  • Error Handling: retry behavior and error propagation
  • Workflow: the top-level process, defined by the scientific result it produces