use axum::http::HeaderMap;
use serde_json::Value;
const LITELLM_COST_HEADER: &str = "x-litellm-response-cost";
pub(super) fn upstream_is_openrouter(base_url: &str) -> bool {
let rest = base_url
.strip_prefix("https://")
.or_else(|| base_url.strip_prefix("http://"))
.unwrap_or(base_url);
let host_port = rest.split(['/', '?']).next().unwrap_or(rest);
let host = host_port.split(':').next().unwrap_or(host_port);
host.eq_ignore_ascii_case("openrouter.ai")
|| host.to_ascii_lowercase().ends_with(".openrouter.ai")
}
pub(super) fn cost_from_headers(headers: &HeaderMap, extra_header: Option<&str>) -> Option<f64> {
let mut names = vec![LITELLM_COST_HEADER];
if let Some(h) = extra_header {
names.push(h);
}
for name in names {
let cost = headers
.get(name)
.and_then(|v| v.to_str().ok())
.and_then(|s| s.trim().parse::<f64>().ok())
.filter(|c| c.is_finite() && *c >= 0.0);
if cost.is_some() {
return cost;
}
}
None
}
pub(super) fn inject_usage_include(doc: &mut Value) {
let Some(obj) = doc.as_object_mut() else {
return;
};
let usage = obj
.entry("usage")
.or_insert_with(|| Value::Object(serde_json::Map::new()));
if let Some(usage_obj) = usage.as_object_mut() {
usage_obj.entry("include").or_insert(Value::Bool(true));
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn openrouter_hosts_are_recognized() {
for url in [
"https://openrouter.ai/api",
"https://openrouter.ai",
"http://openrouter.ai:443/api",
"https://gateway.openrouter.ai/api",
"https://OPENROUTER.AI/api",
] {
assert!(
upstream_is_openrouter(url),
"{url} must count as OpenRouter"
);
}
}
#[test]
fn other_upstreams_are_not_openrouter() {
for url in [
"https://api.openai.com",
"https://my-resource.services.ai.azure.com",
"https://api.groq.com/openai",
"http://127.0.0.1:11434",
"https://evil-openrouter.ai.example.com",
"https://notopenrouter.ai",
] {
assert!(
!upstream_is_openrouter(url),
"{url} must NOT count as OpenRouter"
);
}
}
#[test]
fn litellm_cost_header_is_measured() {
let mut h = HeaderMap::new();
h.insert("x-litellm-response-cost", "0.00042".parse().unwrap());
assert_eq!(cost_from_headers(&h, None), Some(0.00042));
}
#[test]
fn operator_header_is_recognized_and_junk_ignored() {
let mut h = HeaderMap::new();
h.insert("x-corp-billed-usd", "1.25".parse().unwrap());
assert_eq!(
cost_from_headers(&h, Some("x-corp-billed-usd")),
Some(1.25),
"configured gateway header must be read"
);
assert_eq!(
cost_from_headers(&h, None),
None,
"unconfigured extra header is not consulted"
);
let mut junk = HeaderMap::new();
junk.insert("x-litellm-response-cost", "not-a-number".parse().unwrap());
junk.insert("x-corp-billed-usd", "-4".parse().unwrap());
assert_eq!(
cost_from_headers(&junk, Some("x-corp-billed-usd")),
None,
"unparseable and negative figures never enter the ledger"
);
}
#[test]
fn litellm_header_beats_extra_header_order() {
let mut h = HeaderMap::new();
h.insert("x-litellm-response-cost", "0.10".parse().unwrap());
h.insert("x-corp-billed-usd", "9.99".parse().unwrap());
assert_eq!(
cost_from_headers(&h, Some("x-corp-billed-usd")),
Some(0.10),
"the standard header wins when both are present"
);
}
#[test]
fn injects_usage_include_when_absent() {
let mut doc = serde_json::json!({"model": "deepseek/deepseek-v4-flash", "messages": []});
inject_usage_include(&mut doc);
assert_eq!(doc["usage"]["include"], Value::Bool(true));
}
#[test]
fn existing_opt_out_is_respected() {
let mut doc = serde_json::json!({"model": "m", "usage": {"include": false}});
inject_usage_include(&mut doc);
assert_eq!(doc["usage"]["include"], Value::Bool(false));
}
#[test]
fn non_object_usage_is_left_untouched() {
let mut doc = serde_json::json!({"model": "m", "usage": true});
inject_usage_include(&mut doc);
assert_eq!(doc["usage"], Value::Bool(true));
}
}