use super::*;
#[test]
fn machine_and_session_remaining_project_the_tighter_limit() {
reset_cost_state();
let temp = tempfile::tempdir().unwrap();
let quota = crate::llm::MachineSpendQuota::open(
temp.path().join("spend.sqlite"),
"person",
crate::llm::MachineSpendPolicy {
daily_limit_microusd: Some(500_000),
monthly_limit_microusd: Some(700_000),
lifetime_limit_microusd: Some(300_000),
},
)
.unwrap();
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap()
.block_on(async {
quota
.scope(async {
set_llm_cost_budget(Some(0.4));
let result = llm_budget_remaining_impl(&[], &mut String::new()).unwrap();
match result {
VmValue::Float(value) => assert!((value - 0.3).abs() < 1e-9),
other => panic!("expected the effective remaining allowance: {other:?}"),
}
let execution = crate::llm::ConservativeLlmBudget::new(0.2).unwrap();
execution
.scope(async {
let result =
llm_budget_remaining_impl(&[], &mut String::new()).unwrap();
match result {
VmValue::Float(value) => assert!((value - 0.2).abs() < 1e-9),
other => {
panic!("expected the tighter execution allowance: {other:?}")
}
}
})
.await
.unwrap();
})
.await
.unwrap();
});
reset_cost_state();
}
#[test]
fn calculate_cost_uses_catalog_model_pricing() {
let _guard = crate::llm::env_guard();
let mut overlay = crate::llm_config::ProvidersConfig::default();
overlay.models.insert(
"gpt-4o-mini".to_string(),
crate::llm_config::ModelDef {
data_controls: None,
name: "Test GPT-4o Mini".to_string(),
display_name: None,
blurb: None,
provider: "openai".to_string(),
context_window: 128_000,
reasoning_modes: Vec::new(),
logical_model: None,
equivalence_group: None,
served_variant: None,
wire_model: None,
api_dialect: None,
rate_limits: None,
performance: None,
architecture: None,
local_memory: None,
runtime_context_window: None,
stream_timeout: None,
capabilities: Vec::new(),
pricing: Some(crate::llm_config::ModelPricing {
input_per_mtok: 10.0,
output_per_mtok: 20.0,
cache_read_per_mtok: None,
cache_write_per_mtok: None,
cache_write_1h_per_mtok: None,
input_token_bands: Vec::new(),
promotions: Vec::new(),
schedules: Vec::new(),
hosted_tool_fees: Default::default(),
modality_rates: None,
}),
deprecated: false,
deprecation_note: None,
sunset_date: None,
superseded_by: None,
serving_tiers: Vec::new(),
quality_tags: Vec::new(),
availability: crate::llm_config::ModelAvailability::default(),
tier: None,
open_weight: None,
strengths: Vec::new(),
benchmarks: std::collections::BTreeMap::new(),
family: None,
lineage: None,
complementary_with: Vec::new(),
avoid_as_reviewer_for: Vec::new(),
completion_review: None,
released: None,
row_kind: None,
current_snapshot: None,
embedding_dim: None,
operations: None,
embedding_max_tokens: None,
},
);
crate::llm_config::set_user_overrides(Some(overlay));
assert_eq!(
calculate_cost_decimal("gpt-4o-mini", 1000, 1000, settlement_now()),
Decimal::from_str("0.03").unwrap()
);
crate::llm_config::clear_user_overrides();
}
#[test]
fn calculate_cost_is_zero_for_unknown_model() {
let _guard = crate::llm::env_guard();
crate::llm_config::clear_user_overrides();
assert_eq!(
calculate_cost_decimal("definitely-unpriced-model", 1_000, 1_000, settlement_now()),
Decimal::ZERO
);
}
#[test]
fn authored_rate_decimal_recovers_the_written_literal_not_float_noise() {
for (raw, written) in [
(0.15_f64, "0.15"),
(0.8, "0.8"),
(0.08, "0.08"),
(4.0, "4"),
(0.0, "0"),
(3.75, "3.75"),
] {
let recovered = authored_rate_decimal(raw);
assert_eq!(
recovered,
Decimal::from_str(written).unwrap(),
"rate {raw} should recover as {written}"
);
}
assert_ne!(
authored_rate_decimal(0.1),
Decimal::from_f64_retain(0.1).unwrap()
);
}
#[test]
fn calculate_cost_decimal_is_exact_for_inexact_catalog_rates() {
let _guard = crate::llm::env_guard();
let mut overlay = crate::llm_config::ProvidersConfig::default();
overlay.models.insert(
"gpt-4o-mini".to_string(),
crate::llm_config::ModelDef {
data_controls: None,
name: "Test GPT-4o Mini".to_string(),
display_name: None,
blurb: None,
provider: "openai".to_string(),
context_window: 128_000,
reasoning_modes: Vec::new(),
logical_model: None,
equivalence_group: None,
served_variant: None,
wire_model: None,
api_dialect: None,
rate_limits: None,
performance: None,
architecture: None,
local_memory: None,
runtime_context_window: None,
stream_timeout: None,
capabilities: Vec::new(),
pricing: Some(crate::llm_config::ModelPricing {
input_per_mtok: 0.15,
output_per_mtok: 0.60,
cache_read_per_mtok: None,
cache_write_per_mtok: None,
cache_write_1h_per_mtok: None,
input_token_bands: Vec::new(),
promotions: Vec::new(),
schedules: Vec::new(),
hosted_tool_fees: Default::default(),
modality_rates: None,
}),
deprecated: false,
deprecation_note: None,
sunset_date: None,
superseded_by: None,
serving_tiers: Vec::new(),
quality_tags: Vec::new(),
availability: crate::llm_config::ModelAvailability::default(),
tier: None,
open_weight: None,
strengths: Vec::new(),
benchmarks: std::collections::BTreeMap::new(),
family: None,
lineage: None,
complementary_with: Vec::new(),
avoid_as_reviewer_for: Vec::new(),
completion_review: None,
released: None,
row_kind: None,
current_snapshot: None,
embedding_dim: None,
operations: None,
embedding_max_tokens: None,
},
);
crate::llm_config::set_user_overrides(Some(overlay));
assert_eq!(
calculate_cost_decimal("gpt-4o-mini", 1000, 500, settlement_now()),
Decimal::from_str("0.00045").unwrap()
);
crate::llm_config::clear_user_overrides();
}
#[test]
fn calculate_cost_for_mock_uses_the_modeled_catalog_price() {
let _guard = crate::llm::env_guard();
crate::llm_config::clear_user_overrides();
let mocked = calculate_cost_for_provider("mock", "gpt-4o-mini", 3_000, 4_000, settlement_now());
let live = calculate_cost_for_provider("openai", "gpt-4o-mini", 3_000, 4_000, settlement_now());
assert!(mocked > 0.001);
assert!((mocked - live).abs() < 1e-12);
}
#[test]
fn calculate_cost_for_provider_falls_back_to_provider_economics() {
let _guard = crate::llm::env_guard();
crate::llm_config::clear_user_overrides();
let cost = calculate_cost_for_provider(
"openai",
"some-bespoke-openai-deployment",
1_000,
1_000,
settlement_now(),
);
let (input_per_1k, output_per_1k, _) = crate::llm_config::provider_economics("openai");
let expected = (1_000.0 * input_per_1k.unwrap() + 1_000.0 * output_per_1k.unwrap()) / 1_000.0;
assert!(
(cost - expected).abs() < 1e-9,
"cost={cost}, expected={expected}"
);
}
#[test]
fn self_hosted_routes_are_priced_at_zero_and_paid_routes_stay_unpriced() {
let _guard = crate::llm::env_guard();
crate::llm_config::clear_user_overrides();
for provider in ["llamacpp", "ollama", "mlx", "vllm"] {
let cost = pricing_aware_call_cost(
provider,
"any-locally-served-model",
1_000,
1_000,
settlement_now(),
);
assert_eq!(
cost,
Some(0.0),
"{provider} declares local_runtime, so its rate is known-zero, not unknown"
);
}
let mut overlay = crate::llm_config::ProvidersConfig::default();
overlay.providers.insert(
"rateless-local".to_string(),
crate::llm_config::ProviderDef {
local_runtime: Some(crate::llm_config::LocalRuntimeDef::default()),
cost_per_1k_in: None,
cost_per_1k_out: None,
..crate::llm_config::ProviderDef::default()
},
);
crate::llm_config::set_user_overrides(Some(overlay));
assert!(crate::llm_config::provider_is_self_hosted("rateless-local"));
assert_eq!(
pricing_aware_call_cost("rateless-local", "whatever", 1_000, 1_000, settlement_now()),
Some(0.0),
"a self-hosted provider that declares no rate is still known-zero"
);
crate::llm_config::clear_user_overrides();
assert_eq!(
pricing_aware_call_cost(
"some-unlisted-paid-provider",
"whatever",
1_000,
1_000,
settlement_now()
),
None,
"a provider with neither catalog pricing nor a local runtime stays unpriced"
);
assert!(crate::llm_config::provider_is_self_hosted("llamacpp"));
assert!(!crate::llm_config::provider_is_self_hosted("openai"));
assert!(!crate::llm_config::provider_is_self_hosted(
"some-unlisted-paid-provider"
));
}
#[test]
fn calculate_cost_for_provider_with_cache_applies_cache_read_discount() {
let _guard = crate::llm::env_guard();
crate::llm_config::clear_user_overrides();
let without_cache = calculate_cost_for_provider(
"anthropic",
"claude-sonnet-4-20250514",
1_000,
1_000,
settlement_now(),
);
let with_cache = pricing_aware_call_cost_with_cache(
"anthropic",
"claude-sonnet-4-20250514",
1_000,
1_000,
500,
0,
settlement_now(),
None,
)
.expect("catalog-priced model");
assert!(with_cache > 0.0);
assert!(
with_cache < without_cache,
"cache reads should be priced below uncached prompt input"
);
}
#[test]
fn pricing_detail_reports_source() {
let _guard = crate::llm::env_guard();
crate::llm_config::clear_user_overrides();
let exact =
pricing_detail_for("anthropic", "claude-sonnet-4-20250514", settlement_now()).unwrap();
assert_eq!(exact.source, PricingSource::CatalogModel);
assert!(exact.cache_read_per_1k.is_some());
let provider_only =
pricing_detail_for("openai", "some-bespoke-openai-deployment", settlement_now()).unwrap();
assert_eq!(provider_only.source, PricingSource::ProviderEconomics);
assert!(provider_only.cache_read_per_1k.is_none());
assert!(pricing_detail_for("local", "no-such-local-model", settlement_now()).is_some()); assert!(pricing_detail_for("nonexistent_provider", "ghost-model", settlement_now()).is_none());
}
#[test]
fn pricing_aware_call_cost_distinguishes_unpriced_from_zero() {
let _guard = crate::llm::env_guard();
crate::llm_config::clear_user_overrides();
let priced = pricing_aware_call_cost(
"anthropic",
"claude-sonnet-4-20250514",
1_000,
1_000,
settlement_now(),
);
let expected = calculate_cost_for_provider(
"anthropic",
"claude-sonnet-4-20250514",
1_000,
1_000,
settlement_now(),
);
assert!(priced.is_some());
assert!((priced.unwrap() - expected).abs() < 1e-9);
assert_eq!(
pricing_aware_call_cost(
"nonexistent_provider",
"ghost-model",
1_000,
1_000,
settlement_now()
),
None
);
assert_eq!(
calculate_cost_for_provider(
"nonexistent_provider",
"ghost-model",
1_000,
1_000,
settlement_now()
),
0.0
);
}
#[test]
fn format_usd_amount_auto_precision_and_grouping() {
assert_eq!(format_usd_amount(0.000_045, None, false), "$0.000045");
assert_eq!(format_usd_amount(1.234_5, None, false), "$1.2345");
assert_eq!(format_usd_amount(1234.5, None, false), "$1,234.50");
assert_eq!(format_usd_amount(-1234.5, None, false), "-$1,234.50");
assert_eq!(format_usd_amount(1234.5, None, true), "+$1,234.50");
assert_eq!(format_usd_amount(0.123_456_789, Some(2), false), "$0.12");
assert_eq!(format_usd_amount(1.0, Some(0), false), "$1");
}
#[test]
fn format_usd_handles_fractional_carry_into_whole() {
let amount = 0.000_27_f64 * 300_000.0;
assert!((amount - 81.0).abs() < 1e-6);
assert_eq!(format_usd_amount(amount, None, false), "$81.0000");
}
#[test]
fn fast_tier_bills_premium_pricing_when_served_fast() {
let _guard = crate::llm::env_guard();
crate::llm_config::clear_user_overrides();
let standard =
pricing_detail_for_tier("anthropic", "claude-opus-4-8", false, 0, settlement_now())
.unwrap();
let fast =
pricing_detail_for_tier("anthropic", "claude-opus-4-8", true, 0, settlement_now()).unwrap();
assert_eq!(standard.source, PricingSource::CatalogModel);
assert_eq!(fast.source, PricingSource::CatalogServingTier);
assert!((fast.input_per_1k - 2.0 * standard.input_per_1k).abs() < 1e-9);
assert!((fast.output_per_1k - 2.0 * standard.output_per_1k).abs() < 1e-9);
let no_fast = pricing_detail_for_tier(
"anthropic",
"claude-sonnet-4-20250514",
true,
0,
settlement_now(),
)
.unwrap();
assert_eq!(no_fast.source, PricingSource::CatalogModel);
}
#[test]
fn project_call_cost_excludes_cached_input_from_full_rate() {
let detail =
pricing_detail_for("anthropic", "claude-sonnet-4-20250514", settlement_now()).unwrap();
let with_cache = project_call_cost(&detail, 10_000, 500, 8_000, 0, None);
let no_cache = project_call_cost(&detail, 10_000, 500, 0, 0, None);
assert!(with_cache < no_cache);
}
#[test]
fn project_call_cost_openai_subset_convention_subtracts_cache() {
let detail =
pricing_detail_for("anthropic", "claude-sonnet-4-20250514", settlement_now()).unwrap();
let cache_read_rate = detail.cache_read_per_1k.unwrap_or(detail.input_per_1k);
let got = project_call_cost(&detail, 10_000, 500, 8_000, 0, None);
let expected =
(2_000.0 * detail.input_per_1k + 500.0 * detail.output_per_1k + 8_000.0 * cache_read_rate)
/ 1000.0;
assert!((got - expected).abs() < 1e-9);
}
#[test]
fn project_call_cost_normalized_anthropic_bills_fresh_read_and_write() {
let detail =
pricing_detail_for("anthropic", "claude-sonnet-4-20250514", settlement_now()).unwrap();
let cache_read_rate = detail.cache_read_per_1k.unwrap_or(detail.input_per_1k);
let cache_write_rate = detail.cache_write_per_1k.unwrap_or(detail.input_per_1k);
for fresh in [200, 20_000] {
let counts = crate::llm::usage::PromptTokenCounts::from_reported(
fresh,
10_000,
100,
crate::llm::usage::InputTokenBasis::Fresh,
)
.unwrap();
let got = project_call_cost(&detail, counts.total, 500, 10_000, 100, None);
let expected = (fresh as f64 * detail.input_per_1k
+ 500.0 * detail.output_per_1k
+ 10_000.0 * cache_read_rate
+ 100.0 * cache_write_rate)
/ 1000.0;
assert!((got - expected).abs() < 1e-9);
}
}
#[test]
fn cache_savings_uses_catalog_cache_pricing() {
let _guard = crate::llm::env_guard();
crate::llm_config::clear_user_overrides();
let savings = cache_savings_usd_for_provider(
"anthropic",
"claude-sonnet-4-20250514",
1000,
1000,
0,
settlement_now(),
None,
);
assert!((savings - 0.0027).abs() < 0.0000001);
let write_delta = cache_savings_usd_for_provider(
"anthropic",
"claude-sonnet-4-20250514",
1000,
0,
1000,
settlement_now(),
None,
);
assert!((write_delta + 0.00075).abs() < 0.0000001);
crate::llm_config::clear_user_overrides();
}
#[test]
fn cache_hit_ratio_uses_full_prompt_totals() {
assert!((cache_hit_ratio(1000, 250) - 0.25).abs() < f64::EPSILON);
assert!((cache_hit_ratio(1000, 900) - 0.9).abs() < f64::EPSILON);
assert_eq!(cache_hit_ratio(0, 0), 0.0);
}
#[test]
fn token_budget_guard_restores_prior_state_on_drop() {
let _guard_outer = crate::llm::env_guard();
reset_cost_state();
let outer = install_llm_token_budget(100);
assert_eq!(peek_total_tokens(), 0);
accumulate_llm_usage("test", 50, 0, 0.0).unwrap();
{
let _inner = install_llm_token_budget(10);
assert_eq!(peek_total_tokens(), 0);
accumulate_llm_usage("test", 5, 0, 0.0).unwrap();
}
assert_eq!(peek_total_tokens(), 50);
drop(outer);
assert_eq!(peek_total_tokens(), 0);
reset_cost_state();
}
#[test]
fn set_budget_rearms_in_place_without_resetting_accumulation() {
let _guard_outer = crate::llm::env_guard();
reset_cost_state();
let _budget = install_llm_cost_budget(1.0);
accumulate_llm_usage("test", 0, 0, 0.60).unwrap();
set_llm_cost_budget(Some(0.50));
assert!((peek_total_cost() - 0.60).abs() < f64::EPSILON);
assert_eq!(peek_llm_cost_budget(), Some(0.50));
set_llm_cost_budget(Some(2.0));
assert!((peek_total_cost() - 0.60).abs() < f64::EPSILON);
assert_eq!(peek_llm_cost_budget(), Some(2.0));
set_llm_cost_budget(None);
assert_eq!(peek_llm_cost_budget(), None);
set_llm_cost_budget(Some(-5.0));
assert_eq!(peek_llm_cost_budget(), Some(0.0));
reset_cost_state();
}
#[test]
fn set_token_budget_rearms_in_place_without_resetting_accumulation() {
let _guard_outer = crate::llm::env_guard();
reset_cost_state();
let _budget = install_llm_token_budget(100);
accumulate_llm_usage("test", 60, 0, 0.0).unwrap();
set_llm_token_budget(Some(50));
assert_eq!(peek_total_tokens(), 60);
assert_eq!(peek_llm_token_budget(), Some(50));
set_llm_token_budget(None);
assert_eq!(peek_total_tokens(), 60);
assert_eq!(peek_llm_token_budget(), None);
reset_cost_state();
}
#[test]
fn token_budget_raises_categorized_error_when_exhausted() {
let _guard_outer = crate::llm::env_guard();
reset_cost_state();
let _budget = install_llm_token_budget(10);
let first = accumulate_llm_usage("claude-sonnet-4-20250514", 5, 0, 0.001);
assert!(first.is_ok());
let second = accumulate_llm_usage("claude-sonnet-4-20250514", 8, 0, 0.002);
match second {
Err(VmError::CategorizedError { category, message }) => {
assert_eq!(category, ErrorCategory::BudgetExceeded);
assert!(message.contains("token budget"), "got: {message}");
}
other => panic!("expected BudgetExceeded, got {other:?}"),
}
assert_eq!(peek_total_tokens(), 13);
assert_eq!(
peek_total_cost(),
0.003,
"the completed response remains charged"
);
reset_cost_state();
}
#[test]
fn step_budget_failure_keeps_completed_usage_and_first_error() {
let _guard_outer = crate::llm::env_guard();
reset_cost_state();
crate::step_runtime::reset_thread_local_state();
let _tokens = install_llm_token_budget(10);
let _cost = install_llm_cost_budget(0.001);
crate::step_runtime::register_step(
"paid",
crate::step_runtime::StepDefinition {
name: "paid".into(),
function: "paid".into(),
max_tokens: Some(5),
..Default::default()
},
);
assert!(crate::step_runtime::maybe_push_active_step("paid", 1, &[]));
let error = accumulate_llm_usage("fixture", 100, 20, 0.003).unwrap_err();
assert!(
crate::step_runtime::is_step_budget_exhausted(&error),
"the first failure is preserved: {error:?}"
);
assert_eq!(peek_total_tokens(), 120);
assert_eq!(peek_total_cost(), 0.003);
crate::step_runtime::with_active_step(|step| {
assert_eq!(step.input_tokens, 100);
assert_eq!(step.output_tokens, 20);
assert_eq!(step.cost_usd, 0.003);
})
.expect("step remains active until its owning frame exits");
crate::step_runtime::reset_thread_local_state();
reset_cost_state();
}
#[test]
fn a_long_context_call_bills_at_the_input_token_band() {
let _guard = crate::llm::env_guard();
let (provider, model) = ("gemini", "gemini-2.5-pro");
let below =
pricing_aware_call_cost(provider, model, 100_000, 1_000, settlement_now()).expect("priced");
assert!(
(below - (100_000.0 * 1.25 + 1_000.0 * 10.0) / 1_000_000.0).abs() < 1e-9,
"below the band must bill at the base rate, got {below}"
);
let above =
pricing_aware_call_cost(provider, model, 300_000, 1_000, settlement_now()).expect("priced");
assert!(
(above - (300_000.0 * 2.50 + 1_000.0 * 15.0) / 1_000_000.0).abs() < 1e-9,
"above the band must bill at the banded rate, got {above}"
);
let (base_in, base_out) = pricing_per_1k_for(provider, model).expect("priced");
let unbanded = (300_000.0 * base_in + 1_000.0 * base_out) / 1000.0;
assert!(
above > unbanded,
"the banded price must exceed the base-rate price: {above} vs {unbanded}"
);
}
#[test]
fn haiku_55_bills_its_long_prompt_card_above_100k_input_tokens() {
let _guard = crate::llm::env_guard();
for (provider, model) in [
("anthropic", "claude-haiku-5-5"),
("openrouter", "anthropic/claude-haiku-5.5"),
] {
let fee = 1.0
+ crate::llm_config::provider_config(provider)
.and_then(|config| config.platform_fee_percent)
.unwrap_or(0.0)
/ 100.0;
let at_boundary =
pricing_aware_call_cost(provider, model, 100_000, 1_000, settlement_now())
.expect("priced");
assert!(
(at_boundary - fee * (100_000.0 * 0.10 + 1_000.0 * 0.50) / 1_000_000.0).abs() < 1e-12,
"{model}: 100K input tokens must bill the short-prompt card, got {at_boundary}"
);
let above = pricing_aware_call_cost(provider, model, 100_001, 1_000, settlement_now())
.expect("priced");
assert!(
(above - fee * (100_001.0 * 0.50 + 1_000.0 * 2.50) / 1_000_000.0).abs() < 1e-12,
"{model}: one token past 100K must bill the long-prompt card, got {above}"
);
}
let flat = pricing_aware_call_cost(
"anthropic",
"claude-haiku-4-5-20251001",
150_000,
1_000,
settlement_now(),
)
.expect("priced");
assert!(
(flat - (150_000.0 * 1.00 + 1_000.0 * 5.00) / 1_000_000.0).abs() < 1e-12,
"Haiku 4.5 has no long-prompt band, got {flat}"
);
}
#[test]
fn mock_provider_has_an_authoritative_zero_cost() {
assert_eq!(
pricing_aware_call_cost("mock", "any-fixture", 10, 20, settlement_now()),
Some(0.0)
);
assert_eq!(
pricing_aware_call_cost_with_cache(
"mock",
"any-fixture",
10,
20,
5,
2,
settlement_now(),
None
),
Some(0.0)
);
}
fn cached_call_result() -> crate::llm::api::LlmResult {
crate::llm::api::LlmResult {
attempts: Default::default(),
text_projection: None,
text: "ok".to_string(),
tool_calls: Vec::new(),
raw_tool_calls: Vec::new(),
input_tokens: 30_969,
output_tokens: 470,
cache_read_tokens: 28_410,
cache_write_tokens: 2_468,
cache_supported: true,
model: "claude-haiku-4-5-20251001".to_string(),
provider: "anthropic".to_string(),
thinking: None,
thinking_summary: None,
stop_reason: Some("stop".to_string()),
served_fast: false,
blocks: Vec::new(),
logprobs: Vec::new(),
telemetry: Box::new(crate::llm::api::ProviderTelemetry {
server_prompt_tokens: Some(91),
..Default::default()
}),
}
}
fn long_transcript_opts(total_budget_usd: f64) -> crate::llm::api::LlmCallOptions {
let mut opts = crate::llm::api::options::base_opts("anthropic");
opts.model = "claude-haiku-4-5-20251001".to_string();
opts.max_tokens = 16_000;
opts.system = None;
opts.transcript_summary = None;
opts.native_tools = None;
opts.provider_tools = Vec::new();
opts.messages = vec![serde_json::json!({
"role": "user",
"content": "token ".repeat(70_000),
})];
opts.budget = Some(LlmBudgetEnvelope {
total_budget_usd: Some(total_budget_usd),
..LlmBudgetEnvelope::default()
});
opts
}
fn record_cached_calls(count: usize) {
for _ in 0..count {
record_llm_usage(&cached_call_result()).expect("recording a completed call");
}
}
fn dict_float(dict: &DictMap, key: &str) -> f64 {
match dict.get(key) {
Some(VmValue::Float(value)) => *value,
other => panic!("expected float at {key}, got {other:?}"),
}
}
fn dict_str(dict: &DictMap, key: &str) -> String {
match dict.get(key) {
Some(value) => value.display(),
None => panic!("missing {key} in the budget error"),
}
}
fn thrown_dict(error: VmError) -> DictMap {
match error {
VmError::Thrown(VmValue::Dict(dict)) => (*dict).clone(),
other => panic!("expected a thrown dict, got {other:?}"),
}
}
#[test]
fn cached_session_is_not_stopped_by_an_uncached_worst_case_projection() {
let _guard = crate::llm::env_guard();
crate::llm_config::clear_user_overrides();
reset_cost_state();
record_cached_calls(22);
let session_cost = peek_total_cost();
let observed_mean_call_cost = session_cost / 22.0;
assert!(
(0.15..0.22).contains(&session_cost),
"fixture drifted from the measured session: {session_cost}"
);
let opts = long_transcript_opts(0.33);
let projection = project_llm_call_cost(&opts, session_cost);
assert_eq!(projection.basis, ProjectionBasis::Observed);
assert!(
projection.costed_output_tokens < projection.projected_output_tokens,
"observed mean output must replace the full output budget: {} vs {}",
projection.costed_output_tokens,
projection.projected_output_tokens
);
assert!(
projection.projected_cost_usd <= observed_mean_call_cost * 3.0,
"projection {} is more than 3x the observed mean call cost {}",
projection.projected_cost_usd,
observed_mean_call_cost
);
check_llm_preflight_budget(&opts).expect("a cached session under its cap must not be stopped");
reset_cost_state();
}
#[test]
fn first_call_of_a_session_keeps_the_worst_case_projection() {
let _guard = crate::llm::env_guard();
crate::llm_config::clear_user_overrides();
reset_cost_state();
let opts = long_transcript_opts(0.33);
let projection = project_llm_call_cost(&opts, 0.0);
assert_eq!(projection.basis, ProjectionBasis::WorstCase);
assert_eq!(
projection.costed_output_tokens,
projection.projected_output_tokens
);
assert_eq!(
projection.projected_cost_usd,
calculate_cost_for_provider(
&opts.provider,
&opts.model,
projection.projected_input_tokens,
projection.projected_output_tokens,
settlement_now(),
),
"with no evidence the projection must stay uncached and full-output"
);
record_cached_calls(22);
let session_cost = peek_total_cost();
let observed = project_llm_call_cost(&opts, session_cost);
assert!(
observed.projected_cost_usd * 5.0 < projection.projected_cost_usd,
"worst case {} should dwarf the observed projection {}",
projection.projected_cost_usd,
observed.projected_cost_usd
);
let cap = 0.33;
assert!(
session_cost + projection.projected_cost_usd > cap,
"worst case must overrun the cap: spent {session_cost}, projected {}",
projection.projected_cost_usd
);
assert!(
session_cost + observed.projected_cost_usd < cap,
"observed projection must fit under the cap: spent {session_cost}, projected {}",
observed.projected_cost_usd
);
assert!(
session_cost < cap * 0.6,
"the measured session was stopped at about half its cap: {session_cost}"
);
reset_cost_state();
}
#[test]
fn a_worst_case_projection_denies_the_next_call_at_56_percent_of_actual_spend() {
let _guard = crate::llm::env_guard();
crate::llm_config::clear_user_overrides();
reset_cost_state();
record_cached_calls(22);
let session_cost = peek_total_cost();
let cap = session_cost / 0.56;
let opts = long_transcript_opts(cap);
reset_cost_state();
let projection = project_llm_call_cost(&opts, session_cost);
assert_eq!(projection.basis, ProjectionBasis::WorstCase);
let envelope = opts
.budget
.clone()
.expect("the fixture sets a total budget");
let error = check_budget_envelope(&envelope, &projection)
.expect_err("a worst-case bound over 44% headroom must deny the call");
let dict = thrown_dict(error);
assert_eq!(dict_str(&dict, "limit"), "total_budget_usd");
assert_eq!(dict_str(&dict, "projection_basis"), "worst_case");
let reported_actual = dict_float(&dict, "session_cost_usd");
let reported_projection = dict_float(&dict, "projected_cost_usd");
assert!(
(reported_actual / cap - 0.56).abs() < 1e-6,
"the fixture must stop the run at 56% of its cap, got {}",
reported_actual / cap
);
assert!(
reported_projection > cap - reported_actual,
"the projected bound {reported_projection} must exceed the {} of headroom left",
cap - reported_actual
);
record_cached_calls(22);
let observed = project_llm_call_cost(&opts, session_cost);
assert_eq!(observed.basis, ProjectionBasis::Observed);
check_budget_envelope(&envelope, &observed)
.expect("an observed bound inside the remaining 44% must be admitted");
reset_cost_state();
}
#[test]
fn observed_projection_that_exceeds_the_cap_still_stops_and_says_so() {
let _guard = crate::llm::env_guard();
crate::llm_config::clear_user_overrides();
reset_cost_state();
record_cached_calls(22);
let session_cost = peek_total_cost();
let limit = session_cost + 0.01;
let opts = long_transcript_opts(limit);
let projection = project_llm_call_cost(&opts, session_cost);
assert_eq!(projection.basis, ProjectionBasis::Observed);
assert!(projection.projected_cost_usd > 0.01);
let error = check_llm_preflight_budget(&opts).expect_err("the observed projection must stop");
let dict = thrown_dict(error);
assert_eq!(dict_str(&dict, "projection_basis"), "observed");
assert_eq!(dict_str(&dict, "limit"), "total_budget_usd");
let reported_session_cost = dict_float(&dict, "session_cost_usd");
let headroom = dict_float(&dict, "headroom_usd");
assert!((reported_session_cost - session_cost).abs() < 1e-9);
assert!(
(headroom - 0.01).abs() < 1e-6,
"headroom must be limit minus session cost, got {headroom}"
);
reset_cost_state();
}
#[test]
fn budget_error_reports_the_worst_case_basis_before_any_call() {
let _guard = crate::llm::env_guard();
crate::llm_config::clear_user_overrides();
reset_cost_state();
let opts = long_transcript_opts(0.01);
let error = check_llm_preflight_budget(&opts).expect_err("worst case exceeds a 1c cap");
let dict = thrown_dict(error);
assert_eq!(dict_str(&dict, "projection_basis"), "worst_case");
let headroom = dict_float(&dict, "headroom_usd");
assert!((headroom - 0.01).abs() < 1e-9, "unspent cap: {headroom}");
reset_cost_state();
}
#[test]
fn nested_budget_scope_cannot_pollute_the_outer_sessions_observed_usage() {
let _guard = crate::llm::env_guard();
crate::llm_config::clear_user_overrides();
reset_cost_state();
record_cached_calls(3);
let outer = peek_observed_session_usage();
assert_eq!(outer.calls, 3);
{
let _inner = install_llm_cost_budget(5.0);
assert_eq!(
peek_observed_session_usage(),
ObservedSessionUsage::default()
);
let mut chatty = cached_call_result();
chatty.output_tokens = 8_000;
chatty.cache_read_tokens = 0;
chatty.cache_write_tokens = 0;
record_llm_usage(&chatty).expect("recording the child's call");
assert_eq!(peek_observed_session_usage().calls, 1);
}
assert_eq!(
peek_observed_session_usage(),
outer,
"the child's usage must not survive its scope"
);
reset_cost_state();
}
#[test]
fn a_seeded_cost_scope_charges_the_sessions_earlier_spend_against_its_ceiling() {
let _guard = crate::llm::env_guard();
crate::llm_config::clear_user_overrides();
reset_cost_state();
let opts = long_transcript_opts(100.0);
{
let _fresh = install_llm_cost_budget(1.0);
check_llm_preflight_budget(&opts).expect("an unspent $1 cap admits a ~15c call");
}
let outer_total = peek_total_cost();
{
let _seeded = install_llm_cost_budget_seeded(Some(1.0), 0.95);
assert!((peek_total_cost() - 0.95).abs() < 1e-12);
let dict = thrown_dict(
check_llm_preflight_budget(&opts).expect_err("95c spent leaves no room for ~15c"),
);
assert!((dict_float(&dict, "session_cost_usd") - 0.95).abs() < 1e-12);
assert!(dict_str(&dict, "message").contains("spent $0.950000 of $1.000000"));
accumulate_llm_usage("fixture", 10, 10, 0.01).expect("96c is under the $1 cap");
assert!((peek_total_cost() - 0.96).abs() < 1e-12);
}
assert_eq!(peek_total_cost(), outer_total, "the seed must not leak out");
{
let _uncapped = install_llm_cost_budget_seeded(None, 0.5);
check_llm_preflight_budget(&opts).expect("no ceiling admits the call");
accumulate_llm_usage("fixture", 10, 10, 0.25).expect("no ceiling to exceed");
assert!((peek_total_cost() - 0.75).abs() < 1e-12);
}
reset_cost_state();
}