// Copyright 2026 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.geminidataanalytics.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/geminidataanalytics/v1/context.proto";
import "google/cloud/geminidataanalytics/v1/conversation.proto";
import "google/cloud/geminidataanalytics/v1/credentials.proto";
import "google/cloud/geminidataanalytics/v1/datasource.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/struct.proto";
import "google/protobuf/timestamp.proto";

option csharp_namespace = "Google.Cloud.GeminiDataAnalytics.V1";
option go_package = "cloud.google.com/go/geminidataanalytics/apiv1/geminidataanalyticspb;geminidataanalyticspb";
option java_multiple_files = true;
option java_outer_classname = "DataChatServiceProto";
option java_package = "com.google.cloud.geminidataanalytics.v1";
option php_namespace = "Google\\Cloud\\GeminiDataAnalytics\\V1";
option ruby_package = "Google::Cloud::GeminiDataAnalytics::V1";

// Service to ask a natural language question on top of BigQuery
// and Looker Studio datasources to get back streamed responses of various kinds
// to help provide a rich conversational answer.
service DataChatService {
  option (google.api.default_host) = "geminidataanalytics.googleapis.com";
  option (google.api.oauth_scopes) =
      "https://www.googleapis.com/auth/cloud-platform";

  // Answers a data question by generating a stream of
  // [Message][google.cloud.geminidataanalytics.v1.Message] objects.
  rpc Chat(ChatRequest) returns (stream Message) {
    option (google.api.http) = {
      post: "/v1/{parent=projects/*/locations/*}:chat"
      body: "*"
    };
  }

  // Creates a new conversation to persist the conversation history. Each
  // conversation will have multiple messages associated with it.
  rpc CreateConversation(CreateConversationRequest) returns (Conversation) {
    option (google.api.http) = {
      post: "/v1/{parent=projects/*/locations/*}/conversations"
      body: "conversation"
    };
    option (google.api.method_signature) =
        "parent,conversation,conversation_id";
  }

  // Deletes a conversation.
  rpc DeleteConversation(DeleteConversationRequest)
      returns (google.protobuf.Empty) {
    option (google.api.http) = {
      delete: "/v1/{name=projects/*/locations/*/conversations/*}"
    };
    option (google.api.method_signature) = "name";
  }

  // Gets details of a single conversation by using conversation id and parent.
  rpc GetConversation(GetConversationRequest) returns (Conversation) {
    option (google.api.http) = {
      get: "/v1/{name=projects/*/locations/*/conversations/*}"
    };
    option (google.api.method_signature) = "name";
  }

  // Lists all conversations for a given parent.
  rpc ListConversations(ListConversationsRequest)
      returns (ListConversationsResponse) {
    option (google.api.http) = {
      get: "/v1/{parent=projects/*/locations/*}/conversations"
    };
    option (google.api.method_signature) = "parent";
  }

  // Lists all messages for a given conversation.
  rpc ListMessages(ListMessagesRequest) returns (ListMessagesResponse) {
    option (google.api.http) = {
      get: "/v1/{parent=projects/*/locations/*/conversations/*}/messages"
    };
    option (google.api.method_signature) = "parent";
  }
}

// Request for listing chat messages based on parent and conversation_id.
message ListMessagesRequest {
  // Required. The conversation to list messages under.
  // Format:
  // `projects/{project}/locations/{location}/conversations/{conversation_id}`
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "geminidataanalytics.googleapis.com/Conversation"
    }
  ];

  // Optional. Requested page size. Server may return fewer items than
  // requested. The max page size is `100`. All larger page sizes will be
  // coerced to `100`. If unspecified, server will pick `50` as an appropriate
  // default.
  int32 page_size = 3 [(google.api.field_behavior) = OPTIONAL];

  // Optional. A token identifying a page of results the server should return.
  string page_token = 4 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Filtering results. See [AIP-160](https://google.aip.dev/160) for
  // syntax.
  //
  // ListMessages allows filtering by:
  //  * create_time (e.g., `createTime > "2025-01-28T06:51:56-08:00"`)
  //  * update_time
  string filter = 5 [(google.api.field_behavior) = OPTIONAL];
}

// Response for listing chat messages.
message ListMessagesResponse {
  // The list of chat messages.
  repeated StorageMessage messages = 1;

  // A token identifying a page of results the server should return.
  string next_page_token = 2;
}

// A stored message containing user message or system message.
message StorageMessage {
  // The unique resource name of a chat message.
  string message_id = 1;

  // The message content.
  Message message = 2;
}

// Request for Chat.
message ChatRequest {
  // Mode of thinking for the agent.
  enum ThinkingMode {
    // Unspecified thinking mode, agent will use THINKING mode by default.
    THINKING_MODE_UNSPECIFIED = 0;

    // Fast mode, answers quickly.
    FAST = 1;

    // Thinking mode, solves complex problems.
    THINKING = 2;
  }

  // Model selection for the agent.
  enum Model {
    // No model specified. The default model will be used. Currently, this is
    // `gemini-3.0-flash-preview`.
    MODEL_UNSPECIFIED = 0;

    // Use the most up-to-date non-preview model. Currently, this is
    // `gemini-2.5-flash`. This constrains the request level settings. The
    // default will change to `gemini-2.5-flash`, and setting `thinking_mode`
    // will not be supported.
    LATEST_GA_MODEL = 1;
  }

  // Context Provider for the chat request.
  // It can either be -
  // inline_context, which is a context provided inline in the request.
  // data_agent, which is a reference to a data agent resource.
  // conversation_reference, which is a reference to a persisted conversation
  // and context using conversation_id and agent_id.
  oneof context_provider {
    // Optional. Inline context for the chat request. Use this to chat
    // statelessly (without managed conversation persistence and without an
    // Agent) by passing all context inline.
    Context inline_context = 101 [(google.api.field_behavior) = OPTIONAL];

    // Optional. Reference to a persisted conversation and agent context.
    // Use this to chat with an Agent using managed conversation persistence.
    ConversationReference conversation_reference = 103
        [(google.api.field_behavior) = OPTIONAL];

    // Optional. Context for the chat request. Use this to chat with an Agent
    // statelessly, without managed conversation persistence.
    DataAgentContext data_agent_context = 104
        [(google.api.field_behavior) = OPTIONAL];

    // Optional. Context with client managed resources.
    // Some clients may not use GDA managed resources including
    // conversations and agents, instead they create and manage their own
    // conversations and agents resources.
    ClientManagedResourceContext client_managed_resource_context = 105
        [(google.api.field_behavior) = OPTIONAL];
  }

  // Optional settings to customize request behavior, specific to the target
  // datasource.
  oneof datasource_settings {
    // Optional. Looker specific settings.
    LookerSettings looker_settings = 13
        [(google.api.field_behavior) = OPTIONAL];
  }

  // Required. The parent value for chat request.
  // Pattern: `projects/{project}/locations/{location}`
  string parent = 3 [(google.api.field_behavior) = REQUIRED];

  // Required. Content of current conversation.
  repeated Message messages = 2 [(google.api.field_behavior) = REQUIRED];

  // Optional. The credentials to use when calling the data source(s) specified
  // in the context.
  //
  // This field can be used to provide credentials for various data sources.
  // For example, when connecting to Looker, it currently supports both OAuth
  // token and API key-based credentials, as described in
  // [Authentication with an
  // SDK](https://cloud.google.com/looker/docs/api-auth#authentication_with_an_sdk).
  Credentials credentials = 7 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The thinking mode to use for the agent loop.
  // Defaults to THINKING_MODE_UNSPECIFIED if not specified.
  ThinkingMode thinking_mode = 9 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The model to use for the agent loop when processing the request.
  // This setting only has an effect when context.options.model is not set.
  Model model = 11 [(google.api.field_behavior) = OPTIONAL];
}

// Context for the chat request using a data agent.
message DataAgentContext {
  // List of context versions supported by DCS.
  // There are two versions of context. This is to maintain versioning for the
  // data agent.
  enum ContextVersion {
    // Unspecified or unrecognized.
    CONTEXT_VERSION_UNSPECIFIED = 0;

    // Using this version, DCS will use the latest staging context for the
    // data agent.
    STAGING = 1;

    // Using this version, DCS will use the latest published context for the
    // data agent.
    PUBLISHED = 2;
  }

  // Required. The name of the data agent resource.
  string data_agent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "geminidataanalytics.googleapis.com/DataAgent"
    }
  ];

  // Optional. Version of context to be used by DCS (e.g. STAGING, PUBLISHED)
  ContextVersion context_version = 3 [(google.api.field_behavior) = OPTIONAL];
}

// Reference to a persisted conversation and agent context.
message ConversationReference {
  // Required. Name of the conversation resource.
  // Format:
  // `projects/{project}/locations/{location}/conversations/{conversation_id}`
  string conversation = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "geminidataanalytics.googleapis.com/Conversation"
    }
  ];

  // Required. Context for the chat request using a data agent.
  DataAgentContext data_agent_context = 3
      [(google.api.field_behavior) = REQUIRED];
}

// Context with client managed resources.
// Some clients may not use GDA managed resources including
// conversations and agents, instead they create and manage their own
// conversations and agents resources.
message ClientManagedResourceContext {
  // Required. Context for the chat request. Use this to chat without GDA API
  // managed conversation and agent persistence by passing all context inline.
  Context inline_context = 1 [(google.api.field_behavior) = REQUIRED];

  // Optional. The client managed conversation id.
  string conversation_id = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The client managed agent id.
  string agent_id = 3 [(google.api.field_behavior) = OPTIONAL];
}

// A message from an interaction between the user and the system.
message Message {
  // The kind of message.
  oneof kind {
    // A message from the user that is interacting with the system.
    UserMessage user_message = 2;

    // A message from the system in response to the user.
    SystemMessage system_message = 3;
  }

  // Output only. For user messages, this is the time at which the system
  // received the message. For system messages, this is the time at which the
  // system generated the message.
  google.protobuf.Timestamp timestamp = 1
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Optional. unique id of the message in the conversation for persistence.
  string message_id = 4 [(google.api.field_behavior) = OPTIONAL];
}

// Message to hold Looker specific custom settings.
message LookerSettings {
  // Optional. Whether to operate in Looker's Development Mode.
  // If true, the API session will be switched to the "dev" workspace,
  // allowing interaction with LookML changes in the user's development branch.
  // If false or unset, the session remains in the default state (Production
  // Mode).
  // See https://cloud.google.com/looker/docs/dev-mode-prod-mode.
  bool enable_dev_mode = 1 [(google.api.field_behavior) = OPTIONAL];
}

// A message from the user that is interacting with the system.
message UserMessage {
  // The kind of content in the user message.
  oneof kind {
    // Text should use this field instead of blob.
    string text = 1;
  }
}

// A message from the system in response to the user. This message can also be a
// message from the user as historical context for multi-turn conversations with
// the system.
message SystemMessage {
  // The kind of content in the system message.
  oneof kind {
    // A direct natural language response to the user message.
    TextMessage text = 1;

    // A message produced during schema resolution.
    SchemaMessage schema = 2;

    // A message produced during data retrieval.
    DataMessage data = 3;

    // A message produced during analysis.
    AnalysisMessage analysis = 4;

    // A message produced during chart generation.
    ChartMessage chart = 5;

    // An error message.
    ErrorMessage error = 6;

    // Optional. A message containing example queries.
    ExampleQueries example_queries = 13
        [(google.api.field_behavior) = OPTIONAL];
  }

  // Identifies the group that the event belongs to. Similar events are deemed
  // to be logically relevant to each other and should be shown together in
  // the UI.
  optional int32 group_id = 12;

  // Output only. Citation information for the system message.
  Citation citation = 15 [(google.api.field_behavior) = OUTPUT_ONLY];
}

// A multi-part text message.
message TextMessage {
  // The type of the text message.
  enum TextType {
    // The default text type.
    TEXT_TYPE_UNSPECIFIED = 0;

    // The text is a final response to the user question.
    FINAL_RESPONSE = 1;

    // The text is a thought from the model.
    THOUGHT = 2;

    // The text is an informational message about the agent's progress, such as
    // a tool being invoked. This is distinct from the agent's internal thought
    // process (`THOUGHT`) and the final answer to the user
    // (`FINAL_RESPONSE`). These messages provide insight into the agent's
    // actions.
    PROGRESS = 3;

    // The text is a list of follow-up questions suggested.
    // Each item in parts is a follow-up question.
    FOLLOWUP_QUESTIONS = 4;
  }

  // Optional. The parts of the message.
  repeated string parts = 1 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The type of the text message.
  TextType text_type = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. An opaque signature for a thought so it can be reused in
  // subsequent requests.
  bytes thought_signature = 3 [(google.api.field_behavior) = OPTIONAL];
}

// A message produced during schema resolution.
message SchemaMessage {
  // Whether this message contains the query or the result of the schema
  // resolution.
  oneof kind {
    // A schema resolution query.
    SchemaQuery query = 1;

    // The result of a schema resolution query.
    SchemaResult result = 2;
  }
}

// A query for resolving the schema relevant to the posed question.
message SchemaQuery {
  // Optional. The question to send to the system for schema resolution.
  string question = 1 [(google.api.field_behavior) = OPTIONAL];
}

// The result of schema resolution.
message SchemaResult {
  // Optional. The datasources used to resolve the schema query.
  repeated Datasource datasources = 1 [(google.api.field_behavior) = OPTIONAL];
}

// A message produced during data retrieval.
message DataMessage {
  // Whether this message contains the query, the result, or generated SQL for
  // the data retrieval.
  oneof kind {
    // A data retrieval query.
    DataQuery query = 1;

    // SQL generated by the system to retrieve data.
    string generated_sql = 2;

    // Retrieved data.
    DataResult result = 3;

    // A BigQuery job executed by the system to retrieve data.
    BigQueryJob big_query_job = 5;

    // A pre-existing query that was matched to retrieve data.
    MatchedQuery matched_query = 6;
  }
}

// A query for retrieving data.
message DataQuery {
  // The type of query to execute.
  oneof query_type {
    // Optional. A query for retrieving data from a Looker explore.
    LookerQuery looker = 4 [(google.api.field_behavior) = OPTIONAL];
  }

  // Optional. A natural language question to answer.
  string question = 1 [(google.api.field_behavior) = OPTIONAL];

  // Optional. A snake-case name for the query that reflects its intent. It is
  // used to name the corresponding data result, so that it can be referenced in
  // later steps.
  //
  // * Example: "total_sales_by_product"
  // * Example: "sales_for_product_12345"
  string name = 3 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The datasources available to answer the question.
  repeated Datasource datasources = 2 [(google.api.field_behavior) = OPTIONAL];
}

// Retrieved data.
message DataResult {
  // Optional. A snake-case name for the data result that reflects its contents.
  // The name is used to pass the result around by reference, and serves as a
  // signal about its meaning.
  //
  // * Example: "total_sales_by_product"
  // * Example: "sales_for_product_12345"
  string name = 3 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The schema of the data.
  Schema schema = 5 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The content of the data. Each row is a struct that matches the
  // schema. Simple values are represented as strings, while nested structures
  // are represented as lists or structs.
  repeated google.protobuf.Struct data = 2
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. Formatted representation of the data, when applicable.
  // Each row is a struct that directly corresponds to the row at the same index
  // within the `data` field. Its values are string representations of the
  // original data, formatted according to data source specifications (e.g.,
  // "$1,234.56" for currency). Columns without formatting will default to
  // their raw value representation. If no columns have formatting rules, this
  // field will be empty.
  repeated google.protobuf.Struct formatted_data = 6
      [(google.api.field_behavior) = OPTIONAL];
}

// A BigQuery job executed by the system.
message BigQueryJob {
  // Required. The project that the job belongs to.
  //
  // See
  // [JobReference](https://cloud.google.com/bigquery/docs/reference/rest/v2/JobReference).
  string project_id = 1 [(google.api.field_behavior) = REQUIRED];

  // Required. The ID of the job.
  //
  // See
  // [JobReference](https://cloud.google.com/bigquery/docs/reference/rest/v2/JobReference).
  string job_id = 2 [(google.api.field_behavior) = REQUIRED];

  // Optional. The location of the job.
  //
  // See
  // [JobReference](https://cloud.google.com/bigquery/docs/reference/rest/v2/JobReference).
  string location = 5 [(google.api.field_behavior) = OPTIONAL];

  // Optional. A reference to the destination table of the job's query results.
  //
  // See
  // [JobConfigurationQuery](https://cloud.google.com/bigquery/docs/reference/rest/v2/Job#jobconfigurationquery).
  BigQueryTableReference destination_table = 3
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. The schema of the job's query results.
  //
  // See
  // [JobStatistics2](https://cloud.google.com/bigquery/docs/reference/rest/v2/Job#jobstatistics2).
  Schema schema = 7 [(google.api.field_behavior) = OPTIONAL];
}

// A message produced during analysis.
message AnalysisMessage {
  // Whether this message contains the query or one of the events from the
  // analysis.
  oneof kind {
    // An analysis query.
    AnalysisQuery query = 1;

    // An event indicating the progress of the analysis.
    AnalysisEvent progress_event = 2;
  }
}

// A query for performing an analysis.
message AnalysisQuery {
  // Optional. An analysis question to help answer the user's original question.
  string question = 1 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The names of previously retrieved data results to analyze.
  repeated string data_result_names = 2
      [(google.api.field_behavior) = OPTIONAL];
}

// An event indicating the progress of an analysis.
message AnalysisEvent {
  // The kind of event that occurred during the analysis.
  oneof kind {
    // Python codegen planner's reasoning.
    string planner_reasoning = 2;

    // Instructions issued for code generation.
    string coder_instruction = 3;

    // Generated code.
    string code = 4;

    // Output from code execution.
    string execution_output = 5;

    // An error from code execution.
    string execution_error = 6;

    // Result as Vega chart JSON string.
    string result_vega_chart_json = 7;

    // Result as NL string.
    string result_natural_language = 8;

    // Result as CSV string.
    string result_csv_data = 9;

    // Result as a reference to a data source.
    string result_reference_data = 10;

    // A generic error message.
    string error = 11;
  }
}

// A message produced during chart generation.
message ChartMessage {
  // Whether this message contains the query or the result of the chart
  // generation.
  oneof kind {
    // A query for generating a chart.
    ChartQuery query = 1;

    // The result of a chart generation query.
    ChartResult result = 2;
  }
}

// A query for generating a chart.
message ChartQuery {
  // Optional. Natural language instructions for generating the chart.
  string instructions = 1 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The name of a previously retrieved data result to use in the
  // chart.
  string data_result_name = 2 [(google.api.field_behavior) = OPTIONAL];
}

// The result of a chart generation query.
message ChartResult {
  // Optional. A generated Vega chart config.
  // See https://vega.github.io/vega/docs/config/
  google.protobuf.Struct vega_config = 2
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. A rendering of the chart if this was requested in the context.
  Blob image = 3 [(google.api.field_behavior) = OPTIONAL];
}

// An error message from a tool call.
// This message is used to represent an error that occurred while an agent was
// trying to use a tool. It's important to note that not all errors are
// terminal. Many are recoverable, and the agent may use the information from
// this error message to self-correct and retry the tool call or try a
// different approach.
//
// For example, if a data query fails, the agent might receive an
// `ErrorMessage`, analyze it, and then generate a corrected query.
//
// Clients should be cautious about interpreting this message as a definitive
// failure. It can be part of the agent's normal, iterative process of
// completing a task. Surfacing these errors directly to end-users without
// context (e.g., as a "hard failure") may be misleading.
message ErrorMessage {
  // Output only. The text of the error.
  string text = 1 [(google.api.field_behavior) = OUTPUT_ONLY];
}

// A message containing derived and authored example queries.
message ExampleQueries {
  // Optional. A list of derived and authored example queries, providing
  // examples of relevant and commonly used SQL queries and their corresponding
  // natural language queries optionally present. Currently only used for
  // BigQuery data sources.
  repeated ExampleQuery example_queries = 1
      [(google.api.field_behavior) = OPTIONAL];
}

// A blob of data with a MIME type.
message Blob {
  // Required. The IANA standard MIME type of the message data.
  string mime_type = 1 [(google.api.field_behavior) = REQUIRED];

  // Required. The data represented as bytes.
  bytes data = 2 [(google.api.field_behavior) = REQUIRED];
}
