// 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.dialogflow.v2;

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

option cc_enable_arenas = true;
option csharp_namespace = "Google.Cloud.Dialogflow.V2";
option go_package = "cloud.google.com/go/dialogflow/apiv2/dialogflowpb;dialogflowpb";
option java_multiple_files = true;
option java_outer_classname = "GeneratorProto";
option java_package = "com.google.cloud.dialogflow.v2";
option objc_class_prefix = "DF";

// Generator Service for LLM powered Agent Assist. This service manages the
// configurations of user owned Generators, such as description, context and
// instruction, input/output format, etc. The generator resources will be used
// inside a conversation and will be triggered by TriggerEvent to query LLM for
// answers.
service Generators {
  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";

  // Creates a generator.
  rpc CreateGenerator(CreateGeneratorRequest) returns (Generator) {
    option (google.api.http) = {
      post: "/v2/{parent=projects/*/locations/*}/generators"
      body: "generator"
      additional_bindings {
        post: "/v2/{parent=projects/*}/generators"
        body: "generator"
      }
    };
    option (google.api.method_signature) = "parent,generator,generator_id";
  }

  // Retrieves a generator.
  rpc GetGenerator(GetGeneratorRequest) returns (Generator) {
    option (google.api.http) = {
      get: "/v2/{name=projects/*/locations/*/generators/*}"
    };
    option (google.api.method_signature) = "name";
  }

  // Lists generators.
  rpc ListGenerators(ListGeneratorsRequest) returns (ListGeneratorsResponse) {
    option (google.api.http) = {
      get: "/v2/{parent=projects/*/locations/*}/generators"
      additional_bindings { get: "/v2/{parent=projects/*}/generators" }
    };
    option (google.api.method_signature) = "parent";
  }

  // Deletes a generator.
  rpc DeleteGenerator(DeleteGeneratorRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      delete: "/v2/{name=projects/*/locations/*/generators/*}"
    };
    option (google.api.method_signature) = "name";
  }

  // Updates a generator.
  rpc UpdateGenerator(UpdateGeneratorRequest) returns (Generator) {
    option (google.api.http) = {
      patch: "/v2/{generator.name=projects/*/locations/*/generators/*}"
      body: "generator"
    };
    option (google.api.method_signature) = "generator,update_mask";
  }
}

// Request message of CreateGenerator.
message CreateGeneratorRequest {
  // Required. The project/location to create generator for. Format:
  // `projects/<Project ID>/locations/<Location ID>`
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "cloudresourcemanager.googleapis.com/Project"
    }
  ];

  // Required. The generator to create.
  Generator generator = 2 [(google.api.field_behavior) = REQUIRED];

  // Optional. The ID to use for the generator, which will become the final
  // component of the generator's resource name.
  //
  // The generator ID must be compliant with the regression fomula
  // `[a-zA-Z][a-zA-Z0-9_-]*` with the characters length in range of [3,64].
  // If the field is not provided, an Id will be auto-generated.
  // If the field is provided, the caller is resposible for
  // 1. the uniqueness of the ID, otherwise the request will be rejected.
  // 2. the consistency for whether to use custom ID or not under a project to
  // better ensure uniqueness.
  string generator_id = 3 [(google.api.field_behavior) = OPTIONAL];
}

// Request message of GetGenerator.
message GetGeneratorRequest {
  // Required. The generator resource name to retrieve. Format:
  // `projects/<Project ID>/locations/<Location ID>`/generators/<Generator ID>`
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "dialogflow.googleapis.com/Generator"
    }
  ];
}

// Request message of ListGenerators.
message ListGeneratorsRequest {
  // Required. The project/location to list generators for. Format:
  // `projects/<Project ID>/locations/<Location ID>`
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "cloudresourcemanager.googleapis.com/Project"
    }
  ];

  // Optional. Maximum number of conversation models to return in a single page.
  // Default to 10.
  int32 page_size = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The next_page_token value returned from a previous list request.
  string page_token = 3 [(google.api.field_behavior) = OPTIONAL];
}

// Response of ListGenerators.
message ListGeneratorsResponse {
  // List of generators retrieved.
  repeated Generator generators = 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;
}

// Request of DeleteGenerator.
message DeleteGeneratorRequest {
  // Required. The generator resource name to delete. Format:
  // `projects/<Project ID>/locations/<Location ID>/generators/<Generator ID>`
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "dialogflow.googleapis.com/Generator"
    }
  ];
}

// Request of UpdateGenerator.
message UpdateGeneratorRequest {
  // Required. The generator to update.
  // The name field of generator is to identify the generator to update.
  Generator generator = 1 [(google.api.field_behavior) = REQUIRED];

  // Optional. The list of fields to update.
  google.protobuf.FieldMask update_mask = 2
      [(google.api.field_behavior) = OPTIONAL];
}

// Represents a message entry of a conversation.
message MessageEntry {
  // Enumeration of the roles a participant can play in a conversation.
  enum Role {
    // Participant role not set.
    ROLE_UNSPECIFIED = 0;

    // Participant is a human agent.
    HUMAN_AGENT = 1;

    // Participant is an automated agent, such as a Dialogflow agent.
    AUTOMATED_AGENT = 2;

    // Participant is an end user that has called or chatted with
    // Dialogflow services.
    END_USER = 3;
  }

  // Optional. Participant role of the message.
  Role role = 1 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Transcript content of the message.
  string text = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The language of the text. See [Language
  // Support](https://cloud.google.com/dialogflow/docs/reference/language) for a
  // list of the currently supported language codes.
  string language_code = 3 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Create time of the message entry.
  google.protobuf.Timestamp create_time = 4
      [(google.api.field_behavior) = OPTIONAL];
}

// Context of the conversation, including transcripts.
message ConversationContext {
  // Optional. List of message transcripts in the conversation.
  repeated MessageEntry message_entries = 1
      [(google.api.field_behavior) = OPTIONAL];
}

// List of summarization sections.
message SummarizationSectionList {
  // Optional. Summarization sections.
  repeated SummarizationSection summarization_sections = 1
      [(google.api.field_behavior) = OPTIONAL];
}

// Providing examples in the generator (i.e. building a few-shot generator)
// helps convey the desired format of the LLM response.
// NEXT_ID: 10
message FewShotExample {
  // Optional. Conversation transcripts.
  ConversationContext conversation_context = 3
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. Key is the placeholder field name in input, value is the value of
  // the placeholder. E.g. instruction contains "@price", and ingested data has
  // <"price", "10">
  map<string, string> extra_info = 4 [(google.api.field_behavior) = OPTIONAL];

  // Instruction list of this few_shot example.
  oneof instruction_list {
    // Summarization sections.
    SummarizationSectionList summarization_section_list = 6;
  }

  // Required. Example output of the model.
  GeneratorSuggestion output = 7 [(google.api.field_behavior) = REQUIRED];
}

// The parameters of inference.
message InferenceParameter {
  // Optional. Maximum number of the output tokens for the generator.
  optional int32 max_output_tokens = 1 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Controls the randomness of LLM predictions.
  // Low temperature = less random. High temperature = more random.
  // If unset (or 0), uses a default value of 0.
  optional double temperature = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Top-k changes how the model selects tokens for output. A top-k of
  // 1 means the selected token is the most probable among all tokens in the
  // model's vocabulary (also called greedy decoding), while a top-k of 3 means
  // that the next token is selected from among the 3 most probable tokens
  // (using temperature). For each token selection step, the top K tokens with
  // the highest probabilities are sampled. Then tokens are further filtered
  // based on topP with the final token selected using temperature sampling.
  // Specify a lower value for less random responses and a higher value for more
  // random responses. Acceptable value is [1, 40], default to 40.
  optional int32 top_k = 3 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Top-p changes how the model selects tokens for output. Tokens are
  // selected from most K (see topK parameter) probable to least until the sum
  // of their probabilities equals the top-p value. For example, if tokens A, B,
  // and C have a probability of 0.3, 0.2, and 0.1 and the top-p value is 0.5,
  // then the model will select either A or B as the next token (using
  // temperature) and doesn't consider C. The default top-p value is 0.95.
  // Specify a lower value for less random responses and a higher value for more
  // random responses. Acceptable value is [0.0, 1.0], default to 0.95.
  optional double top_p = 4 [(google.api.field_behavior) = OPTIONAL];
}

// Represents the section of summarization.
message SummarizationSection {
  // Type enum of the summarization sections.
  enum Type {
    // Undefined section type, does not return anything.
    TYPE_UNSPECIFIED = 0;

    // What the customer needs help with or has question about.
    // Section name: "situation".
    SITUATION = 1;

    // What the agent does to help the customer.
    // Section name: "action".
    ACTION = 2;

    // Result of the customer service. A single word describing the result
    // of the conversation.
    // Section name: "resolution".
    RESOLUTION = 3;

    // Reason for cancellation if the customer requests for a cancellation.
    // "N/A" otherwise.
    // Section name: "reason_for_cancellation".
    REASON_FOR_CANCELLATION = 4;

    // "Unsatisfied" or "Satisfied" depending on the customer's feelings at
    // the end of the conversation.
    // Section name: "customer_satisfaction".
    CUSTOMER_SATISFACTION = 5;

    // Key entities extracted from the conversation, such as ticket number,
    // order number, dollar amount, etc.
    // Section names are prefixed by "entities/".
    ENTITIES = 6;

    // Customer defined sections.
    CUSTOMER_DEFINED = 7;
  }

  // Optional. Name of the section, for example, "situation".
  string key = 1 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Definition of the section, for example, "what the customer needs
  // help with or has question about."
  string definition = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Type of the summarization section.
  Type type = 3 [(google.api.field_behavior) = OPTIONAL];
}

// Summarization context that customer can configure.
message SummarizationContext {
  // Optional. List of sections. Note it contains both predefined section sand
  // customer defined sections.
  repeated SummarizationSection summarization_sections = 1
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. List of few shot examples.
  repeated FewShotExample few_shot_examples = 2
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. Version of the feature. If not set, default to latest version.
  // Current candidates are ["1.0"].
  string version = 3 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The target language of the generated summary. The language code
  // for conversation will be used if this field is empty. Supported 2.0 and
  // later versions.
  string output_language_code = 6 [(google.api.field_behavior) = OPTIONAL];
}

// LLM generator.
message Generator {
  option (google.api.resource) = {
    type: "dialogflow.googleapis.com/Generator"
    pattern: "projects/{project}/locations/{location}/generators/{generator}"
    plural: "generators"
    singular: "generator"
  };

  // Output only. Identifier. The resource name of the generator. Format:
  // `projects/<Project ID>/locations/<Location ID>/generators/<Generator ID>`
  string name = 1 [
    (google.api.field_behavior) = IDENTIFIER,
    (google.api.field_behavior) = OUTPUT_ONLY
  ];

  // Optional. Human readable description of the generator.
  string description = 2 [(google.api.field_behavior) = OPTIONAL];

  // Required. Input context of the generator.
  oneof context {
    // Input of prebuilt Summarization feature.
    SummarizationContext summarization_context = 13;
  }

  // Optional. Inference parameters for this generator.
  InferenceParameter inference_parameter = 4
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. The trigger event of the generator. It defines when the generator
  // is triggered in a conversation.
  TriggerEvent trigger_event = 5 [(google.api.field_behavior) = OPTIONAL];

  // Output only. Creation time of this generator.
  google.protobuf.Timestamp create_time = 8
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Update time of this generator.
  google.protobuf.Timestamp update_time = 9
      [(google.api.field_behavior) = OUTPUT_ONLY];
}

// Suggested summary of the conversation.
message SummarySuggestion {
  // A component of the generated summary.
  message SummarySection {
    // Required. Name of the section.
    string section = 1 [(google.api.field_behavior) = REQUIRED];

    // Required. Summary text for the section.
    string summary = 2 [(google.api.field_behavior) = REQUIRED];
  }

  // Required. All the parts of generated summary.
  repeated SummarySection summary_sections = 1
      [(google.api.field_behavior) = REQUIRED];
}

// Suggestion generated using a Generator.
message GeneratorSuggestion {
  // The suggestion could be one of the many types
  oneof suggestion {
    // Optional. Suggested summary.
    SummarySuggestion summary_suggestion = 2
        [(google.api.field_behavior) = OPTIONAL];
  }
}

// The event that triggers the generator and LLM execution.
enum TriggerEvent {
  // Default value for TriggerEvent.
  TRIGGER_EVENT_UNSPECIFIED = 0;

  // Triggers when each chat message or voice utterance ends.
  END_OF_UTTERANCE = 1;

  // Triggers on the conversation manually by API calls, such as
  // Conversations.GenerateStatelessSuggestion and
  // Conversations.GenerateSuggestions.
  MANUAL_CALL = 2;
}
