Adding Workflow Input Parameters#

Say you have a workflow that does some processing on a plate, but you don’t know which plate you’ll be processing until you run the workflow. It would be nice to be able to specify the plate barcode when you run the workflow in LabOps. Workflow Parameters allow you to do just that.

Parameters can be used for anything from plate barcodes to different timings to different reagents to full csv or json files or even plate maps.

Add a Simple Parameter to Your Workflow#

To add a parameter to the workflow, we’ll use the @parameter decorator.

from artificial.workflows.decorators import workflow, parameter
from artificial.workflows.runtime import show_info

@workflow('My Workflow', 'my_wf', 'lab_a73a05f3-6045-47c5-bd54-59d7e78a628c')
@parameter('my_barcode', {'uiTitle': 'My Barcode'})
async def my_wf(my_barcode: str = "P836726") -> None:
    await show_info(f"Running on barcode ${my_barcode}")

For a full list of parameter types and UI widgets available, see Workflow Parameter Types.

Add a Complex Parameter to Your Workflow#

To add a complex parameter to the workflow, we’ll use the @parameter decorator in combination with dataclasses and the @field decorator to set parameter options.

from artificial.workflows.decorators import workflow, parameter, field
from artificial.workflows.runtime import show_info
from dataclasses import dataclass

@dataclass
@field('my_barcode', {'uiTitle': 'My Barcode'})
class MyParameters:
     my_barcode: str = "P836726"

@workflow('Dataclass Parameter Workflow', 'dataclass_parameter_wf', 'lab_a73a05f3-6045-47c5-bd54-59d7e78a628c')
@parameter('my_parameters', {'uiTitle': 'My Parameters'})
async def dataclass_parameter_wf(my_parameters: MyParameters) -> None:
    await show_info(my_message)

When published and run, this code creates this Request Form UI:

_images/dataclass_parameter.png

Nested Dataclass Parameters#

You can also nest dataclasses to create arbitrarily complex parameter structures.

from artificial.workflows.decorators import parameter, workflow
from artificial.workflows.runtime import show_info
from dataclasses import dataclass
from enum import Enum

@dataclass
class IncubatorParams:
    temperature: int
    duration: int


class WorkcellType(Enum):
    _1: str = 'ELIZA'
    _2: str = 'Cell Culture'
    _3: str = 'DNA Isolation'


@dataclass
class WorkcellParams:
    type: WorkcellType
    incubator_params: IncubatorParams


@dataclass
class MyComplexParameters:
    barcode: str
    workcell_params: WorkcellParams


@workflow("Nested Dataclass Parameters", "nested_dataclass_parameters_wf", "lab_3d1485d1-020b-40cd-8acd-c2226eea164d")
@parameter('parameters', {'required': True, 'uiTitle': 'Params'})
async def nested_dataclass_parameters_wf(parameters: MyComplexParameters) -> None:
    await show_info(f"barcode={parameters.barcode}")
    await show_info(f"workcell_type={parameters.workcell_params.type}")
    await show_info(f"temperature={parameters.workcell_params.incubator_params.temperature}")

When published and run, this code creates this Request Form UI:

_images/nested_dataclass_parameters.png

Customizing Which Parameters are Visible in the Request Table#

When starting a new Job, you can see the parameters for each available request in the Request Table.

_images/request_parameters.png

By default, only the first three non-dataclass parameters are visible in the Request Table. You can force specific simple-valued parameter fields to be prioritized by using the alwaysDisplay option in the parameter/field config.

from artificial.workflows.decorators import parameter, workflow, field
from artificial.workflows.runtime import show_info

@workflow('Many Parameter Workflow', "many_parameter_wf", "lab_3d1485d1-020b-40cd-8acd-c2226eea164d", quick=True)
@parameter('param1', {'uiTitle': 'Param1'})
@parameter('param2', {'uiTitle': 'Param2'})
@parameter('param3', {'uiTitle': 'Param3'})
@parameter('param4', {'uiTitle': 'Param4'})
@parameter('param5', {'uiTitle': 'Param5', 'alwaysDisplay': True})
async def many_parameter_wf(param1: str, param2: str, param3: str, param4: str, param5: str) -> None:
    await show_info('so many parameters...')

When requests are created from this workflow, they show up in the Requests Table like this (note how Param5 is visible):

_images/reordered_request_parameters.png

This also works for fields in dataclass parameters:

Warning

Without alwaysDisplay on a specific field, dataclass-valued parameters will not be visible in the Request Table.

from artificial.workflows.decorators import parameter, workflow, field
from artificial.workflows.runtime import show_info
from dataclasses import dataclass

@dataclass
@field('my_barcode', {'uiTitle': 'My Barcode', 'alwaysDisplay': True})
class MyParameters:
    my_barcode: str


@workflow('Dataclass Parameter Workflow', "dataclass_param_workflow", "lab_3d1485d1-020b-40cd-8acd-c2226eea164d", quick=True)
@parameter('my_parameters', {'uiTitle': 'My Parameters'})
async def dataclass_param_workflow(my_parameters: MyParameters) -> None:
    await show_info(f"Received barcode: {my_parameters.my_barcode}")

When requests are created from this workflow, they show up in the Requests Table like this:

_images/reordered_complex_parameters.png

Using Parameters from the API#

You can also set parameters when creating a job via our REST API. You can access the full REST API documentation from the link in your LabOps profile settings with Developer Mode enabled.

Say we want to create a job based on this workflow:

from dataclasses import dataclass

from artificial.workflows.decorators import parameter, workflow
from artificial.workflows.runtime import show_info


@dataclass
class ComplexParams:
    param1: str = 'default'
    param2: int = 0


@workflow('Parameterized Workflow', 'parameterized_workflow', 'lab_27928400-415e-4b54-8737-3e94ceb01a49')
@parameter('barcode', {'required': True, 'uiTitle': 'Barcode'})
@parameter('iteration_count', {'required': True, 'uiTitle': 'Iteration Count'})
@parameter('complex_params', {'required': True, 'uiTitle': 'Complex Parameters'})
async def parameterized_workflow(barcode: str, iteration_count: int, complex_params: ComplexParams) -> None:
    show_info(f'Barcode: {barcode}, Iterations: {iteration_count}, Complex Params: {complex_params}')

Calling the POST /jobs endpoint with the following JSON payload will create a job with the specified parameters:

{
  "name": "API-Generated Job",
  "lab_id": "lab_27928400-415e-4b54-8737-3e94ceb01a49",
  "workflow_id": "parameterized_workflow",
  "parameters": {
    "barcode": "PF182784",
    "iteration_count": 3,
    "complex_params": {
        "param1": "string1",
        "param2": 3
    }
  }
}

When to use Parameters vs. Workflow/Job Config#

Parameters and Workflow/Job Config represent two different ways to get information into your workflow.

Parameters are set when the job is created or scheduled, and are specific to that job. Parameters are useful when you need to pass in information that is different for each run of the workflow, especially for information that should be easily settable by the person running the job. For example, you might use a parameter to specify the plate barcode you want to process in a workflow that processes plates. Once set, parameters cannot be changed.

Job Config is set when the job is created or scheduled and is specific to that job. The Job Config defaults to a copy of the Workflow Config of the job’s workflow. Job Config is useful when you want to set information that is specific to that job that might need to be modified mid-run. For example, you might use Job Config to specify the timing of a cell culture refeed cycle

Parameters

Job Config

Set through the Request form

Yes

No

Modify during Job execution

No

Yes

Visible in the Job Record

Yes

Yes

Available outside the Job

No

Yes