// Vani Protocol — Action Execution Layer
// VAM/1.0 — action.proto
//
// Defines how tool/function calls (the "Action" in Voice↔Text↔Action) are
// exchanged between the Vani Gateway and Action Servers.
//
// Design: MCP (Model Context Protocol) is used as the semantic action protocol.
// MCP tool calls are wrapped in Protobuf envelopes so they travel over the same
// gRPC stream as audio/transcript events (GatewayStreamMessage.action_request_payload
// and ClientStreamMessage.action_result_payload in stream.proto).
//
// This means a single gRPC connection carries audio, transcripts, turn signals,
// AND tool execution — no second connection needed.
//
// An Action Server is any MCP-compatible server that implements the tools
// listed in spec/IndiaToolRegistry.md (PAN validate, Aadhaar OTP, mandi price, etc.)
// or any custom tool registered by the application.
//
// SPDX-License-Identifier: Apache-2.0
// Copyright 2026 Vani Protocol Authors

syntax = "proto3";

package vani.v1;

option java_package = "io.vani.protocol.v1";
option java_outer_classname = "ActionProto";
option java_multiple_files = true;
option go_package = "github.com/vani-protocol/vani/gen/go/vani/v1";

import "google/protobuf/struct.proto";
import "google/protobuf/timestamp.proto";

// ─────────────────────────────────────────────────────────────────────────────
// Enumerations
// ─────────────────────────────────────────────────────────────────────────────

// Status of an action execution.
enum ActionStatus {
  ACTION_STATUS_UNSPECIFIED = 0;
  ACTION_STATUS_PENDING     = 1; // Tool call dispatched; result not yet received
  ACTION_STATUS_SUCCESS     = 2; // Tool returned a result
  ACTION_STATUS_ERROR       = 3; // Tool returned an error or timed out
  ACTION_STATUS_UNSUPPORTED = 4; // Gateway does not have this tool registered
  ACTION_STATUS_POLICY_DENY = 5; // Data residency or security policy blocked execution
}

// Source of the tool call. Useful for audit logging.
enum ActionSource {
  ACTION_SOURCE_UNSPECIFIED = 0;
  ACTION_SOURCE_LLM         = 1; // Tool call was generated by the LLM
  ACTION_SOURCE_GATEWAY     = 2; // Tool call was generated by gateway-side logic
  ACTION_SOURCE_CLIENT      = 3; // Client application explicitly requested a tool call
}

// ─────────────────────────────────────────────────────────────────────────────
// MCP Tool Call Wrapper
// ─────────────────────────────────────────────────────────────────────────────

// Represents a single MCP tool call.
// Maps directly to the MCP JSON-RPC CallTool request shape
// (https://spec.modelcontextprotocol.io/specification/server/tools/).
//
// The `arguments` field carries the tool input as a JSON object (google.protobuf.Struct
// preserves the JSON semantics without requiring generated message types per tool).
message McpToolCall {
  // Name of the tool as registered on the MCP server.
  // Examples from IndiaToolRegistry: "pan_validate", "enam_mandi_price",
  // "pm_kisan_eligibility", "bhashini_translate"
  string tool_name  = 1;

  // Tool input arguments as a JSON object.
  // Must conform to the tool's input schema defined in the Action Server manifest.
  google.protobuf.Struct arguments = 2;
}

// Represents the result of an MCP tool call.
// Maps to MCP CallToolResult.
message McpToolResult {
  // Whether the tool call was successful from an MCP protocol perspective.
  bool is_error = 1;

  // Result content. For text tools, content[0].text carries the result string.
  // For binary tools (e.g., document lookup), content[0].data carries base64.
  repeated McpContent content = 2;
}

// An individual content item within an MCP tool result.
message McpContent {
  // "text", "image", "resource"
  string type = 1;

  // Populated for type = "text"
  string text = 2;

  // Populated for type = "image" — base64-encoded image bytes
  string data      = 3;
  string mime_type = 4;

  // Populated for type = "resource" — an MCP resource URI
  string resource_uri = 5;
}

// ─────────────────────────────────────────────────────────────────────────────
// Action Request Envelope (Gateway → Client / Action Server)
// ─────────────────────────────────────────────────────────────────────────────

// Wraps an MCP tool call for transport within the Vani gRPC stream.
// Serialized as bytes in GatewayStreamMessage.action_request_payload.
//
// The client (or a sidecar action executor) deserializes this, dispatches
// the McpToolCall to the appropriate Action Server, then returns
// ActionResultEnvelope with the same call_id.
message ActionRequestEnvelope {
  string       session_id = 1;
  string       call_id    = 2; // UUID v4 — must be echoed in ActionResultEnvelope
  string       turn_id    = 3; // The conversation turn that triggered this action
  ActionSource source     = 4;

  McpToolCall  tool_call  = 5;

  // Maximum time the gateway will wait for a result before timing out.
  uint32 timeout_ms = 6; // Default: 5000ms

  // If true, the gateway will NOT pause TTS to wait for this result.
  // Useful for fire-and-forget logging actions.
  bool   fire_and_forget = 7;

  google.protobuf.Timestamp dispatched_at = 8;
}

// ─────────────────────────────────────────────────────────────────────────────
// Action Result Envelope (Client → Gateway)
// ─────────────────────────────────────────────────────────────────────────────

// Carries the tool result back from the client/action-executor to the gateway.
// Serialized as bytes in ClientStreamMessage.action_result_payload.
//
// The gateway injects the result into the LLM context as a "tool" message
// and continues generating the agent response.
message ActionResultEnvelope {
  string       session_id = 1;
  string       call_id    = 2; // Must match ActionRequestEnvelope.call_id
  ActionStatus status     = 3;

  McpToolResult result    = 4;

  // Human-readable error message if status = ACTION_STATUS_ERROR.
  string error_message = 5;

  // Latency of the tool execution as measured by the client.
  uint32 execution_ms  = 6;

  google.protobuf.Timestamp completed_at = 7;
}

// ─────────────────────────────────────────────────────────────────────────────
// Action Server Registration
// ─────────────────────────────────────────────────────────────────────────────

// Describes a registered MCP Action Server.
// Action Servers are registered with the Vani Gateway at session init or via
// VaniActionService.RegisterActionServer. The gateway stores the manifest and
// routes tool calls to the correct server.
message ActionServerManifest {
  string server_id    = 1; // Unique identifier for this Action Server
  string display_name = 2; // Human-readable name (e.g., "ENAM Mandi Price Service")
  string endpoint_uri = 3; // HTTP or stdio MCP endpoint
  string version      = 4; // Semantic version of the server

  // List of tool names this server exposes.
  repeated ToolDeclaration tools = 5;

  // Data residency of this server. Must be compatible with the session constraint.
  // Example: a server with DATA_RESIDENCY_INDIA_ONLY cannot be used in a session
  // with DATA_RESIDENCY_ON_PREM unless it is deployed locally.
  string data_residency = 6;

  google.protobuf.Timestamp registered_at = 7;
}

// A summary declaration of a tool available on an Action Server.
// Full input/output JSON schemas are fetched via MCP list_tools().
message ToolDeclaration {
  string name        = 1;
  string description = 2;

  // Whether this tool is listed in the Vani India Tool Registry.
  // See spec/IndiaToolRegistry.md for the canonical registry.
  bool   is_registry_tool = 3;

  // The registry key if is_registry_tool = true.
  // Examples: "pan_validate", "enam_mandi_price", "pm_kisan_eligibility"
  string registry_key = 4;
}

// ─────────────────────────────────────────────────────────────────────────────
// Action Service
// ─────────────────────────────────────────────────────────────────────────────

// VaniActionService allows clients to register and manage Action Servers
// independently of the audio stream. This is useful for registering tools
// once at application startup and reusing them across many sessions.
service VaniActionService {
  // Register an MCP Action Server with this gateway.
  // Tools from the server become available to all sessions that have
  // action_execution enabled.
  rpc RegisterActionServer(ActionServerManifest) returns (ActionServerRegistrationResponse);

  // Deregister an Action Server.
  rpc DeregisterActionServer(DeregisterActionServerRequest) returns (DeregisterActionServerResponse);

  // List all registered Action Servers (and their tool manifests).
  rpc ListActionServers(ListActionServersRequest) returns (ListActionServersResponse);
}

message ActionServerRegistrationResponse {
  bool   success    = 1;
  string server_id  = 2;
  string message    = 3;
  // Tools that were successfully validated and registered.
  repeated string registered_tools = 4;
  // Tools that failed validation (schema mismatch, residency conflict, etc.).
  repeated string rejected_tools = 5;
  google.protobuf.Timestamp registered_at = 6;
}

message DeregisterActionServerRequest {
  string server_id = 1;
}

message DeregisterActionServerResponse {
  bool   success = 1;
  string message = 2;
}

message ListActionServersRequest {
  // If set, filter to servers that have a specific tool.
  string tool_name_filter = 1;
}

message ListActionServersResponse {
  repeated ActionServerManifest servers = 1;
}
