Skip to main content

chatty_rs/config/
models.rs

1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4
5use crate::config::constants::{KEEP_N_MEESAGES, MAX_CONTEXT_LENGTH, MAX_CONVO_LENGTH};
6use crate::models::BackendConnection;
7
8#[allow(unused_imports)]
9use super::CONFIG;
10use super::model_filter::ModelFilter;
11
12use super::constants::{
13    HELLO_MESSAGE, LOG_FILE_PATH, MAX_BUBBLE_WIDTH_PERCENT, MIN_BUBBLE_WIDTH_PERCENT,
14};
15use super::defaults::*;
16
17#[derive(Deserialize, Serialize, Debug, Clone, Default)]
18pub struct Configuration {
19    #[serde(default)]
20    pub general: GeneralConfig,
21
22    #[serde(default)]
23    pub log: LogConfig,
24
25    #[serde(default)]
26    pub theme: ThemeConfig,
27
28    #[serde(default)]
29    pub backend: BackendConfig,
30
31    #[serde(default)]
32    pub storage: StorageConfig,
33
34    #[serde(default)]
35    pub context: ContextConfig,
36}
37
38#[derive(Deserialize, Serialize, Debug, Clone)]
39pub struct GeneralConfig {
40    #[serde(default = "hello_message")]
41    pub hello_message: Option<String>,
42
43    #[serde(default)]
44    pub show_usage: Option<bool>,
45
46    #[serde(default)]
47    pub verbose: bool,
48
49    #[serde(default = "bubble_width_percent")]
50    pub bubble_width_percent: usize,
51
52    #[serde(default)]
53    pub auto_start: Option<bool>,
54}
55
56#[derive(Default, Deserialize, Serialize, Debug, Clone)]
57pub struct ContextConfig {
58    #[serde(default)]
59    pub compression: ContextCompression,
60
61    #[serde(default)]
62    pub truncation: TokenTruncation,
63}
64
65#[derive(Deserialize, Serialize, Debug, Clone)]
66pub struct ContextCompression {
67    #[serde(default)]
68    pub enabled: bool,
69
70    #[serde(skip_serializing_if = "Option::is_none")]
71    pub compress_model: Option<String>,
72
73    #[serde(default = "max_context_length")]
74    pub max_tokens: usize,
75
76    #[serde(default = "max_convo_length")]
77    pub max_messages: usize,
78
79    #[serde(default = "keep_n_messages")]
80    pub keep_n_messages: usize,
81}
82
83#[derive(Deserialize, Serialize, Debug, Clone)]
84pub struct TokenTruncation {
85    #[serde(default)]
86    pub enabled: bool,
87
88    #[serde(default = "max_context_length")]
89    pub max_tokens: usize,
90}
91
92#[derive(Deserialize, Serialize, Debug, Clone)]
93pub struct LogConfig {
94    #[serde(default = "log_level")]
95    pub level: Option<String>,
96
97    #[serde(default)]
98    pub filters: Option<Vec<LogFilter>>,
99
100    #[serde(default)]
101    pub file: LogFile,
102}
103
104#[derive(Deserialize, Serialize, Debug, Clone)]
105pub struct LogFilter {
106    #[serde(default)]
107    pub module: Option<String>,
108
109    #[serde(default)]
110    pub level: Option<String>,
111}
112
113#[derive(Deserialize, Serialize, Debug, Clone)]
114pub struct LogFile {
115    #[serde(default = "log_file_path")]
116    pub path: String,
117
118    #[serde(default)]
119    pub append: bool,
120}
121
122#[derive(Deserialize, Serialize, Debug, Clone)]
123pub struct ThemeConfig {
124    #[serde(default)]
125    pub name: Option<String>,
126
127    #[serde(default)]
128    pub folder_path: Option<String>,
129}
130
131#[derive(Default, Deserialize, Serialize, Debug, Clone)]
132pub struct BackendConfig {
133    #[serde(default)]
134    pub default_model: Option<String>,
135
136    #[serde(default)]
137    pub timeout_secs: Option<u16>,
138
139    #[serde(default)]
140    pub connections: Vec<BackendConnection>,
141
142    #[serde(default)]
143    pub mcp: McpConfig,
144
145    #[serde(default)]
146    pub model_settings: Vec<ModelSetting>,
147}
148
149#[derive(Default, Deserialize, Serialize, Debug, Clone)]
150pub struct McpConfig {
151    #[serde(default)]
152    pub notice_on_call_tool: Option<bool>,
153
154    #[serde(default)]
155    pub servers: Vec<McpServerConfig>,
156}
157
158#[derive(Deserialize, Serialize, Debug, Clone)]
159pub struct ModelSetting {
160    pub model: ModelFilter,
161    #[serde(default = "default_option_true")]
162    pub enable_mcp: Option<bool>,
163}
164
165#[derive(Deserialize, Serialize, Debug, Clone)]
166pub enum McpServer {
167    #[serde(rename = "binary")]
168    Binary(BinaryConfig),
169    #[serde(rename = "websocket")]
170    WebSocket(WebSocketConfig),
171}
172
173#[derive(Deserialize, Serialize, Debug, Clone)]
174pub struct McpServerConfig {
175    #[serde(default = "default_option_true")]
176    pub enabled: Option<bool>,
177    pub provider: String,
178    #[serde(flatten)]
179    pub server: McpServer,
180}
181
182#[derive(Deserialize, Serialize, Debug, Clone)]
183pub struct BinaryConfig {
184    pub filename: String,
185
186    #[serde(default)]
187    pub args: Vec<String>,
188
189    #[serde(default)]
190    pub env: HashMap<String, String>,
191}
192
193#[derive(Deserialize, Serialize, Debug, Clone)]
194pub struct WebSocketConfig {
195    pub url: String,
196}
197
198#[derive(Deserialize, Serialize, Debug, Clone)]
199pub enum StorageConfig {
200    #[serde(rename = "sqlite")]
201    Sqlite(SqliteStorage),
202}
203
204#[derive(Default, Deserialize, Serialize, Debug, Clone)]
205pub struct SqliteStorage {
206    pub path: Option<String>,
207}
208
209impl GeneralConfig {
210    pub fn get_bubble_width_percent(&self) -> usize {
211        let percent = self.bubble_width_percent.min(MAX_BUBBLE_WIDTH_PERCENT);
212        percent.max(MIN_BUBBLE_WIDTH_PERCENT)
213    }
214}
215
216impl Default for LogConfig {
217    fn default() -> Self {
218        Self {
219            level: Some("info".to_string()),
220            file: LogFile::default(),
221            filters: None,
222        }
223    }
224}
225
226impl Default for LogFile {
227    fn default() -> Self {
228        Self {
229            path: LOG_FILE_PATH.to_string(),
230            append: false,
231        }
232    }
233}
234
235impl Default for ThemeConfig {
236    fn default() -> Self {
237        Self {
238            name: Some("base16-ocean.dark".to_string()),
239            folder_path: None,
240        }
241    }
242}
243
244impl Default for ContextCompression {
245    fn default() -> Self {
246        Self {
247            enabled: false,
248            compress_model: None,
249            max_tokens: MAX_CONTEXT_LENGTH,
250            max_messages: MAX_CONVO_LENGTH,
251            keep_n_messages: KEEP_N_MEESAGES,
252        }
253    }
254}
255
256impl Default for TokenTruncation {
257    fn default() -> Self {
258        Self {
259            enabled: false,
260            max_tokens: MAX_CONTEXT_LENGTH,
261        }
262    }
263}
264
265impl Default for GeneralConfig {
266    fn default() -> Self {
267        Self {
268            verbose: false,
269            hello_message: Some(HELLO_MESSAGE.to_string()),
270            show_usage: None,
271            bubble_width_percent: 80,
272            auto_start: None,
273        }
274    }
275}
276
277impl Default for StorageConfig {
278    fn default() -> Self {
279        Self::Sqlite(SqliteStorage::default())
280    }
281}