UniteLabs

Input

Parameterize a workflow or phase with typed values provided at run time — from the UI, the API, or a human operator.

Inputs are typed parameters you declare on a workflow or phase. They are provided at run time — when a run is started, or when a phase is triggered manually. This lets a single workflow definition handle different samples, concentrations, or experimental conditions without changing the code. This is particularly useful for presenting error recovery options to the human or machine user on the phase level for decision-making.

Workflow inputs

Declare inputs as typed function parameters on the @workflow function:

workflows/elisa.py
from unitelabs.sdk.automate import workflow, phase

@workflow(name="ELISA")
async def main_workflow(sample_id: str, concentration: float = 1.0):
    plate = await sample_preparation(sample_id)
    await detection(plate, min_concentration=concentration)

When the run is started via the platform UI, the operator provides the sample_id. concentration is optional and defaults to 1.0. If triggered through the API, these values are sent as JSON in the request body.

Phase inputs

Phases also accept typed parameters. They receive values passed by the workflow or from the output of a previous phase:

workflows/phases.py
@phase()
async def detection(target: Plate, min_concentration: float):
    result = await measure(target)
    assert result.concentration >= min_concentration

Reading inputs via the context object

Only workflow inputs are published automatically to the run's context. The moment main_workflow above is called, sample_id and concentration become readable anywhere in the run via get_context().workflow_parameters — without adding them to any phase's or step's own signature:

workflows/steps.py
from unitelabs.sdk import get_context, step

@step()
async def measure(target: Plate):
    concentration = get_context().workflow_parameters.get("concentration", 1.0)
    ...

This is the recommended way to thread run-wide settings — run mode, simulation flags, feature flags — through many phases and steps: declare them once as workflow inputs, read them from context wherever they're needed. Adding a new workflow input later never requires touching an existing phase's or step's signature, since nothing downstream needs to name it as an argument to see it.

Phase inputs, like target and min_concentration above, work differently: they stay ordinary function arguments, passed explicitly by whatever calls the phase, and are not added to workflow_parameters. A phase can still read the parameters its enclosing workflow declared, via the same get_context().workflow_parameters.

workflow_parameters is a read-only view (types.MappingProxyType), populated only from the top-level @workflow call — treat values read from it as immutable. It is only available with SDK >= 0.15.0 or liquid handling SDK >= 0.34.0.

Input types

Inputs support standard Python types and are validated before the run starts:

TypeExample
strSample identifiers, protocol names
int, floatVolumes, concentrations, durations
boolFeature flags, approval gates
listLists of values
dictKey-value mappings
Complex data typesNested structures
Pydantic modelsStructured sample metadata

Providing inputs via the API

Terminal
curl -X POST https://api.unitelabs.io/v1/workflows/{workflow_id}/runs \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"inputs": {"sample_id": "S-042", "concentration": 2.5}}'
  • Workflow: where inputs are declared
  • Human in the Loop: pausing for operator-provided inputs at phase execution time
  • Runs: inputs are bound to a specific run and stored with the run record