// Copyright 2021, OpenTelemetry 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.

// OpAMP: Open Agent Management Protocol (https://github.com/open-telemetry/opamp-spec)

syntax = "proto3";

package opamp.proto;

import "anyvalue.proto";

option go_package = "github.com/open-telemetry/opamp-go/protobufs";

message AgentToServer {
    // Globally unique identifier of the running instance of the Agent. SHOULD remain
    // unchanged for the lifetime of the Agent process.
    // MUST be 16 bytes long and SHOULD be generated using the UUID v7 spec.
    bytes instance_uid = 1;

    // The sequence number is incremented by 1 for every AgentToServer sent
    // by the Agent. This allows the Server to detect that it missed a message when
    // it notices that the sequence_num is not exactly by 1 greater than the previously
    // received one.
    uint64 sequence_num = 2;

    // Data that describes the Agent, its type, where it runs, etc.
    // May be omitted if nothing changed since last AgentToServer message.
    AgentDescription agent_description = 3;

    // Bitmask of flags defined by AgentCapabilities enum.
    // All bits that are not defined in AgentCapabilities enum MUST be set to 0 by
    // the Agent. This allows extending the protocol and the AgentCapabilities enum
    // in the future such that old Agents automatically report that they don't
    // support the new capability.
    // This field MUST be always set.
    uint64 capabilities = 4;

    // The current health of the Agent and sub-components. The top-level ComponentHealth represents
    // the health of the Agent overall. May be omitted if nothing changed since last AgentToServer
    // message.
    // Status: [Beta]
    ComponentHealth health = 5;

    // The current effective configuration of the Agent. The effective configuration is
    // the one that is currently used by the Agent. The effective configuration may be
    // different from the remote configuration received from the Server earlier, e.g.
    // because the Agent uses a local configuration instead (or in addition).
    //
    // This field SHOULD be unset if the effective config is unchanged since the last
    // AgentToServer message.
    EffectiveConfig effective_config = 6;

    // The status of the remote config that was previously received from the Server.
    // This field SHOULD be unset if the remote config status is unchanged since the
    // last AgentToServer message.
    RemoteConfigStatus remote_config_status = 7;

    // The list of the Agent packages, including package statuses. This field SHOULD be
    // unset if this information is unchanged since the last AgentToServer message for
    // this Agent was sent in the stream.
    // Status: [Beta]
    PackageStatuses package_statuses = 8;

    // AgentDisconnect MUST be set in the last AgentToServer message sent from the
    // Agent to the Server.
    AgentDisconnect agent_disconnect = 9;

    // Bit flags as defined by AgentToServerFlags bit masks.
    uint64 flags = 10;

    // A request to create connection settings. This field is set for flows where
    // the Agent initiates the creation of connection settings.
    // Status: [Development]
    ConnectionSettingsRequest connection_settings_request = 11;

    // A message indicating custom capabilities supported by the Agent.
    // Status: [Development]
    CustomCapabilities custom_capabilities = 12;

    // A custom message sent from an Agent to the Server.
    // Status: [Development]
    CustomMessage custom_message = 13;

    // A message indicating the components that are available for configuration on the agent.
    // Status: [Development]
    AvailableComponents available_components = 14;

    // The status of the OfferedConnectionSettings that was previously received
    // from the Server. This field SHOULD be unset if the offered connection
    // settings status is unchanged since the last AgentToServer message.
    // Status: [Development]
    ConnectionSettingsStatus connection_settings_status = 15;
}

enum AgentToServerFlags {
    AgentToServerFlags_Unspecified = 0;

    // AgentToServerFlags is a bit mask. Values below define individual bits.

    // The Agent requests Server go generate a new instance_uid, which will
    // be sent back in ServerToAgent message
    AgentToServerFlags_RequestInstanceUid     = 0x00000001;
}

// AgentDisconnect is the last message sent from the Agent to the Server. The Server
// SHOULD forget the association of the Agent instance with the message stream.
//
// If the message stream is closed in the transport layer then the Server SHOULD
// forget association of all Agent instances that were previously established for
// this message stream using AgentConnect message, even if the corresponding
// AgentDisconnect message were not explicitly received from the Agent.
message AgentDisconnect {
}

// ConnectionSettingsRequest is a request from the Agent to the Server to create
// and respond with an offer of connection settings for the Agent.
// Status: [Development]
message ConnectionSettingsRequest {
    // Request for OpAMP connection settings. If this field is unset
    // then the ConnectionSettingsRequest message is empty and is not actionable
    // for the Server.
    OpAMPConnectionSettingsRequest opamp = 1;

    // In the future we can add request fields for non-OpAMP connection types
    // (own telemetry, other connections).
}

// OpAMPConnectionSettingsRequest is a request for the Server to produce
// a OpAMPConnectionSettings in its response.
// Status: [Development]
message OpAMPConnectionSettingsRequest {
    // A request to create a client certificate. This is used to initiate a
    // Client Signing Request (CSR) flow.
    // Required.
    CertificateRequest certificate_request = 1;
}

// Status: [Development]
message CertificateRequest {
    // PEM-encoded Client Certificate Signing Request (CSR), signed by client's private key.
    // The Server SHOULD validate the request and SHOULD respond with a
    // OpAMPConnectionSettings where the certificate.cert contains the issued
    // certificate.
    bytes csr = 1;
}

// AvailableComponents contains metadata relating to the components included
// within the agent.
// status: [Development]
message AvailableComponents {
    // A map of a unique component ID to details about the component.
    // This may be omitted from the message if the server has not
    // explicitly requested it be sent by setting the ReportAvailableComponents
    // flag in the previous ServerToAgent message.
    map<string, ComponentDetails> components = 1;

    // Agent-calculated hash of the components.
    // This hash should be included in every AvailableComponents message.
    bytes hash = 2;
 }

message ComponentDetails {
    // Extra key/value pairs that may be used to describe the component.
    // The key/value pairs are according to semantic conventions, see:
    // https://opentelemetry.io/docs/specs/semconv/
    //
    // For example, you may use the "code" semantic conventions to
    // report the location of the code for a specific component:
    // https://opentelemetry.io/docs/specs/semconv/attributes-registry/code/
    //
    // Or you may use the "vcs" semantic conventions to report the
    // repository the component may be a part of:
    // https://opentelemetry.io/docs/specs/semconv/attributes-registry/vcs/
    repeated KeyValue metadata = 1;

    // A map of component ID to sub components details. It can nest as deeply as needed to
    // describe the underlying system.
    map<string, ComponentDetails> sub_component_map = 2;
}


message ServerToAgent {
    // Agent instance uid. MUST match the instance_uid field in AgentToServer message.
    // Used for multiplexing messages from/to multiple agents using one message stream.
    bytes instance_uid = 1;

    // error_response is set if the Server wants to indicate that something went wrong
    // during processing of an AgentToServer message. If error_response is set then
    // all other fields below must be unset and vice versa, if any of the fields below is
    // set then error_response must be unset.
    ServerErrorResponse error_response = 2;

    // remote_config field is set when the Server has a remote config offer for the Agent.
    AgentRemoteConfig remote_config = 3;

    // This field is set when the Server wants the Agent to change one or more
    // of its client connection settings (destination, headers, certificate, etc).
    // Status: [Beta]
    ConnectionSettingsOffers connection_settings = 4;

    // This field is set when the Server has packages to offer to the Agent.
    // Status: [Beta]
    PackagesAvailable packages_available = 5;

    // Bit flags as defined by ServerToAgentFlags bit masks.
    uint64 flags = 6;

    // Bitmask of flags defined by ServerCapabilities enum.
    // All bits that are not defined in ServerCapabilities enum MUST be set to 0
    // by the Server. This allows extending the protocol and the ServerCapabilities
    // enum in the future such that old Servers automatically report that they
    // don't support the new capability.
    // This field MUST be set in the first ServerToAgent sent by the Server and MAY
    // be omitted in subsequent ServerToAgent messages by setting it to
    // UnspecifiedServerCapability value.
    uint64 capabilities = 7;

    // Properties related to identification of the Agent, which can be overridden
    // by the Server if needed.
    AgentIdentification agent_identification = 8;

    // Allows the Server to instruct the Agent to perform a command, e.g. RESTART. This field should not be specified
    // with fields other than instance_uid and capabilities. If specified, other fields will be ignored and the command
    // will be performed.
    // Status: [Beta]
    ServerToAgentCommand command = 9;

    // A message indicating custom capabilities supported by the Server.
    // Status: [Development]
    CustomCapabilities custom_capabilities = 10;

    // A custom message sent from the Server to an Agent.
    // Status: [Development]
    CustomMessage custom_message = 11;
}

enum ServerToAgentFlags {
    ServerToAgentFlags_Unspecified = 0;

    // Flags is a bit mask. Values below define individual bits.

    // ReportFullState flag can be used by the Server if the Agent did not include the
    // particular bit of information in the last status report (which is an allowed
    // optimization) but the Server detects that it does not have it (e.g. was
    // restarted and lost state). The detection happens using
    // AgentToServer.sequence_num values.
    // The Server asks the Agent to report full status.
    ServerToAgentFlags_ReportFullState = 0x00000001;

    // ReportAvailableComponents flag can be used by the server if the Agent did
    // not include the full AvailableComponents message, but only the hash.
    // If this flag is specified, the agent will populate available_components.components
    // with a full description of the agent's components.
    // Status: [Development]
    ServerToAgentFlags_ReportAvailableComponents = 0x00000002;
}

enum ServerCapabilities {
    // The capabilities field is unspecified.
    ServerCapabilities_Unspecified = 0;

    // The Server can accept status reports. This bit MUST be set, since all Server
    // MUST be able to accept status reports.
    ServerCapabilities_AcceptsStatus            = 0x00000001;
    // The Server can offer remote configuration to the Agent.
    ServerCapabilities_OffersRemoteConfig       = 0x00000002;
    // The Server can accept EffectiveConfig in AgentToServer.
    ServerCapabilities_AcceptsEffectiveConfig   = 0x00000004;
    // The Server can offer Packages.
    // Status: [Beta]
    ServerCapabilities_OffersPackages           = 0x00000008;
    // The Server can accept Packages status.
    // Status: [Beta]
    ServerCapabilities_AcceptsPackagesStatus    = 0x00000010;
    // The Server can offer connection settings.
    // Status: [Beta]
    ServerCapabilities_OffersConnectionSettings = 0x00000020;
    // The Server can accept ConnectionSettingsRequest and respond with an offer.
    // Status: [Development]
    ServerCapabilities_AcceptsConnectionSettingsRequest = 0x00000040;

    // Add new capabilities here, continuing with the least significant unused bit.
}

// The OpAMPConnectionSettings message is a collection of fields which comprise an
// offer from the Server to the Agent to use the specified settings for OpAMP
// connection.
// Status: [Beta]
message OpAMPConnectionSettings {
    // OpAMP Server URL This MUST be a WebSocket or HTTP URL and MUST be non-empty, for
    // example: "wss://example.com:4318/v1/opamp"
    string destination_endpoint = 1;

    // Optional headers to use when connecting. Typically used to set access tokens or
    // other authorization headers. For HTTP-based protocols the Agent should
    // set these in the request headers.
    // For example:
    // key="Authorization", Value="Basic YWxhZGRpbjpvcGVuc2VzYW1l".
    Headers headers = 2;

    // The Agent should use the offered certificate to connect to the destination
    // from now on. If the Agent is able to validate and connect using the offered
    // certificate the Agent SHOULD forget any previous client certificates
    // for this connection.
    // This field is optional: if omitted the client SHOULD NOT use a client-side certificate.
    // This field can be used to perform a client certificate revocation/rotation.
    TLSCertificate certificate = 3;

    // The Agent MUST periodically send an AgentToServer message if the
    // AgentCapabilities_ReportsHeartbeat capability is true. At a minimum the instance_uid
    // field MUST be set.
    //
    // An HTTP Client MUST use the value as polling interval, if heartbeat_interval_seconds is non-zero.
    //
    // A heartbeat is used to keep the connection active and inform the server that the Agent
    // is still alive and active.
    //
    // If this field has no value or is set to 0, the Agent should not send any heartbeats.
    // Status: [Development]
    uint64 heartbeat_interval_seconds = 4;

    // Optional connection specific TLS settings.
    // Status: [Development]
    TLSConnectionSettings tls = 5;

    // Optional connection specific proxy settings.
    // Status: [Development]
    ProxyConnectionSettings proxy = 6;
}

// The TelemetryConnectionSettings message is a collection of fields which comprise an
// offer from the Server to the Agent to use the specified settings for a network
// connection to report own telemetry.
// Status: [Beta]
message TelemetryConnectionSettings {
    // The value MUST be a full URL an OTLP/HTTP/Protobuf receiver with path. Schema
    // SHOULD begin with "https://", for example "https://example.com:4318/v1/metrics"
    // The Agent MAY refuse to send the telemetry if the URL begins with "http://".
    string destination_endpoint = 1;

    // Optional headers to use when connecting. Typically used to set access tokens or
    // other authorization headers. For HTTP-based protocols the Agent should
    // set these in the request headers.
    // For example:
    // key="Authorization", Value="Basic YWxhZGRpbjpvcGVuc2VzYW1l".
    Headers headers = 2;

    // The Agent should use the offered certificate to connect to the destination
    // from now on. If the Agent is able to validate and connect using the offered
    // certificate the Agent SHOULD forget any previous client certificates
    // for this connection.
    // This field is optional: if omitted the client SHOULD NOT use a client-side certificate.
    // This field can be used to perform a client certificate revocation/rotation.
    TLSCertificate certificate = 3;

    // Optional connection specific TLS settings.
    // Status: [Development]
    TLSConnectionSettings tls = 4;

    // Optional connection specific proxy settings.
    // Status: [Development]
    ProxyConnectionSettings proxy = 5;
}

// The OtherConnectionSettings message is a collection of fields which comprise an
// offer from the Server to the Agent to use the specified settings for a network
// connection. It is not required that all fields in this message are specified.
// The Server may specify only some of the fields, in which case it means that
// the Server offers the Agent to change only those fields, while keeping the
// rest of the fields unchanged.
//
// For example the Server may send a ConnectionSettings message with only the
// certificate field set, while all other fields are unset. This means that
// the Server wants the Agent to use a new certificate and continue sending to
// the destination it is currently sending using the current header and other
// settings.
//
// For fields which reference other messages the field is considered unset
// when the reference is unset.
//
// For primitive field (string) we rely on the "flags" to describe that the
// field is not set (this is done to overcome the limitation of old protoc
// compilers don't generate methods that allow to check for the presence of
// the field.
// Status: [Beta]
message OtherConnectionSettings {
    // A URL, host:port or some other destination specifier.
    string destination_endpoint = 1;

    // Optional headers to use when connecting. Typically used to set access tokens or
    // other authorization headers. For HTTP-based protocols the Agent should
    // set these in the request headers.
    // For example:
    // key="Authorization", Value="Basic YWxhZGRpbjpvcGVuc2VzYW1l".
    Headers headers = 2;

    // The Agent should use the offered certificate to connect to the destination
    // from now on. If the Agent is able to validate and connect using the offered
    // certificate the Agent SHOULD forget any previous client certificates
    // for this connection.
    // This field is optional: if omitted the client SHOULD NOT use a client-side certificate.
    // This field can be used to perform a client certificate revocation/rotation.
    TLSCertificate certificate = 3;

    // Other connection settings. These are Agent-specific and are up to the Agent
    // interpret.
    map<string, string> other_settings = 4;

    // Optional connection specific TLS settings.
    // Status: [Development]
    TLSConnectionSettings tls = 5;

    // Optional connection specific proxy settings.
    // Status: [Development]
    ProxyConnectionSettings proxy = 6;
}


// TLSConnectionSettings are optional connection settings that can be passed to
// the client in order to specify TLS configuration.
// Status: [Development]
message TLSConnectionSettings {
  // Provides CA cert contents as a string.
  string ca_pem_contents = 1;

  // Load system CA pool alongside any passed CAs.
  bool include_system_ca_certs_pool = 2;

  // skip certificate verification.
  bool insecure_skip_verify = 3;

  // Miniumum accepted TLS version; default "1.2".
  string min_version = 4;

  // Maxiumum accepted TLS version; default "".
  string max_version = 5;

  // Explicit list of cipher suites.
  repeated string cipher_suites = 6;
}

// Status: [Development]
message ProxyConnectionSettings {
    // A URL, host:port or some other destination specifier.
    string url = 1;

    // Optional headers to send to proxies during CONNECT requests.
    // These headers can be ignored for non-HTTP based proxies.
    // For example:
    // key="Authorization", Value="Basic YWxhZGRpbjpvcGVuc2VzYW1l".
    Headers connect_headers = 2;
}

// Status: [Beta]
message Headers {
    repeated Header headers = 1;
}

// Status: [Beta]
message Header {
    string key = 1;
    string value = 2;
}

// Status: [Beta]
message TLSCertificate {
    // The (cert,private_key) pair should be issued and signed by a Certificate
    // Authority (CA) that the destination Server recognizes.
    //
    // It is highly recommended that the private key of the CA certificate is NOT
    // stored on the destination Server otherwise compromising the Server will allow
    // a malicious actor to issue valid Server certificates which will be automatically
    // trusted by all agents and will allow the actor to trivially MITM Agent-to-Server
    // traffic of all servers that use this CA certificate for their Server-side
    // certificates.
    //
    // Alternatively the certificate may be self-signed, assuming the Server can
    // verify the certificate.

    // PEM-encoded certificate. Required.
    bytes cert = 1;

    // PEM-encoded private key of the certificate. Required.
    bytes private_key = 2;

    // PEM-encoded certificate of the signing CA.
    // Optional. MUST be specified if the certificate is CA-signed.
    // Can be stored by TLS-terminating intermediary proxies in order to verify
    // the connecting client's certificate in the future.
    // It is not recommended that the Agent accepts this CA as an authority for
    // any purposes.
    bytes ca_cert = 3;
}

// Status: [Beta]
message ConnectionSettingsOffers {
    // Hash of all settings, including settings that may be omitted from this message
    // because they are unchanged.
    bytes hash = 1;

    // Settings to connect to the OpAMP Server.
    // If this field is not set then the Agent should assume that the settings are
    // unchanged and should continue using existing settings.
    // The Agent MUST verify the offered connection settings by actually connecting
    // before accepting the setting to ensure it does not loose access to the OpAMP
    // Server due to invalid settings.
    OpAMPConnectionSettings opamp = 2;

    // Settings to connect to an OTLP metrics backend to send Agent's own metrics to.
    // If this field is not set then the Agent should assume that the settings
    // are unchanged.
    //
    // Once accepted the Agent should periodically send to the specified destination
    // its own metrics, i.e. metrics of the Agent process and any custom metrics that
    // describe the Agent state.
    //
    // All attributes specified in the identifying_attributes field in AgentDescription
    // message SHOULD be also specified in the Resource of the reported OTLP metrics.
    //
    // Attributes specified in the non_identifying_attributes field in
    // AgentDescription message may be also specified in the Resource of the reported
    // OTLP metrics, in which case they SHOULD have exactly the same values.
    //
    // Process metrics MUST follow the conventions for processes:
    // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/semantic_conventions/process-metrics.md
    TelemetryConnectionSettings own_metrics = 3;

    // Similar to own_metrics, but for traces.
    TelemetryConnectionSettings own_traces = 4;

    // Similar to own_metrics, but for logs.
    TelemetryConnectionSettings own_logs = 5;

    // Another set of connection settings, with a string name associated with each.
    // How the Agent uses these is Agent-specific. Typically the name represents
    // the name of the destination to connect to (as it is known to the Agent).
    // If this field is not set then the Agent should assume that the other_connections
    // settings are unchanged.
    map<string,OtherConnectionSettings> other_connections = 6;
}

// List of packages that the Server offers to the Agent.
// Status: [Beta]
message PackagesAvailable {
    // Map of packages. Keys are package names, values are the packages available for download.
    map<string, PackageAvailable> packages = 1;

    // Aggregate hash of all remotely installed packages. The Agent SHOULD include this
    // value in subsequent PackageStatuses messages. This in turn allows the management
    // Server to identify that a different set of packages is available for the Agent
    // and specify the available packages in the next ServerToAgent message.
    //
    // This field MUST be always set if the management Server supports packages
    // of agents.
    //
    // The hash is calculated as an aggregate of all packages names and content.
    bytes all_packages_hash = 2;
}

// Each Agent is composed of one or more packages. A package has a name and
// content stored in a file. The content of the files, functionality
// provided by the packages, how they are stored and used by the Agent side is Agent
// type-specific and is outside the concerns of the OpAMP protocol.
//
// If the Agent does not have an installed package with the specified name then
// it SHOULD download it from the specified URL and install it.
//
// If the Agent already has an installed package with the specified name
// but with a different hash then the Agent SHOULD download and
// install the package again, since it is a different version of the same package.
//
// If the Agent has an installed package with the specified name and the same
// hash then the Agent does not need to do anything, it already
// has the right version of the package.
// Status: [Beta]
message PackageAvailable {
    PackageType type = 1;

    // The package version that is available on the Server side. The Agent may for
    // example use this information to avoid downloading a package that was previously
    // already downloaded and failed to install.
    string version = 2;

    // The downloadable file of the package.
    DownloadableFile file = 3;

    // The hash of the package. SHOULD be calculated based on all other fields of the
    // PackageAvailable message and content of the file of the package. The hash is
    // used by the Agent to determine if the package it has is different from the
    // package the Server is offering.
    bytes hash = 4;
}

// The type of the package, either an addon or a top-level package.
// Status: [Beta]
enum PackageType {
    PackageType_TopLevel = 0;
    PackageType_Addon    = 1;
}

// Status: [Beta]
message DownloadableFile {
    // The URL from which the file can be downloaded using HTTP GET request.
    // The Server at the specified URL SHOULD support range requests
    // to allow for resuming downloads.
    string download_url = 1;

    // The hash of the file content. Can be used by the Agent to verify that the file
    // was downloaded correctly.
    bytes content_hash = 2;

    // Optional signature of the file content. Can be used by the Agent to verify the
    // authenticity of the downloaded file, for example can be the
    // [detached GPG signature](https://www.gnupg.org/gph/en/manual/x135.html#AEN160).
    // The exact signing and verification method is Agent specific. See
    // https://github.com/open-telemetry/opamp-spec/blob/main/specification.md#code-signing
    // for recommendations.
    bytes signature = 3;

    // Optional headers to use when downloading a file. Typically used to set
    // access tokens or other authorization headers. For HTTP-based protocols
    // the Agent should set these in the request headers.
    // For example:
    // key="Authorization", Value="Basic YWxhZGRpbjpvcGVuc2VzYW1l".
    // Status: [Development]
    Headers headers = 4;
}

message ServerErrorResponse {
    ServerErrorResponseType type = 1;

    // Error message in the string form, typically human readable.
    string error_message = 2;

    oneof Details {
        // Additional information about retrying if type==UNAVAILABLE.
        RetryInfo retry_info = 3;
    }
}

enum ServerErrorResponseType {
    // Unknown error. Something went wrong, but it is not known what exactly.
    // The Agent SHOULD NOT retry the message.
    // The error_message field may contain a description of the problem.
    ServerErrorResponseType_Unknown = 0;

    // The AgentToServer message was malformed. The Agent SHOULD NOT retry
    // the message.
    ServerErrorResponseType_BadRequest = 1;

    // The Server is overloaded and unable to process the request. The Agent
    // should retry the message later. retry_info field may be optionally
    // set with additional information about retrying.
    ServerErrorResponseType_Unavailable = 2;
}

message RetryInfo {
    uint64 retry_after_nanoseconds = 1;
}

// ServerToAgentCommand is sent from the Server to the Agent to request that the Agent
// perform a command.
// Status: [Beta]
message ServerToAgentCommand {
    CommandType type = 1;
}

// Status: [Beta]
enum CommandType {
    // The Agent should restart. This request will be ignored if the Agent does not
    // support restart.
    CommandType_Restart = 0;
}

////////////////////////////////////////////////////////////////////////////////////
// Status reporting

message AgentDescription {
    // Attributes that identify the Agent.
    // Keys/values are according to OpenTelemetry semantic conventions, see:
    // https://github.com/open-telemetry/opentelemetry-specification/tree/main/specification/resource/semantic_conventions
    //
    // For standalone running Agents (such as OpenTelemetry Collector) the following
    // attributes SHOULD be specified:
    // - service.name should be set to a reverse FQDN that uniquely identifies the
    //   Agent type, e.g. "io.opentelemetry.collector"
    // - service.namespace if it is used in the environment where the Agent runs.
    // - service.version should be set to version number of the Agent build.
    // - service.instance.id should be set. It may be set equal to the Agent's
    //   instance uid (equal to ServerToAgent.instance_uid field) or any other value
    //   that uniquely identifies the Agent in combination with other attributes.
    // - any other attributes that are necessary for uniquely identifying the Agent's
    //   own telemetry.
    //
    // The Agent SHOULD also include these attributes in the Resource of its own
    // telemetry. The combination of identifying attributes SHOULD be sufficient to
    // uniquely identify the Agent's own telemetry in the destination system to which
    // the Agent sends its own telemetry.
    repeated KeyValue identifying_attributes = 1;

    // Attributes that do not necessarily identify the Agent but help describe
    // where it runs.
    // The following attributes SHOULD be included:
    // - os.type, os.version - to describe where the Agent runs.
    // - host.* to describe the host the Agent runs on.
    // - cloud.* to describe the cloud where the host is located.
    // - any other relevant Resource attributes that describe this Agent and the
    //   environment it runs in.
    // - any user-defined attributes that the end user would like to associate
    //   with this Agent.
    repeated KeyValue non_identifying_attributes = 2;

    // TODO: add ability to specify related entities (such as the Service the Agent is
    // is responsible/associated with).
}

enum AgentCapabilities {
    // The capabilities field is unspecified.
    AgentCapabilities_Unspecified = 0;
    // The Agent can report status. This bit MUST be set, since all Agents MUST
    // report status.
    AgentCapabilities_ReportsStatus                   = 0x00000001;
    // The Agent can accept remote configuration from the Server.
    AgentCapabilities_AcceptsRemoteConfig             = 0x00000002;
    // The Agent will report EffectiveConfig in AgentToServer.
    AgentCapabilities_ReportsEffectiveConfig          = 0x00000004;
    // The Agent can accept package offers.
    // Status: [Beta]
    AgentCapabilities_AcceptsPackages                 = 0x00000008;
    // The Agent can report package status.
    // Status: [Beta]
    AgentCapabilities_ReportsPackageStatuses          = 0x00000010;
    // The Agent can report own trace to the destination specified by
    // the Server via ConnectionSettingsOffers.own_traces field.
    // Status: [Beta]
    AgentCapabilities_ReportsOwnTraces                = 0x00000020;
    // The Agent can report own metrics to the destination specified by
    // the Server via ConnectionSettingsOffers.own_metrics field.
    // Status: [Beta]
    AgentCapabilities_ReportsOwnMetrics               = 0x00000040;
    // The Agent can report own logs to the destination specified by
    // the Server via ConnectionSettingsOffers.own_logs field.
    // Status: [Beta]
    AgentCapabilities_ReportsOwnLogs                  = 0x00000080;
    // The can accept connections settings for OpAMP via
    // ConnectionSettingsOffers.opamp field.
    // Status: [Beta]
    AgentCapabilities_AcceptsOpAMPConnectionSettings  = 0x00000100;
    // The can accept connections settings for other destinations via
    // ConnectionSettingsOffers.other_connections field.
    // Status: [Beta]
    AgentCapabilities_AcceptsOtherConnectionSettings  = 0x00000200;
    // The Agent can accept restart requests.
    // Status: [Beta]
    AgentCapabilities_AcceptsRestartCommand           = 0x00000400;
    // The Agent will report Health via AgentToServer.health field.
    AgentCapabilities_ReportsHealth                   = 0x00000800;
    // The Agent will report RemoteConfig status via AgentToServer.remote_config_status field.
    AgentCapabilities_ReportsRemoteConfig             = 0x00001000;
    // The Agent can report heartbeats.
    // This is specified by the ServerToAgent.OpAMPConnectionSettings.heartbeat_interval_seconds field.
    // If this capability is true, but the Server does not set a heartbeat_interval_seconds field, the
    // Agent should use its own configured interval, which by default will be 30s. The Server may not
    // know the configured interval and should not make assumptions about it.
    // Status: [Development]
    AgentCapabilities_ReportsHeartbeat                = 0x00002000;
    // The agent will report AvailableComponents via the AgentToServer.available_components field.
    // Status: [Development]
    AgentCapabilities_ReportsAvailableComponents      = 0x00004000;
    // The agent will report ConnectionSettingsOffers status via AgentToServer.connection_settings_status field.
    // Status: [Development]
    AgentCapabilities_ReportsConnectionSettingsStatus = 0x00008000;
    // Add new capabilities here, continuing with the least significant unused bit.
}

// The health of the Agent and sub-components
// Status: [Beta]
message ComponentHealth {
    // Set to true if the component is up and healthy.
    bool healthy = 1;

    // Timestamp since the component is up, i.e. when the component was started.
    // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970.
    // If the component is not running MUST be set to 0.
    fixed64 start_time_unix_nano = 2;

    // Human-readable error message if the component is in erroneous state. SHOULD be set
    // when healthy==false.
    string last_error = 3;

    // Component status represented as a string. The status values are defined by agent-specific
    // semantics and not at the protocol level.
    string status = 4;

    // The time when the component status was observed. Value is UNIX Epoch time in
    // nanoseconds since 00:00:00 UTC on 1 January 1970.
    fixed64 status_time_unix_nano = 5;

    // A map to store more granular, sub-component health. It can nest as deeply as needed to
    // describe the underlying system.
    map<string, ComponentHealth> component_health_map = 6;
}

message EffectiveConfig {
    // The effective config of the Agent.
    AgentConfigMap config_map = 1;
}

message RemoteConfigStatus {
    // The hash of the remote config that was last received by this Agent in the
    // AgentRemoteConfig.config_hash field.
    // The Server SHOULD compare this hash with the config hash
    // it has for the Agent and if the hashes are different the Server MUST include
    // the remote_config field in the response in the ServerToAgent message.
    bytes last_remote_config_hash = 1;

    RemoteConfigStatuses status = 2;

    // Optional error message if status==FAILED.
    string error_message = 3;
}

// Status: [Development]
message ConnectionSettingsStatus {
    // The hash of the connection settings that was last recieved by this Agent
    // in the connection_settings.hash field. The Server SHOULD compare this
    // hash with the OfferedConnectionSettings hash it has for the Agent and if
    // the hashes are different the Server MUST include the connection_settings
    // field in the response in the ServerToAgent message.
    bytes last_connection_settings_hash = 1;

    ConnectionSettingsStatuses status = 2;

    // Optional error message if status==FAILED.
    string error_message = 3;
}

// Status: [Development]
enum ConnectionSettingsStatuses {
    // The value of status field is not set.
    ConnectionSettingsStatuses_UNSET = 0;

    // ConnectionSettings were successfully applied by the Agent.
    ConnectionSettingsStatuses_APPLIED = 1;

    // Agent is currently applying the ConnectionSettings that it received.
    ConnectionSettingsStatuses_APPLYING = 2;

    // Agent tried to apply the ConnectionSettings it received earlier, but failed.
    // See error_message for more details.
    ConnectionSettingsStatuses_FAILED = 3;
}

enum RemoteConfigStatuses {
    // The value of status field is not set.
    RemoteConfigStatuses_UNSET = 0;

    // Remote config was successfully applied by the Agent.
    RemoteConfigStatuses_APPLIED = 1;

    // Agent is currently applying the remote config that it received earlier.
    RemoteConfigStatuses_APPLYING = 2;

    // Agent tried to apply the config received earlier, but it failed.
    // See error_message for more details.
    RemoteConfigStatuses_FAILED = 3;
}

// The PackageStatuses message describes the status of all packages that the Agent
// has or was offered.
// Status: [Beta]
message PackageStatuses {
    // A map of PackageStatus messages, where the keys are package names.
    // The key MUST match the name field of PackageStatus message.
    map<string, PackageStatus> packages = 1;

    // The aggregate hash of all packages that this Agent previously received from the
    // Server via PackagesAvailable message.
    //
    // The Server SHOULD compare this hash to the aggregate hash of all packages that
    // it has for this Agent and if the hashes are different the Server SHOULD send
    // an PackagesAvailable message to the Agent.
    bytes server_provided_all_packages_hash = 2;

    // This field is set if the Agent encountered an error when processing the
    // PackagesAvailable message and that error is not related to any particular single
    // package.
    // The field must be unset is there were no processing errors.
    string error_message = 3;
}

// The status of a single package.
// Status: [Beta]
message PackageStatus {
    // Package name. MUST be always set and MUST match the key in the packages field
    // of PackageStatuses message.
    string name = 1;

    // The version of the package that the Agent has.
    // MUST be set if the Agent has this package.
    // MUST be empty if the Agent does not have this package. This may be the case
    // for example if the package was offered by the Server but failed to install
    // and the Agent did not have this package previously.
    string agent_has_version = 2;

    // The hash of the package that the Agent has.
    // MUST be set if the Agent has this package.
    // MUST be empty if the Agent does not have this package. This may be the case for
    // example if the package was offered by the Server but failed to install and the
    // Agent did not have this package previously.
    bytes agent_has_hash = 3;

    // The version of the package that the Server offered to the Agent.
    // MUST be set if the installation of the package is initiated by an earlier offer
    // from the Server to install this package.
    //
    // MUST be empty if the Agent has this package but it was installed locally and
    // was not offered by the Server.
    //
    // Note that it is possible for both agent_has_version and server_offered_version
    // fields to be set and to have different values. This is for example possible if
    // the Agent already has a version of the package successfully installed, the Server
    // offers a different version, but the Agent fails to install that version.
    string server_offered_version = 4;

    // The hash of the package that the Server offered to the Agent.
    // MUST be set if the installation of the package is initiated by an earlier
    // offer from the Server to install this package.
    //
    // MUST be empty if the Agent has this package but it was installed locally and
    // was not offered by the Server.
    //
    // Note that it is possible for both agent_has_hash and server_offered_hash
    // fields to be set and to have different values. This is for example possible if
    // the Agent already has a version of the package successfully installed, the
    // Server offers a different version, but the Agent fails to install that version.
    bytes server_offered_hash = 5;

    PackageStatusEnum status = 6;

    // Error message if the status is erroneous.
    string error_message = 7;

    // Optional details that may be of interest to a user.
    // Should only be set if status is Downloading.
    // Status: [Development]
    PackageDownloadDetails download_details = 8;
}


// Additional details that an agent can use to describe an in-progress package download.
// Status: [Development]
message PackageDownloadDetails {
    // The package download progress as a percentage.
    double download_percent = 1;

    // The current package download rate in bytes per second.
    double download_bytes_per_second = 2;
}

// The status of this package.
// Status: [Beta]
enum PackageStatusEnum {
    // Package is successfully installed by the Agent.
    // The error_message field MUST NOT be set.
    PackageStatusEnum_Installed = 0;

    // Installation of this package has not yet started.
    PackageStatusEnum_InstallPending = 1;

    // Agent is currently installing the package.
    // server_offered_hash field MUST be set to indicate the version that the
    // Agent is installing. The error_message field MUST NOT be set.
    PackageStatusEnum_Installing = 2;

    // Agent tried to install the package but installation failed.
    // server_offered_hash field MUST be set to indicate the version that the Agent
    // tried to install. The error_message may also contain more details about
    // the failure.
    PackageStatusEnum_InstallFailed = 3;

    // Agent is currently downloading the package.
    // server_offered_hash field MUST be set to indicate the version that the
    // Agent is installing. The error_message field MUST NOT be set.
    // Status: [Development]
    PackageStatusEnum_Downloading = 4;
}

// Properties related to identification of the Agent, which can be overridden
// by the Server if needed
message AgentIdentification {
    // When new_instance_uid is set, Agent MUST update instance_uid
    // to the value provided and use it for all further communication.
    // MUST be 16 bytes long and SHOULD be generated using the UUID v7 spec.
    bytes new_instance_uid = 1;
}

/////////////////////////////////////////////////////////////////////////////////////
// Config messages
/////////////////////////////////////////////////////////////////////////////////////

message AgentRemoteConfig {
    // Agent config offered by the management Server to the Agent instance. SHOULD NOT be
    // set if the config for this Agent has not changed since it was last requested (i.e.
    // AgentConfigRequest.last_remote_config_hash field is equal to
    // AgentConfigResponse.config_hash field).
    AgentConfigMap config = 1;

    // Hash of "config". The Agent SHOULD include this value in subsequent
    // RemoteConfigStatus messages in the last_remote_config_hash field. This in turn
    // allows the management Server to identify that a new config is available for the Agent.
    //
    // This field MUST be always set if the management Server supports remote configuration
    // of agents.
    //
    // Management Server must choose a hashing function that guarantees lack of hash
    // collisions in practice.
    bytes config_hash = 2;
}

message AgentConfigMap {
    // Map of configs. Keys are config file names or config section names.
    // The configuration is assumed to be a collection of one or more named config files
    // or sections.
    // For agents that use a single config file or section the map SHOULD contain a single
    // entry and the key may be an empty string.
    map<string, AgentConfigFile> config_map = 1;
}

message AgentConfigFile {
    // Config file or section body. The content, format and encoding depends on the Agent
    // type. The content_type field may optionally describe the MIME type of the body.
    bytes body = 1;

    // Optional MIME Content-Type that describes what's in the body field, for
    // example "text/yaml".
    string content_type = 2;
}

/////////////////////////////////////////////////////////////////////////////////////
// Custom messages
/////////////////////////////////////////////////////////////////////////////////////

message CustomCapabilities {
    // A list of custom capabilities that are supported. Each capability is a reverse FQDN
    // with optional version information that uniquely identifies the custom capability
    // and should match a capability specified in a supported CustomMessage.
    // Status: [Development]
    repeated string capabilities = 1;
}

message CustomMessage {
    // A reverse FQDN that uniquely identifies the capability and matches one of the
    // capabilities in the CustomCapabilities message.
    // Status: [Development]
    string capability = 1;

    // Type of message within the capability. The capability defines the types of custom
    // messages that are used to implement the capability. The type must only be unique
    // within the capability.
    // Status: [Development]
    string type = 2;

    // Binary data of the message. The capability must specify the format of the contents
    // of the data for each custom message type it defines.
    // Status: [Development]
    bytes data = 3;
}