mermaid_cli/tui/state/model.rs
1//! Model state management
2//!
3//! Handles LLM configuration and identity.
4
5use std::sync::Arc;
6use tokio::sync::RwLock;
7
8use crate::models::{Model, ModelConfig};
9
10/// Model state - LLM configuration and identity
11pub struct ModelState {
12 pub model: Arc<RwLock<Box<dyn Model>>>,
13 pub model_id: String,
14 pub model_name: String,
15 /// Thinking mode state:
16 /// - Some(true) = model supports thinking, currently enabled
17 /// - Some(false) = model supports thinking, currently disabled
18 /// - None = model does not support thinking (or unknown)
19 pub thinking_enabled: Option<bool>,
20 /// Vision support state:
21 /// - Some(true) = model supports vision
22 /// - Some(false) = model does not support vision (detected from error)
23 /// - None = unknown (optimistic default)
24 pub vision_supported: Option<bool>,
25 /// Base model configuration from app config. Used by build_config() to
26 /// produce API-ready ModelConfig with runtime-only fields set.
27 pub base_config: ModelConfig,
28}
29
30impl ModelState {
31 pub fn new(model: Box<dyn Model>, model_id: String, base_config: ModelConfig) -> Self {
32 let model_name = model.name().to_string();
33 Self {
34 model: Arc::new(RwLock::new(model)),
35 model_id,
36 model_name,
37 thinking_enabled: Some(true),
38 vision_supported: None,
39 base_config,
40 }
41 }
42
43 /// Get a reference to the model for reading
44 pub fn model_ref(&self) -> &Arc<RwLock<Box<dyn Model>>> {
45 &self.model
46 }
47
48 /// Toggle thinking mode (only if model supports it)
49 /// Returns the new state, or None if model doesn't support thinking
50 pub fn toggle_thinking(&mut self) -> Option<bool> {
51 match self.thinking_enabled {
52 Some(enabled) => {
53 self.thinking_enabled = Some(!enabled);
54 self.thinking_enabled
55 },
56 None => None, // Model doesn't support thinking, can't toggle
57 }
58 }
59
60 /// Mark model as not supporting thinking
61 /// Called when we get "does not support thinking" error from Ollama
62 pub fn disable_thinking_support(&mut self) {
63 self.thinking_enabled = None;
64 }
65
66 /// Check if thinking is currently active
67 pub fn is_thinking_active(&self) -> bool {
68 self.thinking_enabled == Some(true)
69 }
70
71 /// Build a ModelConfig for API calls using current model state.
72 /// Clones the base config and sets runtime-only fields.
73 pub fn build_config(&self) -> ModelConfig {
74 let mut config = self.base_config.clone();
75 config.model = self.model_id.clone();
76 config.thinking_enabled = self.thinking_enabled;
77 config
78 }
79}