Skip to main content

mermaid_cli/tui/state/
generation.rs

1/// Generation state machine
2///
3/// Tracks the application lifecycle during model interactions.
4
5use std::time::Instant;
6
7use crate::agents::AgentAction;
8
9/// Generation status for the status line
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum GenerationStatus {
12    /// Not currently generating
13    Idle,
14    /// Message sent upstream, waiting for model to start responding
15    Sending,
16    /// Model is loading/initializing (before first token)
17    Initializing,
18    /// Waiting for first token from model (thinking/reasoning)
19    Thinking,
20    /// Actively receiving and displaying tokens
21    Streaming,
22}
23
24impl GenerationStatus {
25    pub fn display_text(&self) -> &str {
26        match self {
27            GenerationStatus::Idle => "Idle",
28            GenerationStatus::Sending => "Sending",
29            GenerationStatus::Initializing => "Initializing",
30            GenerationStatus::Thinking => "Thinking",
31            GenerationStatus::Streaming => "Streaming",
32        }
33    }
34}
35
36/// Comprehensive state machine for the application lifecycle
37/// Impossible states become impossible to represent
38#[derive(Debug, Clone)]
39pub enum AppState {
40    /// Idle - not doing anything, ready for input
41    Idle,
42
43    /// Currently generating a response from the model
44    Generating {
45        status: GenerationStatus,
46        start_time: Instant,
47        tokens_received: usize,
48        abort_handle: Option<tokio::task::AbortHandle>,
49    },
50
51    /// Executing an action
52    ExecutingAction {
53        action: AgentAction,
54        start_time: Instant,
55    },
56
57    /// Waiting for file read feedback from user
58    ReadingFileFeedback {
59        intent: Option<String>,
60        started_at: Instant,
61    },
62}
63
64impl AppState {
65    /// Get generation status if we're generating
66    pub fn generation_status(&self) -> Option<GenerationStatus> {
67        match self {
68            AppState::Generating { status, .. } => Some(*status),
69            _ => None,
70        }
71    }
72
73    /// Check if we're currently generating
74    pub fn is_generating(&self) -> bool {
75        matches!(self, AppState::Generating { .. })
76    }
77
78    /// Check if we're idle
79    pub fn is_idle(&self) -> bool {
80        matches!(self, AppState::Idle)
81    }
82
83    /// Get generation start time if we're generating
84    pub fn generation_start_time(&self) -> Option<Instant> {
85        match self {
86            AppState::Generating { start_time, .. } => Some(*start_time),
87            _ => None,
88        }
89    }
90
91    /// Get tokens received if we're generating
92    pub fn tokens_received(&self) -> Option<usize> {
93        match self {
94            AppState::Generating { tokens_received, .. } => Some(*tokens_received),
95            _ => None,
96        }
97    }
98
99    /// Get abort handle if we're generating
100    pub fn abort_handle(&self) -> Option<&tokio::task::AbortHandle> {
101        match self {
102            AppState::Generating { abort_handle, .. } => abort_handle.as_ref(),
103            _ => None,
104        }
105    }
106
107    /// Check if currently reading file feedback
108    pub fn is_reading_file_feedback(&self) -> bool {
109        matches!(self, AppState::ReadingFileFeedback { .. })
110    }
111
112    /// Get action start time if executing
113    pub fn action_start_time(&self) -> Option<Instant> {
114        match self {
115            AppState::ExecutingAction { start_time, .. } => Some(*start_time),
116            _ => None,
117        }
118    }
119}