aura-gui 0.2.2

UI nativa acelerada por GPU para escritorio, Android e iOS, en un solo crate: estilo tipo Tailwind, componentes, sombras, animaciones y agentes de IA. Reposo a cero. Licencia AGPL-3.0 o comercial.
//! Proveedores alojados que solo necesitan una clave de API: dirección, variable de entorno y página donde se saca la
//! clave. Es la única lista: la conexión, el llavero y el selector de proveedores la leen de aquí.

use crate::ai::ProviderKind;

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Hosted {
    pub id: &'static str,
    pub label: &'static str,
    pub kind: ProviderKind,
    pub base_url: &'static str,
    /// Variable de entorno que se mira si el llavero no tiene la clave.
    pub env: &'static str,
    /// Página donde se inicia sesión y se copia la clave.
    pub console: &'static str,
}

const fn openai_like(
    id: &'static str,
    label: &'static str,
    base_url: &'static str,
    env: &'static str,
    console: &'static str,
) -> Hosted {
    Hosted { id, label, kind: ProviderKind::OpenAiCompatible, base_url, env, console }
}

pub const HOSTED: &[Hosted] = &[
    Hosted {
        id: "anthropic",
        label: "Anthropic · Claude",
        kind: ProviderKind::Anthropic,
        base_url: "https://api.anthropic.com",
        env: "ANTHROPIC_API_KEY",
        console: "https://console.anthropic.com/settings/keys",
    },
    openai_like(
        "openai",
        "OpenAI",
        "https://api.openai.com/v1",
        "OPENAI_API_KEY",
        "https://platform.openai.com/api-keys",
    ),
    // La misma clave sirve para OpenCode Zen y Go, y así la llaman sus guías.
    openai_like(
        "opencode-go",
        "OpenCode Go · suscripción",
        crate::ai::opencode::BASE_URL,
        "OPENCODE_API_KEY",
        "https://opencode.ai/console",
    ),
    openai_like(
        "opencode-zen",
        "OpenCode Zen",
        "https://opencode.ai/zen/v1",
        "OPENCODE_API_KEY",
        "https://opencode.ai/console",
    ),
    openai_like(
        "deepseek",
        "DeepSeek",
        "https://api.deepseek.com",
        "DEEPSEEK_API_KEY",
        "https://platform.deepseek.com/api_keys",
    ),
    openai_like(
        "openrouter",
        "OpenRouter",
        "https://openrouter.ai/api/v1",
        "OPENROUTER_API_KEY",
        "https://openrouter.ai/keys",
    ),
    openai_like(
        "gemini",
        "Google · Gemini",
        "https://generativelanguage.googleapis.com/v1beta/openai",
        "GEMINI_API_KEY",
        "https://aistudio.google.com/apikey",
    ),
    openai_like("xai", "xAI · Grok", "https://api.x.ai/v1", "XAI_API_KEY", "https://console.x.ai"),
    openai_like(
        "mistral",
        "Mistral",
        "https://api.mistral.ai/v1",
        "MISTRAL_API_KEY",
        "https://console.mistral.ai/api-keys",
    ),
    openai_like("groq", "Groq", "https://api.groq.com/openai/v1", "GROQ_API_KEY", "https://console.groq.com/keys"),
    openai_like(
        "moonshot",
        "Moonshot · Kimi",
        "https://api.moonshot.ai/v1",
        "MOONSHOT_API_KEY",
        "https://platform.moonshot.ai/console/api-keys",
    ),
    openai_like(
        "zai",
        "Z.ai · GLM",
        "https://api.z.ai/api/paas/v4",
        "ZAI_API_KEY",
        "https://z.ai/manage-apikey/apikey-list",
    ),
    openai_like(
        "qwen",
        "Qwen · Alibaba Cloud",
        "https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
        "DASHSCOPE_API_KEY",
        "https://modelstudio.console.alibabacloud.com/",
    ),
];

pub fn hosted(id: &str) -> Option<&'static Hosted> {
    HOSTED.iter().find(|hosted| hosted.id == id)
}

pub fn is_hosted(id: &str) -> bool {
    hosted(id).is_some()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn cada_proveedor_tiene_id_unico_https_y_pagina_de_claves() {
        for (index, hosted) in HOSTED.iter().enumerate() {
            assert!(HOSTED[index + 1..].iter().all(|other| other.id != hosted.id), "{} repetido", hosted.id);
            assert!(crate::ai::connection::validate_base_url(hosted.base_url).is_ok(), "{}", hosted.id);
            assert!(hosted.base_url.starts_with("https://") && hosted.console.starts_with("https://"), "{}", hosted.id);
            assert!(hosted.env.ends_with("_API_KEY"), "{}", hosted.id);
        }
        assert!(is_hosted("deepseek") && !is_hosted("custom") && !is_hosted("ollama"));
    }
}