use super::super::response::Usage;
use super::super::wire::{price_or_unpriced, CostOutcome, Provider, TokenPrice};
#[derive(Debug, Clone, Default)]
pub struct OpenAiProvider;
impl Provider for OpenAiProvider {
fn openrouter_slug(&self) -> Option<&'static str> {
Some("openai")
}
fn openai_request_usage(&self, body: &mut serde_json::Value, stream: bool) {
if stream {
body["stream_options"] = serde_json::json!({ "include_usage": true });
}
}
fn cost_of(&self, usage: Usage, price: Option<&TokenPrice>) -> CostOutcome {
price_or_unpriced(usage, price)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::provider::CostResolution;
fn usage(prompt: u32, completion: u32) -> Usage {
Usage {
uncached_input_tokens: prompt,
completion_tokens: completion,
..Default::default()
}
}
#[test]
fn openai_is_unpriced_without_a_price_and_resolved_with_one() {
let acct = OpenAiProvider;
let unpriced = acct.cost_of(usage(100, 50), None);
assert_eq!(unpriced.resolution, CostResolution::Unpriced);
assert_eq!(unpriced.usd, 0.0);
assert_eq!(unpriced.usage.prompt_tokens(), 100);
let price = TokenPrice::new(1.0, 1.0); let resolved = acct.cost_of(usage(1_000_000, 0), Some(&price));
assert_eq!(resolved.resolution, CostResolution::Resolved);
assert!((resolved.usd - 1.0).abs() < 1e-9);
}
}