@@ -417,9 +417,9 @@ pub enum EventMsg {
417
417
/// Agent has completed all actions
418
418
TaskComplete ( TaskCompleteEvent ) ,
419
419
420
- /// Token count event, sent periodically to report the number of tokens
421
- /// used in the current session .
422
- TokenCount ( TokenUsage ) ,
420
+ /// Usage update for the current session, including totals and last turn.
421
+ /// Optional means unknown — UIs should not display when `None` .
422
+ TokenCount ( TokenCountEvent ) ,
423
423
424
424
/// Agent text output message
425
425
AgentMessage ( AgentMessageEvent ) ,
@@ -521,12 +521,54 @@ pub struct TaskStartedEvent {
521
521
#[ derive( Debug , Clone , Deserialize , Serialize , Default ) ]
522
522
pub struct TokenUsage {
523
523
pub input_tokens : u64 ,
524
- pub cached_input_tokens : Option < u64 > ,
524
+ pub cached_input_tokens : u64 ,
525
525
pub output_tokens : u64 ,
526
- pub reasoning_output_tokens : Option < u64 > ,
526
+ pub reasoning_output_tokens : u64 ,
527
527
pub total_tokens : u64 ,
528
528
}
529
529
530
+ #[ derive( Debug , Clone , Deserialize , Serialize ) ]
531
+ pub struct TokenUsageInfo {
532
+ pub total_token_usage : TokenUsage ,
533
+ pub last_token_usage : TokenUsage ,
534
+ pub model_context_window : Option < u64 > ,
535
+ }
536
+
537
+ impl TokenUsageInfo {
538
+ pub fn new_or_append (
539
+ info : & Option < TokenUsageInfo > ,
540
+ last : & Option < TokenUsage > ,
541
+ model_context_window : Option < u64 > ,
542
+ ) -> Option < Self > {
543
+ if info. is_none ( ) && last. is_none ( ) {
544
+ return None ;
545
+ }
546
+
547
+ let mut info = match info {
548
+ Some ( info) => info. clone ( ) ,
549
+ None => Self {
550
+ total_token_usage : TokenUsage :: default ( ) ,
551
+ last_token_usage : TokenUsage :: default ( ) ,
552
+ model_context_window,
553
+ } ,
554
+ } ;
555
+ if let Some ( last) = last {
556
+ info. append_last_usage ( last) ;
557
+ }
558
+ Some ( info)
559
+ }
560
+
561
+ pub fn append_last_usage ( & mut self , last : & TokenUsage ) {
562
+ self . total_token_usage . add_assign ( last) ;
563
+ self . last_token_usage = last. clone ( ) ;
564
+ }
565
+ }
566
+
567
+ #[ derive( Debug , Clone , Deserialize , Serialize ) ]
568
+ pub struct TokenCountEvent {
569
+ pub info : Option < TokenUsageInfo > ,
570
+ }
571
+
530
572
// Includes prompts, tools and space to call compact.
531
573
const BASELINE_TOKENS : u64 = 12000 ;
532
574
@@ -536,7 +578,7 @@ impl TokenUsage {
536
578
}
537
579
538
580
pub fn cached_input ( & self ) -> u64 {
539
- self . cached_input_tokens . unwrap_or ( 0 )
581
+ self . cached_input_tokens
540
582
}
541
583
542
584
pub fn non_cached_input ( & self ) -> u64 {
@@ -554,7 +596,7 @@ impl TokenUsage {
554
596
/// This will be off for the current turn and pending function calls.
555
597
pub fn tokens_in_context_window ( & self ) -> u64 {
556
598
self . total_tokens
557
- . saturating_sub ( self . reasoning_output_tokens . unwrap_or ( 0 ) )
599
+ . saturating_sub ( self . reasoning_output_tokens )
558
600
}
559
601
560
602
/// Estimate the remaining user-controllable percentage of the model's context window.
@@ -579,6 +621,15 @@ impl TokenUsage {
579
621
let remaining = effective_window. saturating_sub ( used) ;
580
622
( ( remaining as f32 / effective_window as f32 ) * 100.0 ) . clamp ( 0.0 , 100.0 ) as u8
581
623
}
624
+
625
+ /// In-place element-wise sum of token counts.
626
+ pub fn add_assign ( & mut self , other : & TokenUsage ) {
627
+ self . input_tokens += other. input_tokens ;
628
+ self . cached_input_tokens += other. cached_input_tokens ;
629
+ self . output_tokens += other. output_tokens ;
630
+ self . reasoning_output_tokens += other. reasoning_output_tokens ;
631
+ self . total_tokens += other. total_tokens ;
632
+ }
582
633
}
583
634
584
635
#[ derive( Debug , Clone , Deserialize , Serialize ) ]
@@ -606,10 +657,11 @@ impl fmt::Display for FinalOutput {
606
657
String :: new( )
607
658
} ,
608
659
token_usage. output_tokens,
609
- token_usage
610
- . reasoning_output_tokens
611
- . map( |r| format!( " (reasoning {r})" ) )
612
- . unwrap_or_default( )
660
+ if token_usage. reasoning_output_tokens > 0 {
661
+ format!( " (reasoning {})" , token_usage. reasoning_output_tokens)
662
+ } else {
663
+ String :: new( )
664
+ }
613
665
)
614
666
}
615
667
}
0 commit comments