use crate::adapter::adapters::together::TogetherAdapter;
use crate::adapter::adapters::zai::ZaiAdapter;
use crate::adapter::anthropic::AnthropicAdapter;
use crate::adapter::bigmodel::BigModelAdapter;
use crate::adapter::cohere::CohereAdapter;
use crate::adapter::deepseek::{self, DeepSeekAdapter};
use crate::adapter::fireworks::FireworksAdapter;
use crate::adapter::gemini::GeminiAdapter;
use crate::adapter::groq::{self, GroqAdapter};
use crate::adapter::mimo::{self, MimoAdapter};
use crate::adapter::nebius::NebiusAdapter;
use crate::adapter::openai::OpenAIAdapter;
use crate::adapter::xai::XaiAdapter;
use crate::adapter::zai;
use crate::{ModelName, Result};
use derive_more::Display;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, Display, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum AdapterKind {
OpenAI,
OpenAIResp,
Gemini,
Anthropic,
Fireworks,
Together,
Groq,
Mimo,
Nebius,
Xai,
DeepSeek,
Zai,
BigModel,
Cohere,
Ollama,
}
impl AdapterKind {
pub fn as_str(&self) -> &'static str {
match self {
AdapterKind::OpenAI => "OpenAI",
AdapterKind::OpenAIResp => "OpenAIResp",
AdapterKind::Gemini => "Gemini",
AdapterKind::Anthropic => "Anthropic",
AdapterKind::Fireworks => "Fireworks",
AdapterKind::Together => "Together",
AdapterKind::Groq => "Groq",
AdapterKind::Mimo => "Mimo",
AdapterKind::Nebius => "Nebius",
AdapterKind::Xai => "xAi",
AdapterKind::DeepSeek => "DeepSeek",
AdapterKind::Zai => "Zai",
AdapterKind::BigModel => "BigModel",
AdapterKind::Cohere => "Cohere",
AdapterKind::Ollama => "Ollama",
}
}
pub fn as_lower_str(&self) -> &'static str {
match self {
AdapterKind::OpenAI => "openai",
AdapterKind::OpenAIResp => "openai_resp",
AdapterKind::Gemini => "gemini",
AdapterKind::Anthropic => "anthropic",
AdapterKind::Fireworks => "fireworks",
AdapterKind::Together => "together",
AdapterKind::Groq => "groq",
AdapterKind::Mimo => "mimo",
AdapterKind::Nebius => "nebius",
AdapterKind::Xai => "xai",
AdapterKind::DeepSeek => "deepseek",
AdapterKind::Zai => "zai",
AdapterKind::BigModel => "BigModel",
AdapterKind::Cohere => "cohere",
AdapterKind::Ollama => "ollama",
}
}
pub fn from_lower_str(name: &str) -> Option<Self> {
match name {
"openai" => Some(AdapterKind::OpenAI),
"openai_resp" => Some(AdapterKind::OpenAIResp),
"gemini" => Some(AdapterKind::Gemini),
"anthropic" => Some(AdapterKind::Anthropic),
"fireworks" => Some(AdapterKind::Fireworks),
"together" => Some(AdapterKind::Together),
"groq" => Some(AdapterKind::Groq),
"mimo" => Some(AdapterKind::Mimo),
"nebius" => Some(AdapterKind::Nebius),
"xai" => Some(AdapterKind::Xai),
"deepseek" => Some(AdapterKind::DeepSeek),
"zai" => Some(AdapterKind::Zai),
"bigmodel" => Some(AdapterKind::BigModel),
"cohere" => Some(AdapterKind::Cohere),
"ollama" => Some(AdapterKind::Ollama),
_ => None,
}
}
}
impl AdapterKind {
pub fn default_key_env_name(&self) -> Option<&'static str> {
match self {
AdapterKind::OpenAI => Some(OpenAIAdapter::API_KEY_DEFAULT_ENV_NAME),
AdapterKind::OpenAIResp => Some(OpenAIAdapter::API_KEY_DEFAULT_ENV_NAME),
AdapterKind::Gemini => Some(GeminiAdapter::API_KEY_DEFAULT_ENV_NAME),
AdapterKind::Anthropic => Some(AnthropicAdapter::API_KEY_DEFAULT_ENV_NAME),
AdapterKind::Fireworks => Some(FireworksAdapter::API_KEY_DEFAULT_ENV_NAME),
AdapterKind::Together => Some(TogetherAdapter::API_KEY_DEFAULT_ENV_NAME),
AdapterKind::Groq => Some(GroqAdapter::API_KEY_DEFAULT_ENV_NAME),
AdapterKind::Mimo => Some(MimoAdapter::API_KEY_DEFAULT_ENV_NAME),
AdapterKind::Nebius => Some(NebiusAdapter::API_KEY_DEFAULT_ENV_NAME),
AdapterKind::Xai => Some(XaiAdapter::API_KEY_DEFAULT_ENV_NAME),
AdapterKind::DeepSeek => Some(DeepSeekAdapter::API_KEY_DEFAULT_ENV_NAME),
AdapterKind::Zai => Some(ZaiAdapter::API_KEY_DEFAULT_ENV_NAME),
AdapterKind::BigModel => Some(BigModelAdapter::API_KEY_DEFAULT_ENV_NAME),
AdapterKind::Cohere => Some(CohereAdapter::API_KEY_DEFAULT_ENV_NAME),
AdapterKind::Ollama => None,
}
}
}
impl AdapterKind {
pub fn from_model(model: &str) -> Result<Self> {
if let Some(adapter) = Self::from_model_namespace(model) {
return Ok(adapter);
};
if model.starts_with("o3")
|| model.starts_with("o4")
|| model.starts_with("o1")
|| model.starts_with("chatgpt")
|| model.starts_with("codex")
|| (model.starts_with("gpt") && !model.starts_with("gpt-oss"))
|| model.starts_with("text-embedding")
{
if model.starts_with("gpt") && (model.contains("codex") || model.contains("pro")) {
Ok(Self::OpenAIResp)
} else {
Ok(Self::OpenAI)
}
} else if model.starts_with("gemini") {
Ok(Self::Gemini)
} else if model.starts_with("claude") {
Ok(Self::Anthropic)
} else if model.contains("fireworks") {
Ok(Self::Fireworks)
} else if groq::MODELS.contains(&model) {
Ok(Self::Groq)
} else if mimo::MODELS.contains(&model) {
Ok(Self::Mimo)
} else if model.starts_with("command") || model.starts_with("embed-") {
Ok(Self::Cohere)
} else if deepseek::MODELS.contains(&model) {
Ok(Self::DeepSeek)
} else if model.starts_with("grok") {
Ok(Self::Xai)
} else if model.starts_with("glm") {
Ok(Self::Zai)
}
else {
Ok(Self::Ollama)
}
}
}
impl AdapterKind {
fn from_model_namespace(model: &str) -> Option<Self> {
let (namespace, _) = ModelName::split_as_namespace_and_name(model);
let namespace = namespace?;
if let Some(adapter) = Self::from_lower_str(namespace) {
Some(adapter)
}
else if namespace == zai::ZAI_CODING_NAMESPACE {
Some(Self::Zai)
}
else {
None
}
}
}