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}