@@ -1356,6 +1356,13 @@ fn token_details_from_usage(
13561356 serde_json:: json!( cached_tokens) ,
13571357 ) ;
13581358 }
1359+ // Cache writes (Anthropic only at the moment). Disjoint from reads.
1360+ if let Some ( creation_tokens) = usage. cache_creation_token_count {
1361+ details. insert (
1362+ "cacheCreationTokenCount" . to_string ( ) ,
1363+ serde_json:: json!( creation_tokens) ,
1364+ ) ;
1365+ }
13591366
13601367 ( !details. is_empty ( ) ) . then_some ( serde_json:: Value :: Object ( details) )
13611368}
@@ -1973,4 +1980,50 @@ mod tests {
19731980 use super :: detect_placeholder_patterns;
19741981 assert ! ( detect_placeholder_patterns( "" ) . is_none( ) ) ;
19751982 }
1983+
1984+ #[ test]
1985+ fn token_details_emits_both_cache_keys_when_present ( ) {
1986+ use crate :: util:: types:: ai:: GeminiUsage ;
1987+ let usage = GeminiUsage {
1988+ prompt_token_count : 100 ,
1989+ candidates_token_count : 20 ,
1990+ total_token_count : 120 ,
1991+ reasoning_token_count : None ,
1992+ cached_content_token_count : Some ( 30 ) ,
1993+ cache_creation_token_count : Some ( 20 ) ,
1994+ } ;
1995+ let details = super :: token_details_from_usage ( & usage) . expect ( "details" ) ;
1996+ assert_eq ! ( details. get( "cachedContentTokenCount" ) . and_then( |v| v. as_u64( ) ) , Some ( 30 ) ) ;
1997+ assert_eq ! ( details. get( "cacheCreationTokenCount" ) . and_then( |v| v. as_u64( ) ) , Some ( 20 ) ) ;
1998+ }
1999+
2000+ #[ test]
2001+ fn token_details_emits_only_read_when_creation_absent ( ) {
2002+ use crate :: util:: types:: ai:: GeminiUsage ;
2003+ let usage = GeminiUsage {
2004+ prompt_token_count : 100 ,
2005+ candidates_token_count : 20 ,
2006+ total_token_count : 120 ,
2007+ reasoning_token_count : None ,
2008+ cached_content_token_count : Some ( 30 ) ,
2009+ cache_creation_token_count : None ,
2010+ } ;
2011+ let details = super :: token_details_from_usage ( & usage) . expect ( "details" ) ;
2012+ assert_eq ! ( details. get( "cachedContentTokenCount" ) . and_then( |v| v. as_u64( ) ) , Some ( 30 ) ) ;
2013+ assert ! ( details. get( "cacheCreationTokenCount" ) . is_none( ) ) ;
2014+ }
2015+
2016+ #[ test]
2017+ fn token_details_is_none_when_no_cache_info ( ) {
2018+ use crate :: util:: types:: ai:: GeminiUsage ;
2019+ let usage = GeminiUsage {
2020+ prompt_token_count : 100 ,
2021+ candidates_token_count : 20 ,
2022+ total_token_count : 120 ,
2023+ reasoning_token_count : None ,
2024+ cached_content_token_count : None ,
2025+ cache_creation_token_count : None ,
2026+ } ;
2027+ assert ! ( super :: token_details_from_usage( & usage) . is_none( ) ) ;
2028+ }
19762029}
0 commit comments