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    /// Temperature from app config (wired through so build_config uses it)
26    pub temperature: f32,
27    /// Max tokens from app config
28    pub max_tokens: usize,
29}
30
31impl ModelState {
32    pub fn new(model: Box<dyn Model>, model_id: String) -> Self {
33        let model_name = model.name().to_string();
34        Self {
35            model: Arc::new(RwLock::new(model)),
36            model_id,
37            model_name,
38            thinking_enabled: Some(true),
39            vision_supported: None,
40            temperature: crate::constants::DEFAULT_TEMPERATURE,
41            max_tokens: crate::constants::DEFAULT_MAX_TOKENS,
42        }
43    }
44
45    /// Get a reference to the model for reading
46    pub fn model_ref(&self) -> &Arc<RwLock<Box<dyn Model>>> {
47        &self.model
48    }
49
50    /// Toggle thinking mode (only if model supports it)
51    /// Returns the new state, or None if model doesn't support thinking
52    pub fn toggle_thinking(&mut self) -> Option<bool> {
53        match self.thinking_enabled {
54            Some(enabled) => {
55                self.thinking_enabled = Some(!enabled);
56                self.thinking_enabled
57            }
58            None => None, // Model doesn't support thinking, can't toggle
59        }
60    }
61
62    /// Mark model as not supporting thinking
63    /// Called when we get "does not support thinking" error from Ollama
64    pub fn disable_thinking_support(&mut self) {
65        self.thinking_enabled = None;
66    }
67
68    /// Check if thinking is currently active
69    pub fn is_thinking_active(&self) -> bool {
70        self.thinking_enabled == Some(true)
71    }
72
73    /// Build a ModelConfig for API calls using current model state
74    pub fn build_config(&self) -> ModelConfig {
75        ModelConfig {
76            model: self.model_id.clone(),
77            thinking_enabled: self.is_thinking_active(),
78            temperature: self.temperature,
79            max_tokens: self.max_tokens,
80            ..ModelConfig::default()
81        }
82    }
83}