import pytest from llm_connect.costs import CostEstimate, CostModel, estimate_cost from llm_connect.rates import ModelRate, ModelRateRegistry def test_known_model_cost_matches_lefevre_smoke_budget(): estimate = estimate_cost("openai/gpt-4o-mini", 28_000, 7_500) assert estimate.cost_source == "rate_table:openai/gpt-4o-mini" assert estimate.cost_usd == pytest.approx(0.0087) assert estimate.cost_usd == pytest.approx(0.009, rel=0.2) assert estimate.cost_eur is not None assert estimate.fx_source is not None def test_unknown_model_returns_unknown_without_zeroing_cost(): estimate = estimate_cost("unknown/model", 100, 50) assert estimate.cost_usd is None assert estimate.cost_eur is None assert estimate.cost_source == "unknown" def test_registry_override_controls_estimate(): registry = ModelRateRegistry( { "vendor/model": ModelRate( "vendor/model", prompt_per_1k=1.0, completion_per_1k=2.0, ) } ) estimate = estimate_cost("vendor/model", 1_000, 500, registry=registry, fx=1.0) assert estimate.cost_usd == pytest.approx(2.0) assert estimate.prompt_cost_usd == pytest.approx(1.0) assert estimate.completion_cost_usd == pytest.approx(1.0) assert estimate.cost_eur == pytest.approx(2.0) def test_zero_tokens_are_valid_and_cost_zero_for_known_model(): estimate = CostModel(fx=1.0).estimate_cost("openai/gpt-4o-mini", 0, 0) assert estimate.cost_usd == 0 assert estimate.prompt_cost_usd == 0 assert estimate.completion_cost_usd == 0 assert estimate.cost_eur == 0 def test_negative_tokens_are_rejected(): with pytest.raises(ValueError, match="prompt_tokens"): estimate_cost("openai/gpt-4o-mini", -1, 0) def test_kimi_k3_rate_and_eur_conversion(): estimate = estimate_cost("moonshotai/kimi-k3", 1_000, 1_000, fx=0.92) # $0.003 + $0.015 = $0.018; ×0.92 = €0.01656 assert estimate.cost_usd == pytest.approx(0.018) assert estimate.cost_eur == pytest.approx(0.01656) assert estimate.cost_source == "rate_table:moonshotai/kimi-k3" def test_apply_fx_false_skips_eur(): estimate = estimate_cost("moonshotai/kimi-k3", 100, 0, apply_fx=False) assert estimate.cost_usd is not None assert estimate.cost_eur is None assert estimate.fx_source is None