Skip to content

Commit eb7ef03

Browse files
zhangzqsCopilot
andauthored
Add pricing entries for newly observed models (#156)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent b31551e commit eb7ef03

1 file changed

Lines changed: 167 additions & 0 deletions

File tree

src/models.rs

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,6 +1157,22 @@ fn populate_defaults(
11571157
true
11581158
);
11591159

1160+
// DeepSeek Models
1161+
// Source: https://api-docs.deepseek.com/quick_start/pricing/ (official pricing page;
1162+
// use the standard rates rather than the temporary promotional discount:
1163+
// cache hit $0.0145/M, cache miss $1.74/M, output $3.48/M)
1164+
add_model!(
1165+
"deepseek-v4-pro",
1166+
PricingStructure::Flat {
1167+
input_per_1m: 1.74,
1168+
output_per_1m: 3.48
1169+
},
1170+
CachingSupport::OpenAI {
1171+
cached_input_per_1m: 0.0145
1172+
},
1173+
false
1174+
);
1175+
11601176
// Z.AI (Zhipu AI) - Additional Models
11611177
add_model!(
11621178
"glm-5",
@@ -1192,6 +1208,18 @@ fn populate_defaults(
11921208
false
11931209
);
11941210

1211+
// Xiaomi Models
1212+
// Source: https://openrouter.ai/xiaomi/mimo-v2.5-pro
1213+
add_model!(
1214+
"mimo-v2.5-pro",
1215+
PricingStructure::Flat {
1216+
input_per_1m: 1.0,
1217+
output_per_1m: 3.0
1218+
},
1219+
CachingSupport::None,
1220+
true
1221+
);
1222+
11951223
// MiniMax Models
11961224
add_model!(
11971225
"minimax-m2.1",
@@ -1212,6 +1240,42 @@ fn populate_defaults(
12121240
false
12131241
);
12141242

1243+
// Moonshot AI Models
1244+
// Source: https://openrouter.ai/moonshotai/kimi-k2.5
1245+
add_model!(
1246+
"kimi-k2.5",
1247+
PricingStructure::Flat {
1248+
input_per_1m: 0.44,
1249+
output_per_1m: 2.0
1250+
},
1251+
CachingSupport::None,
1252+
true
1253+
);
1254+
1255+
// Qwen Models
1256+
// Source: https://openrouter.ai/qwen/qwen3.5-35b-a3b
1257+
add_model!(
1258+
"qwen3.5-35b-a3b",
1259+
PricingStructure::Flat {
1260+
input_per_1m: 0.1625,
1261+
output_per_1m: 1.30
1262+
},
1263+
CachingSupport::None,
1264+
true
1265+
);
1266+
1267+
// Meituan Models
1268+
// Source: https://anotherwrapper.com/tools/llm-pricing/longcat-flash-lite
1269+
add_model!(
1270+
"longcat-flash-lite",
1271+
PricingStructure::Flat {
1272+
input_per_1m: 0.10,
1273+
output_per_1m: 0.40
1274+
},
1275+
CachingSupport::None,
1276+
true
1277+
);
1278+
12151279
// StepFun Models
12161280
add_model!(
12171281
"step-3.5-flash",
@@ -1244,6 +1308,19 @@ fn populate_defaults(
12441308
CachingSupport::None,
12451309
false
12461310
);
1311+
// OpenRouter router labels
1312+
// Source: https://openrouter.ai/docs/guides/routing/routers/auto-router
1313+
// Auto Router has no standalone per-token price; usage is billed at the routed model's rate.
1314+
// Keep a zero-cost estimated placeholder so historical logs with only `auto` do not warn.
1315+
add_model!(
1316+
"auto",
1317+
PricingStructure::Flat {
1318+
input_per_1m: 0.0,
1319+
output_per_1m: 0.0
1320+
},
1321+
CachingSupport::None,
1322+
true
1323+
);
12471324

12481325
// Populate Aliases
12491326
macro_rules! add_alias {
@@ -1735,6 +1812,7 @@ mod tests {
17351812
};
17361813

17371814
use std::collections::HashMap;
1815+
use std::sync::{Mutex, OnceLock};
17381816

17391817
fn approx_eq(left: f64, right: f64) {
17401818
assert!((left - right).abs() < 1e-9, "left={left}, right={right}");
@@ -1745,6 +1823,14 @@ mod tests {
17451823
*registry.write() = Registry::new_with_defaults();
17461824
}
17471825

1826+
fn registry_test_guard() -> std::sync::MutexGuard<'static, ()> {
1827+
static TEST_MUTEX: OnceLock<Mutex<()>> = OnceLock::new();
1828+
TEST_MUTEX
1829+
.get_or_init(|| Mutex::new(()))
1830+
.lock()
1831+
.expect("registry test mutex should not be poisoned")
1832+
}
1833+
17481834
#[test]
17491835
fn test_registry_merging() {
17501836
let mut registry = Registry::new_with_defaults();
@@ -1784,6 +1870,7 @@ mod tests {
17841870

17851871
#[test]
17861872
fn init_external_models_accepts_multiple_calls() {
1873+
let _guard = registry_test_guard();
17871874
reset_global_registry();
17881875

17891876
let mut first_models = HashMap::new();
@@ -1834,6 +1921,7 @@ mod tests {
18341921

18351922
#[test]
18361923
fn transitive_aliases_resolve_to_the_final_model() {
1924+
let _guard = registry_test_guard();
18371925
reset_global_registry();
18381926

18391927
let mut models = HashMap::new();
@@ -1869,6 +1957,7 @@ mod tests {
18691957

18701958
#[test]
18711959
fn invalid_external_tier_configs_are_skipped() {
1960+
let _guard = registry_test_guard();
18721961
reset_global_registry();
18731962

18741963
let mut models = HashMap::new();
@@ -2035,4 +2124,82 @@ mod tests {
20352124
_ => panic!("Expected Google caching"),
20362125
}
20372126
}
2127+
2128+
#[test]
2129+
fn mimo_v2_5_pro_pricing_is_available() {
2130+
let model_info = get_model_info("mimo-v2.5-pro").expect("model should exist");
2131+
assert!(model_info.is_estimated);
2132+
2133+
let input_cost = calculate_input_cost("mimo-v2.5-pro", 1_000_000);
2134+
let output_cost = calculate_output_cost("mimo-v2.5-pro", 1_000_000);
2135+
2136+
approx_eq(input_cost, 1.0);
2137+
approx_eq(output_cost, 3.0);
2138+
}
2139+
2140+
#[test]
2141+
fn deepseek_v4_pro_pricing_is_available() {
2142+
let model_info = get_model_info("deepseek-v4-pro").expect("model should exist");
2143+
assert!(!model_info.is_estimated);
2144+
2145+
let input_cost = calculate_input_cost("deepseek-v4-pro", 1_000_000);
2146+
let output_cost = calculate_output_cost("deepseek-v4-pro", 1_000_000);
2147+
let cache_cost = calculate_cache_cost("deepseek-v4-pro", 0, 1_000_000);
2148+
2149+
approx_eq(input_cost, 1.74);
2150+
approx_eq(output_cost, 3.48);
2151+
approx_eq(cache_cost, 0.0145);
2152+
}
2153+
2154+
#[test]
2155+
fn qwen_3_5_35b_a3b_provider_alias_resolves() {
2156+
let model_info =
2157+
get_model_info("qwen/qwen3.5-35b-a3b").expect("provider-prefixed model should exist");
2158+
assert!(model_info.is_estimated);
2159+
2160+
let input_cost = calculate_input_cost("qwen/qwen3.5-35b-a3b", 1_000_000);
2161+
let output_cost = calculate_output_cost("qwen/qwen3.5-35b-a3b", 1_000_000);
2162+
2163+
approx_eq(input_cost, 0.1625);
2164+
approx_eq(output_cost, 1.30);
2165+
}
2166+
2167+
#[test]
2168+
fn longcat_flash_lite_provider_alias_resolves() {
2169+
let model_info = get_model_info("meituan/longcat-flash-lite")
2170+
.expect("provider-prefixed model should exist");
2171+
assert!(model_info.is_estimated);
2172+
2173+
let input_cost = calculate_input_cost("meituan/longcat-flash-lite", 1_000_000);
2174+
let output_cost = calculate_output_cost("meituan/longcat-flash-lite", 1_000_000);
2175+
2176+
approx_eq(input_cost, 0.10);
2177+
approx_eq(output_cost, 0.40);
2178+
}
2179+
2180+
#[test]
2181+
fn kimi_k2_5_pricing_is_available() {
2182+
let model_info = get_model_info("kimi-k2.5").expect("model should exist");
2183+
assert!(model_info.is_estimated);
2184+
2185+
let input_cost = calculate_input_cost("kimi-k2.5", 1_000_000);
2186+
let output_cost = calculate_output_cost("kimi-k2.5", 1_000_000);
2187+
2188+
approx_eq(input_cost, 0.44);
2189+
approx_eq(output_cost, 2.0);
2190+
}
2191+
2192+
#[test]
2193+
fn auto_router_placeholder_is_estimated_and_free() {
2194+
let model_info = get_model_info("auto").expect("router placeholder should exist");
2195+
assert!(model_info.is_estimated);
2196+
2197+
let input_cost = calculate_input_cost("auto", 1_000_000);
2198+
let output_cost = calculate_output_cost("auto", 1_000_000);
2199+
let cache_cost = calculate_cache_cost("auto", 0, 1_000_000);
2200+
2201+
approx_eq(input_cost, 0.0);
2202+
approx_eq(output_cost, 0.0);
2203+
approx_eq(cache_cost, 0.0);
2204+
}
20382205
}

0 commit comments

Comments
 (0)