Skip to main content

codewhale_config/route/
offering.rs

1//! Provider model offerings (#3084).
2//!
3//! A [`ProviderModelOffering`] binds a provider to a canonical model, the
4//! provider-owned wire id that serves it, and the endpoint key. This is the
5//! seam that proves the #2608 invariant: the SAME canonical model can be served
6//! by multiple providers under DIFFERENT wire ids (some aggregator-prefixed),
7//! and a prefix never implies provider ownership.
8//!
9//! The hand-curated seed table is gone (#4139 / #3830 P1): catalog-derived
10//! offerings from [`crate::catalog::bundled_catalog_offerings`] are the single
11//! bundled source of truth. [`bundled_offerings`] remains as an empty seam so
12//! the resolver can still prepend curated overrides later without reintroducing
13//! a parallel seed list.
14
15use serde::{Deserialize, Serialize};
16
17use super::candidate::PricingSku;
18use super::capabilities::RouteCapabilities;
19use super::ids::{ModelId, ProviderId, WireModelId};
20
21/// Token limits for one resolved route/offering.
22///
23/// These are optional because hosted catalogs, local runtimes, and custom
24/// endpoints can legitimately omit some or all limit facts. Callers should
25/// treat `None` as unknown, not zero.
26#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
27pub struct RouteLimits {
28    /// Total context window (input + output), in tokens.
29    #[serde(default, skip_serializing_if = "Option::is_none")]
30    pub context_tokens: Option<u64>,
31    /// Input-token limit, when the provider reports it separately.
32    #[serde(default, skip_serializing_if = "Option::is_none")]
33    pub input_tokens: Option<u64>,
34    /// Output-token cap for the route/offering, when known.
35    #[serde(default, skip_serializing_if = "Option::is_none")]
36    pub output_tokens: Option<u64>,
37}
38
39impl RouteLimits {
40    /// Whether at least one limit fact is known.
41    #[must_use]
42    pub const fn has_known_limit(self) -> bool {
43        self.context_tokens.is_some() || self.input_tokens.is_some() || self.output_tokens.is_some()
44    }
45}
46
47/// One provider's way of serving a (possibly canonical) model.
48///
49/// `Eq` is intentionally NOT derived: [`PricingSku::Token`] carries `f64` rates,
50/// so the offering is only `PartialEq`. No caller keys a set/map on offerings.
51#[derive(Debug, Clone, PartialEq)]
52pub struct ProviderModelOffering {
53    /// Provider serving this offering.
54    pub provider: ProviderId,
55    /// Canonical model identity, if this offering maps to one.
56    pub canonical_model: Option<ModelId>,
57    /// Provider-owned wire id sent on the request (verbatim).
58    pub wire_model_id: WireModelId,
59    /// Endpoint key the offering is served on.
60    pub endpoint_key: String,
61    /// Whether this is the provider's default offering.
62    pub default_for_provider: bool,
63    /// Provider/offering-scoped token limits, when known.
64    pub limits: RouteLimits,
65    /// Provider/model-scoped capability facts. Unknown is preserved rather
66    /// than inferred from the wire protocol.
67    pub capabilities: RouteCapabilities,
68    /// Coarse route-facing pricing meter for this offering (#3085).
69    ///
70    /// Projected from the offering's sourced cost at the layer that owns it
71    /// (`CatalogOffering::to_offering` → [`crate::pricing::route_pricing_sku`]).
72    /// The resolver carries this verbatim onto the candidate; it is
73    /// [`PricingSku::UnknownOrStale`] whenever no price was sourced — never a
74    /// fabricated zero (the #2608 / #3085 honesty rule).
75    pub pricing: PricingSku,
76}
77
78/// Return the bundled offering seam as owned [`ProviderModelOffering`] rows.
79///
80/// Empty by design: every former hand-seed row is covered by the bundled
81/// Models.dev catalog ([`crate::catalog::bundled_catalog_offerings`]), which
82/// carries the same canonical-model joins via `base_model` plus honest limits
83/// and pricing the old seeds lacked (#4139 / #3830 P1 OFFERING_SEEDS dedupe).
84#[must_use]
85pub fn bundled_offerings() -> Vec<ProviderModelOffering> {
86    Vec::new()
87}