use crate::protocol::{claude, openai};
use super::super::scalar::{u32_to_u64, u64_to_u32};
pub(in crate::transform::generate_content) fn completion_usage_to_claude(
usage: Option<openai::CompletionUsage>,
) -> claude::Usage {
let Some(usage) = usage else {
return empty_claude_usage();
};
let (cached_tokens, cache_write_tokens) = usage
.prompt_tokens_details
.map(|details| (details.cached_tokens, details.cache_write_tokens))
.unwrap_or((None, None));
let non_cached = usage
.prompt_tokens
.saturating_sub(cached_tokens.unwrap_or_default())
.saturating_sub(cache_write_tokens.unwrap_or_default());
crate::protocol::wire!(claude::Usage {
input_tokens: Some(u32_to_u64(non_cached)),
output_tokens: Some(u32_to_u64(usage.completion_tokens)),
cache_creation_input_tokens: cache_write_tokens.map(u32_to_u64),
cache_read_input_tokens: cached_tokens.map(u32_to_u64),
cache_creation: None,
output_tokens_details: usage.completion_tokens_details.and_then(|details| {
details.reasoning_tokens.map(|tokens| {
crate::protocol::wire!(claude::OutputTokensDetails {
thinking_tokens: u32_to_u64(tokens),
extra: Default::default(),
})
})
}),
server_tool_use: None,
iterations: None,
inference_geo: None,
service_tier: None,
speed: None,
extra: Default::default(),
})
}
pub(in crate::transform::generate_content) fn empty_claude_usage() -> claude::Usage {
crate::protocol::wire!(claude::Usage {
input_tokens: Some(0),
output_tokens: Some(0),
cache_creation_input_tokens: None,
cache_read_input_tokens: None,
cache_creation: None,
output_tokens_details: None,
server_tool_use: None,
iterations: None,
inference_geo: None,
service_tier: None,
speed: None,
extra: Default::default(),
})
}
pub(in crate::transform::generate_content) fn claude_usage_to_completion(
usage: claude::Usage,
) -> openai::CompletionUsage {
let cached_tokens = usage.cache_read_input_tokens.map(u64_to_u32);
let cache_write_tokens = usage.cache_creation_total().map(u64_to_u32);
let prompt_tokens = usage
.input_tokens
.map(u64_to_u32)
.unwrap_or_default()
.saturating_add(cached_tokens.unwrap_or_default())
.saturating_add(cache_write_tokens.unwrap_or_default());
let completion_tokens = usage.output_tokens.map(u64_to_u32).unwrap_or_default();
let reasoning_tokens = usage
.output_tokens_details
.map(|details| u64_to_u32(details.thinking_tokens));
crate::protocol::wire!(openai::CompletionUsage {
completion_tokens,
prompt_tokens,
total_tokens: prompt_tokens.saturating_add(completion_tokens),
completion_tokens_details: reasoning_tokens.map(|reasoning_tokens| {
crate::protocol::wire!(openai::CompletionTokensDetails {
accepted_prediction_tokens: None,
audio_tokens: None,
reasoning_tokens: Some(reasoning_tokens),
rejected_prediction_tokens: None,
extra: Default::default(),
})
}),
prompt_tokens_details: (cached_tokens.is_some() || cache_write_tokens.is_some()).then(
|| crate::protocol::wire!(openai::PromptTokensDetails {
audio_tokens: None,
cache_write_tokens,
cached_tokens,
extra: Default::default(),
}),
),
extra: Default::default(),
})
}