pub struct CostModel {
pub input_per_mtok: Option<f64>,
pub output_per_mtok: Option<f64>,
pub cache_read_input_per_mtok: Option<f64>,
pub cache_write_input_per_mtok: Option<f64>,
pub pricing_tiers: Vec<TokenPricingTier>,
pub size_mb: Option<u64>,
pub ram_mb: Option<u64>,
}Fields§
§input_per_mtok: Option<f64>USD per 1M input tokens (remote models).
output_per_mtok: Option<f64>USD per 1M output tokens (remote models).
cache_read_input_per_mtok: Option<f64>USD per 1M cache-read input tokens. Unlike protocol-wide cache multipliers, this is model-specific and comes from the provider’s published catalog.
cache_write_input_per_mtok: Option<f64>USD per 1M cache-write input tokens, when the provider charges one.
pricing_tiers: Vec<TokenPricingTier>Prompt-size pricing overrides, sorted by increasing threshold. The highest threshold not greater than the prompt size wins.
size_mb: Option<u64>On-disk size in MB (local models).
ram_mb: Option<u64>RAM required during inference in MB.
Implementations§
Source§impl CostModel
impl CostModel
pub fn prices_for(&self, prompt_tokens: usize) -> TokenPrices
Sourcepub fn estimated_usd(
&self,
prompt_tokens: usize,
output_tokens: usize,
cache_read_tokens: usize,
cache_write_tokens: usize,
) -> f64
pub fn estimated_usd( &self, prompt_tokens: usize, output_tokens: usize, cache_read_tokens: usize, cache_write_tokens: usize, ) -> f64
Estimated request cost from the provider’s declared token prices.
Unknown price components contribute zero; callers that need to
distinguish unknown pricing should inspect prices_for first.
This is the routing-score input, not a display or billing figure.
The zero-fill is load-bearing here — adaptive_router normalizes the
result into a 0..1 cost score, and it separately neutralizes models
with no pricing at all, so changing the fill would change routing.
For anything a human reads, use
estimated_usd_bounded, which refuses
to bill an unrated bucket at zero and says which way it can be wrong.
Sourcepub fn estimated_usd_bounded(
&self,
tier_prompt_tokens: Option<usize>,
uncached_input_tokens: usize,
output_tokens: usize,
cache_read_tokens: usize,
cache_write_tokens: usize,
) -> Option<ApproxCost>
pub fn estimated_usd_bounded( &self, tier_prompt_tokens: Option<usize>, uncached_input_tokens: usize, output_tokens: usize, cache_read_tokens: usize, cache_write_tokens: usize, ) -> Option<ApproxCost>
Cost estimate for a figure a person will read, carrying which way it can be wrong.
Differs from estimated_usd in refusing to
invent numbers. A token bucket the provider charges for but whose rate
this catalog does not declare is never billed at zero, and a figure
that might be wrong never presents itself as exact.
tier_prompt_tokens selects the prompt-size pricing tier and is the
parameter callers most often get wrong:
Some(n)— the prompt size of one request. Tiers resolve exactly.None— the caller cannot say (a lifetime accumulator has summed many requests and lost their boundaries). Base rates are used and the result is flagged in whichever direction the model’s own tiers run.
Passing a summed token count as Some is the bug this signature
exists to prevent: thirty 10K-token requests sum to 300K, which crosses
a 272K threshold that no individual request came near, and every token
ever sent gets priced at the high-context rate — roughly double, stated
with total confidence.
Two rejected alternatives, for the next person who wants tiers on an
aggregate. Pricing lifetime totals at the tier their sum lands in is
the bug above. Pricing everything at the highest declared tier does
yield a true ceiling, but a useless one — it doubles the figure for a
user whose prompts never approached the threshold, which is the same
confident wrongness in the other direction. Resolving tiers properly
needs per-request prompt sizes, which means crate::ModelProfile
would have to accumulate per-tier token buckets at record time; that is
a real feature with a persisted-schema change, not something to fake
here from data that has already been summed away.
Returns None when no defensible number exists — either the model
declares no rate card at all, or a bucket carrying tokens has no rate
and no usable substitute. Output deliberately has no input-rate
fallback: it runs 1.5x–8x input across this catalog, far enough out of
range that no marker could rescue the number. Which buckets substitute,
and which way each substitution can be wrong, is decided in
bucket_rates from observed provider pricing —
notably cache reads and cache writes do not share a direction.
None means unpriced, and a caller must render it as such, not as free.
Trait Implementations§
Source§impl<'de> Deserialize<'de> for CostModel
impl<'de> Deserialize<'de> for CostModel
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl JsonSchema for CostModel
impl JsonSchema for CostModel
Source§fn schema_name() -> String
fn schema_name() -> String
Source§fn schema_id() -> Cow<'static, str>
fn schema_id() -> Cow<'static, str>
Source§fn json_schema(generator: &mut SchemaGenerator) -> Schema
fn json_schema(generator: &mut SchemaGenerator) -> Schema
Source§fn is_referenceable() -> bool
fn is_referenceable() -> bool
$ref keyword. Read moreAuto Trait Implementations§
impl Freeze for CostModel
impl RefUnwindSafe for CostModel
impl Send for CostModel
impl Sync for CostModel
impl Unpin for CostModel
impl UnsafeUnpin for CostModel
impl UnwindSafe for CostModel
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
impl<T> ErasedDestructor for Twhere
T: 'static,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more