Skip to main content

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}