use serde::Serialize;
use super::AgentKind;
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
pub struct ProviderId(String);
impl ProviderId {
pub fn new(id: impl Into<String>) -> Self {
Self(id.into())
}
pub fn unknown() -> Self {
Self("unknown".to_string())
}
pub fn as_str(&self) -> &str {
&self.0
}
pub fn is_unknown(&self) -> bool {
self.0 == "unknown"
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
pub enum MeteringShape {
AccountPool,
PerModelFamily,
SpendBudget,
Subscription,
None,
Unknown,
}
pub fn provider_for_cli(cli: AgentKind) -> (ProviderId, MeteringShape) {
let (id, shape) = match cli {
AgentKind::Codex => ("openai-chatgpt-plan", MeteringShape::AccountPool),
AgentKind::Qwen => ("alibaba-modelstudio-token-plan", MeteringShape::AccountPool),
AgentKind::Antigravity => ("google-antigravity-individual", MeteringShape::PerModelFamily),
AgentKind::OpenCode => ("opencode-zen", MeteringShape::SpendBudget),
AgentKind::Oz => ("warp", MeteringShape::AccountPool),
AgentKind::Droid => ("factory", MeteringShape::AccountPool),
AgentKind::Grok => ("xai", MeteringShape::Unknown),
AgentKind::Cursor => ("cursor-subscription", MeteringShape::Subscription),
AgentKind::Claude => ("anthropic", MeteringShape::Unknown),
AgentKind::Gemini => ("google-genai", MeteringShape::Unknown),
AgentKind::Copilot => ("github-copilot", MeteringShape::Subscription),
AgentKind::Kilo | AgentKind::MiMoCode | AgentKind::Codebuff | AgentKind::Custom => {
("unknown", MeteringShape::Unknown)
}
};
(ProviderId::new(id), shape)
}
pub fn model_family(model: &str) -> &'static str {
let model = model.to_ascii_lowercase();
if model.starts_with("gemini") {
"gemini"
} else if model.starts_with("claude") {
"claude"
} else if model.starts_with("gpt") {
"gpt-oss"
} else {
"other"
}
}
#[cfg(test)]
#[path = "provider_tests.rs"]
mod tests;