// Copyright 2025 The Kubeflow Authors
//
// 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";

option go_package = "github.com/kubeflow/pipelines/backend/api/v2beta1/go_client";
package kubeflow.pipelines.backend.api.v2beta1;

import "google/api/annotations.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/struct.proto";
import "protoc-gen-openapiv2/options/annotations.proto";

option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
  schemes: [1, 2], // http + https
  responses: {
    key: "default";
    value: {
      schema: {
        json_schema: {
          ref: ".google.rpc.Status";
        }
      }
    }
  }
  // Use bearer token for authorizing access to artifact service.
  // Kubernetes client library(https://kubernetes.io/docs/reference/using-api/client-libraries/)
  // uses bearer token as default for authorization. The section below
  // ensures security definition object is generated in the swagger definition.
  // For more details see https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityDefinitionsObject
  security_definitions: {
    security: {
      key: "Bearer";
      value: {
        type: TYPE_API_KEY;
        in: IN_HEADER;
        name: "Authorization";
      }
    }
  }
};

service ArtifactService {
  // Finds all artifacts within the specified namespace.
  rpc ListArtifacts(ListArtifactRequest) returns (ListArtifactResponse) {
    option (google.api.http) = {
      get: "/apis/v2beta1/artifacts"
    };
    option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
      operation_id: "list_artifacts"
      summary: "Finds all artifacts within the specified namespace."
      tags: "ArtifactService"
    };
  }

  // Finds a specific Artifact by ID.
  rpc GetArtifact(GetArtifactRequest) returns (Artifact) {
    option (google.api.http) = {
      get: "/apis/v2beta1/artifacts/{artifact_id}"
    };
    option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
      operation_id: "get_artifact"
      summary: "Finds a specific Artifact by ID."
      tags: "ArtifactService"
    };
  }

  rpc ListArtifactTasks(ListArtifactTasksRequest) returns (ListArtifactTasksResponse) {
    option (google.api.http) = {
      get: "/apis/v2beta1/artifact_tasks"
    };
    option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
      operation_id: "list_artifact_tasks"
      summary: "Lists artifact-task relationships."
      tags: "ArtifactService"
    };
  }

  // Creates an artifact-task relationship.
  // While we always create an artifact-task link when an artifact is created,
  // In the case of Importer, we only create a link (and not an artifact)
  // if Reimport = false.
  rpc CreateArtifactTask(CreateArtifactTaskRequest) returns (ArtifactTask) {
    option (google.api.http) = {
      post: "/apis/v2beta1/artifact_tasks"
      body: "*"
    };
    option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
      operation_id: "create_artifact_task"
      summary: "Creates an artifact-task relationship."
      tags: "ArtifactService"
    };
  }

  // Creates a new artifact.
  rpc CreateArtifact(CreateArtifactRequest) returns (Artifact) {
    option (google.api.http) = {
      post: "/apis/v2beta1/artifacts"
      body: "*"
    };
    option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
      operation_id: "create_artifact"
      summary: "Creates a new artifact."
      tags: "ArtifactService"
    };
  }
}

message CreateArtifactRequest {
  // Required. The artifact to create.
  Artifact artifact = 1;

  // An artifact is always created in the context of a
  // run.
  string run_id = 2;
  string task_id = 3;
  ArtifactTaskType type = 4;
  string producer_task_name = 5;
  string producer_key = 6;
}

message GetArtifactRequest {
  // Required. The ID of the artifact to be retrieved.
  string artifact_id = 1;
}

message ListArtifactRequest {
  // Optional input. Namespace for the artifacts.
  string namespace = 1;

  // A page token to request the results page.
  string page_token = 2;

  // The number of artifacts to be listed per page. If there are more artifacts
  // than this number, the response message will contain a valid value in the
  // nextPageToken field.
  int32 page_size = 3;

  // Sorting order in form of "field_name", "field_name asc" or "field_name desc".
  // Ascending by default.
  string sort_by = 4;

  // A url-encoded, JSON-serialized filter protocol buffer (see
  // [filter.proto](https://github.com/kubeflow/artifacts/blob/master/backend/api/filter.proto)).
  string filter = 5;
}

message ListArtifactResponse {
  // The list of artifacts returned.
  repeated Artifact artifacts = 1;

  // The total number of artifacts available. This field is not always populated.
  int32 total_size = 2;

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

// The fields here work the same as previous backend api calls
message ListArtifactTasksRequest {
  // Optional, filter artifact task by a set of task_ids
  // We can also likely just rely on filter for this and omit this field
  repeated string task_ids = 1;
  // Optional, filter artifact task by a set of run_ids
  repeated string run_ids = 2;
  // Optional, filter artifact task by a set of artifact_ids
  // We can also likely just rely on filter for this and omit this field
  repeated string artifact_ids = 3;

  // Optional. Only list artifact tasks that have artifacts of this type.
  ArtifactTaskType type = 4;

  string page_token = 5;
  int32 page_size = 6;
  string sort_by = 7;
  string filter = 8;
}

message ListArtifactTasksResponse {
  repeated ArtifactTask artifact_tasks = 1;
  int32 total_size = 2;
  string next_page_token = 3;
}

// Request to create an artifact-task relationship
message CreateArtifactTaskRequest {
  // Required. The artifact-task relationship to create.
  ArtifactTask artifact_task = 1;
}

// Describes the I/O relationship between
// this Artifact and Task
enum ArtifactTaskType {
  INPUT = 0;
  OUTPUT = 1;
}

message ArtifactTask {
  // Output only. The unique server generated id of the ArtifactTask.
  string id = 1;
  string artifact_id = 2;
  string run_id = 3;
  string task_id = 4;
  ArtifactTaskType type = 5;

  // The task that produced this artifact
  // For example in the case of a pipeline channel
  // that is an output artifact you might have as
  // input something like the following in the IR:
  //   taskOutputArtifact:
  //     outputArtifactKey: output_dataset
  //     producerTask: create-dataset
  // These fields are used to track this lineage.
  //
  // For outputs, the producer task is the component name
  // of the task that produced the artifact.
  string producer_task_name = 6;
  // The key is often the parameter name used
  // as input/output on the component, but
  // can also take on the value of other values.
  // For example:
  //  * "param-#" when using parameters in a ParallelFor
  //  * "Output" when using Pythonic Artifacts
  //
  // For outputs, the key is the name of the parameter
  // in the component spec (found in OutputDefinitions)
  // used to output the artifact.
  string producer_key = 7;

  // The parameter name for the input/output artifact
  // This maybe the same as the Artifact name if the
  // artifact name is not specified. It is used to
  // resolve artifact pipeline channels.
  string artifact_key = 8;
}

// Note to be confused with RuntimeArtifact in pipelinespec
message Artifact {
  // Output only. The unique server generated id of the artifact.
  // Note: Updated id name to be consistent with other api naming patterns (with prefix)
  string artifact_id = 1;

  // Required. The client provided name of the artifact.
  // Note: it seems in MLMD when name was set, it had to be unique for that type_id
  // this restriction is removed here
  // If this is a "Metric" artifact, the name of the metric
  // is treated as the Key in its K/V pair.
  string name = 2;

  string description = 3;

  enum ArtifactType {
    // default; treated as "not set"
    // reject if unset.
    TYPE_UNSPECIFIED = 0;

    Artifact = 1;
    Model = 2;
    Dataset = 3;
    HTML = 4;
    Markdown = 5;

    Metric = 6;
    ClassificationMetric = 7;
    SlicedClassificationMetric = 8;
  }
  // Required. The name of an ArtifactType. E.g. Dataset
  ArtifactType type = 4;

  // The uniform resource identifier of the physical artifact.
  // May be empty if there is no physical artifact.
  optional string uri = 5;

  // Optional. User provided custom properties which are not defined by its type.
  map<string, google.protobuf.Value> metadata = 6;

  // Used primarily for metrics
  optional double number_value = 7;

  // Output only. Create time of the artifact in millisecond since epoch.
  // Note: The type and name is updated from mlmd artifact to be consistent with other backend apis.
  google.protobuf.Timestamp created_at = 8;

  string namespace = 9;
}
