use tracing::debug;
use super::INFERENCE_PROFILE_PREFIXES;
pub(super) fn bedrock_cost_per_million(model: &str) -> (f64, f64) {
let after_geo = INFERENCE_PROFILE_PREFIXES
.iter()
.find_map(|pfx| model.strip_prefix(pfx))
.unwrap_or(model);
let normalized = normalize_model_family(after_geo);
match normalized {
"anthropic.claude-sonnet-4-6" => (3.00, 15.00),
"anthropic.claude-sonnet-4-5" => (3.00, 15.00),
"anthropic.claude-haiku-4-5" => (0.80, 4.00),
"anthropic.claude-opus-4-8" => (15.00, 75.00),
"anthropic.claude-3-5-sonnet-20241022-v2:0" | "anthropic.claude-3-5-sonnet" => {
(3.00, 15.00)
}
"anthropic.claude-3-haiku-20240307-v1:0" | "anthropic.claude-3-haiku" => (0.25, 1.25),
_ => {
debug!(
model = %model,
"BedrockProvider: no pricing entry for model id — cost_usd will be 0.0"
);
(0.0, 0.0)
}
}
}
pub fn normalize_model_family(model: &str) -> &str {
let mut end = model.len();
while let Some(dash_pos) = model[..end].rfind('-') {
let segment = &model[dash_pos + 1..end];
let is_date_segment = segment.len() == 8 && segment.bytes().all(|b| b.is_ascii_digit());
let is_version_segment = segment.starts_with('v')
&& segment[1..]
.bytes()
.all(|b| b.is_ascii_digit() || b == b':');
if is_date_segment || is_version_segment {
end = dash_pos;
} else {
break;
}
}
&model[..end]
}
pub fn estimate_bedrock_cost_usd(model: &str, input_tokens: u32, output_tokens: u32) -> f64 {
let (in_price, out_price) = bedrock_cost_per_million(model);
(input_tokens as f64 / 1_000_000.0) * in_price
+ (output_tokens as f64 / 1_000_000.0) * out_price
}