syntax = "proto3";

package macp.v1;

import "macp/v1/envelope.proto";
import "macp/v1/policy.proto";

message Root {
  string uri = 1;
  string name = 2;
}

message ClientInfo {
  string name = 1;
  string title = 2;
  string version = 3;
  string description = 4;
  string website_url = 5;
}

message RuntimeInfo {
  string name = 1;
  string title = 2;
  string version = 3;
  string description = 4;
  string website_url = 5;
}

message SessionsCapability {
  bool stream = 1;
}

message CancellationCapability {
  bool cancel_session = 1;
}

message ProgressCapability {
  bool progress = 1;
}

message ManifestCapability {
  bool get_manifest = 1;
}

message ModeRegistryCapability {
  bool list_modes = 1;
  bool list_changed = 2;
}

message RootsCapability {
  bool list_roots = 1;
  bool list_changed = 2;
}

message ExperimentalCapabilities {
  map<string, string> features = 1;
}

message Capabilities {
  SessionsCapability sessions = 1;
  CancellationCapability cancellation = 2;
  ProgressCapability progress = 3;
  ManifestCapability manifest = 4;
  ModeRegistryCapability mode_registry = 5;
  RootsCapability roots = 6;
  PolicyRegistryCapability policy_registry = 7;
  ExperimentalCapabilities experimental = 100;
}

message InitializeRequest {
  repeated string supported_protocol_versions = 1;
  ClientInfo client_info = 2;
  Capabilities capabilities = 3;
}

message InitializeResponse {
  string selected_protocol_version = 1;
  RuntimeInfo runtime_info = 2;
  Capabilities capabilities = 3;
  repeated string supported_modes = 4;
  string instructions = 5;
}

message SignalPayload {
  string signal_type = 1;
  bytes data = 2;
  double confidence = 3;
  string correlation_session_id = 4;
}

message ProgressPayload {
  string progress_token = 1;
  double progress = 2;
  double total = 3;
  string message = 4;
  string target_message_id = 5;
}

message SessionStartPayload {
  string intent = 1;
  repeated string participants = 2;
  string mode_version = 3;
  string configuration_version = 4;
  string policy_version = 5;
  int64 ttl_ms = 6;
  bytes context = 7;
  repeated Root roots = 8;
}

message SessionCancelPayload {
  string reason = 1;
  // Set by the runtime; MUST match the authenticated sender of the CancelSession RPC.
  string cancelled_by = 2;
}

message CommitmentPayload {
  string commitment_id = 1;
  // Action identifier describing the outcome (e.g., "decision.approved",
  // "task.completed", "quorum.rejected").  Mode RFCs define the normative
  // vocabulary for their action values.
  string action = 2;
  string authority_scope = 3;
  string reason = 4;
  string mode_version = 5;
  string policy_version = 6;
  string configuration_version = 7;
  // True when the commitment represents a positive/successful outcome;
  // false for definitive negative outcomes (e.g., rejection, failure).
  // Modes that allow negative commitments MUST set this field explicitly.
  bool outcome_positive = 8;
}

message ParticipantActivity {
  string participant_id = 1;
  int64 last_message_at_unix_ms = 2;
  uint32 message_count = 3;
}

message SessionMetadata {
  string session_id = 1;
  string mode = 2;
  SessionState state = 3;
  int64 started_at_unix_ms = 4;
  int64 expires_at_unix_ms = 5;
  string mode_version = 6;
  string configuration_version = 7;
  string policy_version = 8;
  repeated string participants = 9;
  repeated ParticipantActivity participant_activity = 10;
  // The sender of the accepted SessionStart message.
  // Used for cancellation authorization and audit.
  string initiator = 11;
}

message GetSessionRequest {
  string session_id = 1;
}

message CancelSessionRequest {
  string session_id = 1;
  string reason = 2;
}

// Empty agent_id requests the manifest of the serving runtime/agent.
// Non-empty agent_id requests a locally-known manifest for that identifier.
message GetManifestRequest {
  string agent_id = 1;
}

message TransportEndpoint {
  string transport = 1;
  string uri = 2;
  repeated string content_types = 3;
  map<string, string> metadata = 4;
}

message AgentManifest {
  string agent_id = 1;
  string title = 2;
  string description = 3;
  repeated string supported_modes = 4;
  repeated string input_content_types = 5;
  repeated string output_content_types = 6;
  map<string, string> metadata = 7;
  repeated TransportEndpoint transport_endpoints = 8;
}

message ModeDescriptor {
  string mode = 1;
  string mode_version = 2;
  string title = 3;
  string description = 4;
  string determinism_class = 5;
  string participant_model = 6;
  repeated string message_types = 7;
  repeated string terminal_message_types = 8;
  map<string, string> schema_uris = 9;
}

message ListModesRequest {}

message ListModesResponse {
  repeated ModeDescriptor modes = 1;
}

message ListRootsRequest {}

message ListRootsResponse {
  repeated Root roots = 1;
}

message WatchModeRegistryRequest {}

message WatchRootsRequest {}

message RegistryChanged {
  string registry = 1;
  int64 observed_at_unix_ms = 2;
}

message RootsChanged {
  int64 observed_at_unix_ms = 1;
}

message SendRequest {
  Envelope envelope = 1;
}

message SendResponse {
  Ack ack = 1;
}

// StreamSession carries canonical MACP envelopes only.
// Standard per-message negative acknowledgements remain the responsibility of Send.
message StreamSessionRequest {
  Envelope envelope = 1;
}

message StreamSessionResponse {
  oneof response {
    Envelope envelope = 1;
    MACPError error = 2;  // Application-level validation error; stream remains open.
  }
}

message GetSessionResponse {
  SessionMetadata metadata = 1;
}

message CancelSessionResponse {
  Ack ack = 1;
}

message GetManifestResponse {
  AgentManifest manifest = 1;
}

message WatchModeRegistryResponse {
  RegistryChanged change = 1;
}

message WatchRootsResponse {
  RootsChanged change = 1;
}

// Extension mode lifecycle management
message ListExtModesRequest {}

message ListExtModesResponse {
  repeated ModeDescriptor modes = 1;
}

message RegisterExtModeRequest {
  ModeDescriptor mode_descriptor = 1;
}

message RegisterExtModeResponse {
  bool ok = 1;
  string error = 2;
}

message UnregisterExtModeRequest {
  string mode = 1;
}

message UnregisterExtModeResponse {
  bool ok = 1;
  string error = 2;
}

message PromoteModeRequest {
  string mode = 1;
  // Optional new identifier for the promoted mode (e.g., "macp.mode.foo.v1").
  // If empty, the existing identifier is kept.
  string promoted_mode_name = 2;
}

message PromoteModeResponse {
  bool ok = 1;
  string error = 2;
  string mode = 3;
}

message WatchSignalsRequest {}

message WatchSignalsResponse {
  Envelope envelope = 1;
}

service MACPRuntimeService {
  rpc Initialize(InitializeRequest) returns (InitializeResponse);
  rpc Send(SendRequest) returns (SendResponse);
  rpc StreamSession(stream StreamSessionRequest) returns (stream StreamSessionResponse);
  rpc GetSession(GetSessionRequest) returns (GetSessionResponse);
  rpc CancelSession(CancelSessionRequest) returns (CancelSessionResponse);
  rpc GetManifest(GetManifestRequest) returns (GetManifestResponse);
  rpc ListModes(ListModesRequest) returns (ListModesResponse);
  rpc WatchModeRegistry(WatchModeRegistryRequest) returns (stream WatchModeRegistryResponse);
  rpc ListRoots(ListRootsRequest) returns (ListRootsResponse);
  rpc WatchRoots(WatchRootsRequest) returns (stream WatchRootsResponse);
  // Extension mode lifecycle
  rpc ListExtModes(ListExtModesRequest) returns (ListExtModesResponse);
  rpc RegisterExtMode(RegisterExtModeRequest) returns (RegisterExtModeResponse);
  rpc UnregisterExtMode(UnregisterExtModeRequest) returns (UnregisterExtModeResponse);
  rpc PromoteMode(PromoteModeRequest) returns (PromoteModeResponse);
  // Ambient Signal observation
  rpc WatchSignals(WatchSignalsRequest) returns (stream WatchSignalsResponse);
  // Governance policy lifecycle (RFC-MACP-0012)
  rpc RegisterPolicy(RegisterPolicyRequest) returns (RegisterPolicyResponse);
  rpc UnregisterPolicy(UnregisterPolicyRequest) returns (UnregisterPolicyResponse);
  rpc GetPolicy(GetPolicyRequest) returns (GetPolicyResponse);
  rpc ListPolicies(ListPoliciesRequest) returns (ListPoliciesResponse);
  rpc WatchPolicies(WatchPoliciesRequest) returns (stream WatchPoliciesResponse);
}
