ricecoder_modes/
think_more_controller.rs1use crate::error::{ModeError, Result};
2use crate::models::{ComplexityLevel, ThinkMoreConfig, ThinkingDepth};
3use std::sync::{Arc, Mutex};
4use std::time::{Duration, Instant};
5
6#[derive(Debug, Clone)]
8pub struct ThinkMoreController {
9 global_config: Arc<Mutex<ThinkMoreConfig>>,
11 task_configs: Arc<Mutex<std::collections::HashMap<String, ThinkMoreConfig>>>,
13 thinking_state: Arc<Mutex<ThinkingState>>,
15}
16
17#[derive(Debug, Clone)]
19struct ThinkingState {
20 active: bool,
22 start_time: Option<Instant>,
24 thinking_content: String,
26 depth: ThinkingDepth,
28}
29
30impl Default for ThinkingState {
31 fn default() -> Self {
32 Self {
33 active: false,
34 start_time: None,
35 thinking_content: String::new(),
36 depth: ThinkingDepth::Medium,
37 }
38 }
39}
40
41impl ThinkMoreController {
42 pub fn new() -> Self {
44 Self {
45 global_config: Arc::new(Mutex::new(ThinkMoreConfig::default())),
46 task_configs: Arc::new(Mutex::new(std::collections::HashMap::new())),
47 thinking_state: Arc::new(Mutex::new(ThinkingState::default())),
48 }
49 }
50
51 pub fn with_config(config: ThinkMoreConfig) -> Self {
53 Self {
54 global_config: Arc::new(Mutex::new(config)),
55 task_configs: Arc::new(Mutex::new(std::collections::HashMap::new())),
56 thinking_state: Arc::new(Mutex::new(ThinkingState::default())),
57 }
58 }
59
60 pub fn enable(&self) -> Result<()> {
62 let mut config = self.global_config.lock().map_err(|_| {
63 ModeError::ConfigError("Failed to acquire lock on global config".to_string())
64 })?;
65 config.enabled = true;
66 Ok(())
67 }
68
69 pub fn disable(&self) -> Result<()> {
71 let mut config = self.global_config.lock().map_err(|_| {
72 ModeError::ConfigError("Failed to acquire lock on global config".to_string())
73 })?;
74 config.enabled = false;
75 Ok(())
76 }
77
78 pub fn is_enabled(&self) -> Result<bool> {
80 let config = self.global_config.lock().map_err(|_| {
81 ModeError::ConfigError("Failed to acquire lock on global config".to_string())
82 })?;
83 Ok(config.enabled)
84 }
85
86 pub fn set_depth(&self, depth: ThinkingDepth) -> Result<()> {
88 let mut config = self.global_config.lock().map_err(|_| {
89 ModeError::ConfigError("Failed to acquire lock on global config".to_string())
90 })?;
91 config.depth = depth;
92 Ok(())
93 }
94
95 pub fn get_depth(&self) -> Result<ThinkingDepth> {
97 let config = self.global_config.lock().map_err(|_| {
98 ModeError::ConfigError("Failed to acquire lock on global config".to_string())
99 })?;
100 Ok(config.depth)
101 }
102
103 pub fn set_timeout(&self, timeout: Duration) -> Result<()> {
105 let mut config = self.global_config.lock().map_err(|_| {
106 ModeError::ConfigError("Failed to acquire lock on global config".to_string())
107 })?;
108 config.timeout = timeout;
109 Ok(())
110 }
111
112 pub fn get_timeout(&self) -> Result<Duration> {
114 let config = self.global_config.lock().map_err(|_| {
115 ModeError::ConfigError("Failed to acquire lock on global config".to_string())
116 })?;
117 Ok(config.timeout)
118 }
119
120 pub fn enable_auto_enable(&self) -> Result<()> {
122 let mut config = self.global_config.lock().map_err(|_| {
123 ModeError::ConfigError("Failed to acquire lock on global config".to_string())
124 })?;
125 config.auto_enable = true;
126 Ok(())
127 }
128
129 pub fn disable_auto_enable(&self) -> Result<()> {
131 let mut config = self.global_config.lock().map_err(|_| {
132 ModeError::ConfigError("Failed to acquire lock on global config".to_string())
133 })?;
134 config.auto_enable = false;
135 Ok(())
136 }
137
138 pub fn is_auto_enable_enabled(&self) -> Result<bool> {
140 let config = self.global_config.lock().map_err(|_| {
141 ModeError::ConfigError("Failed to acquire lock on global config".to_string())
142 })?;
143 Ok(config.auto_enable)
144 }
145
146 pub fn set_task_config(&self, task_id: String, config: ThinkMoreConfig) -> Result<()> {
148 let mut task_configs = self.task_configs.lock().map_err(|_| {
149 ModeError::ConfigError("Failed to acquire lock on task configs".to_string())
150 })?;
151 task_configs.insert(task_id, config);
152 Ok(())
153 }
154
155 pub fn get_task_config(&self, task_id: &str) -> Result<Option<ThinkMoreConfig>> {
157 let task_configs = self.task_configs.lock().map_err(|_| {
158 ModeError::ConfigError("Failed to acquire lock on task configs".to_string())
159 })?;
160 Ok(task_configs.get(task_id).cloned())
161 }
162
163 pub fn remove_task_config(&self, task_id: &str) -> Result<()> {
165 let mut task_configs = self.task_configs.lock().map_err(|_| {
166 ModeError::ConfigError("Failed to acquire lock on task configs".to_string())
167 })?;
168 task_configs.remove(task_id);
169 Ok(())
170 }
171
172 pub fn get_effective_config(&self, task_id: Option<&str>) -> Result<ThinkMoreConfig> {
174 if let Some(id) = task_id {
176 if let Some(config) = self.get_task_config(id)? {
177 return Ok(config);
178 }
179 }
180 let config = self.global_config.lock().map_err(|_| {
182 ModeError::ConfigError("Failed to acquire lock on global config".to_string())
183 })?;
184 Ok(config.clone())
185 }
186
187 pub fn start_thinking(&self, depth: ThinkingDepth) -> Result<()> {
189 let mut state = self.thinking_state.lock().map_err(|_| {
190 ModeError::ConfigError("Failed to acquire lock on thinking state".to_string())
191 })?;
192 state.active = true;
193 state.start_time = Some(Instant::now());
194 state.thinking_content.clear();
195 state.depth = depth;
196 Ok(())
197 }
198
199 pub fn stop_thinking(&self) -> Result<String> {
201 let mut state = self.thinking_state.lock().map_err(|_| {
202 ModeError::ConfigError("Failed to acquire lock on thinking state".to_string())
203 })?;
204 state.active = false;
205 state.start_time = None;
206 Ok(state.thinking_content.clone())
207 }
208
209 pub fn add_thinking_content(&self, content: &str) -> Result<()> {
211 let mut state = self.thinking_state.lock().map_err(|_| {
212 ModeError::ConfigError("Failed to acquire lock on thinking state".to_string())
213 })?;
214 if state.active {
215 state.thinking_content.push_str(content);
216 state.thinking_content.push('\n');
217 }
218 Ok(())
219 }
220
221 pub fn is_thinking(&self) -> Result<bool> {
223 let state = self.thinking_state.lock().map_err(|_| {
224 ModeError::ConfigError("Failed to acquire lock on thinking state".to_string())
225 })?;
226 Ok(state.active)
227 }
228
229 pub fn get_thinking_content(&self) -> Result<String> {
231 let state = self.thinking_state.lock().map_err(|_| {
232 ModeError::ConfigError("Failed to acquire lock on thinking state".to_string())
233 })?;
234 Ok(state.thinking_content.clone())
235 }
236
237 pub fn get_elapsed_time(&self) -> Result<Option<Duration>> {
239 let state = self.thinking_state.lock().map_err(|_| {
240 ModeError::ConfigError("Failed to acquire lock on thinking state".to_string())
241 })?;
242 Ok(state.start_time.map(|start| start.elapsed()))
243 }
244
245 pub fn has_exceeded_timeout(&self) -> Result<bool> {
247 let config = self.global_config.lock().map_err(|_| {
248 ModeError::ConfigError("Failed to acquire lock on global config".to_string())
249 })?;
250 let state = self.thinking_state.lock().map_err(|_| {
251 ModeError::ConfigError("Failed to acquire lock on thinking state".to_string())
252 })?;
253
254 if let Some(start) = state.start_time {
255 Ok(start.elapsed() > config.timeout)
256 } else {
257 Ok(false)
258 }
259 }
260
261 pub fn cancel_thinking(&self) -> Result<()> {
263 let mut state = self.thinking_state.lock().map_err(|_| {
264 ModeError::ConfigError("Failed to acquire lock on thinking state".to_string())
265 })?;
266 state.active = false;
267 state.start_time = None;
268 Ok(())
269 }
270
271 pub fn should_auto_enable(&self, complexity: ComplexityLevel) -> Result<bool> {
273 let config = self.global_config.lock().map_err(|_| {
274 ModeError::ConfigError("Failed to acquire lock on global config".to_string())
275 })?;
276
277 if !config.auto_enable {
278 return Ok(false);
279 }
280
281 Ok(complexity == ComplexityLevel::Complex)
283 }
284
285 pub fn get_thinking_metadata(&self) -> Result<ThinkingMetadata> {
287 let config = self.global_config.lock().map_err(|_| {
288 ModeError::ConfigError("Failed to acquire lock on global config".to_string())
289 })?;
290 let state = self.thinking_state.lock().map_err(|_| {
291 ModeError::ConfigError("Failed to acquire lock on thinking state".to_string())
292 })?;
293
294 Ok(ThinkingMetadata {
295 enabled: config.enabled,
296 active: state.active,
297 depth: state.depth,
298 elapsed_time: state.start_time.map(|start| start.elapsed()),
299 timeout: config.timeout,
300 content_length: state.thinking_content.len(),
301 auto_enable: config.auto_enable,
302 })
303 }
304}
305
306impl Default for ThinkMoreController {
307 fn default() -> Self {
308 Self::new()
309 }
310}
311
312#[derive(Debug, Clone)]
314pub struct ThinkingMetadata {
315 pub enabled: bool,
317 pub active: bool,
319 pub depth: ThinkingDepth,
321 pub elapsed_time: Option<Duration>,
323 pub timeout: Duration,
325 pub content_length: usize,
327 pub auto_enable: bool,
329}
330
331#[cfg(test)]
332mod tests {
333 use super::*;
334
335 #[test]
336 fn test_think_more_controller_creation() {
337 let controller = ThinkMoreController::new();
338 assert!(!controller.is_enabled().unwrap());
339 }
340
341 #[test]
342 fn test_enable_disable() {
343 let controller = ThinkMoreController::new();
344 controller.enable().unwrap();
345 assert!(controller.is_enabled().unwrap());
346 controller.disable().unwrap();
347 assert!(!controller.is_enabled().unwrap());
348 }
349
350 #[test]
351 fn test_set_get_depth() {
352 let controller = ThinkMoreController::new();
353 controller.set_depth(ThinkingDepth::Deep).unwrap();
354 assert_eq!(controller.get_depth().unwrap(), ThinkingDepth::Deep);
355 }
356
357 #[test]
358 fn test_set_get_timeout() {
359 let controller = ThinkMoreController::new();
360 let timeout = Duration::from_secs(60);
361 controller.set_timeout(timeout).unwrap();
362 assert_eq!(controller.get_timeout().unwrap(), timeout);
363 }
364
365 #[test]
366 fn test_auto_enable() {
367 let controller = ThinkMoreController::new();
368 controller.enable_auto_enable().unwrap();
369 assert!(controller.is_auto_enable_enabled().unwrap());
370 controller.disable_auto_enable().unwrap();
371 assert!(!controller.is_auto_enable_enabled().unwrap());
372 }
373
374 #[test]
375 fn test_task_config() {
376 let controller = ThinkMoreController::new();
377 let config = ThinkMoreConfig {
378 enabled: true,
379 depth: ThinkingDepth::Deep,
380 timeout: Duration::from_secs(60),
381 auto_enable: false,
382 };
383 controller
384 .set_task_config("task1".to_string(), config.clone())
385 .unwrap();
386 let retrieved = controller.get_task_config("task1").unwrap();
387 assert!(retrieved.is_some());
388 assert_eq!(retrieved.unwrap().depth, ThinkingDepth::Deep);
389 }
390
391 #[test]
392 fn test_remove_task_config() {
393 let controller = ThinkMoreController::new();
394 let config = ThinkMoreConfig::default();
395 controller
396 .set_task_config("task1".to_string(), config)
397 .unwrap();
398 controller.remove_task_config("task1").unwrap();
399 assert!(controller.get_task_config("task1").unwrap().is_none());
400 }
401
402 #[test]
403 fn test_effective_config_task_override() {
404 let controller = ThinkMoreController::new();
405 let global_config = ThinkMoreConfig {
406 enabled: false,
407 depth: ThinkingDepth::Light,
408 timeout: Duration::from_secs(30),
409 auto_enable: false,
410 };
411 let task_config = ThinkMoreConfig {
412 enabled: true,
413 depth: ThinkingDepth::Deep,
414 timeout: Duration::from_secs(60),
415 auto_enable: true,
416 };
417
418 *controller.global_config.lock().unwrap() = global_config;
419 controller
420 .set_task_config("task1".to_string(), task_config)
421 .unwrap();
422
423 let effective = controller.get_effective_config(Some("task1")).unwrap();
424 assert!(effective.enabled);
425 assert_eq!(effective.depth, ThinkingDepth::Deep);
426 }
427
428 #[test]
429 fn test_effective_config_global_fallback() {
430 let controller = ThinkMoreController::new();
431 let global_config = ThinkMoreConfig {
432 enabled: true,
433 depth: ThinkingDepth::Medium,
434 timeout: Duration::from_secs(30),
435 auto_enable: false,
436 };
437 *controller.global_config.lock().unwrap() = global_config;
438
439 let effective = controller
440 .get_effective_config(Some("nonexistent"))
441 .unwrap();
442 assert!(effective.enabled);
443 assert_eq!(effective.depth, ThinkingDepth::Medium);
444 }
445
446 #[test]
447 fn test_start_stop_thinking() {
448 let controller = ThinkMoreController::new();
449 controller.start_thinking(ThinkingDepth::Deep).unwrap();
450 assert!(controller.is_thinking().unwrap());
451
452 let content = controller.stop_thinking().unwrap();
453 assert!(!controller.is_thinking().unwrap());
454 assert_eq!(content, "");
455 }
456
457 #[test]
458 fn test_add_thinking_content() {
459 let controller = ThinkMoreController::new();
460 controller.start_thinking(ThinkingDepth::Deep).unwrap();
461 controller.add_thinking_content("First thought").unwrap();
462 controller.add_thinking_content("Second thought").unwrap();
463
464 let content = controller.get_thinking_content().unwrap();
465 assert!(content.contains("First thought"));
466 assert!(content.contains("Second thought"));
467 }
468
469 #[test]
470 fn test_cancel_thinking() {
471 let controller = ThinkMoreController::new();
472 controller.start_thinking(ThinkingDepth::Deep).unwrap();
473 assert!(controller.is_thinking().unwrap());
474
475 controller.cancel_thinking().unwrap();
476 assert!(!controller.is_thinking().unwrap());
477 }
478
479 #[test]
480 fn test_should_auto_enable() {
481 let controller = ThinkMoreController::new();
482 controller.enable_auto_enable().unwrap();
483
484 assert!(controller
485 .should_auto_enable(ComplexityLevel::Complex)
486 .unwrap());
487 assert!(!controller
488 .should_auto_enable(ComplexityLevel::Moderate)
489 .unwrap());
490 assert!(!controller
491 .should_auto_enable(ComplexityLevel::Simple)
492 .unwrap());
493 }
494
495 #[test]
496 fn test_should_not_auto_enable_when_disabled() {
497 let controller = ThinkMoreController::new();
498 controller.disable_auto_enable().unwrap();
499
500 assert!(!controller
501 .should_auto_enable(ComplexityLevel::Complex)
502 .unwrap());
503 }
504
505 #[test]
506 fn test_thinking_metadata() {
507 let controller = ThinkMoreController::new();
508 controller.enable().unwrap();
509 controller.start_thinking(ThinkingDepth::Deep).unwrap();
510
511 let metadata = controller.get_thinking_metadata().unwrap();
512 assert!(metadata.enabled);
513 assert!(metadata.active);
514 assert_eq!(metadata.depth, ThinkingDepth::Deep);
515 assert!(metadata.elapsed_time.is_some());
516 }
517
518 #[test]
519 fn test_has_exceeded_timeout() {
520 let controller = ThinkMoreController::new();
521 controller.set_timeout(Duration::from_millis(1)).unwrap();
522 controller.start_thinking(ThinkingDepth::Deep).unwrap();
523
524 std::thread::sleep(Duration::from_millis(10));
526
527 assert!(controller.has_exceeded_timeout().unwrap());
528 }
529
530 #[test]
531 fn test_default_implementation() {
532 let controller = ThinkMoreController::default();
533 assert!(!controller.is_enabled().unwrap());
534 }
535
536 #[test]
537 fn test_with_config() {
538 let config = ThinkMoreConfig {
539 enabled: true,
540 depth: ThinkingDepth::Deep,
541 timeout: Duration::from_secs(60),
542 auto_enable: true,
543 };
544 let controller = ThinkMoreController::with_config(config);
545 assert!(controller.is_enabled().unwrap());
546 assert_eq!(controller.get_depth().unwrap(), ThinkingDepth::Deep);
547 }
548}