// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

package google.cloud.dialogflow.cx.v3;

import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/field_mask.proto";
import "google/protobuf/timestamp.proto";

option csharp_namespace = "Google.Cloud.Dialogflow.Cx.V3";
option go_package = "cloud.google.com/go/dialogflow/cx/apiv3/cxpb;cxpb";
option java_multiple_files = true;
option java_outer_classname = "ExperimentProto";
option java_package = "com.google.cloud.dialogflow.cx.v3";
option objc_class_prefix = "DF";
option ruby_package = "Google::Cloud::Dialogflow::CX::V3";

// Service for managing [Experiments][google.cloud.dialogflow.cx.v3.Experiment].
service Experiments {
  option (google.api.default_host) = "dialogflow.googleapis.com";
  option (google.api.oauth_scopes) =
      "https://www.googleapis.com/auth/cloud-platform,"
      "https://www.googleapis.com/auth/dialogflow";

  // Returns the list of all experiments in the specified
  // [Environment][google.cloud.dialogflow.cx.v3.Environment].
  rpc ListExperiments(ListExperimentsRequest)
      returns (ListExperimentsResponse) {
    option (google.api.http) = {
      get: "/v3/{parent=projects/*/locations/*/agents/*/environments/*}/experiments"
    };
    option (google.api.method_signature) = "parent";
  }

  // Retrieves the specified
  // [Experiment][google.cloud.dialogflow.cx.v3.Experiment].
  rpc GetExperiment(GetExperimentRequest) returns (Experiment) {
    option (google.api.http) = {
      get: "/v3/{name=projects/*/locations/*/agents/*/environments/*/experiments/*}"
    };
    option (google.api.method_signature) = "name";
  }

  // Creates an [Experiment][google.cloud.dialogflow.cx.v3.Experiment] in the
  // specified [Environment][google.cloud.dialogflow.cx.v3.Environment].
  rpc CreateExperiment(CreateExperimentRequest) returns (Experiment) {
    option (google.api.http) = {
      post: "/v3/{parent=projects/*/locations/*/agents/*/environments/*}/experiments"
      body: "experiment"
    };
    option (google.api.method_signature) = "parent,experiment";
  }

  // Updates the specified
  // [Experiment][google.cloud.dialogflow.cx.v3.Experiment].
  rpc UpdateExperiment(UpdateExperimentRequest) returns (Experiment) {
    option (google.api.http) = {
      patch: "/v3/{experiment.name=projects/*/locations/*/agents/*/environments/*/experiments/*}"
      body: "experiment"
    };
    option (google.api.method_signature) = "experiment,update_mask";
  }

  // Deletes the specified
  // [Experiment][google.cloud.dialogflow.cx.v3.Experiment].
  rpc DeleteExperiment(DeleteExperimentRequest)
      returns (google.protobuf.Empty) {
    option (google.api.http) = {
      delete: "/v3/{name=projects/*/locations/*/agents/*/environments/*/experiments/*}"
    };
    option (google.api.method_signature) = "name";
  }

  // Starts the specified
  // [Experiment][google.cloud.dialogflow.cx.v3.Experiment]. This rpc only
  // changes the state of experiment from PENDING to RUNNING.
  rpc StartExperiment(StartExperimentRequest) returns (Experiment) {
    option (google.api.http) = {
      post: "/v3/{name=projects/*/locations/*/agents/*/environments/*/experiments/*}:start"
      body: "*"
    };
    option (google.api.method_signature) = "name";
  }

  // Stops the specified [Experiment][google.cloud.dialogflow.cx.v3.Experiment].
  // This rpc only changes the state of experiment from RUNNING to DONE.
  rpc StopExperiment(StopExperimentRequest) returns (Experiment) {
    option (google.api.http) = {
      post: "/v3/{name=projects/*/locations/*/agents/*/environments/*/experiments/*}:stop"
      body: "*"
    };
    option (google.api.method_signature) = "name";
  }
}

// Represents an experiment in an environment.
message Experiment {
  option (google.api.resource) = {
    type: "dialogflow.googleapis.com/Experiment"
    pattern: "projects/{project}/locations/{location}/agents/{agent}/environments/{environment}/experiments/{experiment}"
  };

  // The state of the experiment.
  enum State {
    // State unspecified.
    STATE_UNSPECIFIED = 0;

    // The experiment is created but not started yet.
    DRAFT = 1;

    // The experiment is running.
    RUNNING = 2;

    // The experiment is done.
    DONE = 3;

    // The experiment with auto-rollout enabled has failed.
    ROLLOUT_FAILED = 4;
  }

  // Definition of the experiment.
  message Definition {
    // The condition defines which subset of sessions are selected for
    // this experiment. If not specified, all sessions are eligible. E.g.
    // "query_input.language_code=en" See the [conditions
    // reference](https://cloud.google.com/dialogflow/cx/docs/reference/condition).
    string condition = 1;

    // The variants of the experiment. We currently only support single variant
    // experiment.
    oneof variants {
      // The flow versions as the variants of this experiment.
      VersionVariants version_variants = 2;
    }
  }

  // The inference result which includes an objective metric to optimize and the
  // confidence interval.
  message Result {
    // Types of ratio-based metric for Dialogflow experiment.
    enum MetricType {
      // Metric unspecified.
      METRIC_UNSPECIFIED = 0;

      // Percentage of contained sessions without user calling back in 24 hours.
      CONTAINED_SESSION_NO_CALLBACK_RATE = 1;

      // Percentage of sessions that were handed to a human agent.
      LIVE_AGENT_HANDOFF_RATE = 2;

      // Percentage of sessions with the same user calling back.
      CALLBACK_SESSION_RATE = 3;

      // Percentage of sessions where user hung up.
      ABANDONED_SESSION_RATE = 4;

      // Percentage of sessions reached Dialogflow 'END_PAGE' or
      // 'END_SESSION'.
      SESSION_END_RATE = 5;
    }

    // Types of count-based metric for Dialogflow experiment.
    enum CountType {
      // Count type unspecified.
      COUNT_TYPE_UNSPECIFIED = 0;

      // Total number of occurrences of a 'NO_MATCH'.
      TOTAL_NO_MATCH_COUNT = 1;

      // Total number of turn counts.
      TOTAL_TURN_COUNT = 2;

      // Average turn count in a session.
      AVERAGE_TURN_COUNT = 3;
    }

    // A confidence interval is a range of possible values for the experiment
    // objective you are trying to measure.
    message ConfidenceInterval {
      // The confidence level used to construct the interval, i.e. there is X%
      // chance that the true value is within this interval.
      double confidence_level = 1;

      // The percent change between an experiment metric's value and the value
      // for its control.
      double ratio = 2;

      // Lower bound of the interval.
      double lower_bound = 3;

      // Upper bound of the interval.
      double upper_bound = 4;
    }

    // Metric and corresponding confidence intervals.
    message Metric {
      // Ratio-based metric type. Only one of type or count_type is specified in
      // each Metric.
      MetricType type = 1;

      // Count-based metric type. Only one of type or count_type is specified in
      // each Metric.
      CountType count_type = 5;

      // The actual value of the metric.
      oneof value {
        // Ratio value of a metric.
        double ratio = 2;

        // Count value of a metric.
        double count = 4;
      }

      // The probability that the treatment is better than all other treatments
      // in the experiment
      ConfidenceInterval confidence_interval = 3;
    }

    // Version variant and associated metrics.
    message VersionMetrics {
      // The name of the flow [Version][google.cloud.dialogflow.cx.v3.Version].
      // Format:
      // `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>/flows/<FlowID>/versions/<VersionID>`.
      string version = 1 [(google.api.resource_reference) = {
        type: "dialogflow.googleapis.com/Version"
      }];

      // The metrics and corresponding confidence intervals in the inference
      // result.
      repeated Metric metrics = 2;

      // Number of sessions that were allocated to this version.
      int32 session_count = 3;
    }

    // Version variants and metrics.
    repeated VersionMetrics version_metrics = 1;

    // The last time the experiment's stats data was updated. Will have default
    // value if stats have never been computed for this experiment.
    google.protobuf.Timestamp last_update_time = 2;
  }

  // The name of the experiment.
  // Format:
  // projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>/environments/<EnvironmentID>/experiments/<ExperimentID>.
  string name = 1;

  // Required. The human-readable name of the experiment (unique in an
  // environment). Limit of 64 characters.
  string display_name = 2 [(google.api.field_behavior) = REQUIRED];

  // The human-readable description of the experiment.
  string description = 3;

  // The current state of the experiment.
  // Transition triggered by Experiments.StartExperiment: DRAFT->RUNNING.
  // Transition triggered by Experiments.CancelExperiment: DRAFT->DONE or
  // RUNNING->DONE.
  State state = 4;

  // The definition of the experiment.
  Definition definition = 5;

  // The configuration for auto rollout. If set, there should be exactly two
  // variants in the experiment (control variant being the default version of
  // the flow), the traffic allocation for the non-control variant will
  // gradually increase to 100% when conditions are met, and eventually
  // replace the control variant to become the default version of the flow.
  RolloutConfig rollout_config = 14;

  // State of the auto rollout process.
  RolloutState rollout_state = 15;

  // The reason why rollout has failed. Should only be set when state is
  // ROLLOUT_FAILED.
  string rollout_failure_reason = 16;

  // Inference result of the experiment.
  Result result = 6;

  // Creation time of this experiment.
  google.protobuf.Timestamp create_time = 7;

  // Start time of this experiment.
  google.protobuf.Timestamp start_time = 8;

  // End time of this experiment.
  google.protobuf.Timestamp end_time = 9;

  // Last update time of this experiment.
  google.protobuf.Timestamp last_update_time = 10;

  // Maximum number of days to run the experiment/rollout. If auto-rollout is
  // not enabled, default value and maximum will be 30 days. If auto-rollout is
  // enabled, default value and maximum will be 6 days.
  google.protobuf.Duration experiment_length = 11;

  // The history of updates to the experiment variants.
  repeated VariantsHistory variants_history = 12;
}

// A list of flow version variants.
message VersionVariants {
  // A single flow version with specified traffic allocation.
  message Variant {
    // The name of the flow version.
    // Format:
    // `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>/flows/<FlowID>/versions/<VersionID>`.
    string version = 1;

    // Percentage of the traffic which should be routed to this
    // version of flow. Traffic allocation for a single flow must sum up to 1.0.
    float traffic_allocation = 2;

    // Whether the variant is for the control group.
    bool is_control_group = 3;
  }

  // A list of flow version variants.
  repeated Variant variants = 1;
}

// The history of variants update.
message VariantsHistory {
  // The variants updated. We currently only support single variant
  // experiment.
  oneof variants {
    // The flow versions as the variants.
    VersionVariants version_variants = 1;
  }

  // Update time of the variants.
  google.protobuf.Timestamp update_time = 2;
}

// The configuration for auto rollout.
message RolloutConfig {
  // A single rollout step with specified traffic allocation.
  message RolloutStep {
    // The name of the rollout step;
    string display_name = 1;

    // The percentage of traffic allocated to the flow version of this rollout
    // step. (0%, 100%].
    int32 traffic_percent = 2;

    // The minimum time that this step should last. Should be longer than 1
    // hour. If not set, the default minimum duration for each step will be 1
    // hour.
    google.protobuf.Duration min_duration = 3;
  }

  // Steps to roll out a flow version. Steps should be sorted by percentage in
  // ascending order.
  repeated RolloutStep rollout_steps = 1;

  // The conditions that are used to evaluate the success of a rollout
  // step. If not specified, all rollout steps will proceed to the next one
  // unless failure conditions are met. E.g. "containment_rate > 60% AND
  // callback_rate < 20%". See the [conditions
  // reference](https://cloud.google.com/dialogflow/cx/docs/reference/condition).
  string rollout_condition = 2;

  // The conditions that are used to evaluate the failure of a rollout
  // step. If not specified, no rollout steps will fail. E.g. "containment_rate
  // < 10% OR average_turn_count < 3". See the [conditions
  // reference](https://cloud.google.com/dialogflow/cx/docs/reference/condition).
  string failure_condition = 3;
}

// State of the auto-rollout process.
message RolloutState {
  // Display name of the current auto rollout step.
  string step = 1;

  // Index of the current step in the auto rollout steps list.
  int32 step_index = 3;

  // Start time of the current step.
  google.protobuf.Timestamp start_time = 2;
}

// The request message for
// [Experiments.ListExperiments][google.cloud.dialogflow.cx.v3.Experiments.ListExperiments].
message ListExperimentsRequest {
  // Required. The [Environment][google.cloud.dialogflow.cx.v3.Environment] to
  // list all environments for. Format:
  // `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>/environments/<EnvironmentID>`.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "dialogflow.googleapis.com/Experiment"
    }
  ];

  // The maximum number of items to return in a single page. By default 20 and
  // at most 100.
  int32 page_size = 2;

  // The next_page_token value returned from a previous list request.
  string page_token = 3;
}

// The response message for
// [Experiments.ListExperiments][google.cloud.dialogflow.cx.v3.Experiments.ListExperiments].
message ListExperimentsResponse {
  // The list of experiments. There will be a maximum number of items
  // returned based on the page_size field in the request. The list may in some
  // cases be empty or contain fewer entries than page_size even if this isn't
  // the last page.
  repeated Experiment experiments = 1;

  // Token to retrieve the next page of results, or empty if there are no more
  // results in the list.
  string next_page_token = 2;
}

// The request message for
// [Experiments.GetExperiment][google.cloud.dialogflow.cx.v3.Experiments.GetExperiment].
message GetExperimentRequest {
  // Required. The name of the
  // [Environment][google.cloud.dialogflow.cx.v3.Environment]. Format:
  // `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>/environments/<EnvironmentID>/experiments/<ExperimentID>`.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "dialogflow.googleapis.com/Experiment"
    }
  ];
}

// The request message for
// [Experiments.CreateExperiment][google.cloud.dialogflow.cx.v3.Experiments.CreateExperiment].
message CreateExperimentRequest {
  // Required. The [Agent][google.cloud.dialogflow.cx.v3.Agent] to create an
  // [Environment][google.cloud.dialogflow.cx.v3.Environment] for. Format:
  // `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>/environments/<EnvironmentID>`.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "dialogflow.googleapis.com/Experiment"
    }
  ];

  // Required. The experiment to create.
  Experiment experiment = 2 [(google.api.field_behavior) = REQUIRED];
}

// The request message for
// [Experiments.UpdateExperiment][google.cloud.dialogflow.cx.v3.Experiments.UpdateExperiment].
message UpdateExperimentRequest {
  // Required. The experiment to update.
  Experiment experiment = 1 [(google.api.field_behavior) = REQUIRED];

  // Required. The mask to control which fields get updated.
  google.protobuf.FieldMask update_mask = 2
      [(google.api.field_behavior) = REQUIRED];
}

// The request message for
// [Experiments.DeleteExperiment][google.cloud.dialogflow.cx.v3.Experiments.DeleteExperiment].
message DeleteExperimentRequest {
  // Required. The name of the
  // [Environment][google.cloud.dialogflow.cx.v3.Environment] to delete. Format:
  // `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>/environments/<EnvironmentID>/experiments/<ExperimentID>`.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "dialogflow.googleapis.com/Experiment"
    }
  ];
}

// The request message for
// [Experiments.StartExperiment][google.cloud.dialogflow.cx.v3.Experiments.StartExperiment].
message StartExperimentRequest {
  // Required. Resource name of the experiment to start.
  // Format:
  // `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>/environments/<EnvironmentID>/experiments/<ExperimentID>`.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "dialogflow.googleapis.com/Experiment"
    }
  ];
}

// The request message for
// [Experiments.StopExperiment][google.cloud.dialogflow.cx.v3.Experiments.StopExperiment].
message StopExperimentRequest {
  // Required. Resource name of the experiment to stop.
  // Format:
  // `projects/<ProjectID>/locations/<LocationID>/agents/<AgentID>/environments/<EnvironmentID>/experiments/<ExperimentID>`.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "dialogflow.googleapis.com/Experiment"
    }
  ];
}
