Skip to main content

llm_manager/tui/app/
types.rs

1pub mod sub;
2use crate::config::Config;
3use crate::config::Profile;
4use crate::models::Backend;
5use crate::models::{
6    BenchTuneConfig, DiscoveredModel, ModelSettings, ModelState, SearchResult, SearchSort,
7    ServerMetrics,
8};
9use ratatui::layout::Rect;
10use ratatui::text::Line;
11use serde::{Deserialize, Serialize};
12use std::collections::HashMap;
13use std::sync::atomic::AtomicBool;
14use std::sync::{Arc, Mutex};
15
16// Re-export sub-structs
17pub use sub::{
18    BenchTuneState, DownloadState, EditState, LoadingState, LogState, PendingOperations,
19    PickerState, SearchState, ServerState, SettingsState, UIState,
20};
21
22/// Static cell for caching the API port string in help text.
23pub static API_PORT_CACHE: Mutex<(u16, String)> = Mutex::new((0, String::new()));
24
25/// State for an in-progress panel resize drag.
26pub struct ResizeState {
27    /// Starting X position of the mouse when drag began.
28    pub start_x: u16,
29    /// Starting left_pct value when drag began.
30    pub start_pct: u16,
31    /// The area of the top panels container (for border detection).
32    pub container: Rect,
33}
34
35/// Cache for the settings panel render output.
36pub struct SettingsRenderCache {
37    pub hash: u64,
38    pub selected: usize,
39    pub lines: Vec<Line<'static>>,
40}
41
42/// Which panel has focus.
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
44pub enum ActivePanel {
45    #[default]
46    Models,
47    Log,
48    ServerSettings,
49    LlmSettings,
50    Profiles,
51    SystemPromptPresets,
52    SearchReadme,
53    ActiveModel,
54    ModelInfo,
55    Downloads,
56}
57
58/// Mode for the models panel.
59#[derive(Debug, Clone)]
60pub enum ModelsMode {
61    /// Normal mode: list of local models.
62    List,
63    /// Search mode: searching HuggingFace.
64    Search {
65        query: String,
66        results: Vec<SearchResult>,
67        sort_by: SearchSort,
68        show_readme: bool,
69        page: usize,
70        /// Whether results are currently being loaded.
71        loading: bool,
72        /// Whether more results are available.
73        has_more: bool,
74    },
75    /// Files mode: listing available GGUF files for a model.
76    Files {
77        model_id: String,
78        files: Vec<(String, u64, String)>, // (filename, size, url)
79        selected_idx: Option<usize>,
80        previous_query: String,
81        previous_results: Vec<SearchResult>,
82        selected_result: Option<SearchResult>,
83    },
84    /// Benchmark tuning mode: running bench_tune on a model.
85    BenchTune,
86}
87
88/// Global mode that overlays all panels.
89#[derive(Debug, Clone, PartialEq)]
90pub enum GlobalMode {
91    Normal,
92    CmdLine {
93        cmd_line: String,
94    },
95    HostPicker {
96        entries: Vec<(String, String)>, // (ip, interface_name)
97        selected: usize,
98    },
99    BackendPicker {
100        entries: Vec<(Backend, Option<String>)>,
101        selected: usize,
102    },
103    Confirmation {
104        selected: bool,
105        kind: ConfirmationKind,
106    },
107    RpcManager,
108    About,
109    MaxConcurrentPicker {
110        value: String,
111    },
112    SpecTypePicker {
113        entries: Vec<String>,
114        selected: usize,
115    },
116    YarnRoPESettings {
117        scale: String,
118        freq_base: String,
119        freq_scale: String,
120        selected_field: i32, // -1=enabled, 0=scale, 1=freq_base, 2=freq_scale
121        editing: bool,
122        edit_buffer: String,
123        edit_cursor_pos: usize,
124    },
125    BenchTuneSetup {
126        config: BenchTuneConfig,
127        selected_idx: usize,
128        editing_param: bool,
129        editing_param_field: i32,
130        param_edit_buffer: String,
131        param_edit_cursor_pos: usize,
132        bench_mode_selection: usize,
133        editing_prompt: bool,
134        editing_kwargs: bool,
135    },
136    PromptPicker {
137        entries: Vec<(String, String)>, // (name, description)
138        selected: usize,
139        editing: bool,
140        edit_buffer: String,
141        edit_cursor_pos: usize,
142        confirm_delete: bool,
143    },
144    ProfilePicker {
145        entries: Vec<(String, String)>, // (name, description)
146        selected: usize,
147        profiles: Vec<Profile>,
148    },
149    DashboardPicker {
150        enabled: bool,
151        port: String,
152        auth_key: String,
153        tls_enabled: bool,
154        tls_cert: String,
155        tls_key: String,
156        selected_field: i32, // -1=enabled, 0=port, 1=auth_key, 2=tls_enabled, 3=tls_cert, 4=tls_key
157        editing: bool,
158        edit_buffer: String,
159        edit_cursor_pos: usize,
160    },
161    DashboardUrl {
162        host: String,
163        port: String,
164        auth_key: String,
165        ws_enabled: bool,
166        tls_enabled: bool,
167    },
168    SearchInput {
169        buffer: String,
170        cursor_pos: usize,
171    },
172}
173
174#[derive(Debug, Clone, Copy, PartialEq, Eq)]
175pub enum ConfirmationKind {
176    Exit,
177    Reset,
178    Delete,
179    Unload,
180    DeleteBackend,
181}
182
183/// Scroll state for text that exceeds display width.
184#[derive(Debug, Clone)]
185pub struct TextScrollState {
186    pub offset: usize,
187    pub last_tick: std::time::Instant,
188    pub direction: i8,
189    pub hold_count: u8,
190    pub max_offset: usize,
191    pub visible: bool,
192}
193
194/// Phase of model loading.
195#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
196pub enum LoadingPhase {
197    ServerStarting,
198    LoadingModel,
199    LoadingMeta,
200    LoadingTensors,
201    ServerListening,
202    Complete,
203}
204
205impl LoadingPhase {
206    pub fn label(&self) -> &'static str {
207        match self {
208            LoadingPhase::ServerStarting => "Server starting...",
209            LoadingPhase::LoadingModel => "Loading model weights...",
210            LoadingPhase::LoadingMeta => "Loading metadata...",
211            LoadingPhase::LoadingTensors => "Loading tensors...",
212            LoadingPhase::ServerListening => "Server listening...",
213            LoadingPhase::Complete => "Ready",
214        }
215    }
216}
217
218/// The main application state.
219pub struct App {
220    // Core state
221    pub running: bool,
222    pub config: Config,
223    pub models: Vec<DiscoveredModel>,
224    pub selected_model_idx: Option<usize>,
225    pub models_mode: ModelsMode,
226    pub settings: ModelSettings,
227    pub model_settings_cache: ModelSettings,
228    pub model_states: HashMap<String, ModelState>,
229    pub metrics: ServerMetrics,
230    pub max_threads: u32,
231    pub cancelled: Option<Arc<AtomicBool>>,
232    pub server_mode: crate::models::ServerMode,
233    pub router_max_models: u32,
234    pub ws_server_handle: Option<tokio::task::JoinHandle<()>>,
235    pub background_tasks: HashMap<String, tokio::task::JoinHandle<()>>,
236
237    // Sub-structs
238    pub settings_state: SettingsState,
239    pub picker: PickerState,
240    pub download: DownloadState,
241    pub server: ServerState,
242    pub bench_tune: BenchTuneState,
243    pub log: LogState,
244    pub loading: LoadingState,
245    pub pending: PendingOperations,
246    pub search: SearchState,
247    pub ui: UIState,
248    pub edit: EditState,
249}