velocia 0.3.0

velocia – production-ready AI agent framework using ADK-Rust, A2A protocol, and AWS DynamoDB
use std::collections::HashMap;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ToolType {
    Mcp,
    Function,
    ClassMethod,
}

// ── MCP transport ─────────────────────────────────────────────────────────────

/// Authentication header configuration for MCP tools.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Header {
    pub header_name: Option<String>,
    /// Name of an environment variable whose value becomes the header value.
    pub header_value: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Auth {
    pub headers: Option<Vec<Header>>,
}

/// Streamable-HTTP MCP transport parameters.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct McpTypeStreamable {
    pub url: String,
    pub port: u16,
    #[serde(default = "McpTypeStreamable::default_path")]
    pub path: String,
    pub auth: Option<Auth>,
}

impl McpTypeStreamable {
    fn default_path() -> String { "/".to_string() }
}

/// Stdio MCP transport parameters.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct McpTypeStdio {
    pub command: String,
    pub args: Vec<String>,
    pub env: Option<HashMap<String, String>>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum McpConfig {
    Streamable(McpTypeStreamable),
    Stdio(McpTypeStdio),
}

// ── Tool config variants ──────────────────────────────────────────────────────

/// Base fields shared by every tool config.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolConfigBase {
    #[serde(rename = "type")]
    pub tool_type: ToolType,
    #[serde(default)]
    pub name: String,
    #[serde(default)]
    pub description: String,
}

/// Configuration for an MCP-backed tool.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct McpToolConfig {
    #[serde(flatten)]
    pub base: ToolConfigBase,
    pub mcp_config: McpConfig,
    /// When set, only the listed tool names are exposed from the server.
    pub tool_filter: Option<Vec<String>>,
}

/// Configuration for a standalone async function tool.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FunctionToolConfig {
    #[serde(flatten)]
    pub base: ToolConfigBase,
    /// Rust module path (informational; resolved at build time via the registry).
    pub module_path: String,
    pub function_name: String,
}

/// Configuration for a method on an instantiated struct.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClassMethodToolConfig {
    #[serde(flatten)]
    pub base: ToolConfigBase,
    pub module_path: String,
    pub class_name: String,
    pub method_name: String,
    #[serde(default)]
    pub init_params: serde_json::Value,
}

/// Discriminated union of all supported tool configurations.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ToolConfig {
    Mcp(McpToolConfig),
    Function(FunctionToolConfig),
    ClassMethod(ClassMethodToolConfig),
}

impl ToolConfig {
    pub fn name(&self) -> &str {
        match self {
            ToolConfig::Mcp(c) => &c.base.name,
            ToolConfig::Function(c) => &c.base.name,
            ToolConfig::ClassMethod(c) => &c.base.name,
        }
    }

    pub fn tool_type(&self) -> &ToolType {
        match self {
            ToolConfig::Mcp(c) => &c.base.tool_type,
            ToolConfig::Function(c) => &c.base.tool_type,
            ToolConfig::ClassMethod(c) => &c.base.tool_type,
        }
    }
}