@@ -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