codetether_agent/tui/app/state/
timing.rs1use std::time::Instant;
7
8impl super::AppState {
9 pub fn begin_request_timing(&mut self) {
10 self.processing_started_at = Some(Instant::now());
11 self.current_request_first_token_ms = None;
12 self.current_request_last_token_ms = None;
13 }
14
15 pub fn current_request_elapsed_ms(&self) -> Option<u64> {
16 self.processing_started_at
17 .map(|started| started.elapsed().as_millis() as u64)
18 }
19
20 pub fn note_text_token(&mut self) {
21 let Some(elapsed_ms) = self.current_request_elapsed_ms() else {
22 return;
23 };
24 if self.current_request_first_token_ms.is_none() {
25 self.current_request_first_token_ms = Some(elapsed_ms);
26 }
27 self.current_request_last_token_ms = Some(elapsed_ms);
28 }
29
30 pub fn complete_request_timing(&mut self) {
31 self.last_request_first_token_ms = self.current_request_first_token_ms;
32 self.last_request_last_token_ms = self.current_request_last_token_ms;
33 self.clear_request_timing();
34 }
35
36 pub fn clear_request_timing(&mut self) {
37 self.processing_started_at = None;
38 self.current_request_first_token_ms = None;
39 self.current_request_last_token_ms = None;
40 }
41
42 pub fn complete_turn_timing(&mut self) {
47 let e2e_ms = self.current_request_elapsed_ms();
48 let ttft_ms = self.current_request_first_token_ms;
49 if let Some(e2e) = e2e_ms {
50 self.chat_latency.record(e2e, ttft_ms);
51 }
52 self.complete_request_timing();
53 }
54
55 pub fn begin_streaming(&mut self) {
56 self.streaming_start = Some(Instant::now());
57 self.streaming_chars = 0;
58 }
59
60 pub fn record_streaming_chars(&mut self, len: usize) {
61 self.streaming_chars = self.streaming_chars.saturating_add(len);
62 }
63
64 pub fn streaming_tok_per_sec(&self) -> Option<f64> {
65 let start = self.streaming_start?;
66 let elapsed = start.elapsed().as_secs_f64();
67 if elapsed < 0.1 {
68 return None;
69 }
70 let tokens = self.streaming_chars as f64 / 4.0;
71 Some(tokens / elapsed)
72 }
73}