UniteLabs

Handling Dialogs

How to handle FluentControl dialogs, warnings, and query prompts when running methods through the connector.

FluentControl shows dialogs during method execution for errors, warnings, and operator queries. The connector exposes these dialogs through the RuntimeController and RunController features so that your workflow can react to them automatically or present them to an operator.

A dialog is returned as a dictionary with three keys:

  • DialogIdentifier: a unique ID (for example, VX_PROG_000_000).
  • Description: the message shown on the FluentControl screen.
  • Buttons: the available response buttons (for example, ["Abort", "Retry", "Ignore"]).

Automatic dialog handling with RunController.Run

The high-level run_controller.run() (RunController.Run) command has an auto_close_dialogs parameter.

  • auto_close_dialogs=True: if the run stops on an error, the stop-on-error dialog (VX_PROG_000_000) is closed automatically by pressing Abort, and the run fails with a FailedExecution error. Any other dialog that appears while the run is paused or stopped is still emitted as an intermediate response, and the run waits until you resolve it with runtime_controller.respond_to_dialog().
  • auto_close_dialogs=False: every such dialog, including VX_PROG_000_000, is emitted as an intermediate response from run(). Inspect the dialog, then call runtime_controller.respond_to_dialog() to choose a button and continue.

Awaiting run() returns only the final result and skips intermediate responses, so a run that is waiting on a dialog appears to hang unless something else resolves it. Follow the intermediate responses of a running command as described in Observe a long-running control. Each one carries the dialog's identifier, description and buttons. See Responding to a Dialog for the call that resolves it.

Listing active dialogs

To check which dialogs are currently waiting for a response without subscribing to a stream, use run_controller.get_active_dialogs() (RunController.ActiveDialogs):

active_dialogs = await service.run_controller.get_active_dialogs()
for dialog in active_dialogs:
    print(dialog["DialogIdentifier"], dialog["Description"], dialog["Buttons"])

Subscribing to dialogs

If you are using the low-level runtime_controller workflow, subscribe with runtime_controller.subscribe_dialog() (RuntimeController.Dialog) to be notified whenever a new dialog appears:

subscription = await service.runtime_controller.subscribe_dialog()
async with subscription:
    async for dialog in subscription:
        # The stream can open with an event that carries no dialog
        if not isinstance(dialog, dict) or "DialogIdentifier" not in dialog:
            continue
        print(f"New dialog: {dialog['DialogIdentifier']}")
        print(dialog["Description"])
        print(dialog["Buttons"])

Responding to a dialog

Use runtime_controller.respond_to_dialog() (RuntimeController.RespondToDialog) to press a button on an open dialog. The dialog_identifier must match an active dialog, and button_to_press must be one of the strings in the dialog's Buttons.

await service.runtime_controller.respond_to_dialog(
    dialog_identifier="VX_PROG_000_000",
    button_to_press="Abort",
)

Startup variable query dialog

When a method has variables marked as QueryAtStartup, FluentControl opens a query dialog before the method begins. In the high-level RunController.Run command this dialog is closed automatically after the supplied parameters are written.

In the low-level workflow you can close it explicitly:

# Confirm the current variable values and close the startup query dialog
await service.runtime_controller.close_query_at_startup_dialog(accept_values=True)

# Or cancel it to stop the method from starting
await service.runtime_controller.close_query_at_startup_dialog(accept_values=False)

To discover which variables will be queried, call get_query_variables() after preparing the method:

await service.runtime_controller.prepare_method(method="plate_prep")
query_variables = await service.runtime_controller.get_query_variables()
print(query_variables)
# ["plate_count", "volume"]

Errors vs dialogs

runtime_controller.subscribe_error() (RuntimeController.Error) and runtime_controller.subscribe_dialog() (RuntimeController.Dialog) carry different kinds of runtime feedback from FluentControl.

  • subscribe_error() emits raw error message strings from the FluentControl COM API. Examples include:
    • Connection lost / communication fault
    • "PrepareMethod could not be executed. Only allowed in Edit Mode!"
    • "Method not found"
    • "Variable not found"
    • "Run Method not possible: Another run is currently active"

    These messages describe what went wrong but do not include resolution options. Use this stream for logging, alerting, or displaying a plain error message and to react to error programmatically.
  • subscribe_dialog() emits Dialog objects whenever FluentControl shows a Common Error Dialog or the QueryAtStartup dialog. A dialog always contains available buttons such as Abort, Retry, Ignore, Continue, Yes, or No. Examples include:
    • VX_RUNTM_002_019: "The run was aborted. Do you want to return to edit-mode?"
    • Startup variable queries for methods with QueryAtStartup variables
    • Operator prompts and other runtime blocking dialogs

    Many runtime errors that would otherwise stop the method are surfaced as dialogs. Use this stream when you need to react interactively — either by pressing a button automatically or by presenting the dialog to an operator.

Last updated