syntax="proto3"; package minknow_api.protocol; option java_package = "com.nanoporetech.minknow_api"; option objc_class_prefix = "MKAPI"; import "minknow_api/acquisition.proto"; import "minknow_api/basecaller.proto"; import "minknow_api/device.proto"; import "minknow_api/protocol_settings.proto"; import "minknow_api/rpc_options.proto"; import "google/protobuf/timestamp.proto"; import "google/protobuf/wrappers.proto"; service ProtocolService { // Initiates a python instance that runs the script specified by the `path` argument. // `list_protocols` will give back a list of protocol scripts that can be started by this call rpc start_protocol (StartProtocolRequest) returns (StartProtocolResponse) {} // Stops the currently running protocol script instance. rpc stop_protocol (StopProtocolRequest) returns (StopProtocolResponse) {} // Request the protocol to pause. // // This will return an error unless the ProtocolRunInfo has the `can_pause` field set to true. // It will have no effect if the protocol is already paused or pausing. // // Since 4.4. rpc pause_protocol (PauseProtocolRequest) returns (PauseProtocolResponse) { option idempotency_level = IDEMPOTENT; } // Request the protocol to resume. // // This will return an error unless the ProtocolRunInfo has the `can_pause` field set to true. // It will have no effect if the protocol is not paused or pausing. // // Since 4.4. rpc resume_protocol (ResumeProtocolRequest) returns (ResumeProtocolResponse) { option idempotency_level = IDEMPOTENT; } // Request the protocol to perform a mux scan. // // This will return an error unless the ProtocolRunInfo has the `can_trigger_mux_scan` field set // to true. It will have no effect if the protocol is already running or preparing for a mux // scan. // // Since 4.4. rpc trigger_mux_scan (TriggerMuxScanRequest) returns (TriggerMuxScanResponse) { option idempotency_level = IDEMPOTENT; } // Wait for a protocol run to finish. // // The call blocks until the run with the given run ID has finished (or returns immediately if // it had already finished) and returns information about the protocol run. // // If no run has been started with the provided run ID (or no run ID is given), an error is // returned. // // If NOTIFY_BEFORE_TERMINATION is specified for state, the protocol end time is an estimate, including // the allowed timeout. // // Since 1.10 rpc wait_for_finished (WaitForFinishedRequest) returns (ProtocolRunInfo) { option idempotency_level = NO_SIDE_EFFECTS; } // Gets information about a protocol run. // // If no run ID is provided, information about the most recently started protocol run is // provided. // // Since 1.10 rpc get_run_info (GetRunInfoRequest) returns (ProtocolRunInfo) { option idempotency_level = NO_SIDE_EFFECTS; } // List previously started protocol run ids (including any current protocol), in order of starting. // // The returned object can be used to find protocol information with get_run_info. // // Since 1.11 rpc list_protocol_runs (ListProtocolRunsRequest) returns (ListProtocolRunsResponse) { option idempotency_level = NO_SIDE_EFFECTS; } // Returns the name and run id of the currently running protocol. // // Will fail with FAILED_PRECONDITION if there is no protocol running // // Since 1.11 rpc get_current_protocol_run (GetCurrentProtocolRunRequest) returns (ProtocolRunInfo) { option idempotency_level = NO_SIDE_EFFECTS; } // Returns current protocol run info and streams any changes to the current protocol // // This call can be made even if there is no current protocol running. In this case, the next streamed // response will be the start of a new protocol instance and you will receive updates for that protocol // until it finishes // // If a protocol finishes this stream will still continue to run and you will be notified when a new protocol starts // // Since 1.12 rpc watch_current_protocol_run (WatchCurrentProtocolRunRequest) returns (stream ProtocolRunInfo) { option idempotency_level = NO_SIDE_EFFECTS; } // Gives back a list that contains info about each possible protocol script minknow is aware of. // This will most likely be used to retrieve a suitable protocol script that can be passed on to `start_protocol` // // Since 1.10 rpc list_protocols (ListProtocolsRequest) returns (ListProtocolsResponse) { option idempotency_level = IDEMPOTENT; } // Returns string-to-string map of the context tags // // Since 1.11 rpc get_context_info (GetContextInfoRequest) returns (GetContextInfoResponse) { option idempotency_level = NO_SIDE_EFFECTS; } // Store context tags as arbitary string-to-string map // // Since 1.11 rpc set_context_info (SetContextInfoRequest) returns (SetContextInfoResponse) { option idempotency_level = IDEMPOTENT; } // Value set by protocol scripts to define the purpose of the script. Gets this value // // Since 1.11 rpc get_protocol_purpose (GetProtocolPurposeRequest) returns (GetProtocolPurposeResponse) { option idempotency_level = NO_SIDE_EFFECTS; } // Sets the protocol purpose. See also get_protocol_purpose // // Since 1.11 rpc set_protocol_purpose (SetProtocolPurposeRequest) returns (SetProtocolPurposeResponse) { option idempotency_level = IDEMPOTENT; } // Links an epi2me workflow reference to a run id. // // Since 1.15 rpc add_epi2me_workflow (AddEpi2meWorkflowRequest) returns (AddEpi2meWorkflowResponse) {} // List all used protocol group ids used in any previous protocol on the box. // // Since 3.2 rpc list_protocol_group_ids(ListProtocolGroupIdsRequest) returns (ListProtocolGroupIdsResponse) { option idempotency_level = NO_SIDE_EFFECTS; } // Run a hardware check on the connected flow cell. // // Throws an error if there is no flow cell connected. // // Since 4.3 rpc begin_hardware_check(BeginHardwareCheckRequest) returns (BeginHardwareCheckResponse) { option (experimental) = true; } // Run platform qc on the connected flow cell // // Throws an error if there is no flow cell connected. // // Since 4.3 rpc begin_platform_qc(BeginPlatformQcRequest) returns (BeginPlatformQcResponse) { option (experimental) = true; } // Run protocol on the connected flow cell // // The protocol must be described by a toml file. The request identifies the // protocol and supplies overrides to the default protocol-settings described // in the toml file, in addition it provides user-info for the experiment. // // Throws an error if there is no flow cell connected. // // Since 5.0 rpc begin_protocol(BeginProtocolRequest) returns (BeginProtocolResponse) { option (experimental) = true; } rpc set_platform_qc_result(SetPlatformQcResultRequest) returns (SetPlatformQcResultResponse) { option idempotency_level = IDEMPOTENT; } // Associated a post processing analysis process, and schedule it to run once the protocol is complete. // // If the protocol is already complete, the post proecssing analysis is executed immediately. // // Since 4.4 rpc associate_post_processing_analysis_for_protocol(AssociatePostProcessingAnalysisRequest) returns (AssociatePostProcessingAnalysisResponse) {} // Clears history data for specified protocol(s) // // History data includes protocol protocol info, acquisition info and statistics. // // Also clears any persistence data that has been written to disk for those protocols -- this // data will not be available after a restart. // // Does NOT clear experiment results (fast5, fastq, sequencing_summary, etc) // // Since 4.4 // rpc clear_protocol_history_data(ClearProtocolHistoryDataRequest) returns (ClearProtocolHistoryDataResponse) {} // This RPC should only be used by the protocol script. // // The protocol script can call this to opt in to protocol phase management. It can report the // phase it is currently in, and handle requests to change phase. // // Only one call to this RPC is possible at once. Ending the call will reset the phase to // PHASE_UNKNOWN and clear any set capabilities. // // Since 4.4. rpc protocol_phase_management (stream ProtocolPhaseManagementRequest) returns (stream ProtocolPhaseManagementResponse) {} // Generate a run report and return the report data. // // If the protocol selected for report generation is already complete the report is a completed report, otherwise // the report will be from the in progress protocol. // // Since 5.0 rpc generate_run_report(GenerateRunReportRequest) returns (stream GenerateRunReportResponse) { option idempotency_level = IDEMPOTENT; } } message BarcodeUserData { enum SampleType { // The barcode sample is a real sample being tested. test_sample = 0; // The barcode sample is a control which is expected to result in positive identification. positive_control = 1; // The barcode sample is a control which is expected to result in negative identification. negative_control = 2; // Indended to show that a result has not occured due to contamination. no_template_control = 3; // Separate positive controls for when kits expect 2. positive_control_1 = 4; // Separate positive controls for when kits expect 2. positive_control_2 = 5; } // Barcode name the user data applies to, eg: "barcode02". // // Acts as the external barcode name `barcode_name_internal` is // also set for dual barcoding // // Acts as the rapid barcode name in lampore barcoding if `lamp_barcode_id` // is set string barcode_name = 1; // The internal barcode name if using dual barcode string barcode_name_internal = 5; // Lamp barcode id the user data applies to, eg: "FIP04" string lamp_barcode_id = 2; // User defined string alias for the barcode. string alias = 3; // Sample type grouping for the barcode. SampleType type = 4; } message KitInfo { // The sequencing kit used to select the protocol e.g. "SQK-LSK108" string sequencing_kit = 1; // The expansion barcoding kits that the protocol supports e.g. "EXP-NBD104" repeated string barcode_expansion_kits = 2; } message ProtocolRunUserInfo { // The group which the experiment should be held in. // // note: This value could be unset if a user did not specify a group_id when starting the protocol. google.protobuf.StringValue protocol_group_id = 1; // sample_id created by the user google.protobuf.StringValue sample_id = 2; // User supplied info for barcodes repeated BarcodeUserData barcode_user_info = 3; // user_specified_flow_cell_id created by the user google.protobuf.StringValue user_specified_flow_cell_id = 4; // user_specified_product_code created by the user google.protobuf.StringValue user_specified_product_code = 5; // Kit information the user requested KitInfo kit_info = 6; } message OffloadLocationInfo { // Data offload locations to use to store protocol data, specified using their `location_id`. // // Valid `location_id`s can be retrieved using mooneye.offload_manager.list_offload_locations() // // If any `offload_location_ids` are specified, then: // - Data is not stored locally // - `offload_location_path` must NOT be set (or must be set to an empty value) // - The `offload_location_ids` indicate that data should be offloaded, rather than // stored locally; the `offload_location_path` is used to set a local storage location. // - If both are set, an error is returned // // This requires a running instance of Mooneye // // Since 5.0. repeated string offload_location_ids = 1; // Local, e.g., internal / external drive, paths to where the protocol output will be stored. // // This setting overrides the default output locations (as set through configuration files // and/or the instance service). // // If `offload_location_path` is set to a non-empty value, then: // - `offload_location_ids` MUST be empty // - The `offload_location_ids` indicate that data should be offloaded, rather than // stored locally; the `offload_location_path` is used to set a local storage location. // - If both are set, an error is returned // // This does not require a running instance of Mooneye // // Since 5.0 string offload_location_path = 2; } message StartProtocolRequest { // The identifier of the protocol, as provided by list_protocols(). string identifier = 1 [(rpc_required) = true]; // The arguments to pass to the protocol. repeated string args = 2; // User input describing the protocol. ProtocolRunUserInfo user_info = 3; // Information about data offload locations to use to store data // // Since 5.0. OffloadLocationInfo offload_location_info = 4; // Initial Target Run-Until Criteria to use when starting an acquisition for this protocol. // These can be updated during the acquisition using the Run-Until API. // // Since 5.3 acquisition.TargetRunUntilCriteria target_run_until_criteria = 5; } message StartProtocolResponse { // UUID generated when the protocol is started, to uniquely represent this protocol instance string run_id = 1; } message StopProtocolRequest { // Specify how any running acquisition should // be handled when stopping the protocol. // // Protocol state will enter PROTOCOL_WAITING_FOR_ACQUISITION whilst any running // acquisition is finished. // // If a script ends on its own any analysis that was started is stopped, and it // is allowed to catchup. If the caller wants to end catchup they can call stop_protocol // to end catchup. // // Since 1.15 acquisition.StopRequest.DataAction data_action_on_stop = 1; } message StopProtocolResponse { } message PauseProtocolRequest { } message PauseProtocolResponse { } message ResumeProtocolRequest { } message ResumeProtocolResponse { } message TriggerMuxScanRequest { } message TriggerMuxScanResponse { } message ListProtocolsRequest { // If this is false, then will try to use the cached value of the protocol list where possible // (still subject to changes in flow cell). // If this is true, then will force a reload of the protocol list // // Defaults to false bool force_reload = 1; } message ProtocolInfo { message TagValue { oneof tag_value { string string_value = 1; bool bool_value = 2; int64 int_value = 3; double double_value = 4; string array_value = 5; string object_value = 6; } } message TagExtractionResult { bool success = 1; string error_report = 2; } string identifier = 1; map tags = 2; string name = 3; TagExtractionResult tag_extraction_result = 4; } message ListProtocolsResponse { repeated ProtocolInfo protocols = 1; } message WaitForFinishedRequest { enum NotificationState { // Request return just after the protocol has temrinated, including any acquisition periods completing. NOTIFY_ON_TERMINATION = 0; // Request return prior to the script being termiated. // note: will try to return 5s before killing the protocol script. NOTIFY_BEFORE_TERMINATION = 1; // Notify as the protocol script finishes, not waiting for any in progress acquisition to complete. NOTIFY_ON_SCRIPT_TERMINATION = 2; }; // Only consider a specific protocol run. string run_id = 1 [(rpc_required) = true]; // Control what to wait for. // // Specifying NOTIFY_BEFORE_TERMINATION allows a caller to be notified the script will be ended _soon_, // and do final work to end cleanly. // // Since 1.11 NotificationState state = 2; // Timeout to wait for finished, if the timeout expires before the protocol is complete (in the state requested) // then the response returns. // // By default the timeout will wait forever. // // Since 1.15 float timeout = 3; } message GetRunInfoRequest { // The protocol run to get information about. string run_id = 1; } enum ProtocolState { // The protocol is still running. PROTOCOL_RUNNING = 0; // The protocol is waiting for the device to reach temperature // // Since 1.15 PROTOCOL_WAITING_FOR_TEMPERATURE = 4; // Occurs when data protocol has stopped (either from a explicit rpc request or the script naturally ended) // and data is still being processed (basecalling is still in catchup and processing reads). PROTOCOL_WAITING_FOR_ACQUISITION = 5; // The protocol finished on its own and did not report an error. // // This is determined by the protocol process exiting with a zero exit code. PROTOCOL_COMPLETED = 1; // The protocol was terminated by the user. PROTOCOL_STOPPED_BY_USER = 2; // The protocol finished on its own and reported an error. // // This is determined by the protocol process exiting with a non-zero exit code or because of a // signal. Often, this will be because an exception was raised in the Python code and not // caught, but could also indicate that the Python process crashed or was killed by some // mechanism other than by MinKNOW. PROTOCOL_FINISHED_WITH_ERROR = 3; // The protocol was terminated because the sequencing device encountered an error. PROTOCOL_FINISHED_WITH_DEVICE_ERROR = 6; // The protocol was terminated because MinKNOW could not send telemetry to start acquisition. PROTOCOL_FINISHED_UNABLE_TO_SEND_TELEMETRY = 7; } enum ProtocolPhase { // The protocol has not reported what phase it is in. PHASE_UNKNOWN = 0; // The protocol is calibrating, or performing other initialisation tasks. PHASE_INITIALISING = 1; // The protocol is sequencing. PHASE_SEQUENCING = 2; // The protocol is setting up to perform a mux scan. PHASE_PREPARING_FOR_MUX_SCAN = 3; // The protocol is performing a mux scan. This checks whether to switch channels to different // wells (muxes) in order to improve and maintain sequencing performance. PHASE_MUX_SCAN = 4; // The protocol is paused. // // When the protocol is resumed, it is likely to enter the PHASE_RESUMING state before moving to // another state (such as PHASE_SEQUENCING). PHASE_PAUSED = 5; // The protocol is in the process of pausing. // // It should move into PHASE_PAUSED within a short time. PHASE_PAUSING = 6; // The protocol is in the process of resuming from a paused state. // // It should move into another phase, such as PHASE_SEQUENCING or PHASE_PREPARING_FOR_MUX_SCAN, // in a short time. PHASE_RESUMING = 7; } message Epi2meWorkflowReference { // The unique identifier for a workflow ( unique to a specific instance of epi2me ) int64 id = 1; // URL that links to the workflow report. Syntax for a local workflow: file:// otherwise: http(s):// string url = 2; } message AssociatedPostProcessingAnalysis { // Id of analysis if this has been triggered (otherwise empty). string started_id = 1; // Start request for analysis basecaller.StartRequest start_request = 2; } message PlatformQcResult { // The flow cell id that the pqc was performed for string flow_cell_id = 1; // Whether the flow cell passed the platform qc check bool passed = 2; // Total number of pores that were found on the flow cell, across all muxes. uint32 total_pore_count = 3; } message ExternalOffload { // The `id`s associated with active external data offloads associated with the protocol // The offload status can be queried using `mooneye.offload_manager.watch_offloads()`` repeated string offload_ids = 1; } message ProtocolRunInfo { // The unique identifier assigned to this run. // // This is guaranteed to be made of ASCII characters, and at most 40 characters. It is globally // unique across all protocols runs on all MinKNOW instances. string run_id = 1; // The identifier of the protocol, as passed to start_protocol(). string protocol_id = 2; // The arguments passed to start_protocol(). repeated string args = 3; // Output location for protocol data (eg. reads). // // Since 1.16. string output_path = 11; // Indicates the current state of the protocol run. ProtocolState state = 4; // The phase of the protocol. // // This is the state reported by the protocol. If the protocol has not reported any state, it // will be PHASE_UNKNOWN. Completed protocols also report PHASE_UNKNOWN. // // Note that clients should handle unexpected values of this field gracefully. This can happen // if new phases are added but the client is still using an older version of the API // specification. // // Since 4.4. ProtocolPhase phase = 16; // The last time the phase changed. // // This can be used to determine how long the protocol has been in the current phase. // // NB: This will not be set if the phase is PHASE_UNKNOWN. // // Since 4.4. google.protobuf.Timestamp last_phase_change = 17; // Whether the protocol can be paused. // // Not all protocols can be paused, and cannot be paused in all phases. // // Note that if this is true and the phase is PHASE_PAUSING or PHASE_PAUSED, pausing will not // actually do anything. // // Since 4.4. bool can_pause = 18; // Whether a mux scan can be triggered for the protocol. // // Since 4.4. bool can_trigger_mux_scan = 19; // When the protocol was started (UTC). google.protobuf.Timestamp start_time = 5; // When the protocol script terminated (UTC). // // Unset if the protocol script is still running. // // Note that the protocol may still run until final acquisiton completes. google.protobuf.Timestamp script_end_time = 9; // When the protocol terminated (UTC), indicating both the // protocol script and the final acquisition were completed. // // Unset if the protocol is still running. google.protobuf.Timestamp end_time = 6; // A list of acquisition periods started whilst this protocol was running. // repeated string acquisition_run_ids = 7; // User specified information associated with the protocol at start time. // // Since 1.11. ProtocolRunUserInfo user_info = 8; // List of workflows from epi2me associated with this protocol // // Since 1.15. repeated Epi2meWorkflowReference epi2me_workflows = 10; // Information about the device a protocol was started with // // Since 3.4 device.GetDeviceInfoResponse device = 12; // Information about the flow cell a protocol was started with // // Since 3.4 device.GetFlowCellInfoResponse flow_cell = 13; // Meta-info about the protocol // // Since 3.8 ProtocolInfo meta_info = 14; // List of scheduled post processing analysis tasks repeated AssociatedPostProcessingAnalysis associated_post_processing_analysis = 15; // Platform QC result. Set by bream by calling `set_platform_qc_result()`. // Possible to not be set (e.g. not a pqc run) PlatformQcResult pqc_result = 20; // Contains information about external data offloads associated with this protocol // // Since 5.0 ExternalOffload external_offload = 21; } message FilteringInfo { // Intialising this message a filter like `pqc_filter` will imply to restrict results to // that type only. // // Each filter type should also be using wrapper types for each individual value, to // allow for specific filtering within each type message PlatformQcFilter { optional string flow_cell_id = 1; } PlatformQcFilter pqc_filter = 1; } message ListProtocolRunsRequest { FilteringInfo filter_info = 1; } message ListProtocolRunsResponse { repeated string run_ids = 1; } message GetCurrentProtocolRunRequest { } message GetCurrentProtocolRunResponse { ProtocolRunInfo run_info = 3; } message WatchCurrentProtocolRunRequest { } message GetContextInfoRequest { } message GetContextInfoResponse { map context_info = 1; } message SetContextInfoRequest { map context_info = 1; } message SetContextInfoResponse { } message GetProtocolPurposeRequest { } message GetProtocolPurposeResponse { string purpose = 1; } message SetProtocolPurposeRequest { string purpose = 1; } message SetProtocolPurposeResponse { } message AddEpi2meWorkflowRequest { string run_id = 1 [(rpc_required) = true]; Epi2meWorkflowReference epi2me_workflow = 2 [(rpc_required) = true]; } message AddEpi2meWorkflowResponse { } message ListProtocolGroupIdsRequest { } message ListProtocolGroupIdsResponse { // A list of protocol group ids used in any // protocol started on this instance of minknow. // repeated string protocol_group_ids = 1; } message BeginHardwareCheckRequest {} message BeginHardwareCheckResponse { // UUID generated when the protocol is started, to uniquely represent this protocol instance string run_id = 1; } message BeginPlatformQcRequest { } message BeginPlatformQcResponse { // UUID generated when the protocol is started, to uniquely represent this protocol instance string run_id = 1; } message BeginProtocolRequest { oneof protocol_identifier { // Specify the protocol with a string containing all the protocol's identifying components, eg: // "sequencing/sequencing_MIN106_DNA:FLO-MIN106:SQK-RPB004" string identifier = 1; // Specify the protocol providing the identifying components individually, all components are optional. // Exactly one protocol should match the given components otherwise and error will be returned protocol_settings.ProtocolIdentifierComponents components = 2; } // User info options for the protocol ProtocolRunUserInfo user_info = 3; // Information about data offload locations to use to store data // // Since 5.0. OffloadLocationInfo offload_location_info = 5; // Initial Target Run-Until Criteria to use when starting an acquisition for this protocol. // These can be updated during the acquisition using the Run-Until API. // // Since 5.3 acquisition.TargetRunUntilCriteria target_run_until_criteria = 6; // Any settings changed from the defaults specified in the protocol's .toml file. map settings = 4; } message BeginProtocolResponse { // UUID generated when the protocol is started, to uniquely represent this protocol instance string run_id = 1; } message SetPlatformQcResultRequest { // The protocol_run_id that was given when the pqc run was started string protocol_run_id = 1; PlatformQcResult pqc_result = 2; } message SetPlatformQcResultResponse { } message AssociatePostProcessingAnalysisRequest { // Protocol id to associate analysis with: string run_id = 1; basecaller.StartRequest start_request = 2; } message AssociatePostProcessingAnalysisResponse { // Id of the basecaller.proto post processing task that was triggered, if the post processing analysis was executed immediately (protocol was finished). string id = 1; } message ClearProtocolHistoryDataRequest { repeated string protocol_ids = 1; } message ClearProtocolHistoryDataResponse {} enum Action { // No action is requested. ACTION_NONE = 0; // The protocol should pause. // // This will only be sent if the can_pause capability has been set to true by a request // in the current call to protocol_phase_management(). // // If the protocol is already pausing or paused, this message should be ignored. // Otherwise, the protocol should immediately respond with a ProtocolPhaseManagementRequest // that sets the phase to PHASE_PAUSING or PHASE_PAUSED. ACTION_PAUSE = 1; // The protocol should resume. // // This will only be sent if the can_pause capability has been set to true by a request // in the current call to protocol_phase_management(). // // If the protocol is not pausing or paused, this message should be ignored. // Otherwise, the protocol should immediately respond with a ProtocolPhaseManagementRequest // that sets the phase appropriated (eg: to PHASE_RESUMING). ACTION_RESUME = 2; // The protocol should trigger a mux scan. // // This will only be sent if the can_trigger_mux_scan capability has been set to true by a // request in the current call to protocol_phase_management(). // // If the protocol is already performing (or preparing for) a mux scan, this message should be // ignored. Otherwise, the protocol should immediately respond with a // ProtocolPhaseManagementRequest that sets the phase to PHASE_PREPARING_FOR_MUX_SCAN or // PHASE_MUX_SCAN. ACTION_TRIGGER_MUX_SCAN = 3; } message ProtocolPhaseManagementRequest { message Capabilities { // Indicate that the protocol will respond to pause and resume requests. bool can_pause = 1; // Indicate that the protocol will respond to mux scan requests. bool can_trigger_mux_scan = 2; } // Update the set of capabilities (messages that will be responded to by the protocol). Capabilities set_capabilities = 1; // Update the protocol phase. // // Leave empty (ie: PHASE_UNKNOWN) to keep the previous phase. ProtocolPhase phase = 2; } message ProtocolPhaseManagementResponse { // Requests that the protocol changes phase. // // The client should never receive an action type (other than possibly ACTION_NONE) that it has // not explicitly opted into via the `ProtocolPhaseManagementRequest.set_capabilities` field. // // If this is set to ACTION_NONE, the message should be ignored (this is for future // compatibility). Action action = 1; } message GenerateRunReportRequest { // The protocol_run_id to generate a report for. string protocol_run_id = 1; } message GenerateRunReportResponse { // Protocol ID the run report is for. string protocol_run_id = 1; // A section of the run report data (note the api to return this data may stream back several sections). string report_data = 2; // How many further characters of data remain after this message (excluding of this message). int32 remaining_length = 3; }