use serde::Deserialize;
const RAW: &str = cmduse_core::ZEN_JSON;
#[derive(Debug, Clone, Deserialize)]
pub struct RateVariant {
pub peak: Option<String>,
#[serde(rename = "tierMaxTokens")]
pub tier_max_tokens: Option<u64>,
#[serde(rename = "tierMinTokens")]
pub tier_min_tokens: Option<u64>,
pub input: f64,
pub output: f64,
#[serde(rename = "cacheRead")]
pub cache_read: f64,
#[serde(rename = "cacheWrite")]
pub cache_write: f64,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Model {
pub id: String,
pub name: String,
#[serde(rename = "monthlyLimit")]
pub monthly_limit: Option<f64>,
pub variants: Vec<RateVariant>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct WindowShare {
#[serde(rename = "fiveHour")]
pub five_hour: f64,
pub weekly: f64,
pub monthly: f64,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Plans {
#[serde(rename = "priceUsd")]
pub price_usd: f64,
#[serde(rename = "windowShare")]
pub window_share: WindowShare,
pub models: Vec<Model>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Zen {
pub models: Vec<Model>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Catalog {
#[serde(rename = "extractedAt")]
pub extracted_at: String,
pub go: Plans,
pub zen: Zen,
}
pub fn catalog() -> Catalog {
serde_json::from_str(RAW)
.expect("core/zen.json is generated; regenerate with scripts/extract-zen.ts")
}
impl Catalog {
pub fn go_limit(&self, model_id: &str) -> Option<f64> {
self.go
.models
.iter()
.find(|m| m.id == model_id)
.and_then(|m| m.monthly_limit)
}
}
pub fn window_cap(limit: f64, share: f64) -> f64 {
limit * share
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn catalogue_parses_and_carries_limits() {
let c = catalog();
assert!(c.go.models.len() > 20, "go models: {}", c.go.models.len());
assert!(!c.zen.models.is_empty());
assert_eq!(c.go_limit("deepseek-v4.1-flash"), Some(60.0));
assert_eq!(c.go_limit("nope-not-a-model"), None);
}
#[test]
fn window_split_matches_the_docs() {
let c = catalog();
assert_eq!(c.go.window_share.five_hour, 0.2);
assert_eq!(c.go.window_share.weekly, 0.5);
assert_eq!(c.go.window_share.monthly, 1.0);
assert_eq!(window_cap(60.0, c.go.window_share.five_hour), 12.0);
}
#[test]
fn tiered_and_peak_variants_are_kept() {
let c = catalog();
let qwen =
c.go.models
.iter()
.find(|m| m.id == "qwen3.7-plus")
.expect("qwen3.7-plus");
assert_eq!(qwen.variants.len(), 2);
assert!(qwen
.variants
.iter()
.any(|v| v.tier_max_tokens == Some(256_000)));
let deepseek =
c.go.models
.iter()
.find(|m| m.id == "deepseek-v4-flash")
.expect("deepseek");
assert!(deepseek
.variants
.iter()
.any(|v| v.peak.as_deref() == Some("peak")));
}
}