| 1 | //! Pure reviewed model facts in the existing catalog owner. |
| 2 | //! |
| 3 | //! The seed renderer copies the committed `catalog_corrections.json.reviewed` |
| 4 | //! data into the bundled Models.dev asset. Live/config/account rows never enter |
| 5 | //! this projection. An intrinsic fact or alias is metadata, not route authority; |
| 6 | //! executable requests still pass through the existing scoped RouteResolver. |
| 7 | |
| 8 | use std::collections::{BTreeMap, BTreeSet}; |
| 9 | |
| 10 | use serde::{Deserialize, Serialize}; |
| 11 | |
| 12 | use crate::models_dev::{ModelsDevCatalog, ModelsDevModel}; |
| 13 | use crate::route::{ |
| 14 | CapabilityState, ModelId, ProviderId, ProviderModelOffering, RouteCapabilities, RouteLimits, |
| 15 | WireModelId, |
| 16 | }; |
| 17 | |
| 18 | /// Coarse model family for presentation only; never selects a provider. |
| 19 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] |
| 20 | pub enum ModelFamily { |
| 21 | DeepSeek, |
| 22 | Anthropic, |
| 23 | OpenAi, |
| 24 | OpenAiCodex, |
| 25 | Moonshot, |
| 26 | Zai, |
| 27 | Minimax, |
| 28 | Stepfun, |
| 29 | Qwen, |
| 30 | Arcee, |
| 31 | Together, |
| 32 | XiaomiMimo, |
| 33 | Meta, |
| 34 | Xai, |
| 35 | Mistral, |
| 36 | Google, |
| 37 | Other, |
| 38 | } |
| 39 | |
| 40 | /// Reviewed intrinsic facts. Missing fields remain unknown. The generation |
| 41 | /// default is separate from the route maximum (notably Kimi K3). |
| 42 | #[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] |
| 43 | #[serde(deny_unknown_fields)] |
| 44 | pub struct IntrinsicModel { |
| 45 | #[serde(default)] |
| 46 | pub canonical_id: Option<String>, |
| 47 | #[serde(default)] |
| 48 | pub context_window: Option<u32>, |
| 49 | #[serde(default)] |
| 50 | pub max_output: Option<u32>, |
| 51 | #[serde(default)] |
| 52 | pub generation_default: Option<u32>, |
| 53 | #[serde(default)] |
| 54 | pub reasoning: Option<bool>, |
| 55 | #[serde(default)] |
| 56 | pub family: Option<ModelFamily>, |
| 57 | #[serde(default)] |
| 58 | pub display_name: Option<String>, |
| 59 | #[serde(default)] |
| 60 | pub aliases: Vec<String>, |
| 61 | #[serde(default)] |
| 62 | pub modalities: Vec<String>, |
| 63 | #[serde(default)] |
| 64 | pub supported_parameters: Vec<String>, |
| 65 | #[serde(default)] |
| 66 | pub capabilities: RouteCapabilities, |
| 67 | #[serde(default)] |
| 68 | pub architecture: Option<serde_json::Value>, |
| 69 | #[serde(default)] |
| 70 | pub latency: Option<serde_json::Value>, |
| 71 | pub source: String, |
| 72 | } |
| 73 | |
| 74 | /// Exact provider-scoped selector aliases. Their order preserves the released |
| 75 | /// first-match contract. These rows do not assert live account availability. |
| 76 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] |
| 77 | #[serde(deny_unknown_fields)] |
| 78 | pub struct ModelSelection { |
| 79 | pub provider: String, |
| 80 | pub id: String, |
| 81 | pub aliases: Vec<String>, |
| 82 | pub supports_tools: bool, |
| 83 | pub supports_reasoning: bool, |
| 84 | } |
| 85 | |
| 86 | /// Pure transport facts required by model-aware providers, without a second |
| 87 | /// routing implementation or pricing authority. |
| 88 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] |
| 89 | #[serde(deny_unknown_fields)] |
| 90 | pub struct ReviewedTransport { |
| 91 | pub provider: String, |
| 92 | pub id: String, |
| 93 | pub endpoint_key: String, |
| 94 | #[serde(default)] |
| 95 | pub canonical_model: Option<String>, |
| 96 | #[serde(default)] |
| 97 | pub default_for_provider: bool, |
| 98 | #[serde(default)] |
| 99 | pub limits: RouteLimits, |
| 100 | #[serde(default)] |
| 101 | pub capabilities: RouteCapabilities, |
| 102 | pub source: String, |
| 103 | } |
| 104 | |
| 105 | impl ReviewedTransport { |
| 106 | #[must_use] |
| 107 | pub fn to_offering(&self) -> ProviderModelOffering { |
| 108 | ProviderModelOffering { |
| 109 | provider: ProviderId::from(self.provider.clone()), |
| 110 | canonical_model: self.canonical_model.clone().map(ModelId::from), |
| 111 | wire_model_id: WireModelId::from(self.id.clone()), |
| 112 | endpoint_key: self.endpoint_key.clone(), |
| 113 | default_for_provider: self.default_for_provider, |
| 114 | limits: self.limits, |
| 115 | capabilities: self.capabilities, |
| 116 | pricing: crate::route::PricingSku::UnknownOrStale, |
| 117 | } |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | /// Reviewed reference observations used by metadata-only presentation. They |
| 122 | /// never substitute for scoped live prices or authenticated billing facts. |
| 123 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] |
| 124 | #[serde(deny_unknown_fields)] |
| 125 | pub struct ReferencePrice { |
| 126 | pub input: f64, |
| 127 | pub output: f64, |
| 128 | pub cache_read: f64, |
| 129 | #[serde(default)] |
| 130 | pub cache_write: Option<f64>, |
| 131 | pub source: String, |
| 132 | } |
| 133 | |
| 134 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] |
| 135 | #[serde(deny_unknown_fields)] |
| 136 | pub struct PublicModel { |
| 137 | pub id: String, |
| 138 | pub label: Option<String>, |
| 139 | pub added_at: Option<String>, |
| 140 | pub aliases: Vec<String>, |
| 141 | } |
| 142 | |
| 143 | /// A retained compile-time contract name projected from an intrinsic field. |
| 144 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] |
| 145 | #[serde(deny_unknown_fields)] |
| 146 | pub struct NumericRef { |
| 147 | pub model: String, |
| 148 | pub field: String, |
| 149 | } |
| 150 | |
| 151 | /// Supplement to Models.dev's intrinsic/offering schema. The original tables |
| 152 | /// are retired into this one reviewed data owner, not reloaded from a global |
| 153 | /// provider cache. Runtime catalogs retain their existing scope and precedence. |
| 154 | #[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] |
| 155 | #[serde(deny_unknown_fields)] |
| 156 | pub struct ReviewedCatalog { |
| 157 | #[serde(default)] |
| 158 | pub revision: String, |
| 159 | #[serde(default)] |
| 160 | pub intrinsic: BTreeMap<String, IntrinsicModel>, |
| 161 | #[serde(default)] |
| 162 | pub official_deepseek_aliases: BTreeMap<String, String>, |
| 163 | #[serde(default)] |
| 164 | pub openai_reasoning_ids: BTreeMap<String, String>, |
| 165 | #[serde(default)] |
| 166 | pub snapshot_prefixes: BTreeMap<String, String>, |
| 167 | #[serde(default)] |
| 168 | pub selections: Vec<ModelSelection>, |
| 169 | #[serde(default)] |
| 170 | pub public_models: Vec<PublicModel>, |
| 171 | #[serde(default)] |
| 172 | pub transports: Vec<ReviewedTransport>, |
| 173 | #[serde(default)] |
| 174 | pub constants: BTreeMap<String, String>, |
| 175 | #[serde(default)] |
| 176 | pub numeric_refs: BTreeMap<String, NumericRef>, |
| 177 | #[serde(default)] |
| 178 | pub groups: BTreeMap<String, Vec<String>>, |
| 179 | #[serde(default)] |
| 180 | pub compatibility_aliases: BTreeMap<String, BTreeMap<String, String>>, |
| 181 | #[serde(default)] |
| 182 | pub completion_rosters: BTreeMap<String, Vec<String>>, |
| 183 | #[serde(default)] |
| 184 | pub go_aliases: BTreeMap<String, String>, |
| 185 | #[serde(default)] |
| 186 | pub search_models: BTreeMap<String, Vec<String>>, |
| 187 | #[serde(default)] |
| 188 | pub route_model_sets: BTreeMap<String, Vec<String>>, |
| 189 | #[serde(default)] |
| 190 | pub reference_prices: BTreeMap<String, ReferencePrice>, |
| 191 | #[serde(default)] |
| 192 | pub reference_price_policies: BTreeMap<String, String>, |
| 193 | #[serde(default)] |
| 194 | pub source_receipts: BTreeMap<String, String>, |
| 195 | } |
| 196 | |
| 197 | impl ReviewedCatalog { |
| 198 | /// Validate authored source data before it can become a bundled projection. |
| 199 | /// Empty is allowed only for external Models.dev documents with no supplement. |
| 200 | pub fn validate(&self) -> Result<(), String> { |
| 201 | if self.revision.is_empty() { |
| 202 | if self == &Self::default() { |
| 203 | return Ok(()); |
| 204 | } |
| 205 | return Err("reviewed catalog revision missing".into()); |
| 206 | } |
| 207 | let identifier = |s: &str| { |
| 208 | !s.is_empty() && s.len() <= 512 && s.trim() == s && !s.chars().any(char::is_control) |
| 209 | }; |
| 210 | for (id, row) in &self.intrinsic { |
| 211 | if !identifier(id) |
| 212 | || row.source.trim().is_empty() |
| 213 | || row.context_window == Some(0) |
| 214 | || row.max_output == Some(0) |
| 215 | || row.generation_default == Some(0) |
| 216 | { |
| 217 | return Err(format!("malformed intrinsic model {id}")); |
| 218 | } |
| 219 | } |
| 220 | for row in &self.selections { |
| 221 | // Authored rows retain exact legacy table identities; the picker |
| 222 | // parser deliberately collapses those into vendor-primary names. |
| 223 | let provider = crate::ProviderKind::parse_config_identity(&row.provider); |
| 224 | if !identifier(&row.id) |
| 225 | || provider.is_none_or(|p| { |
| 226 | p.as_str() != row.provider || p == crate::ProviderKind::Antigravity |
| 227 | }) |
| 228 | || row.aliases.iter().any(|s| !identifier(s)) |
| 229 | { |
| 230 | return Err(format!( |
| 231 | "malformed provider selector {}/{}", |
| 232 | row.provider, row.id |
| 233 | )); |
| 234 | } |
| 235 | } |
| 236 | let mut routes = BTreeSet::new(); |
| 237 | for row in &self.transports { |
| 238 | if !identifier(&row.id) |
| 239 | || row.source.trim().is_empty() |
| 240 | || !matches!(row.endpoint_key.as_str(), "chat" | "messages" | "responses") |
| 241 | || !routes.insert((&row.provider, &row.id)) |
| 242 | || row.limits.context_tokens == Some(0) |
| 243 | || row.limits.output_tokens == Some(0) |
| 244 | || crate::ProviderKind::parse_config_identity(&row.provider).is_none_or(|p| { |
| 245 | p.as_str() != row.provider || p == crate::ProviderKind::Antigravity |
| 246 | }) |
| 247 | { |
| 248 | return Err(format!("malformed transport {}/{}", row.provider, row.id)); |
| 249 | } |
| 250 | } |
| 251 | for (id, row) in &self.reference_prices { |
| 252 | if !identifier(id) |
| 253 | || row.source.trim().is_empty() |
| 254 | || [ |
| 255 | Some(row.input), |
| 256 | Some(row.output), |
| 257 | Some(row.cache_read), |
| 258 | row.cache_write, |
| 259 | ] |
| 260 | .into_iter() |
| 261 | .flatten() |
| 262 | .any(|v| !v.is_finite() || v < 0.0) |
| 263 | { |
| 264 | return Err(format!("malformed reference price {id}")); |
| 265 | } |
| 266 | } |
| 267 | for (alias, target) in self |
| 268 | .official_deepseek_aliases |
| 269 | .iter() |
| 270 | .chain(&self.go_aliases) |
| 271 | { |
| 272 | if !identifier(alias) || !identifier(target) { |
| 273 | return Err("malformed exact alias".into()); |
| 274 | } |
| 275 | } |
| 276 | for (prefix, target) in &self.snapshot_prefixes { |
| 277 | if !identifier(prefix) || !self.intrinsic.contains_key(target) { |
| 278 | return Err("missing snapshot target".into()); |
| 279 | } |
| 280 | } |
| 281 | for reference in self.numeric_refs.values() { |
| 282 | let row = self |
| 283 | .intrinsic |
| 284 | .get(&reference.model) |
| 285 | .ok_or("missing numeric model")?; |
| 286 | let value = match reference.field.as_str() { |
| 287 | "context_window" => row.context_window, |
| 288 | "max_output" => row.max_output, |
| 289 | "generation_default" => row.generation_default, |
| 290 | _ => return Err("unknown numeric model field".into()), |
| 291 | }; |
| 292 | if value.is_none_or(|value| value == 0) { |
| 293 | return Err("missing numeric model fact".into()); |
| 294 | } |
| 295 | } |
| 296 | for row in &self.public_models { |
| 297 | if !identifier(&row.id) |
| 298 | || !self.intrinsic.contains_key(&row.id.to_ascii_lowercase()) |
| 299 | || row.label.as_deref().is_some_and(|label| !identifier(label)) |
| 300 | || row.aliases.iter().any(|alias| !identifier(alias)) |
| 301 | || row.added_at.as_deref().is_some_and(|date| { |
| 302 | chrono::NaiveDate::parse_from_str(date, "%Y-%m-%d").is_err() |
| 303 | }) |
| 304 | { |
| 305 | return Err(format!("missing public model {}", row.id)); |
| 306 | } |
| 307 | } |
| 308 | for (group, aliases) in &self.compatibility_aliases { |
| 309 | if !identifier(group) |
| 310 | || aliases |
| 311 | .iter() |
| 312 | .any(|(alias, target)| !identifier(alias) || !identifier(target)) |
| 313 | { |
| 314 | return Err("malformed compatibility selector".into()); |
| 315 | } |
| 316 | } |
| 317 | for (provider, entries) in &self.completion_rosters { |
| 318 | if provider != crate::descriptors::LEGACY_DEEPSEEK_CN.id |
| 319 | && crate::ProviderKind::parse_config_identity(provider) |
| 320 | .is_none_or(|kind| kind.as_str() != provider) |
| 321 | || entries.iter().any(|entry| !identifier(entry)) |
| 322 | || matches!(provider.as_str(), "antigravity" | "custom") && !entries.is_empty() |
| 323 | { |
| 324 | return Err(format!("malformed completion roster {provider}")); |
| 325 | } |
| 326 | } |
| 327 | Ok(()) |
| 328 | } |
| 329 | } |
| 330 | |
| 331 | /// The same immutable parsed bundled catalog used by config's existing owner. |
| 332 | #[must_use] |
| 333 | pub fn bundled_reviewed() -> &'static ReviewedCatalog { |
| 334 | &super::bundled_models_dev_catalog().reviewed |
| 335 | } |
| 336 | |
| 337 | /// Exact intrinsic lookup. Canonical facts win over provider enrichment; a |
| 338 | /// provider-scoped row is eligible only through an explicit, conflict-free join. |
| 339 | /// Never examine the process's live/custom/account catalog here. |
| 340 | #[must_use] |
| 341 | pub fn intrinsic_model(model: &str) -> Option<IntrinsicModel> { |
| 342 | intrinsic_model_in(super::bundled_models_dev_catalog(), model) |
| 343 | } |
| 344 | |
| 345 | #[must_use] |
| 346 | pub fn intrinsic_model_in(catalog: &ModelsDevCatalog, model: &str) -> Option<IntrinsicModel> { |
| 347 | let id = model.trim().to_ascii_lowercase(); |
| 348 | let reviewed = catalog.reviewed.intrinsic.get(&id); |
| 349 | let canonical = catalog |
| 350 | .models |
| 351 | .iter() |
| 352 | .find(|(key, _)| key.eq_ignore_ascii_case(&id)) |
| 353 | .map(|(_, row)| row); |
| 354 | let mut result = reviewed.cloned().or_else(|| canonical.map(from_canonical)); |
| 355 | if let Some(canonical) = canonical { |
| 356 | let canonical = from_canonical(canonical); |
| 357 | if let Some(row) = &mut result { |
| 358 | fill_missing(row, &canonical); |
| 359 | } |
| 360 | } |
| 361 | // A shared wire spelling does not establish a canonical model. Only |
| 362 | // explicit joins can supply missing intrinsic facts. |
| 363 | let joined = catalog |
| 364 | .providers |
| 365 | .values() |
| 366 | .flat_map(|provider| provider.models.iter()) |
| 367 | .filter(|(_, row)| { |
| 368 | row.base_model |
| 369 | .as_deref() |
| 370 | .is_some_and(|base| base.eq_ignore_ascii_case(&id)) |
| 371 | }) |
| 372 | .collect::<Vec<_>>(); |
| 373 | let joins = joined |
| 374 | .iter() |
| 375 | .filter_map(|(_, row)| row.base_model.as_deref()) |
| 376 | .map(str::to_ascii_lowercase) |
| 377 | .collect::<BTreeSet<_>>(); |
| 378 | if joins.len() == 1 { |
| 379 | // Enrich the named canonical model only. A provider-owned wire id is |
| 380 | // resolved through its scoped offering, never this model-only lookup. |
| 381 | if let Some(base) = joins.first().and_then(|base| { |
| 382 | catalog |
| 383 | .models |
| 384 | .iter() |
| 385 | .find(|(key, _)| key.eq_ignore_ascii_case(base)) |
| 386 | .map(|(_, row)| row) |
| 387 | }) { |
| 388 | let canonical = from_canonical(base); |
| 389 | if let Some(row) = &mut result { |
| 390 | fill_missing(row, &canonical); |
| 391 | } else { |
| 392 | result = Some(canonical); |
| 393 | } |
| 394 | } |
| 395 | let consensus = IntrinsicModel { |
| 396 | context_window: consensus(joined.iter().filter_map(|(_, row)| { |
| 397 | row.limit |
| 398 | .as_ref() |
| 399 | .and_then(|v| v.context) |
| 400 | .and_then(|v| u32::try_from(v).ok()) |
| 401 | })), |
| 402 | max_output: consensus(joined.iter().filter_map(|(_, row)| { |
| 403 | row.limit |
| 404 | .as_ref() |
| 405 | .and_then(|v| v.output) |
| 406 | .and_then(|v| u32::try_from(v).ok()) |
| 407 | })), |
| 408 | reasoning: consensus(joined.iter().filter_map(|(_, row)| row.reasoning)), |
| 409 | source: "conflict-free explicitly joined bundled offerings".into(), |
| 410 | ..IntrinsicModel::default() |
| 411 | }; |
| 412 | if let Some(row) = &mut result { |
| 413 | fill_missing(row, &consensus); |
| 414 | } else if consensus.context_window.is_some() |
| 415 | || consensus.max_output.is_some() |
| 416 | || consensus.reasoning.is_some() |
| 417 | { |
| 418 | result = Some(consensus); |
| 419 | } |
| 420 | } |
| 421 | result |
| 422 | } |
| 423 | |
| 424 | fn consensus<T: Copy + PartialEq>(values: impl IntoIterator<Item = T>) -> Option<T> { |
| 425 | let mut values = values.into_iter(); |
| 426 | let first = values.next()?; |
| 427 | values.all(|value| value == first).then_some(first) |
| 428 | } |
| 429 | |
| 430 | fn from_canonical(row: &ModelsDevModel) -> IntrinsicModel { |
| 431 | IntrinsicModel { |
| 432 | canonical_id: (!row.id.is_empty()).then(|| row.id.clone()), |
| 433 | context_window: row |
| 434 | .limit |
| 435 | .as_ref() |
| 436 | .and_then(|v| v.context) |
| 437 | .and_then(|v| u32::try_from(v).ok()), |
| 438 | max_output: row |
| 439 | .limit |
| 440 | .as_ref() |
| 441 | .and_then(|v| v.output) |
| 442 | .and_then(|v| u32::try_from(v).ok()), |
| 443 | reasoning: row.reasoning, |
| 444 | display_name: row.name.clone(), |
| 445 | modalities: row |
| 446 | .modalities |
| 447 | .as_ref() |
| 448 | .map(|v| v.input.clone()) |
| 449 | .unwrap_or_default(), |
| 450 | capabilities: RouteCapabilities { |
| 451 | reasoning: CapabilityState::from_optional_bool(row.reasoning), |
| 452 | native_tool_calls: CapabilityState::from_optional_bool(row.tool_call), |
| 453 | structured_output: CapabilityState::from_optional_bool(row.structured_output), |
| 454 | attachments: CapabilityState::from_optional_bool(row.attachment), |
| 455 | image_input: crate::models_dev::image_input_support(row.modalities.as_ref()), |
| 456 | ..RouteCapabilities::default() |
| 457 | }, |
| 458 | source: "bundled canonical Models.dev row".into(), |
| 459 | ..IntrinsicModel::default() |
| 460 | } |
| 461 | } |
| 462 | |
| 463 | fn fill_missing(row: &mut IntrinsicModel, other: &IntrinsicModel) { |
| 464 | row.context_window = row.context_window.or(other.context_window); |
| 465 | row.max_output = row.max_output.or(other.max_output); |
| 466 | row.reasoning = row.reasoning.or(other.reasoning); |
| 467 | row.family = row.family.or(other.family); |
| 468 | if row.display_name.is_none() { |
| 469 | row.display_name.clone_from(&other.display_name); |
| 470 | } |
| 471 | } |
| 472 | |
| 473 | /// Exact public bundled identifiers only. Live/private/configured model IDs |
| 474 | /// can never enlarge a telemetry/UI public-label allowlist. |
| 475 | #[must_use] |
| 476 | pub fn public_model_identifier(model: &str) -> bool { |
| 477 | let catalog = super::bundled_models_dev_catalog(); |
| 478 | catalog.reviewed.intrinsic.contains_key(model) |
| 479 | || catalog.models.contains_key(model) |
| 480 | || catalog.providers.values().any(|provider| { |
| 481 | provider |
| 482 | .models |
| 483 | .iter() |
| 484 | .any(|(id, row)| id == model || row.id == model) |
| 485 | }) |
| 486 | } |
| 487 | |
| 488 | #[must_use] |
| 489 | pub fn official_deepseek_model_id(model: &str) -> Option<&'static str> { |
| 490 | bundled_reviewed() |
| 491 | .official_deepseek_aliases |
| 492 | .get(&model.trim().to_ascii_lowercase()) |
| 493 | .map(String::as_str) |
| 494 | } |
| 495 | |
| 496 | /// Exact data-owned compatibility selector. Provider/endpoint policy remains |
| 497 | /// at the caller; this projection cannot choose or authorize a route. |
| 498 | #[must_use] |
| 499 | pub fn compatibility_alias(group: &str, model: &str) -> Option<&'static str> { |
| 500 | constants::compatibility_alias(group, model) |
| 501 | } |
| 502 | |
| 503 | #[must_use] |
| 504 | pub fn route_model_set_contains(set: &str, model: &str) -> bool { |
| 505 | bundled_reviewed() |
| 506 | .route_model_sets |
| 507 | .get(set) |
| 508 | .is_some_and(|ids| ids.iter().any(|id| id.eq_ignore_ascii_case(model.trim()))) |
| 509 | } |
| 510 | |
| 511 | #[must_use] |
| 512 | pub fn reviewed_transport(provider: &str, model: &str) -> Option<&'static ReviewedTransport> { |
| 513 | bundled_reviewed() |
| 514 | .transports |
| 515 | .iter() |
| 516 | .find(|row| row.provider == provider && row.id == model) |
| 517 | } |
| 518 | |
| 519 | /// Compile-time compatibility names are generated from the same JSON owner. |
| 520 | pub mod constants { |
| 521 | include!(concat!(env!("OUT_DIR"), "/catalog_constants.rs")); |
| 522 | } |
| 523 | |
| 524 | /// Actual source fetch time of the existing generated seed, not an unrelated |
| 525 | /// former bundled asset date. Callers evaluate TTL against their current clock. |
| 526 | #[must_use] |
| 527 | pub fn bundled_source_fetched_at() -> Option<u64> { |
| 528 | let source = super::bundled_models_dev_catalog() |
| 529 | .meta |
| 530 | .get("upstream")? |
| 531 | .as_str()?; |
| 532 | let (_, source) = source.split_once(" fetched ")?; |
| 533 | let time = source.split_whitespace().next()?; |
| 534 | u64::try_from(chrono::DateTime::parse_from_rfc3339(time).ok()?.timestamp()).ok() |
| 535 | } |
| 536 | |
| 537 | #[cfg(test)] |
| 538 | mod tests { |
| 539 | use super::*; |
| 540 | |
| 541 | fn catalog(value: serde_json::Value) -> ModelsDevCatalog { |
| 542 | ModelsDevCatalog::parse_json(&value.to_string()).expect("fixture") |
| 543 | } |
| 544 | |
| 545 | #[test] |
| 546 | fn identical_wire_names_do_not_merge_provider_private_facts() { |
| 547 | let data = catalog(serde_json::json!({ "providers": { |
| 548 | "one": { "models": { "private-name": { "id": "private-name", "reasoning": true, "limit": { "context": 900000 } } } }, |
| 549 | "two": { "models": { "private-name": { "id": "private-name", "reasoning": false, "limit": { "context": 32000 } } } } |
| 550 | }})); |
| 551 | assert!(intrinsic_model_in(&data, "private-name").is_none()); |
| 552 | assert_eq!( |
| 553 | data.provider_offering("one", "private-name") |
| 554 | .unwrap() |
| 555 | .limits |
| 556 | .context_tokens, |
| 557 | Some(900000) |
| 558 | ); |
| 559 | assert_eq!( |
| 560 | data.provider_offering("two", "private-name") |
| 561 | .unwrap() |
| 562 | .limits |
| 563 | .context_tokens, |
| 564 | Some(32000) |
| 565 | ); |
| 566 | assert!(!public_model_identifier("private-name")); |
| 567 | } |
| 568 | |
| 569 | #[test] |
| 570 | fn proven_join_preserves_canonical_facts_and_wire_lookup_stays_scoped() { |
| 571 | let mut fixture = serde_json::json!({ |
| 572 | "models": { "canonical": { "id": "canonical", "reasoning": false, "limit": { "context": 128000 } } }, |
| 573 | "providers": { "one": { "models": { "wire": { "id": "wire", "base_model": "canonical", "reasoning": true, "limit": { "context": 900000 } } } } } |
| 574 | }); |
| 575 | let data = catalog(fixture.clone()); |
| 576 | assert!(intrinsic_model_in(&data, "wire").is_none()); |
| 577 | assert_eq!( |
| 578 | data.provider_offering("one", "wire") |
| 579 | .expect("exact provider-owned offering") |
| 580 | .limits |
| 581 | .context_tokens, |
| 582 | Some(900000) |
| 583 | ); |
| 584 | let joined = intrinsic_model_in(&data, "canonical").unwrap(); |
| 585 | assert_eq!(joined.canonical_id.as_deref(), Some("canonical")); |
| 586 | assert_eq!(joined.context_window, Some(128000)); |
| 587 | assert_eq!(joined.reasoning, Some(false)); |
| 588 | fixture["providers"]["two"] = serde_json::json!({ "models": { "wire": { "id": "wire", "base_model": "different", "reasoning": true } } }); |
| 589 | assert!(intrinsic_model_in(&catalog(fixture), "wire").is_none()); |
| 590 | } |
| 591 | |
| 592 | #[test] |
| 593 | fn reviewed_selection_and_transport_preserve_separate_scopes() { |
| 594 | let reviewed = bundled_reviewed(); |
| 595 | reviewed.validate().expect("committed data"); |
| 596 | assert_eq!(reviewed.selections.len(), 175); |
| 597 | assert_eq!(reviewed.transports.len(), 123); |
| 598 | let go = reviewed_transport("opencode-go", "gpt-5.6-luna").unwrap(); |
| 599 | assert_eq!(go.endpoint_key, "responses"); |
| 600 | assert_eq!( |
| 601 | go.limits, |
| 602 | RouteLimits::default(), |
| 603 | "Go metadata is enriched by existing resolver, not borrowed from another account" |
| 604 | ); |
| 605 | assert_eq!( |
| 606 | reviewed_transport("opencode-zen", "claude-opus-5") |
| 607 | .unwrap() |
| 608 | .endpoint_key, |
| 609 | "messages" |
| 610 | ); |
| 611 | assert!(reviewed_transport("custom", "gpt-5.6").is_none()); |
| 612 | assert!(constants::completion_names("custom").is_empty()); |
| 613 | assert!(constants::completion_names("antigravity").is_empty()); |
| 614 | assert_eq!( |
| 615 | compatibility_alias("canonical_zai_model_id", "glm-5.2"), |
| 616 | Some("GLM-5.2") |
| 617 | ); |
| 618 | assert_eq!( |
| 619 | compatibility_alias("canonical_zai_model_id", "glm-5.3"), |
| 620 | Some("GLM-5.3") |
| 621 | ); |
| 622 | } |
| 623 | |
| 624 | #[test] |
| 625 | fn generation_default_does_not_assert_route_maximum_or_unknown_capability() { |
| 626 | let kimi = intrinsic_model("kimi-k3").unwrap(); |
| 627 | assert_eq!(kimi.generation_default, Some(131072)); |
| 628 | assert_ne!(kimi.generation_default, Some(1_048_576)); |
| 629 | assert_eq!(kimi.capabilities.streaming, CapabilityState::Unknown); |
| 630 | assert!(intrinsic_model("kimi-k3-private").is_none()); |
| 631 | } |
| 632 | |
| 633 | #[test] |
| 634 | fn exact_legacy_identities_validate_without_accepting_picker_aliases() { |
| 635 | let reviewed = ReviewedCatalog { |
| 636 | revision: "fixture".into(), |
| 637 | selections: vec![ModelSelection { |
| 638 | provider: "minimax-anthropic".into(), |
| 639 | id: "MiniMax-M3".into(), |
| 640 | aliases: vec![], |
| 641 | supports_tools: true, |
| 642 | supports_reasoning: true, |
| 643 | }], |
| 644 | transports: vec![ReviewedTransport { |
| 645 | provider: "modelstudio-coding-plan-anthropic".into(), |
| 646 | id: "qwen".into(), |
| 647 | endpoint_key: "messages".into(), |
| 648 | canonical_model: None, |
| 649 | default_for_provider: false, |
| 650 | limits: RouteLimits::default(), |
| 651 | capabilities: RouteCapabilities::default(), |
| 652 | source: "fixture".into(), |
| 653 | }], |
| 654 | ..ReviewedCatalog::default() |
| 655 | }; |
| 656 | reviewed |
| 657 | .validate() |
| 658 | .expect("exact released config identities"); |
| 659 | for bad in ["mini-max-anthropic", "unknown-provider", "antigravity"] { |
| 660 | let mut malformed = reviewed.clone(); |
| 661 | malformed.selections[0].provider = bad.into(); |
| 662 | assert!(malformed.validate().is_err(), "selector {bad}"); |
| 663 | let mut malformed = reviewed.clone(); |
| 664 | malformed.transports[0].provider = bad.into(); |
| 665 | assert!(malformed.validate().is_err(), "transport {bad}"); |
| 666 | } |
| 667 | } |
| 668 | |
| 669 | #[test] |
| 670 | fn malformed_authored_rows_are_refused_before_projection() { |
| 671 | for bad in ["unknown-provider", "antigravity", "openai-compatible"] { |
| 672 | let mut reviewed = bundled_reviewed().clone(); |
| 673 | reviewed.selections[0].provider = bad.into(); |
| 674 | assert!(reviewed.validate().is_err()); |
| 675 | } |
| 676 | let mut reviewed = bundled_reviewed().clone(); |
| 677 | reviewed.transports[0].limits.output_tokens = Some(0); |
| 678 | assert!(reviewed.validate().is_err()); |
| 679 | reviewed = bundled_reviewed().clone(); |
| 680 | reviewed |
| 681 | .completion_rosters |
| 682 | .insert("custom".into(), vec!["private-name".into()]); |
| 683 | assert!(reviewed.validate().is_err()); |
| 684 | } |
| 685 | } |
| 686 |