wsb 0.172.1105

Workspace - A tool suite for file operations, version management, and development workflow automation
Documentation
use crate::prelude::*;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModelPricing {
    pub model_pattern: String,
    pub input_per_mtok: f64,
    pub output_per_mtok: f64,
    pub cache_creation_per_mtok: f64,
    pub cache_read_per_mtok: f64,
}

pub const FALLBACK_VERSION: &str = "2026-04-13";

pub fn fallback_pricing() -> Vec<ModelPricing> {
    vec![
        ModelPricing {
            model_pattern: "claude-sonnet-4-6".to_string(),
            input_per_mtok: 3.0,
            output_per_mtok: 15.0,
            cache_creation_per_mtok: 3.75,
            cache_read_per_mtok: 0.30,
        },
        ModelPricing {
            model_pattern: "claude-opus-4-6".to_string(),
            input_per_mtok: 5.0,
            output_per_mtok: 25.0,
            cache_creation_per_mtok: 6.25,
            cache_read_per_mtok: 0.50,
        },
        ModelPricing {
            model_pattern: "claude-haiku-4-5-20251001".to_string(),
            input_per_mtok: 1.0,
            output_per_mtok: 5.0,
            cache_creation_per_mtok: 1.25,
            cache_read_per_mtok: 0.10,
        },
        ModelPricing {
            model_pattern: "gpt-5.4".to_string(),
            input_per_mtok: 2.50,
            output_per_mtok: 15.0,
            cache_creation_per_mtok: 0.0,
            cache_read_per_mtok: 0.0,
        },
        ModelPricing {
            model_pattern: "gpt-5.2-codex".to_string(),
            input_per_mtok: 1.75,
            output_per_mtok: 14.0,
            cache_creation_per_mtok: 0.0,
            cache_read_per_mtok: 0.0,
        },
        ModelPricing {
            model_pattern: "gpt-5.3-codex".to_string(),
            input_per_mtok: 1.75,
            output_per_mtok: 14.0,
            cache_creation_per_mtok: 0.0,
            cache_read_per_mtok: 0.0,
        },
        ModelPricing {
            model_pattern: "gpt-5.4-mini".to_string(),
            input_per_mtok: 0.75,
            output_per_mtok: 4.50,
            cache_creation_per_mtok: 0.0,
            cache_read_per_mtok: 0.0,
        },
        ModelPricing {
            model_pattern: "gpt-5.4-nano".to_string(),
            input_per_mtok: 0.20,
            output_per_mtok: 1.25,
            cache_creation_per_mtok: 0.0,
            cache_read_per_mtok: 0.0,
        },
        ModelPricing {
            model_pattern: "claude-sonnet-4-20250514".to_string(),
            input_per_mtok: 3.0,
            output_per_mtok: 15.0,
            cache_creation_per_mtok: 3.75,
            cache_read_per_mtok: 0.30,
        },
        ModelPricing {
            model_pattern: "claude-sonnet-4-5-20250514".to_string(),
            input_per_mtok: 3.0,
            output_per_mtok: 15.0,
            cache_creation_per_mtok: 3.75,
            cache_read_per_mtok: 0.30,
        },
        ModelPricing {
            model_pattern: "claude-opus-4-20250514".to_string(),
            input_per_mtok: 15.0,
            output_per_mtok: 75.0,
            cache_creation_per_mtok: 18.75,
            cache_read_per_mtok: 1.50,
        },
        ModelPricing {
            model_pattern: "claude-haiku-3-5-20241022".to_string(),
            input_per_mtok: 0.80,
            output_per_mtok: 4.0,
            cache_creation_per_mtok: 1.0,
            cache_read_per_mtok: 0.08,
        },
    ]
}

pub fn find_pricing<'a>(model: &str, prices: &'a [ModelPricing]) -> Option<&'a ModelPricing> {
    for pricing in prices {
        if model.contains(&pricing.model_pattern) {
            return Some(pricing);
        }
        let pattern_lower = pricing.model_pattern.to_lowercase();
        let model_lower = model.to_lowercase();
        if model_lower.contains(&pattern_lower) {
            return Some(pricing);
        }
    }
    None
}

pub fn calculate_cost(
    input_tokens: i64,
    output_tokens: i64,
    cache_creation_tokens: i64,
    cache_read_tokens: i64,
    pricing: &ModelPricing,
) -> f64 {
    let input_cost = (input_tokens as f64 / 1_000_000.0) * pricing.input_per_mtok;
    let output_cost = (output_tokens as f64 / 1_000_000.0) * pricing.output_per_mtok;
    let cache_creation_cost =
        (cache_creation_tokens as f64 / 1_000_000.0) * pricing.cache_creation_per_mtok;
    let cache_read_cost = (cache_read_tokens as f64 / 1_000_000.0) * pricing.cache_read_per_mtok;
    input_cost + output_cost + cache_creation_cost + cache_read_cost
}