Skip to main content

nemo_relay/codec/
response.rs

1// SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Re-exported normalized LLM response data types and core pricing helpers.
5
6use serde::Deserialize;
7
8pub use nemo_relay_types::codec::response::*;
9
10pub use super::model_pricing::{
11    CacheReadAccounting, ModelPricing, PricingCatalog, PricingCatalogError, PricingConfig,
12    PricingResolver, PricingSource, PricingSourceConfig, PricingUnit, PromptCachePricing,
13    TokenPricingRates, active_pricing_resolver, attach_estimated_cost,
14    attach_estimated_cost_for_provider, estimate_cost, estimate_cost_for_provider,
15    estimate_cost_with_catalog, estimate_cost_with_provider, infer_model_provider,
16    pricing_for_model, pricing_for_provider, reset_active_pricing_resolver,
17    set_active_pricing_resolver,
18};
19
20/// Provider/framework cost object accepted by built-in response codecs.
21#[derive(Debug, Clone, Default, Deserialize)]
22pub(crate) struct RawUsageCost {
23    /// Normalized total cost in the supplied currency.
24    pub total: Option<f64>,
25    /// Uncached prompt/input token cost in the supplied currency.
26    pub input: Option<f64>,
27    /// Completion/output token cost in the supplied currency.
28    pub output: Option<f64>,
29    /// Prompt cache read cost in the supplied currency.
30    pub cache_read: Option<f64>,
31    /// Prompt cache write cost in the supplied currency.
32    pub cache_write: Option<f64>,
33    /// Optional currency override from provider data.
34    pub currency: Option<String>,
35    /// Optional provider provenance.
36    pub pricing_provider: Option<String>,
37    /// Optional model provenance.
38    pub pricing_model: Option<String>,
39    /// Optional as-of provenance.
40    pub pricing_as_of: Option<String>,
41    /// Optional source provenance.
42    pub pricing_source: Option<String>,
43}
44
45pub(crate) fn provider_reported_cost(
46    provider_total_cost: Option<f64>,
47    cost: Option<RawUsageCost>,
48) -> Option<CostEstimate> {
49    let cost = cost.unwrap_or_default();
50    let provider_total_uses_default_currency = provider_total_cost.is_some();
51    let nested_currency_is_default = cost
52        .currency
53        .as_deref()
54        .is_none_or(|currency| currency.eq_ignore_ascii_case("USD"));
55    let keep_component_costs = !provider_total_uses_default_currency || nested_currency_is_default;
56    let input = keep_component_costs.then_some(cost.input).flatten();
57    let output = keep_component_costs.then_some(cost.output).flatten();
58    let cache_read = keep_component_costs.then_some(cost.cache_read).flatten();
59    let cache_write = keep_component_costs.then_some(cost.cache_write).flatten();
60    let has_currency_native_amount = cost.total.is_some()
61        || cost.input.is_some()
62        || cost.output.is_some()
63        || cost.cache_read.is_some()
64        || cost.cache_write.is_some();
65    let component_total = [input, output, cache_read, cache_write]
66        .into_iter()
67        .flatten()
68        .sum();
69    let has_component_cost =
70        input.is_some() || output.is_some() || cache_read.is_some() || cache_write.is_some();
71    let total = provider_total_cost
72        .or(cost.total)
73        .or_else(|| has_component_cost.then_some(component_total));
74
75    if total.is_none()
76        && input.is_none()
77        && output.is_none()
78        && cache_read.is_none()
79        && cache_write.is_none()
80    {
81        return None;
82    }
83
84    Some(CostEstimate {
85        total,
86        currency: if provider_total_uses_default_currency {
87            default_cost_currency()
88        } else if has_currency_native_amount {
89            cost.currency.unwrap_or_else(default_cost_currency)
90        } else {
91            default_cost_currency()
92        },
93        input,
94        output,
95        cache_read,
96        cache_write,
97        source: CostSource::ProviderReported,
98        pricing_provider: cost.pricing_provider,
99        pricing_model: cost.pricing_model,
100        pricing_as_of: cost.pricing_as_of,
101        pricing_source: cost.pricing_source,
102    })
103}
104
105fn default_cost_currency() -> String {
106    "USD".into()
107}
108
109#[cfg(test)]
110#[path = "../../tests/unit/codec/response_tests.rs"]
111mod tests;