use std::collections::HashSet;
use std::sync::LazyLock;
pub const ZEN_PROVIDER: &str = "opencode-zen";
static ZEN_ANTHROPIC_MODELS: LazyLock<HashSet<&'static str>> = LazyLock::new(|| {
let mut s = HashSet::new();
s.insert("big-pickle");
s.insert("minimax-m2.1-free");
s.insert("minimax-m2.5-free");
s.insert("qwen3.5-plus");
s.insert("qwen3.6-plus");
s
});
pub fn is_anthropic_model(model_id: &str) -> bool {
model_id.starts_with("claude-")
|| model_id.starts_with("claude_")
|| ZEN_ANTHROPIC_MODELS.contains(model_id)
}
pub fn is_google_model(model_id: &str) -> bool {
model_id.starts_with("gemini-")
}
pub fn is_responses_model(model_id: &str) -> bool {
model_id.starts_with("gpt-5") || model_id == "gpt-5"
}
pub fn anthropic_api_base(provider_api_base: Option<&str>) -> String {
let base = provider_api_base
.unwrap_or("https://opencode.ai/zen/v1")
.trim_end_matches('/');
base.strip_suffix("/v1").unwrap_or(base).to_owned()
}
pub fn google_api_base(provider_api_base: Option<&str>) -> String {
let base = provider_api_base
.unwrap_or("https://opencode.ai/zen/v1")
.trim_end_matches('/');
base.strip_suffix("/v1").unwrap_or(base).to_owned()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn claude_models_detected_as_anthropic() {
assert!(is_anthropic_model("claude-sonnet-4-6"));
assert!(is_anthropic_model("claude-haiku-4-5"));
assert!(is_anthropic_model("claude-opus-4-7"));
assert!(is_anthropic_model("claude-3-5-haiku"));
}
#[test]
fn non_claude_anthropic_models_detected() {
assert!(is_anthropic_model("big-pickle"));
assert!(is_anthropic_model("qwen3.5-plus"));
assert!(is_anthropic_model("qwen3.6-plus"));
assert!(is_anthropic_model("minimax-m2.5-free"));
assert!(is_anthropic_model("minimax-m2.1-free"));
}
#[test]
fn openai_models_not_anthropic() {
assert!(!is_anthropic_model("gpt-5.5"));
assert!(!is_anthropic_model("glm-5.1"));
assert!(!is_anthropic_model("minimax-m2.7"));
}
#[test]
fn gemini_models_detected_as_google() {
assert!(is_google_model("gemini-3-flash"));
assert!(is_google_model("gemini-3.1-pro"));
assert!(!is_google_model("gpt-5.4"));
}
#[test]
fn gpt_models_detected_as_responses() {
assert!(is_responses_model("gpt-5.5"));
assert!(is_responses_model("gpt-5.4-pro"));
assert!(is_responses_model("gpt-5.4-mini"));
assert!(is_responses_model("gpt-5-nano"));
assert!(is_responses_model("gpt-5"));
assert!(is_responses_model("gpt-5.1-codex"));
assert!(is_responses_model("gpt-5.3-codex-spark"));
assert!(!is_responses_model("claude-sonnet-4-6"));
assert!(!is_responses_model("glm-5.1"));
}
#[test]
fn anthropic_base_url_strips_v1() {
assert_eq!(
anthropic_api_base(Some("https://opencode.ai/zen/v1")),
"https://opencode.ai/zen"
);
assert_eq!(
anthropic_api_base(Some("https://opencode.ai/zen/v1/")),
"https://opencode.ai/zen"
);
}
#[test]
fn google_base_url_strips_v1() {
assert_eq!(
google_api_base(Some("https://opencode.ai/zen/v1")),
"https://opencode.ai/zen"
);
}
}