litellm-rs 0.9.0

A high-performance AI Gateway written in Rust, providing OpenAI-compatible APIs with intelligent routing, load balancing, and enterprise features
Documentation
use super::*;
use crate::core::types::model::ProviderCapability;

#[test]
fn gemini_37_flash_is_registered_with_official_limits() {
    let spec = get_gemini_registry()
        .get_model_spec("gemini-3.7-flash")
        .expect("Gemini 3.7 Flash should be in the static catalog");

    assert_eq!(spec.model_info.id, "gemini-3.7-flash");
    assert_eq!(spec.limits.max_context_length, 1_048_576);
    assert_eq!(spec.limits.max_output_tokens, 65_536);
}

#[test]
fn gemini_37_flash_matches_official_capabilities_and_promotional_pricing() {
    let spec = get_gemini_registry()
        .get_model_spec("gemini-3.7-flash")
        .expect("Gemini 3.7 Flash should be in the static catalog");

    assert_eq!(spec.family, GeminiModelFamily::Gemini37Flash);
    for capability in [
        ProviderCapability::ChatCompletion,
        ProviderCapability::ChatCompletionStream,
        ProviderCapability::ToolCalling,
        ProviderCapability::FunctionCalling,
        ProviderCapability::CodeExecution,
        ProviderCapability::BatchProcessing,
    ] {
        assert!(spec.model_info.capabilities.contains(&capability));
    }
    for feature in [
        ModelFeature::MultimodalSupport,
        ModelFeature::ToolCalling,
        ModelFeature::FunctionCalling,
        ModelFeature::StreamingSupport,
        ModelFeature::ContextCaching,
        ModelFeature::BatchProcessing,
        ModelFeature::JsonMode,
        ModelFeature::CodeExecution,
        ModelFeature::SearchGrounding,
        ModelFeature::VideoUnderstanding,
        ModelFeature::AudioUnderstanding,
    ] {
        assert!(spec.features.contains(&feature), "missing {feature:?}");
    }
    assert!(!spec.features.contains(&ModelFeature::RealtimeStreaming));

    assert_eq!(
        spec.model_info.metadata["google_input_modalities"],
        serde_json::json!(["text", "image", "video", "audio", "pdf"])
    );
    assert_eq!(
        spec.model_info.metadata["google_output_modalities"],
        serde_json::json!(["text"])
    );
    assert_eq!(
        spec.model_info.metadata["google_thinking_levels"],
        serde_json::json!(["low", "medium", "high"])
    );
    assert_eq!(
        spec.model_info.metadata["google_default_thinking_level"],
        serde_json::json!("medium")
    );
    for key in [
        "supports_computer_use_preview",
        "supports_file_search",
        "supports_maps_grounding",
        "supports_url_context",
        "supports_flex_inference",
        "supports_priority_inference",
    ] {
        assert_eq!(spec.model_info.metadata[key], serde_json::json!(true));
    }
    for key in [
        "supports_minimal_thinking",
        "supports_live_api",
        "supports_audio_generation",
        "supports_image_generation",
    ] {
        assert_eq!(spec.model_info.metadata[key], serde_json::json!(false));
    }

    assert_eq!(spec.model_info.input_cost_per_1k_tokens, Some(0.00075));
    assert_eq!(spec.model_info.output_cost_per_1k_tokens, Some(0.00375));
    assert_eq!(spec.pricing.input_cost_per_1k_tokens, 0.00075);
    assert_eq!(spec.pricing.output_cost_per_1k_tokens, 0.00375);
    assert_eq!(spec.pricing.cache_read_input_token_cost, Some(0.000075));
    assert_eq!(spec.pricing.batch_discount, None);
    assert_eq!(
        spec.model_info.metadata["google_promotional_pricing_through"],
        serde_json::json!("2026-12-31")
    );
    assert_eq!(
        spec.model_info.metadata["google_standard_pricing_from"],
        serde_json::json!("2027-01-01")
    );
}

#[test]
fn gemini_37_family_recognition_is_exact_only() {
    assert_eq!(
        GeminiModelRegistry::from_model_name("gemini-3.7-flash"),
        Some(GeminiModelFamily::Gemini37Flash)
    );
    for lookalike in [
        "GEMINI-3.7-FLASH",
        "gemini-3.7-flash-preview",
        "gemini-3.7-flash-20260813",
        "prefix-gemini-3.7-flash",
        "gemini-3.7-flash-suffix",
    ] {
        assert_eq!(GeminiModelRegistry::from_model_name(lookalike), None);
        assert!(get_gemini_registry().get_model_spec(lookalike).is_none());
    }
}

#[test]
fn gemini_37_shared_context_window_is_exact_only() {
    use crate::core::providers::shared::{GEMINI_31_CONTEXT_WINDOW, gemini_context_window};

    assert_eq!(
        gemini_context_window("gemini-3.7-flash"),
        Some(GEMINI_31_CONTEXT_WINDOW)
    );
    for qualified in [
        "gemini/gemini-3.7-flash",
        "google/gemini-3.7-flash",
        "vertex_ai/gemini-3.7-flash",
    ] {
        assert_eq!(
            gemini_context_window(qualified),
            Some(GEMINI_31_CONTEXT_WINDOW),
            "{qualified}"
        );
    }
    for lookalike in [
        "GEMINI-3.7-FLASH",
        "other/gemini-3.7-flash",
        "gemini/gemini/gemini-3.7-flash",
        "gemini-3.7-flash-preview",
        "gemini-3.7-flash-20260813",
        "prefix-gemini-3.7-flash",
        "gemini-3.7-flash-suffix",
    ] {
        assert_eq!(gemini_context_window(lookalike), None, "{lookalike}");
    }
}

#[test]
fn gemini_36_static_catalog_uses_current_promotional_fallback() {
    let spec = get_gemini_registry()
        .get_model_spec("gemini-3.6-flash")
        .expect("Gemini 3.6 Flash should remain in the static catalog");

    assert_eq!(spec.model_info.input_cost_per_1k_tokens, Some(0.00075));
    assert_eq!(spec.model_info.output_cost_per_1k_tokens, Some(0.00375));
    assert_eq!(spec.pricing.input_cost_per_1k_tokens, 0.00075);
    assert_eq!(spec.pricing.output_cost_per_1k_tokens, 0.00375);
    assert_eq!(spec.pricing.cache_read_input_token_cost, Some(0.000075));
    assert_eq!(spec.pricing.batch_discount, None);
}

#[test]
fn gemini_flash_listings_switch_at_the_exact_utc_boundary() {
    use chrono::{TimeZone, Utc};

    let registry = get_gemini_registry();
    let before = Utc.with_ymd_and_hms(2026, 12, 31, 23, 59, 59).unwrap();
    let at = Utc.with_ymd_and_hms(2027, 1, 1, 0, 0, 0).unwrap();

    for surface in [
        GoogleGeminiApiSurface::DeveloperApi,
        GoogleGeminiApiSurface::VertexAi,
    ] {
        let price_at = |time| {
            registry
                .list_model_infos_for_surface_at(surface, time)
                .into_iter()
                .find(|model| model.id == "gemini-3.7-flash")
                .map(|model| {
                    (
                        model.input_cost_per_1k_tokens,
                        model.output_cost_per_1k_tokens,
                        model.metadata["google_current_cache_storage_cost_per_million_token_hour"]
                            .as_f64(),
                    )
                })
        };
        assert_eq!(
            price_at(before),
            Some((Some(0.00075), Some(0.00375), Some(0.5)))
        );
        assert_eq!(price_at(at), Some((Some(0.0015), Some(0.0075), Some(1.0))));
    }
}

#[test]
fn gemini_38_flash_matches_official_capabilities_and_promotional_pricing() {
    let spec = get_gemini_registry()
        .get_model_spec("gemini-3.8-flash")
        .expect("Gemini 3.8 Flash should be in the static catalog");

    assert_eq!(spec.family, GeminiModelFamily::Gemini38Flash);
    for capability in [
        ProviderCapability::ChatCompletion,
        ProviderCapability::ChatCompletionStream,
        ProviderCapability::ToolCalling,
        ProviderCapability::FunctionCalling,
        ProviderCapability::CodeExecution,
        ProviderCapability::BatchProcessing,
    ] {
        assert!(spec.model_info.capabilities.contains(&capability));
    }
    for feature in [
        ModelFeature::MultimodalSupport,
        ModelFeature::ToolCalling,
        ModelFeature::FunctionCalling,
        ModelFeature::StreamingSupport,
        ModelFeature::ContextCaching,
        ModelFeature::BatchProcessing,
        ModelFeature::JsonMode,
        ModelFeature::CodeExecution,
        ModelFeature::SearchGrounding,
        ModelFeature::VideoUnderstanding,
        ModelFeature::AudioUnderstanding,
    ] {
        assert!(spec.features.contains(&feature), "missing {feature:?}");
    }
    assert!(!spec.features.contains(&ModelFeature::RealtimeStreaming));

    assert_eq!(
        spec.model_info.metadata["google_input_modalities"],
        serde_json::json!(["text", "image", "video", "audio", "pdf"])
    );
    assert_eq!(
        spec.model_info.metadata["google_output_modalities"],
        serde_json::json!(["text"])
    );
    assert_eq!(
        spec.model_info.metadata["google_thinking_levels"],
        serde_json::json!(["low", "medium", "high"])
    );
    assert_eq!(
        spec.model_info.metadata["google_default_thinking_level"],
        serde_json::json!("medium")
    );
    for key in [
        "supports_computer_use_preview",
        "supports_file_search",
        "supports_maps_grounding",
        "supports_url_context",
        "supports_flex_inference",
        "supports_priority_inference",
    ] {
        assert_eq!(spec.model_info.metadata[key], serde_json::json!(true));
    }
    for key in [
        "supports_minimal_thinking",
        "supports_live_api",
        "supports_audio_generation",
        "supports_image_generation",
    ] {
        assert_eq!(spec.model_info.metadata[key], serde_json::json!(false));
    }

    assert_eq!(spec.model_info.input_cost_per_1k_tokens, Some(0.00075));
    assert_eq!(spec.model_info.output_cost_per_1k_tokens, Some(0.00375));
    assert_eq!(spec.pricing.input_cost_per_1k_tokens, 0.00075);
    assert_eq!(spec.pricing.output_cost_per_1k_tokens, 0.00375);
    assert_eq!(spec.pricing.cache_read_input_token_cost, Some(0.000075));
    assert_eq!(spec.pricing.batch_discount, None);
    assert_eq!(
        spec.model_info.metadata["google_promotional_pricing_through"],
        serde_json::json!("2026-12-31")
    );
    assert_eq!(
        spec.model_info.metadata["google_standard_pricing_from"],
        serde_json::json!("2027-01-01")
    );
}