use crate::outcome::priced_input_usd;
use crate::registry::UnifiedRegistry;
use crate::schema::{ModelSchema, ModelSource};
use crate::InferenceResult;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InferenceBilling {
Metered,
Subscription,
Unknown,
}
impl InferenceBilling {
pub const fn as_str(self) -> &'static str {
match self {
Self::Metered => "metered",
Self::Subscription => "subscription",
Self::Unknown => "unknown",
}
}
pub fn from_wire(value: &str) -> Option<Self> {
match value {
"metered" => Some(Self::Metered),
"subscription" => Some(Self::Subscription),
"unknown" => Some(Self::Unknown),
_ => None,
}
}
pub const fn combine(self, other: Self) -> Self {
match (self, other) {
(Self::Subscription, _) | (_, Self::Subscription) => Self::Subscription,
(Self::Unknown, _) | (_, Self::Unknown) => Self::Unknown,
_ => Self::Metered,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum PricedInferenceCall {
Metered(f64),
Subscription,
Unknown,
}
impl PricedInferenceCall {
pub const fn billing(self) -> InferenceBilling {
match self {
Self::Metered(_) => InferenceBilling::Metered,
Self::Subscription => InferenceBilling::Subscription,
Self::Unknown => InferenceBilling::Unknown,
}
}
pub const fn cost_usd(self) -> Option<f64> {
match self {
Self::Metered(cost_usd) => Some(cost_usd),
Self::Subscription | Self::Unknown => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum CostSource {
Provider,
ListPrice,
Local,
Subscription,
Unknown,
}
impl CostSource {
pub const fn as_str(self) -> &'static str {
match self {
Self::Provider => "provider",
Self::ListPrice => "list_price",
Self::Local => "local",
Self::Subscription => "subscription",
Self::Unknown => "unknown",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CallCost {
pub micros: Option<i64>,
pub source: CostSource,
}
#[derive(Debug, Clone, Copy)]
pub enum CallUsage<'a> {
Tokens(Option<&'a crate::TokenUsage>),
AudioSeconds(f64),
Characters(u64),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CallKind {
Tokens,
AudioSeconds,
Characters,
}
impl CallUsage<'_> {
pub const fn kind(&self) -> CallKind {
match self {
Self::Tokens(_) => CallKind::Tokens,
Self::AudioSeconds(_) => CallKind::AudioSeconds,
Self::Characters(_) => CallKind::Characters,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PriceKnown {
ListPrice,
ProviderReports,
Local,
Subscription,
Unknown,
}
impl PriceKnown {
pub const fn is_known(self) -> bool {
!matches!(self, Self::Unknown)
}
}
pub fn usd_to_micros_up(usd: f64) -> i64 {
if usd.is_nan() {
return 0;
}
let scaled = usd * 1_000_000.0;
let nearest = scaled.round();
let micros = if (scaled - nearest).abs() <= 1e-9 * nearest.abs().max(1.0) {
nearest
} else {
scaled.ceil()
};
micros as i64
}
pub fn micros_to_usd(micros: i64) -> f64 {
micros as f64 / 1_000_000.0
}
fn subscription(schema: &ModelSchema) -> bool {
schema.tags.iter().any(|tag| tag == "subscription")
}
fn charges_list_price(schema: &ModelSchema) -> bool {
!schema.is_local() && !subscription(schema)
}
pub fn has_list_price(schema: &ModelSchema, kind: CallKind) -> bool {
charges_list_price(schema)
&& match kind {
CallKind::Tokens => {
schema.cost.input_per_mtok.is_some() && schema.cost.output_per_mtok.is_some()
}
CallKind::AudioSeconds => schema.cost.audio_per_minute.is_some(),
CallKind::Characters => schema.cost.per_1k_characters.is_some(),
}
}
pub fn provider_reports_cost(schema: &ModelSchema) -> bool {
match &schema.source {
ModelSource::RemoteApi { protocol, .. } => {
crate::protocol::handler_for(*protocol).reports_cost()
}
_ => false,
}
}
pub fn price_known(schema: &ModelSchema, kind: CallKind) -> PriceKnown {
if has_list_price(schema, kind) {
PriceKnown::ListPrice
} else if kind == CallKind::Tokens && provider_reports_cost(schema) {
PriceKnown::ProviderReports
} else if schema.is_local() {
PriceKnown::Local
} else if subscription(schema) {
PriceKnown::Subscription
} else {
PriceKnown::Unknown
}
}
fn list_price_usd(schema: &ModelSchema, usage: &CallUsage<'_>) -> Option<f64> {
if !has_list_price(schema, usage.kind()) {
return None;
}
match usage {
CallUsage::Tokens(usage) => {
let usage = (*usage)?;
let prompt = usage
.prompt_tokens
.saturating_add(usage.cache_read_input_tokens)
.saturating_add(usage.cache_creation_input_tokens);
let prices = schema
.cost
.prices_for(usize::try_from(prompt).unwrap_or(usize::MAX));
let (Some(input_per_mtok), Some(output_per_mtok)) =
(prices.input_per_mtok, prices.output_per_mtok)
else {
return None;
};
Some(
priced_input_usd(
usage.prompt_tokens,
usage.cache_read_input_tokens,
usage.cache_creation_input_tokens,
input_per_mtok,
schema.cache_rates_at(&prices),
) + (usage.completion_tokens as f64 / 1_000_000.0) * output_per_mtok,
)
}
CallUsage::AudioSeconds(seconds) => {
let per_minute = schema.cost.audio_per_minute?;
seconds
.is_finite()
.then(|| seconds.max(0.0) / 60.0 * per_minute)
}
CallUsage::Characters(characters) => {
let per_1k = schema.cost.per_1k_characters?;
Some(*characters as f64 / 1_000.0 * per_1k)
}
}
}
pub const MAX_UNLISTED_PROVIDER_FIGURE_USD: f64 = 1_000.0;
pub const MAX_PROVIDER_FIGURE_LIST_MULTIPLE: f64 = 100.0;
pub const MIN_PROVIDER_FIGURE_CEILING_USD: f64 = 1.0;
fn ceiling_for(list: Option<f64>) -> f64 {
list.map_or(MAX_UNLISTED_PROVIDER_FIGURE_USD, |list| {
(list * MAX_PROVIDER_FIGURE_LIST_MULTIPLE).max(MIN_PROVIDER_FIGURE_CEILING_USD)
})
}
fn schema_for<'r>(registry: &'r UnifiedRegistry, model_used: &str) -> Option<&'r ModelSchema> {
registry
.get(model_used)
.or_else(|| registry.find_by_name(model_used))
}
pub fn provider_figure_ceiling(
registry: &UnifiedRegistry,
model_used: &str,
usage: Option<&crate::TokenUsage>,
) -> f64 {
ceiling_for(
schema_for(registry, model_used)
.and_then(|schema| list_price_usd(schema, &CallUsage::Tokens(usage))),
)
}
pub fn accept_provider_figure(model_used: &str, usd: f64, ceiling: f64) -> Option<f64> {
if usd.is_finite() && (0.0..=ceiling).contains(&usd) {
return Some(usd);
}
tracing::warn!(
model = %model_used,
figure_usd = usd,
ceiling_usd = ceiling,
"provider cost figure rejected (not a dollar amount, or above the sanity ceiling); pricing the call from the next source"
);
None
}
fn priced(
registry: &UnifiedRegistry,
model_used: &str,
usage: &CallUsage<'_>,
) -> (CostSource, Option<f64>) {
let schema = schema_for(registry, model_used);
if let CallUsage::Tokens(Some(tokens)) = usage {
if let Some(reported) = tokens.reported_cost_usd {
let ceiling = ceiling_for(schema.and_then(|schema| list_price_usd(schema, usage)));
if let Some(usd) = accept_provider_figure(model_used, reported, ceiling) {
return (CostSource::Provider, Some(usd));
}
}
}
let Some(schema) = schema else {
return (CostSource::Unknown, None);
};
if let Some(usd) = list_price_usd(schema, usage) {
return (CostSource::ListPrice, Some(usd));
}
if schema.is_local() {
return (CostSource::Local, Some(0.0));
}
if subscription(schema) {
return (CostSource::Subscription, Some(0.0));
}
(CostSource::Unknown, None)
}
pub fn call_cost(registry: &UnifiedRegistry, model_used: &str, usage: CallUsage<'_>) -> CallCost {
let (source, usd) = priced(registry, model_used, &usage);
CallCost {
micros: usd.map(usd_to_micros_up),
source,
}
}
pub fn price_inference_call(
registry: &UnifiedRegistry,
result: &InferenceResult,
) -> PricedInferenceCall {
price_usage(registry, &result.model_used, result.usage.as_ref())
}
pub fn price_usage(
registry: &UnifiedRegistry,
model_used: &str,
usage: Option<&crate::TokenUsage>,
) -> PricedInferenceCall {
match priced(registry, model_used, &CallUsage::Tokens(usage)) {
(CostSource::Provider | CostSource::ListPrice, Some(usd)) => {
PricedInferenceCall::Metered(usd)
}
(CostSource::Subscription, _) => PricedInferenceCall::Subscription,
(
CostSource::Provider | CostSource::ListPrice | CostSource::Local | CostSource::Unknown,
_,
) => PricedInferenceCall::Unknown,
}
}
#[cfg(test)]
mod tests {
use super::{price_inference_call, InferenceBilling};
use crate::registry::UnifiedRegistry;
use crate::schema::{
ApiProtocol, CostModel, ModelCapability, ModelSchema, ModelSource, PerformanceEnvelope,
TrustTier,
};
use crate::{InferenceResult, TokenUsage};
fn schema(id: &str, name: &str, tags: &[&str]) -> ModelSchema {
ModelSchema {
id: id.into(),
name: name.into(),
provider: "test".into(),
family: "test".into(),
version: "test".into(),
capabilities: vec![ModelCapability::Generate],
context_length: 4096,
max_output_tokens: None,
param_count: String::new(),
quantization: None,
performance: PerformanceEnvelope::default(),
cost: CostModel {
input_per_mtok: Some(2.0),
output_per_mtok: Some(10.0),
..Default::default()
},
source: ModelSource::RemoteApi {
endpoint: "https://example.invalid/v1".into(),
api_key_env: "TEST_API_KEY".into(),
api_key_envs: vec![],
api_version: None,
protocol: ApiProtocol::Anthropic,
},
tags: tags.iter().map(|tag| (*tag).to_string()).collect(),
supported_params: vec![],
public_benchmarks: vec![],
trust_tier: TrustTier::Curated,
deprecated: false,
available: false,
weights_ready: false,
}
}
fn result(model_used: &str, usage: Option<TokenUsage>) -> InferenceResult {
serde_json::from_value(serde_json::json!({
"text": "ok",
"tool_calls": [],
"trace_id": "trace",
"model_used": model_used,
"latency_ms": 0,
"usage": usage,
}))
.expect("inference result fixture")
}
fn usage() -> TokenUsage {
TokenUsage {
prompt_tokens: 1_000,
completion_tokens: 500,
total_tokens: 1_800,
context_window: 4_096,
cache_read_input_tokens: 200,
cache_creation_input_tokens: 100,
reported_cost_usd: None,
reasoning_tokens: None,
}
}
#[test]
fn prices_all_token_buckets_after_exact_id_or_name_resolution() {
let directory = tempfile::tempdir().unwrap();
let mut registry = UnifiedRegistry::new_empty(directory.path().to_path_buf());
registry.register(schema("test/metered:exact", "Metered Name", &[]));
for serving_model in ["test/metered:exact", "Metered Name"] {
let priced = price_inference_call(®istry, &result(serving_model, Some(usage())));
assert_eq!(priced.billing(), InferenceBilling::Metered);
assert_eq!(priced.cost_usd(), Some(0.00729));
}
}
#[test]
fn an_exact_subscription_tag_overrides_usage_and_catalog_dollar_fields() {
let directory = tempfile::tempdir().unwrap();
let mut registry = UnifiedRegistry::new_empty(directory.path().to_path_buf());
registry.register(schema(
"test/subscription:exact",
"Subscription Name",
&["subscription"],
));
for usage in [Some(usage()), None] {
let priced = price_inference_call(®istry, &result("test/subscription:exact", usage));
assert_eq!(priced.billing(), InferenceBilling::Subscription);
assert_eq!(priced.cost_usd(), None);
}
}
#[test]
fn unpriceable_calls_are_unknown_not_free() {
let directory = tempfile::tempdir().unwrap();
let mut registry = UnifiedRegistry::new_empty(directory.path().to_path_buf());
let mut missing_rate = schema("test/unpriced", "Unpriced", &[]);
missing_rate.cost.output_per_mtok = None;
registry.register(missing_rate);
for call in [
result("missing/model", Some(usage())),
result("test/unpriced", Some(usage())),
result("test/unpriced", None),
] {
let priced = price_inference_call(®istry, &call);
assert_eq!(priced.billing(), InferenceBilling::Unknown);
assert_eq!(priced.cost_usd(), None);
}
}
use super::{call_cost, price_known, CallCost, CallKind, CallUsage, CostSource, PriceKnown};
use crate::schema::{TokenPrices, TokenPricingTier};
fn sourced(id: &str, source: ModelSource, priced: bool, tags: &[&str]) -> ModelSchema {
let mut schema = schema(id, id, tags);
schema.source = source;
if !priced {
schema.cost = CostModel::default();
}
schema
}
fn remote(protocol: ApiProtocol) -> ModelSource {
ModelSource::RemoteApi {
endpoint: "https://example.invalid".into(),
api_key_env: "TEST_API_KEY".into(),
api_key_envs: vec![],
api_version: None,
protocol,
}
}
fn local() -> ModelSource {
ModelSource::Local {
hf_repo: "r".into(),
hf_filename: "f".into(),
tokenizer_repo: "t".into(),
}
}
fn with_figure(usd: f64) -> TokenUsage {
TokenUsage {
reported_cost_usd: Some(usd),
..usage()
}
}
fn cost(micros: Option<i64>, source: CostSource) -> CallCost {
CallCost { micros, source }
}
#[test]
fn a_calls_cost_comes_from_the_first_source_that_can_say() {
let directory = tempfile::tempdir().unwrap();
let mut registry = UnifiedRegistry::new_empty(directory.path().to_path_buf());
registry.register(sourced(
"test/priced",
remote(ApiProtocol::Anthropic),
true,
&[],
));
registry.register(sourced("test/local-stale-price", local(), true, &[]));
registry.register(sourced(
"test/subscription",
ModelSource::CodexCli { model: "m".into() },
true,
&["subscription"],
));
registry.register(sourced(
"test/unpriced",
remote(ApiProtocol::OpenAiCompat),
false,
&[],
));
registry.register(sourced(
"test/loopback-vllm",
ModelSource::VllmMlx {
endpoint: "http://127.0.0.1:8000".into(),
model_name: "m".into(),
},
false,
&[],
));
let tokens = usage();
let reported = with_figure(0.5);
let at = |model: &str, usage: &TokenUsage| {
call_cost(®istry, model, CallUsage::Tokens(Some(usage)))
};
assert_eq!(
at("test/priced", &reported),
cost(Some(500_000), CostSource::Provider)
);
assert_eq!(
at("missing/model", &reported),
cost(Some(500_000), CostSource::Provider)
);
assert_eq!(
at("test/priced", &tokens),
cost(Some(7_290), CostSource::ListPrice)
);
for bad in [-1.0, f64::NAN, f64::INFINITY] {
assert_eq!(
at("test/priced", &with_figure(bad)),
cost(Some(7_290), CostSource::ListPrice)
);
}
assert_eq!(
at("test/local-stale-price", &tokens),
cost(Some(0), CostSource::Local)
);
assert_eq!(
at("test/subscription", &tokens),
cost(Some(0), CostSource::Subscription)
);
assert_eq!(
at("test/unpriced", &tokens),
cost(None, CostSource::Unknown)
);
assert_eq!(
at("test/loopback-vllm", &tokens),
cost(None, CostSource::Unknown)
);
assert_eq!(
call_cost(®istry, "test/priced", CallUsage::Tokens(None)),
cost(None, CostSource::Unknown)
);
}
#[test]
fn an_absurd_provider_figure_falls_to_the_next_source() {
let directory = tempfile::tempdir().unwrap();
let mut registry = UnifiedRegistry::new_empty(directory.path().to_path_buf());
registry.register(sourced(
"test/priced",
remote(ApiProtocol::Anthropic),
true,
&[],
));
registry.register(sourced(
"test/unpriced",
remote(ApiProtocol::OpenRouter),
false,
&[],
));
let mut expensive = sourced("test/expensive", remote(ApiProtocol::Anthropic), true, &[]);
expensive.cost.input_per_mtok = Some(2_000.0);
expensive.cost.output_per_mtok = Some(10_000.0);
registry.register(expensive);
let at = |model: &str, usd: f64| {
call_cost(®istry, model, CallUsage::Tokens(Some(&with_figure(usd))))
};
assert_eq!(
at("test/expensive", 700.0),
cost(Some(700_000_000), CostSource::Provider)
);
assert_eq!(
at("test/expensive", 800.0),
cost(Some(7_290_000), CostSource::ListPrice)
);
assert_eq!(
at("test/expensive", 1e12),
cost(Some(7_290_000), CostSource::ListPrice)
);
assert_eq!(
at("test/priced", 1e12),
cost(Some(7_290), CostSource::ListPrice)
);
assert_eq!(
at("test/unpriced", 1_000.0),
cost(Some(1_000_000_000), CostSource::Provider)
);
assert_eq!(
at("test/unpriced", 1_000.01),
cost(None, CostSource::Unknown)
);
assert_eq!(at("missing/model", 1e12), cost(None, CostSource::Unknown));
assert!(
(super::provider_figure_ceiling(®istry, "test/expensive", Some(&usage())) - 729.0)
.abs()
< 1e-9
);
assert_eq!(
super::provider_figure_ceiling(®istry, "test/unpriced", Some(&usage())),
1_000.0
);
}
#[test]
fn a_per_request_fee_on_a_tiny_prompt_is_taken() {
let directory = tempfile::tempdir().unwrap();
let mut registry = UnifiedRegistry::new_empty(directory.path().to_path_buf());
registry.register(sourced(
"test/priced",
remote(ApiProtocol::Anthropic),
true,
&[],
));
let at = |usd: f64| {
let tiny = TokenUsage {
prompt_tokens: 20,
total_tokens: 20,
reported_cost_usd: Some(usd),
..Default::default()
};
call_cost(®istry, "test/priced", CallUsage::Tokens(Some(&tiny)))
};
assert_eq!(at(0.02), cost(Some(20_000), CostSource::Provider));
assert_eq!(at(1.0), cost(Some(1_000_000), CostSource::Provider));
assert_eq!(at(1.01), cost(Some(40), CostSource::ListPrice));
}
#[test]
fn tiers_audio_minutes_and_characters_price_their_calls() {
let directory = tempfile::tempdir().unwrap();
let mut registry = UnifiedRegistry::new_empty(directory.path().to_path_buf());
let mut tiered = sourced("test/tiered", remote(ApiProtocol::Google), true, &[]);
tiered.cost.pricing_tiers = vec![TokenPricingTier {
min_prompt_tokens: 200_000,
prices: TokenPrices {
input_per_mtok: Some(4.0),
output_per_mtok: Some(15.0),
..Default::default()
},
}];
registry.register(tiered);
let mut speech = sourced("test/speech", remote(ApiProtocol::OpenAiCompat), false, &[]);
speech.cost.audio_per_minute = Some(0.40);
speech.cost.per_1k_characters = Some(0.30);
registry.register(speech);
let tokens = |prompt: u64, cached: u64| TokenUsage {
prompt_tokens: prompt,
cache_read_input_tokens: cached,
completion_tokens: 1_000,
..Default::default()
};
let at = |usage: &TokenUsage| {
call_cost(®istry, "test/tiered", CallUsage::Tokens(Some(usage)))
};
assert_eq!(
at(&tokens(100_000, 0)),
cost(Some(210_000), CostSource::ListPrice)
);
assert_eq!(
at(&tokens(250_000, 0)),
cost(Some(1_015_000), CostSource::ListPrice)
);
assert_eq!(
at(&tokens(150_000, 60_000)),
cost(Some(615_000), CostSource::ListPrice)
);
assert_eq!(
call_cost(®istry, "test/speech", CallUsage::AudioSeconds(90.0)),
cost(Some(600_000), CostSource::ListPrice)
);
assert_eq!(
call_cost(®istry, "test/speech", CallUsage::Characters(2_500)),
cost(Some(750_000), CostSource::ListPrice)
);
assert_eq!(
call_cost(
®istry,
"test/speech",
CallUsage::Tokens(Some(&tokens(10, 0)))
),
cost(None, CostSource::Unknown)
);
assert_eq!(
call_cost(®istry, "test/tiered", CallUsage::AudioSeconds(90.0)),
cost(None, CostSource::Unknown)
);
}
fn every_protocol() -> Vec<ApiProtocol> {
let listed = |protocol: ApiProtocol| match protocol {
ApiProtocol::OpenAiCompat
| ApiProtocol::OpenRouter
| ApiProtocol::OpenAiResponses
| ApiProtocol::Anthropic
| ApiProtocol::Google
| ApiProtocol::VertexAi
| ApiProtocol::AzureOpenAi
| ApiProtocol::Bedrock => protocol,
};
[
ApiProtocol::OpenAiCompat,
ApiProtocol::OpenRouter,
ApiProtocol::OpenAiResponses,
ApiProtocol::Anthropic,
ApiProtocol::Google,
ApiProtocol::VertexAi,
ApiProtocol::AzureOpenAi,
ApiProtocol::Bedrock,
]
.into_iter()
.map(listed)
.collect()
}
fn response_with_a_figure(protocol: ApiProtocol) -> &'static str {
match protocol {
ApiProtocol::OpenAiCompat | ApiProtocol::OpenRouter | ApiProtocol::AzureOpenAi => {
r#"{"id":"gen-1","choices":[{"message":{"content":"hi"},"finish_reason":"stop"}],
"usage":{"prompt_tokens":3,"completion_tokens":2,"total_tokens":5,"cost":0.25}}"#
}
ApiProtocol::OpenAiResponses => {
r#"{"output":[{"type":"message","content":[{"type":"output_text","text":"hi"}]}],
"usage":{"input_tokens":3,"output_tokens":2,"total_tokens":5,"cost":0.25}}"#
}
ApiProtocol::Anthropic => {
r#"{"content":[{"type":"text","text":"hi"}],
"usage":{"input_tokens":3,"output_tokens":2,"cost":0.25}}"#
}
ApiProtocol::Google | ApiProtocol::VertexAi => {
r#"{"candidates":[{"content":{"parts":[{"text":"hi"}]},"finishReason":"STOP"}],
"usageMetadata":{"promptTokenCount":3,"candidatesTokenCount":2,"totalTokenCount":5,"cost":0.25}}"#
}
ApiProtocol::Bedrock => {
r#"{"output":{"message":{"content":[{"text":"hi"}]}},"stopReason":"end_turn",
"usage":{"inputTokens":3,"outputTokens":2,"totalTokens":5,"cost":0.25}}"#
}
}
}
fn stream_frame_with_a_figure(protocol: ApiProtocol) -> Option<(&'static str, &'static str)> {
match protocol {
ApiProtocol::OpenAiCompat | ApiProtocol::OpenRouter | ApiProtocol::AzureOpenAi => {
Some((
"",
r#"{"id":"gen-1","choices":[],"usage":{"prompt_tokens":3,"completion_tokens":2,"cost":0.25}}"#,
))
}
ApiProtocol::OpenAiResponses => Some((
"response.completed",
r#"{"type":"response.completed","response":{"status":"completed","usage":{"input_tokens":3,"output_tokens":2,"cost":0.25}}}"#,
)),
ApiProtocol::Anthropic => Some((
"message_delta",
r#"{"type":"message_delta","delta":{"stop_reason":"end_turn"},"usage":{"output_tokens":2,"cost":0.25}}"#,
)),
ApiProtocol::Google | ApiProtocol::VertexAi => Some((
"",
r#"{"candidates":[{"finishReason":"STOP"}],"usageMetadata":{"promptTokenCount":3,"candidatesTokenCount":2,"cost":0.25}}"#,
)),
ApiProtocol::Bedrock => None,
}
}
#[test]
fn every_handlers_reports_cost_matches_what_it_parses() {
use crate::stream::StreamEvent;
let mut reporting = Vec::new();
for protocol in every_protocol() {
let handler = crate::protocol::handler_for(protocol);
let parsed = handler
.parse_response(response_with_a_figure(protocol))
.unwrap_or_else(|error| panic!("{protocol:?}: {error}"));
let usage = parsed
.usage
.unwrap_or_else(|| panic!("{protocol:?}: no usage parsed"));
assert_eq!(
usage.reported_cost_usd.is_some(),
handler.reports_cost(),
"{protocol:?}: one-shot figure {:?}, reports_cost() {}",
usage.reported_cost_usd,
handler.reports_cost()
);
if let Some(figure) = usage.reported_cost_usd {
assert_eq!(figure, 0.25, "{protocol:?}");
}
if let Some((event, data)) = stream_frame_with_a_figure(protocol) {
let events = handler.parse_stream_event(event, data);
assert!(
events
.iter()
.any(|event| matches!(event, StreamEvent::Usage { .. })),
"{protocol:?}: the usage frame parsed to {events:?}"
);
let figures: Vec<f64> = events
.iter()
.filter_map(|event| match event {
StreamEvent::ProviderCost(cost) => Some(*cost),
_ => None,
})
.collect();
assert_eq!(
!figures.is_empty(),
handler.reports_cost(),
"{protocol:?}: streamed figures {figures:?}"
);
}
if handler.reports_cost() {
reporting.push(protocol);
}
}
assert_eq!(reporting, vec![ApiProtocol::OpenRouter]);
}
fn usage_after_a_call(schema: &ModelSchema) -> TokenUsage {
match &schema.source {
ModelSource::RemoteApi { protocol, .. } => crate::protocol::handler_for(*protocol)
.parse_response(response_with_a_figure(*protocol))
.unwrap()
.usage
.unwrap(),
_ => TokenUsage {
prompt_tokens: 3,
completion_tokens: 2,
total_tokens: 5,
..Default::default()
},
}
}
#[test]
fn price_known_says_truthfully_whether_a_cost_will_be_known() {
let directory = tempfile::tempdir().unwrap();
let mut registry = UnifiedRegistry::new_empty(directory.path().to_path_buf());
let mut rows: Vec<ModelSchema> =
serde_json::from_str(include_str!("builtin_catalog.json")).unwrap();
rows.extend(crate::openrouter::builtin_schemas());
rows.push(sourced(
"edge/openrouter-unpriced",
remote(ApiProtocol::OpenRouter),
false,
&[],
));
rows.push(sourced("edge/local-stale-price", local(), true, &[]));
rows.push(sourced(
"edge/loopback-vllm",
ModelSource::VllmMlx {
endpoint: "http://127.0.0.1:8000".into(),
model_name: "m".into(),
},
false,
&[],
));
rows.push(sourced(
"edge/anthropic-unpriced",
remote(ApiProtocol::Anthropic),
false,
&[],
));
for row in &rows {
registry.register_project_model(row.clone());
}
let mut seen = std::collections::BTreeSet::new();
for row in &rows {
let row = registry.get(&row.id).expect("registered");
let known = price_known(row, CallKind::Tokens);
let usage = usage_after_a_call(row);
let priced = call_cost(®istry, &row.id, CallUsage::Tokens(Some(&usage)));
assert_eq!(
known.is_known(),
priced.micros.is_some(),
"{}: price_known {known:?}, priced {priced:?}",
row.id
);
let expected_source = match known {
PriceKnown::ListPrice => CostSource::ListPrice,
PriceKnown::ProviderReports => CostSource::Provider,
PriceKnown::Local => CostSource::Local,
PriceKnown::Subscription => CostSource::Subscription,
PriceKnown::Unknown => CostSource::Unknown,
};
if !(known == PriceKnown::ListPrice && priced.source == CostSource::Provider) {
assert_eq!(priced.source, expected_source, "{}", row.id);
}
seen.insert(format!("{known:?}"));
}
for answer in [
"ListPrice",
"ProviderReports",
"Local",
"Subscription",
"Unknown",
] {
assert!(seen.contains(answer), "no row answered {answer}: {seen:?}");
}
let parslee_managed = rows
.iter()
.find(|row| {
matches!(row.source, ModelSource::Proprietary { .. })
&& row.provider == "parslee"
&& row.cost.input_per_mtok.is_none()
})
.expect("a Parslee managed row");
assert_eq!(
price_known(parslee_managed, CallKind::Tokens),
PriceKnown::Unknown
);
}
#[test]
fn sonnet_4_5_bare_id_is_billed_at_list_price() {
let directory = tempfile::tempdir().unwrap();
let mut registry = UnifiedRegistry::new_empty(directory.path().to_path_buf());
let rows: Vec<ModelSchema> =
serde_json::from_str(include_str!("builtin_catalog.json")).unwrap();
for row in rows {
registry.register(row);
}
let usage = TokenUsage {
prompt_tokens: 1_000_000,
completion_tokens: 1_000_000,
..Default::default()
};
assert_eq!(
call_cost(
®istry,
"anthropic/claude-sonnet-4-5",
CallUsage::Tokens(Some(&usage))
),
cost(Some(18_000_000), CostSource::ListPrice)
);
}
}