// Copyright 2024 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.discoveryengine.v1;

import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/cloud/discoveryengine/v1/answer.proto";
import "google/cloud/discoveryengine/v1/conversation.proto";
import "google/cloud/discoveryengine/v1/search_service.proto";
import "google/cloud/discoveryengine/v1/session.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/field_mask.proto";

option csharp_namespace = "Google.Cloud.DiscoveryEngine.V1";
option go_package = "cloud.google.com/go/discoveryengine/apiv1/discoveryenginepb;discoveryenginepb";
option java_multiple_files = true;
option java_outer_classname = "ConversationalSearchServiceProto";
option java_package = "com.google.cloud.discoveryengine.v1";
option objc_class_prefix = "DISCOVERYENGINE";
option php_namespace = "Google\\Cloud\\DiscoveryEngine\\V1";
option ruby_package = "Google::Cloud::DiscoveryEngine::V1";

// Service for conversational search.
service ConversationalSearchService {
  option (google.api.default_host) = "discoveryengine.googleapis.com";
  option (google.api.oauth_scopes) =
      "https://www.googleapis.com/auth/cloud-platform";

  // Converses a conversation.
  rpc ConverseConversation(ConverseConversationRequest)
      returns (ConverseConversationResponse) {
    option (google.api.http) = {
      post: "/v1/{name=projects/*/locations/*/dataStores/*/conversations/*}:converse"
      body: "*"
      additional_bindings {
        post: "/v1/{name=projects/*/locations/*/collections/*/dataStores/*/conversations/*}:converse"
        body: "*"
      }
      additional_bindings {
        post: "/v1/{name=projects/*/locations/*/collections/*/engines/*/conversations/*}:converse"
        body: "*"
      }
    };
    option (google.api.method_signature) = "name,query";
  }

  // Creates a Conversation.
  //
  // If the [Conversation][google.cloud.discoveryengine.v1.Conversation] to
  // create already exists, an ALREADY_EXISTS error is returned.
  rpc CreateConversation(CreateConversationRequest) returns (Conversation) {
    option (google.api.http) = {
      post: "/v1/{parent=projects/*/locations/*/dataStores/*}/conversations"
      body: "conversation"
      additional_bindings {
        post: "/v1/{parent=projects/*/locations/*/collections/*/dataStores/*}/conversations"
        body: "conversation"
      }
      additional_bindings {
        post: "/v1/{parent=projects/*/locations/*/collections/*/engines/*}/conversations"
        body: "conversation"
      }
    };
    option (google.api.method_signature) = "parent,conversation";
  }

  // Deletes a Conversation.
  //
  // If the [Conversation][google.cloud.discoveryengine.v1.Conversation] to
  // delete does not exist, a NOT_FOUND error is returned.
  rpc DeleteConversation(DeleteConversationRequest)
      returns (google.protobuf.Empty) {
    option (google.api.http) = {
      delete: "/v1/{name=projects/*/locations/*/dataStores/*/conversations/*}"
      additional_bindings {
        delete: "/v1/{name=projects/*/locations/*/collections/*/dataStores/*/conversations/*}"
      }
      additional_bindings {
        delete: "/v1/{name=projects/*/locations/*/collections/*/engines/*/conversations/*}"
      }
    };
    option (google.api.method_signature) = "name";
  }

  // Updates a Conversation.
  //
  // [Conversation][google.cloud.discoveryengine.v1.Conversation] action type
  // cannot be changed. If the
  // [Conversation][google.cloud.discoveryengine.v1.Conversation] to update does
  // not exist, a NOT_FOUND error is returned.
  rpc UpdateConversation(UpdateConversationRequest) returns (Conversation) {
    option (google.api.http) = {
      patch: "/v1/{conversation.name=projects/*/locations/*/dataStores/*/conversations/*}"
      body: "conversation"
      additional_bindings {
        patch: "/v1/{conversation.name=projects/*/locations/*/collections/*/dataStores/*/conversations/*}"
        body: "conversation"
      }
      additional_bindings {
        patch: "/v1/{conversation.name=projects/*/locations/*/collections/*/engines/*/conversations/*}"
        body: "conversation"
      }
    };
    option (google.api.method_signature) = "conversation,update_mask";
  }

  // Gets a Conversation.
  rpc GetConversation(GetConversationRequest) returns (Conversation) {
    option (google.api.http) = {
      get: "/v1/{name=projects/*/locations/*/dataStores/*/conversations/*}"
      additional_bindings {
        get: "/v1/{name=projects/*/locations/*/collections/*/dataStores/*/conversations/*}"
      }
      additional_bindings {
        get: "/v1/{name=projects/*/locations/*/collections/*/engines/*/conversations/*}"
      }
    };
    option (google.api.method_signature) = "name";
  }

  // Lists all Conversations by their parent
  // [DataStore][google.cloud.discoveryengine.v1.DataStore].
  rpc ListConversations(ListConversationsRequest)
      returns (ListConversationsResponse) {
    option (google.api.http) = {
      get: "/v1/{parent=projects/*/locations/*/dataStores/*}/conversations"
      additional_bindings {
        get: "/v1/{parent=projects/*/locations/*/collections/*/dataStores/*}/conversations"
      }
      additional_bindings {
        get: "/v1/{parent=projects/*/locations/*/collections/*/engines/*}/conversations"
      }
    };
    option (google.api.method_signature) = "parent";
  }

  // Answer query method.
  rpc AnswerQuery(AnswerQueryRequest) returns (AnswerQueryResponse) {
    option (google.api.http) = {
      post: "/v1/{serving_config=projects/*/locations/*/dataStores/*/servingConfigs/*}:answer"
      body: "*"
      additional_bindings {
        post: "/v1/{serving_config=projects/*/locations/*/collections/*/dataStores/*/servingConfigs/*}:answer"
        body: "*"
      }
      additional_bindings {
        post: "/v1/{serving_config=projects/*/locations/*/collections/*/engines/*/servingConfigs/*}:answer"
        body: "*"
      }
    };
  }

  // Gets a Answer.
  rpc GetAnswer(GetAnswerRequest) returns (Answer) {
    option (google.api.http) = {
      get: "/v1/{name=projects/*/locations/*/dataStores/*/sessions/*/answers/*}"
      additional_bindings {
        get: "/v1/{name=projects/*/locations/*/collections/*/dataStores/*/sessions/*/answers/*}"
      }
      additional_bindings {
        get: "/v1/{name=projects/*/locations/*/collections/*/engines/*/sessions/*/answers/*}"
      }
    };
    option (google.api.method_signature) = "name";
  }

  // Creates a Session.
  //
  // If the [Session][google.cloud.discoveryengine.v1.Session] to create already
  // exists, an ALREADY_EXISTS error is returned.
  rpc CreateSession(CreateSessionRequest) returns (Session) {
    option (google.api.http) = {
      post: "/v1/{parent=projects/*/locations/*/dataStores/*}/sessions"
      body: "session"
      additional_bindings {
        post: "/v1/{parent=projects/*/locations/*/collections/*/dataStores/*}/sessions"
        body: "session"
      }
      additional_bindings {
        post: "/v1/{parent=projects/*/locations/*/collections/*/engines/*}/sessions"
        body: "session"
      }
    };
    option (google.api.method_signature) = "parent,session";
  }

  // Deletes a Session.
  //
  // If the [Session][google.cloud.discoveryengine.v1.Session] to delete does
  // not exist, a NOT_FOUND error is returned.
  rpc DeleteSession(DeleteSessionRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      delete: "/v1/{name=projects/*/locations/*/dataStores/*/sessions/*}"
      additional_bindings {
        delete: "/v1/{name=projects/*/locations/*/collections/*/dataStores/*/sessions/*}"
      }
      additional_bindings {
        delete: "/v1/{name=projects/*/locations/*/collections/*/engines/*/sessions/*}"
      }
    };
    option (google.api.method_signature) = "name";
  }

  // Updates a Session.
  //
  // [Session][google.cloud.discoveryengine.v1.Session] action type cannot be
  // changed. If the [Session][google.cloud.discoveryengine.v1.Session] to
  // update does not exist, a NOT_FOUND error is returned.
  rpc UpdateSession(UpdateSessionRequest) returns (Session) {
    option (google.api.http) = {
      patch: "/v1/{session.name=projects/*/locations/*/dataStores/*/sessions/*}"
      body: "session"
      additional_bindings {
        patch: "/v1/{session.name=projects/*/locations/*/collections/*/dataStores/*/sessions/*}"
        body: "session"
      }
      additional_bindings {
        patch: "/v1/{session.name=projects/*/locations/*/collections/*/engines/*/sessions/*}"
        body: "session"
      }
    };
    option (google.api.method_signature) = "session,update_mask";
  }

  // Gets a Session.
  rpc GetSession(GetSessionRequest) returns (Session) {
    option (google.api.http) = {
      get: "/v1/{name=projects/*/locations/*/dataStores/*/sessions/*}"
      additional_bindings {
        get: "/v1/{name=projects/*/locations/*/collections/*/dataStores/*/sessions/*}"
      }
      additional_bindings {
        get: "/v1/{name=projects/*/locations/*/collections/*/engines/*/sessions/*}"
      }
    };
    option (google.api.method_signature) = "name";
  }

  // Lists all Sessions by their parent
  // [DataStore][google.cloud.discoveryengine.v1.DataStore].
  rpc ListSessions(ListSessionsRequest) returns (ListSessionsResponse) {
    option (google.api.http) = {
      get: "/v1/{parent=projects/*/locations/*/dataStores/*}/sessions"
      additional_bindings {
        get: "/v1/{parent=projects/*/locations/*/collections/*/dataStores/*}/sessions"
      }
      additional_bindings {
        get: "/v1/{parent=projects/*/locations/*/collections/*/engines/*}/sessions"
      }
    };
    option (google.api.method_signature) = "parent";
  }
}

// Request message for
// [ConversationalSearchService.ConverseConversation][google.cloud.discoveryengine.v1.ConversationalSearchService.ConverseConversation]
// method.
message ConverseConversationRequest {
  // Required. The resource name of the Conversation to get. Format:
  // `projects/{project_number}/locations/{location_id}/collections/{collection}/dataStores/{data_store_id}/conversations/{conversation_id}`.
  // Use
  // `projects/{project_number}/locations/{location_id}/collections/{collection}/dataStores/{data_store_id}/conversations/-`
  // to activate auto session mode, which automatically creates a new
  // conversation inside a ConverseConversation session.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "discoveryengine.googleapis.com/Conversation"
    }
  ];

  // Required. Current user input.
  TextInput query = 2 [(google.api.field_behavior) = REQUIRED];

  // The resource name of the Serving Config to use. Format:
  // `projects/{project_number}/locations/{location_id}/collections/{collection}/dataStores/{data_store_id}/servingConfigs/{serving_config_id}`
  // If this is not set, the default serving config will be used.
  string serving_config = 3 [(google.api.resource_reference) = {
    type: "discoveryengine.googleapis.com/ServingConfig"
  }];

  // The conversation to be used by auto session only. The name field will be
  // ignored as we automatically assign new name for the conversation in auto
  // session.
  Conversation conversation = 5;

  // Whether to turn on safe search.
  bool safe_search = 6;

  // The user labels applied to a resource must meet the following requirements:
  //
  // * Each resource can have multiple labels, up to a maximum of 64.
  // * Each label must be a key-value pair.
  // * Keys have a minimum length of 1 character and a maximum length of 63
  //   characters and cannot be empty. Values can be empty and have a maximum
  //   length of 63 characters.
  // * Keys and values can contain only lowercase letters, numeric characters,
  //   underscores, and dashes. All characters must use UTF-8 encoding, and
  //   international characters are allowed.
  // * The key portion of a label must be unique. However, you can use the same
  //   key with multiple resources.
  // * Keys must start with a lowercase letter or international character.
  //
  // See [Google Cloud
  // Document](https://cloud.google.com/resource-manager/docs/creating-managing-labels#requirements)
  // for more details.
  map<string, string> user_labels = 7;

  // A specification for configuring the summary returned in the response.
  SearchRequest.ContentSearchSpec.SummarySpec summary_spec = 8;

  // The filter syntax consists of an expression language for constructing a
  // predicate from one or more fields of the documents being filtered. Filter
  // expression is case-sensitive. This will be used to filter search results
  // which may affect the summary response.
  //
  // If this field is unrecognizable, an  `INVALID_ARGUMENT`  is returned.
  //
  // Filtering in Vertex AI Search is done by mapping the LHS filter key to a
  // key property defined in the Vertex AI Search backend -- this mapping is
  // defined by the customer in their schema. For example a media customer might
  // have a field 'name' in their schema. In this case the filter would look
  // like this: filter --> name:'ANY("king kong")'
  //
  // For more information about filtering including syntax and filter
  // operators, see
  // [Filter](https://cloud.google.com/generative-ai-app-builder/docs/filter-search-metadata)
  string filter = 9;

  // Boost specification to boost certain documents in search results which may
  // affect the converse response. For more information on boosting, see
  // [Boosting](https://cloud.google.com/retail/docs/boosting#boost)
  SearchRequest.BoostSpec boost_spec = 10;
}

// Response message for
// [ConversationalSearchService.ConverseConversation][google.cloud.discoveryengine.v1.ConversationalSearchService.ConverseConversation]
// method.
message ConverseConversationResponse {
  // Answer to the current query.
  Reply reply = 1;

  // Updated conversation including the answer.
  Conversation conversation = 2;

  // Search Results.
  repeated SearchResponse.SearchResult search_results = 3;
}

// Request for CreateConversation method.
message CreateConversationRequest {
  // Required. Full resource name of parent data store. Format:
  // `projects/{project_number}/locations/{location_id}/collections/{collection}/dataStores/{data_store_id}`
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "discoveryengine.googleapis.com/DataStore"
    }
  ];

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

// Request for UpdateConversation method.
message UpdateConversationRequest {
  // Required. The Conversation to update.
  Conversation conversation = 1 [(google.api.field_behavior) = REQUIRED];

  // Indicates which fields in the provided
  // [Conversation][google.cloud.discoveryengine.v1.Conversation] to update. The
  // following are NOT supported:
  //
  // * [Conversation.name][google.cloud.discoveryengine.v1.Conversation.name]
  //
  // If not set or empty, all supported fields are updated.
  google.protobuf.FieldMask update_mask = 2;
}

// Request for DeleteConversation method.
message DeleteConversationRequest {
  // Required. The resource name of the Conversation to delete. Format:
  // `projects/{project_number}/locations/{location_id}/collections/{collection}/dataStores/{data_store_id}/conversations/{conversation_id}`
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "discoveryengine.googleapis.com/Conversation"
    }
  ];
}

// Request for GetConversation method.
message GetConversationRequest {
  // Required. The resource name of the Conversation to get. Format:
  // `projects/{project_number}/locations/{location_id}/collections/{collection}/dataStores/{data_store_id}/conversations/{conversation_id}`
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "discoveryengine.googleapis.com/Conversation"
    }
  ];
}

// Request for ListConversations method.
message ListConversationsRequest {
  // Required. The data store resource name. Format:
  // `projects/{project_number}/locations/{location_id}/collections/{collection}/dataStores/{data_store_id}`
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "discoveryengine.googleapis.com/DataStore"
    }
  ];

  // Maximum number of results to return. If unspecified, defaults
  // to 50. Max allowed value is 1000.
  int32 page_size = 2;

  // A page token, received from a previous `ListConversations` call.
  // Provide this to retrieve the subsequent page.
  string page_token = 3;

  // A filter to apply on the list results. The supported features are:
  // user_pseudo_id, state.
  //
  // Example:
  // "user_pseudo_id = some_id"
  string filter = 4;

  // A comma-separated list of fields to order by, sorted in ascending order.
  // Use "desc" after a field name for descending.
  // Supported fields:
  //   * `update_time`
  //   * `create_time`
  //   * `conversation_name`
  //
  // Example:
  // "update_time desc"
  // "create_time"
  string order_by = 5;
}

// Response for ListConversations method.
message ListConversationsResponse {
  // All the Conversations for a given data store.
  repeated Conversation conversations = 1;

  // Pagination token, if not returned indicates the last page.
  string next_page_token = 2;
}

// Request message for
// [ConversationalSearchService.AnswerQuery][google.cloud.discoveryengine.v1.ConversationalSearchService.AnswerQuery]
// method.
message AnswerQueryRequest {
  // Safety specification.
  message SafetySpec {
    // Enable the safety filtering on the answer response. It is false by
    // default.
    bool enable = 1;
  }

  // Related questions specification.
  message RelatedQuestionsSpec {
    // Enable related questions feature if true.
    bool enable = 1;
  }

  // Answer generation specification.
  message AnswerGenerationSpec {
    // Answer Generation Model specification.
    message ModelSpec {
      // Model version. If not set, it will use the default stable model.
      // Allowed values are: stable, preview.
      string model_version = 1;
    }

    // Answer generation prompt specification.
    message PromptSpec {
      // Customized preamble.
      string preamble = 1;
    }

    // Answer generation model specification.
    ModelSpec model_spec = 1;

    // Answer generation prompt specification.
    PromptSpec prompt_spec = 2;

    // Specifies whether to include citation metadata in the answer. The default
    // value is `false`.
    bool include_citations = 3;

    // Language code for Answer. Use language tags defined by
    // [BCP47](https://www.rfc-editor.org/rfc/bcp/bcp47.txt).
    // Note: This is an experimental feature.
    string answer_language_code = 4;

    // Specifies whether to filter out adversarial queries. The default value
    // is `false`.
    //
    // Google employs search-query classification to detect adversarial
    // queries. No answer is returned if the search query is classified as an
    // adversarial query. For example, a user might ask a question regarding
    // negative comments about the company or submit a query designed to
    // generate unsafe, policy-violating output. If this field is set to
    // `true`, we skip generating answers for adversarial queries and return
    // fallback messages instead.
    bool ignore_adversarial_query = 5;

    // Specifies whether to filter out queries that are not answer-seeking.
    // The default value is `false`.
    //
    // Google employs search-query classification to detect answer-seeking
    // queries. No answer is returned if the search query is classified as a
    // non-answer seeking query. If this field is set to `true`, we skip
    // generating answers for non-answer seeking queries and return
    // fallback messages instead.
    bool ignore_non_answer_seeking_query = 6;

    // Specifies whether to filter out queries that have low relevance.
    //
    // If this field is set to `false`, all search results are used regardless
    // of relevance to generate answers. If set to `true` or unset, the behavior
    // will be determined automatically by the service.
    optional bool ignore_low_relevant_content = 7;
  }

  // Search specification.
  message SearchSpec {
    // Search parameters.
    message SearchParams {
      // Number of search results to return.
      // The default value is 10.
      int32 max_return_results = 1;

      // The filter syntax consists of an expression language for constructing
      // a predicate from one or more fields of the documents being filtered.
      // Filter expression is case-sensitive. This will be used to filter
      // search results which may affect the Answer response.
      //
      // If this field is unrecognizable, an  `INVALID_ARGUMENT`  is returned.
      //
      // Filtering in Vertex AI Search is done by mapping the LHS filter key
      // to a key property defined in the Vertex AI Search backend -- this
      // mapping is defined by the customer in their schema. For example a
      // media customers might have a field 'name' in their schema. In this
      // case the filter would look like this: filter --> name:'ANY("king
      // kong")'
      //
      // For more information about filtering including syntax and filter
      // operators, see
      // [Filter](https://cloud.google.com/generative-ai-app-builder/docs/filter-search-metadata)
      string filter = 2;

      // Boost specification to boost certain documents in search results which
      // may affect the answer query response. For more information on boosting,
      // see [Boosting](https://cloud.google.com/retail/docs/boosting#boost)
      SearchRequest.BoostSpec boost_spec = 3;

      // The order in which documents are returned. Documents can be ordered
      // by a field in an [Document][google.cloud.discoveryengine.v1.Document]
      // object. Leave it unset if ordered by relevance. `order_by` expression
      // is case-sensitive. For more information on ordering, see
      // [Ordering](https://cloud.google.com/retail/docs/filter-and-order#order)
      //
      // If this field is unrecognizable, an `INVALID_ARGUMENT` is returned.
      string order_by = 4;

      // Specifies the search result mode. If unspecified, the
      // search result mode is based on
      // [DataStore.DocumentProcessingConfig.chunking_config][]:
      // * If [DataStore.DocumentProcessingConfig.chunking_config][] is
      // specified,
      //   it defaults to `CHUNKS`.
      // * Otherwise, it defaults to `DOCUMENTS`.
      // See [parse and chunk
      // documents](https://cloud.google.com/generative-ai-app-builder/docs/parse-chunk-documents)
      SearchRequest.ContentSearchSpec.SearchResultMode search_result_mode = 5;

      // Specs defining dataStores to filter on in a search call and
      // configurations for those dataStores. This is only considered for
      // engines with multiple dataStores use case. For single dataStore within
      // an engine, they should use the specs at the top level.
      repeated SearchRequest.DataStoreSpec data_store_specs = 7;
    }

    // Search result list.
    message SearchResultList {
      // Search result.
      message SearchResult {
        // Unstructured document information.
        message UnstructuredDocumentInfo {
          // Document context.
          message DocumentContext {
            // Page identifier.
            string page_identifier = 1;

            // Document content.
            string content = 2;
          }

          // Extractive segment.
          // [Guide](https://cloud.google.com/generative-ai-app-builder/docs/snippets#extractive-segments)
          message ExtractiveSegment {
            // Page identifier.
            string page_identifier = 1;

            // Extractive segment content.
            string content = 2;
          }

          // Extractive answer.
          // [Guide](https://cloud.google.com/generative-ai-app-builder/docs/snippets#get-answers)
          message ExtractiveAnswer {
            // Page identifier.
            string page_identifier = 1;

            // Extractive answer content.
            string content = 2;
          }

          // Document resource name.
          string document = 1 [(google.api.resource_reference) = {
            type: "discoveryengine.googleapis.com/Document"
          }];

          // URI for the document.
          string uri = 2;

          // Title.
          string title = 3;

          // List of document contexts.
          repeated DocumentContext document_contexts = 4;

          // List of extractive segments.
          repeated ExtractiveSegment extractive_segments = 5;

          // List of extractive answers.
          repeated ExtractiveAnswer extractive_answers = 6;
        }

        // Chunk information.
        message ChunkInfo {
          // Chunk resource name.
          string chunk = 1 [(google.api.resource_reference) = {
            type: "discoveryengine.googleapis.com/Chunk"
          }];

          // Chunk textual content.
          string content = 2;
        }

        // Search result content.
        oneof content {
          // Unstructured document information.
          UnstructuredDocumentInfo unstructured_document_info = 1;

          // Chunk information.
          ChunkInfo chunk_info = 2;
        }
      }

      // Search results.
      repeated SearchResult search_results = 1;
    }

    // Search parameters to control the search behavior.
    // Or provide search result list to generate answer.
    oneof input {
      // Search parameters.
      SearchParams search_params = 1;

      // Search result list.
      SearchResultList search_result_list = 2;
    }
  }

  // Query understanding specification.
  message QueryUnderstandingSpec {
    // Query classification specification.
    message QueryClassificationSpec {
      // Query classification types.
      enum Type {
        // Unspecified query classification type.
        TYPE_UNSPECIFIED = 0;

        // Adversarial query classification type.
        ADVERSARIAL_QUERY = 1;

        // Non-answer-seeking query classification type.
        NON_ANSWER_SEEKING_QUERY = 2;
      }

      // Enabled query classification types.
      repeated Type types = 1;
    }

    // Query rephraser specification.
    message QueryRephraserSpec {
      // Disable query rephraser.
      bool disable = 1;

      // Max rephrase steps.
      // The max number is 5 steps.
      // If not set or set to < 1, it will be set to 1 by default.
      int32 max_rephrase_steps = 2;
    }

    // Query classification specification.
    QueryClassificationSpec query_classification_spec = 1;

    // Query rephraser specification.
    QueryRephraserSpec query_rephraser_spec = 2;
  }

  // Required. The resource name of the Search serving config, such as
  // `projects/*/locations/global/collections/default_collection/engines/*/servingConfigs/default_serving_config`,
  // or
  // `projects/*/locations/global/collections/default_collection/dataStores/*/servingConfigs/default_serving_config`.
  // This field is used to identify the serving configuration name, set
  // of models used to make the search.
  string serving_config = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "discoveryengine.googleapis.com/ServingConfig"
    }
  ];

  // Required. Current user query.
  Query query = 2 [(google.api.field_behavior) = REQUIRED];

  // The session resource name. Not required.
  //
  // When session field is not set, the API is in sessionless mode.
  //
  // We support auto session mode: users can use the wildcard symbol `-` as
  // session ID.  A new ID will be automatically generated and assigned.
  string session = 3 [(google.api.resource_reference) = {
    type: "discoveryengine.googleapis.com/Session"
  }];

  // Model specification.
  SafetySpec safety_spec = 4;

  // Related questions specification.
  RelatedQuestionsSpec related_questions_spec = 5;

  // Answer generation specification.
  AnswerGenerationSpec answer_generation_spec = 7;

  // Search specification.
  SearchSpec search_spec = 8;

  // Query understanding specification.
  QueryUnderstandingSpec query_understanding_spec = 9;

  // Asynchronous mode control.
  //
  // If enabled, the response will be returned with answer/session resource
  // name without final answer. The API users need to do the polling to get
  // the latest status of answer/session by calling
  // [ConversationalSearchService.GetAnswer][google.cloud.discoveryengine.v1.ConversationalSearchService.GetAnswer]
  // or
  // [ConversationalSearchService.GetSession][google.cloud.discoveryengine.v1.ConversationalSearchService.GetSession]
  // method.
  bool asynchronous_mode = 10;

  // A unique identifier for tracking visitors. For example, this could be
  // implemented with an HTTP cookie, which should be able to uniquely identify
  // a visitor on a single device. This unique identifier should not change if
  // the visitor logs in or out of the website.
  //
  // This field should NOT have a fixed value such as `unknown_visitor`.
  //
  // The field must be a UTF-8 encoded string with a length limit of 128
  // characters. Otherwise, an  `INVALID_ARGUMENT`  error is returned.
  string user_pseudo_id = 12;

  // The user labels applied to a resource must meet the following requirements:
  //
  // * Each resource can have multiple labels, up to a maximum of 64.
  // * Each label must be a key-value pair.
  // * Keys have a minimum length of 1 character and a maximum length of 63
  //   characters and cannot be empty. Values can be empty and have a maximum
  //   length of 63 characters.
  // * Keys and values can contain only lowercase letters, numeric characters,
  //   underscores, and dashes. All characters must use UTF-8 encoding, and
  //   international characters are allowed.
  // * The key portion of a label must be unique. However, you can use the same
  //   key with multiple resources.
  // * Keys must start with a lowercase letter or international character.
  //
  // See [Google Cloud
  // Document](https://cloud.google.com/resource-manager/docs/creating-managing-labels#requirements)
  // for more details.
  map<string, string> user_labels = 13;
}

// Response message for
// [ConversationalSearchService.AnswerQuery][google.cloud.discoveryengine.v1.ConversationalSearchService.AnswerQuery]
// method.
message AnswerQueryResponse {
  // Answer resource object.
  // If [AnswerQueryRequest.StepSpec.max_step_count][] is greater than 1,
  // use [Answer.name][google.cloud.discoveryengine.v1.Answer.name] to fetch
  // answer information using
  // [ConversationalSearchService.GetAnswer][google.cloud.discoveryengine.v1.ConversationalSearchService.GetAnswer]
  // API.
  Answer answer = 1;

  // Session resource object.
  // It will be only available when session field is set and valid in the
  // [AnswerQueryRequest][google.cloud.discoveryengine.v1.AnswerQueryRequest]
  // request.
  Session session = 2;

  // A global unique ID used for logging.
  string answer_query_token = 3;
}

// Request for GetAnswer method.
message GetAnswerRequest {
  // Required. The resource name of the Answer to get. Format:
  // `projects/{project_number}/locations/{location_id}/collections/{collection}/engines/{engine_id}/sessions/{session_id}/answers/{answer_id}`
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "discoveryengine.googleapis.com/Answer"
    }
  ];
}

// Request for CreateSession method.
message CreateSessionRequest {
  // Required. Full resource name of parent data store. Format:
  // `projects/{project_number}/locations/{location_id}/collections/{collection}/dataStores/{data_store_id}`
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "discoveryengine.googleapis.com/DataStore"
    }
  ];

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

// Request for UpdateSession method.
message UpdateSessionRequest {
  // Required. The Session to update.
  Session session = 1 [(google.api.field_behavior) = REQUIRED];

  // Indicates which fields in the provided
  // [Session][google.cloud.discoveryengine.v1.Session] to update. The following
  // are NOT supported:
  //
  // * [Session.name][google.cloud.discoveryengine.v1.Session.name]
  //
  // If not set or empty, all supported fields are updated.
  google.protobuf.FieldMask update_mask = 2;
}

// Request for DeleteSession method.
message DeleteSessionRequest {
  // Required. The resource name of the Session to delete. Format:
  // `projects/{project_number}/locations/{location_id}/collections/{collection}/dataStores/{data_store_id}/sessions/{session_id}`
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "discoveryengine.googleapis.com/Session"
    }
  ];
}

// Request for GetSession method.
message GetSessionRequest {
  // Required. The resource name of the Session to get. Format:
  // `projects/{project_number}/locations/{location_id}/collections/{collection}/dataStores/{data_store_id}/sessions/{session_id}`
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "discoveryengine.googleapis.com/Session"
    }
  ];
}

// Request for ListSessions method.
message ListSessionsRequest {
  // Required. The data store resource name. Format:
  // `projects/{project_number}/locations/{location_id}/collections/{collection}/dataStores/{data_store_id}`
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "discoveryengine.googleapis.com/DataStore"
    }
  ];

  // Maximum number of results to return. If unspecified, defaults
  // to 50. Max allowed value is 1000.
  int32 page_size = 2;

  // A page token, received from a previous `ListSessions` call.
  // Provide this to retrieve the subsequent page.
  string page_token = 3;

  // A filter to apply on the list results. The supported features are:
  // user_pseudo_id, state.
  //
  // Example:
  // "user_pseudo_id = some_id"
  string filter = 4;

  // A comma-separated list of fields to order by, sorted in ascending order.
  // Use "desc" after a field name for descending.
  // Supported fields:
  //   * `update_time`
  //   * `create_time`
  //   * `session_name`
  //
  // Example:
  // "update_time desc"
  // "create_time"
  string order_by = 5;
}

// Response for ListSessions method.
message ListSessionsResponse {
  // All the Sessions for a given data store.
  repeated Session sessions = 1;

  // Pagination token, if not returned indicates the last page.
  string next_page_token = 2;
}
