Extracts a `usage` counters object from a transcript record/message, keeping only recognized numeric token counters (so arbitrarily large or provider-private payloads never bloat `metadata_json`). Returns `None` when the value has no `usage` object or it carries no recognized counters.
(value: &Value)
| 335 | /// provider-private payloads never bloat `metadata_json`). Returns `None` |
| 336 | /// when the value has no `usage` object or it carries no recognized counters. |
| 337 | pub(crate) fn usage_counters_from(value: &Value) -> Option<Value> { |
| 338 | let usage = value.get("usage")?.as_object()?; |
| 339 | let mut counters = serde_json::Map::new(); |
| 340 | for key in USAGE_COUNTER_KEYS { |
| 341 | if let Some(count) = usage.get(key).and_then(Value::as_i64) { |
| 342 | counters.insert(key.to_string(), Value::from(count)); |
| 343 | } |
| 344 | } |
| 345 | if !counters.contains_key("cache_read_input_tokens") { |
| 346 | if let Some(count) = usage.get("cached_input_tokens").and_then(Value::as_i64) { |
| 347 | counters.insert("cache_read_input_tokens".to_string(), Value::from(count)); |
| 348 | } |
| 349 | } |
| 350 | if !counters.is_empty() |
| 351 | && !counters.contains_key("input_tokens") |
| 352 | && !counters.contains_key("prompt_tokens") |
| 353 | && !counters.contains_key("output_tokens") |
| 354 | && !counters.contains_key("completion_tokens") |
| 355 | { |
| 356 | counters.insert("input_tokens".to_string(), Value::from(0)); |
| 357 | counters.insert("output_tokens".to_string(), Value::from(0)); |
| 358 | } |
| 359 | (!counters.is_empty()).then_some(Value::Object(counters)) |
| 360 | } |
| 361 | |
| 362 | /// Inserts transcript-recorded token usage into message metadata under the |
| 363 | /// `usage` key the savings dashboard reads. Probes each candidate value in |