mcp_langbase_reasoning/modes/
reflection.rs

1//! Reflection reasoning mode - meta-cognitive analysis and quality improvement.
2//!
3//! This module provides reflection capabilities for analyzing and improving reasoning:
4//! - Iterative refinement with quality thresholds
5//! - Strength and weakness identification
6//! - Improved thought generation
7//! - Session evaluation for overall reasoning quality
8
9use serde::{Deserialize, Serialize};
10use std::time::Instant;
11use tracing::{debug, info, warn};
12
13use super::{extract_json_from_completion, serialize_for_log, ModeCore};
14use crate::config::Config;
15use crate::error::{AppResult, ToolError};
16use crate::langbase::{LangbaseClient, Message, PipeRequest};
17use crate::prompts::REFLECTION_PROMPT;
18use crate::storage::{Invocation, SqliteStorage, Storage, Thought};
19
20/// Input parameters for reflection reasoning
21#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct ReflectionParams {
23    /// The thought ID to reflect upon (optional - if not provided, reflects on content)
24    #[serde(skip_serializing_if = "Option::is_none")]
25    pub thought_id: Option<String>,
26    /// Content to reflect upon (used if thought_id not provided)
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub content: Option<String>,
29    /// Optional session ID (creates new if not provided)
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub session_id: Option<String>,
32    /// Optional branch ID for tree mode integration
33    #[serde(skip_serializing_if = "Option::is_none")]
34    pub branch_id: Option<String>,
35    /// Maximum iterations for iterative refinement
36    #[serde(default = "default_max_iterations")]
37    pub max_iterations: usize,
38    /// Quality threshold to stop iterating (0.0-1.0)
39    #[serde(default = "default_quality_threshold")]
40    pub quality_threshold: f64,
41    /// Whether to include full reasoning chain in context
42    #[serde(default)]
43    pub include_chain: bool,
44}
45
46fn default_max_iterations() -> usize {
47    3
48}
49
50fn default_quality_threshold() -> f64 {
51    0.8
52}
53
54/// Response from reflection reasoning Langbase pipe.
55#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct ReflectionResponse {
57    /// The meta-cognitive analysis of the thought.
58    pub analysis: String,
59    /// Identified strengths in the reasoning.
60    pub strengths: Vec<String>,
61    /// Identified weaknesses in the reasoning.
62    pub weaknesses: Vec<String>,
63    /// Recommendations for improvement.
64    pub recommendations: Vec<String>,
65    /// Confidence in the reflection analysis (0.0-1.0).
66    pub confidence: f64,
67    /// Optional quality score for the original thought (0.0-1.0).
68    #[serde(default)]
69    pub quality_score: Option<f64>,
70    /// Optional improved version of the thought.
71    #[serde(default)]
72    pub improved_thought: Option<String>,
73    /// Additional metadata from the response.
74    #[serde(default)]
75    pub metadata: serde_json::Value,
76}
77
78/// Result of reflection reasoning.
79#[derive(Debug, Clone, Serialize, Deserialize)]
80pub struct ReflectionResult {
81    /// The session ID.
82    pub session_id: String,
83    /// The ID of the reflection thought that was created.
84    pub reflection_thought_id: String,
85    /// The ID of the original thought that was reflected upon, if any.
86    pub original_thought_id: Option<String>,
87    /// The meta-cognitive analysis of the thought.
88    pub analysis: String,
89    /// Identified strengths in the reasoning.
90    pub strengths: Vec<String>,
91    /// Identified weaknesses in the reasoning.
92    pub weaknesses: Vec<String>,
93    /// Recommendations for improvement.
94    pub recommendations: Vec<String>,
95    /// Quality score of the thought (0.0-1.0).
96    pub quality_score: f64,
97    /// Optional improved version of the thought.
98    pub improved_thought: Option<ImprovedThought>,
99    /// Number of reflection iterations performed.
100    pub iterations_performed: usize,
101    /// Whether quality improved from the original.
102    pub quality_improved: bool,
103    /// Optional branch ID for tree mode integration.
104    #[serde(skip_serializing_if = "Option::is_none")]
105    pub branch_id: Option<String>,
106}
107
108/// Improved thought generated from reflection.
109#[derive(Debug, Clone, Serialize, Deserialize)]
110pub struct ImprovedThought {
111    /// The ID of the improved thought.
112    pub thought_id: String,
113    /// The improved content.
114    pub content: String,
115    /// Confidence in the improved thought (0.0-1.0).
116    pub confidence: f64,
117}
118
119/// Reflection reasoning mode handler for meta-cognitive analysis.
120#[derive(Clone)]
121pub struct ReflectionMode {
122    /// Core infrastructure (storage and langbase client).
123    core: ModeCore,
124    /// The Langbase pipe name for reflection.
125    pipe_name: String,
126}
127
128impl ReflectionMode {
129    /// Create a new reflection mode handler
130    pub fn new(storage: SqliteStorage, langbase: LangbaseClient, config: &Config) -> Self {
131        Self {
132            core: ModeCore::new(storage, langbase),
133            pipe_name: config.pipes.reflection.clone(),
134        }
135    }
136
137    /// Process a reflection reasoning request
138    pub async fn process(&self, params: ReflectionParams) -> AppResult<ReflectionResult> {
139        let start = Instant::now();
140
141        // Validate input - need either thought_id or content
142        if params.thought_id.is_none() && params.content.is_none() {
143            return Err(ToolError::Validation {
144                field: "thought_id or content".to_string(),
145                reason: "Either thought_id or content must be provided".to_string(),
146            }
147            .into());
148        }
149
150        // Get or create session
151        let session = self
152            .core
153            .storage()
154            .get_or_create_session(&params.session_id, "reflection")
155            .await?;
156        debug!(session_id = %session.id, "Processing reflection reasoning");
157
158        // Get the content to reflect upon
159        let (original_content, original_thought) = if let Some(thought_id) = &params.thought_id {
160            let thought = self
161                .core
162                .storage()
163                .get_thought(thought_id)
164                .await?
165                .ok_or_else(|| ToolError::Session(format!("Thought not found: {}", thought_id)))?;
166            (thought.content.clone(), Some(thought))
167        } else {
168            (params.content.clone().unwrap_or_default(), None)
169        };
170
171        // Get reasoning chain context if requested
172        let context_chain = if params.include_chain {
173            if let Some(ref thought) = original_thought {
174                self.get_reasoning_chain(&session.id, thought).await?
175            } else {
176                Vec::new()
177            }
178        } else {
179            Vec::new()
180        };
181
182        // Perform iterative reflection
183        let max_iterations = params.max_iterations.min(5);
184        let mut current_content = original_content.clone();
185        let mut iterations_performed = 0;
186        let mut best_quality = 0.0;
187        let mut final_response: Option<ReflectionResponse> = None;
188
189        for iteration in 0..max_iterations {
190            iterations_performed = iteration + 1;
191
192            // Build messages for Langbase
193            let messages = self.build_messages(&current_content, &context_chain, iteration);
194
195            // Create invocation log
196            let mut invocation = Invocation::new(
197                "reasoning.reflection",
198                serde_json::json!({
199                    "iteration": iteration,
200                    "content": &current_content
201                }),
202            )
203            .with_session(&session.id)
204            .with_pipe(&self.pipe_name);
205
206            // Call Langbase pipe
207            let request = PipeRequest::new(&self.pipe_name, messages);
208            let response = match self.core.langbase().call_pipe(request).await {
209                Ok(resp) => resp,
210                Err(e) => {
211                    let latency = start.elapsed().as_millis() as i64;
212                    invocation = invocation.failure(e.to_string(), latency);
213                    self.core.storage().log_invocation(&invocation).await?;
214                    return Err(e.into());
215                }
216            };
217
218            // Parse response
219            let reflection = self.parse_response(&response.completion)?;
220            let quality = reflection.quality_score.unwrap_or(reflection.confidence);
221
222            // Log invocation
223            let latency = start.elapsed().as_millis() as i64;
224            invocation = invocation.success(
225                serialize_for_log(&reflection, "reasoning.reflection output"),
226                latency,
227            );
228            self.core.storage().log_invocation(&invocation).await?;
229
230            // Check if quality threshold met
231            if quality >= params.quality_threshold {
232                debug!(
233                    iteration = iteration,
234                    quality = quality,
235                    threshold = params.quality_threshold,
236                    "Quality threshold met, stopping iterations"
237                );
238                best_quality = quality;
239                final_response = Some(reflection);
240                break;
241            }
242
243            // Update for next iteration if improved thought available
244            if let Some(ref improved) = reflection.improved_thought {
245                if quality > best_quality {
246                    best_quality = quality;
247                    current_content = improved.clone();
248                }
249            }
250
251            final_response = Some(reflection);
252        }
253
254        let reflection = final_response.ok_or_else(|| ToolError::Reasoning {
255            message: "No reflection response generated".to_string(),
256        })?;
257
258        // Create reflection thought
259        let reflection_thought = Thought::new(&session.id, &reflection.analysis, "reflection")
260            .with_confidence(reflection.confidence)
261            .with_metadata(serde_json::json!({
262                "strengths": reflection.strengths,
263                "weaknesses": reflection.weaknesses,
264                "recommendations": reflection.recommendations,
265                "quality_score": best_quality,
266                "iterations": iterations_performed
267            }));
268
269        let reflection_thought = if let Some(ref thought) = original_thought {
270            reflection_thought.with_parent(&thought.id)
271        } else {
272            reflection_thought
273        };
274
275        let reflection_thought = if let Some(ref branch_id) = params.branch_id {
276            reflection_thought.with_branch(branch_id)
277        } else {
278            reflection_thought
279        };
280
281        self.core
282            .storage()
283            .create_thought(&reflection_thought)
284            .await?;
285
286        // Create improved thought if available and different from original
287        let improved_thought = if let Some(ref improved_content) = reflection.improved_thought {
288            if improved_content != &original_content {
289                let improved = Thought::new(&session.id, improved_content, "reflection")
290                    .with_confidence(best_quality)
291                    .with_parent(&reflection_thought.id)
292                    .with_metadata(serde_json::json!({
293                        "is_improved_version": true,
294                        "original_thought_id": original_thought.as_ref().map(|t| &t.id)
295                    }));
296
297                let improved = if let Some(ref branch_id) = params.branch_id {
298                    improved.with_branch(branch_id)
299                } else {
300                    improved
301                };
302
303                self.core.storage().create_thought(&improved).await?;
304
305                Some(ImprovedThought {
306                    thought_id: improved.id,
307                    content: improved_content.clone(),
308                    confidence: best_quality,
309                })
310            } else {
311                None
312            }
313        } else {
314            None
315        };
316
317        let quality_improved = best_quality
318            > original_thought
319                .as_ref()
320                .map(|t| t.confidence)
321                .unwrap_or(0.5);
322
323        info!(
324            session_id = %session.id,
325            reflection_id = %reflection_thought.id,
326            iterations = iterations_performed,
327            quality_score = best_quality,
328            quality_improved = quality_improved,
329            latency_ms = start.elapsed().as_millis(),
330            "Reflection reasoning completed"
331        );
332
333        Ok(ReflectionResult {
334            session_id: session.id,
335            reflection_thought_id: reflection_thought.id,
336            original_thought_id: original_thought.map(|t| t.id),
337            analysis: reflection.analysis,
338            strengths: reflection.strengths,
339            weaknesses: reflection.weaknesses,
340            recommendations: reflection.recommendations,
341            quality_score: best_quality,
342            improved_thought,
343            iterations_performed,
344            quality_improved,
345            branch_id: params.branch_id,
346        })
347    }
348
349    /// Self-evaluate a session's reasoning quality
350    pub async fn evaluate_session(&self, session_id: &str) -> AppResult<SessionEvaluation> {
351        let thoughts = self.core.storage().get_session_thoughts(session_id).await?;
352
353        if thoughts.is_empty() {
354            return Err(
355                ToolError::Session("Session has no thoughts to evaluate".to_string()).into(),
356            );
357        }
358
359        let total_confidence: f64 = thoughts.iter().map(|t| t.confidence).sum();
360        let avg_confidence = total_confidence / thoughts.len() as f64;
361
362        let mode_counts: std::collections::HashMap<String, usize> =
363            thoughts
364                .iter()
365                .fold(std::collections::HashMap::new(), |mut acc, t| {
366                    *acc.entry(t.mode.clone()).or_insert(0) += 1;
367                    acc
368                });
369
370        let coherence_score = self.calculate_coherence(&thoughts);
371
372        Ok(SessionEvaluation {
373            session_id: session_id.to_string(),
374            total_thoughts: thoughts.len(),
375            average_confidence: avg_confidence,
376            mode_distribution: mode_counts,
377            coherence_score,
378            recommendation: if avg_confidence < 0.6 {
379                "Consider reviewing and refining low-confidence thoughts".to_string()
380            } else if coherence_score < 0.5 {
381                "Reasoning chain may have logical gaps - consider reflection mode".to_string()
382            } else {
383                "Reasoning quality is acceptable".to_string()
384            },
385        })
386    }
387
388    async fn get_reasoning_chain(
389        &self,
390        session_id: &str,
391        thought: &Thought,
392    ) -> AppResult<Vec<Thought>> {
393        let all_thoughts = self.core.storage().get_session_thoughts(session_id).await?;
394
395        // Build chain by following parent_id references
396        let mut chain = Vec::new();
397        let mut current_id = thought.parent_id.clone();
398
399        while let Some(parent_id) = current_id {
400            if let Some(parent) = all_thoughts.iter().find(|t| t.id == parent_id) {
401                chain.push(parent.clone());
402                current_id = parent.parent_id.clone();
403            } else {
404                break;
405            }
406
407            // Limit chain length
408            if chain.len() >= 10 {
409                break;
410            }
411        }
412
413        chain.reverse(); // Oldest first
414        chain.push(thought.clone()); // Add the target thought
415
416        Ok(chain)
417    }
418
419    fn calculate_coherence(&self, thoughts: &[Thought]) -> f64 {
420        if thoughts.len() < 2 {
421            return 1.0;
422        }
423
424        // Simple coherence metric based on confidence progression and parent chains
425        let mut linked_count = 0;
426        for thought in thoughts.iter().skip(1) {
427            if thought.parent_id.is_some() {
428                linked_count += 1;
429            }
430        }
431
432        let link_ratio = linked_count as f64 / (thoughts.len() - 1) as f64;
433
434        // Penalize large confidence swings
435        let confidence_stability: f64 = thoughts
436            .windows(2)
437            .map(|w| 1.0 - (w[0].confidence - w[1].confidence).abs())
438            .sum::<f64>()
439            / (thoughts.len() - 1) as f64;
440
441        (link_ratio + confidence_stability) / 2.0
442    }
443
444    fn build_messages(&self, content: &str, chain: &[Thought], iteration: usize) -> Vec<Message> {
445        let mut messages = Vec::new();
446
447        // Enhanced system prompt for iteration
448        let mut system_prompt = REFLECTION_PROMPT.to_string();
449        if iteration > 0 {
450            system_prompt.push_str(&format!(
451                "\n\nThis is iteration {} of reflection. Focus on addressing previously identified weaknesses and improving the thought quality.",
452                iteration + 1
453            ));
454        }
455
456        messages.push(Message::system(system_prompt));
457
458        // Add reasoning chain context if available
459        if !chain.is_empty() {
460            let chain_text: Vec<String> = chain
461                .iter()
462                .map(|t| {
463                    format!(
464                        "- [{}] (confidence: {:.2}) {}",
465                        t.mode, t.confidence, t.content
466                    )
467                })
468                .collect();
469
470            messages.push(Message::user(format!(
471                "Reasoning chain leading to this thought:\n{}\n\nNow reflect on the final thought:",
472                chain_text.join("\n")
473            )));
474        }
475
476        // Add content to reflect upon
477        messages.push(Message::user(format!(
478            "Thought to reflect upon:\n\n{}",
479            content
480        )));
481
482        messages
483    }
484
485    fn parse_response(&self, completion: &str) -> AppResult<ReflectionResponse> {
486        let json_str = extract_json_from_completion(completion).map_err(|e| {
487            warn!(
488                error = %e,
489                completion_preview = %completion.chars().take(200).collect::<String>(),
490                "Failed to extract JSON from reflection response"
491            );
492            ToolError::Reasoning {
493                message: format!("Reflection response extraction failed: {}", e),
494            }
495        })?;
496
497        serde_json::from_str::<ReflectionResponse>(json_str).map_err(|e| {
498            ToolError::Reasoning {
499                message: format!("Failed to parse reflection response: {}", e),
500            }
501            .into()
502        })
503    }
504}
505
506/// Session evaluation result showing overall reasoning quality.
507#[derive(Debug, Clone, Serialize, Deserialize)]
508pub struct SessionEvaluation {
509    /// The session ID that was evaluated.
510    pub session_id: String,
511    /// Total number of thoughts in the session.
512    pub total_thoughts: usize,
513    /// Average confidence across all thoughts (0.0-1.0).
514    pub average_confidence: f64,
515    /// Distribution of thoughts by reasoning mode.
516    pub mode_distribution: std::collections::HashMap<String, usize>,
517    /// Coherence score measuring logical consistency (0.0-1.0).
518    pub coherence_score: f64,
519    /// Recommendation for improving reasoning quality.
520    pub recommendation: String,
521}
522
523impl ReflectionParams {
524    /// Create new params with thought ID
525    pub fn for_thought(thought_id: impl Into<String>) -> Self {
526        Self {
527            thought_id: Some(thought_id.into()),
528            content: None,
529            session_id: None,
530            branch_id: None,
531            max_iterations: default_max_iterations(),
532            quality_threshold: default_quality_threshold(),
533            include_chain: false,
534        }
535    }
536
537    /// Create new params with content
538    pub fn for_content(content: impl Into<String>) -> Self {
539        Self {
540            thought_id: None,
541            content: Some(content.into()),
542            session_id: None,
543            branch_id: None,
544            max_iterations: default_max_iterations(),
545            quality_threshold: default_quality_threshold(),
546            include_chain: false,
547        }
548    }
549
550    /// Set the session ID
551    pub fn with_session(mut self, session_id: impl Into<String>) -> Self {
552        self.session_id = Some(session_id.into());
553        self
554    }
555
556    /// Set the branch ID
557    pub fn with_branch(mut self, branch_id: impl Into<String>) -> Self {
558        self.branch_id = Some(branch_id.into());
559        self
560    }
561
562    /// Set the maximum iterations
563    pub fn with_max_iterations(mut self, max: usize) -> Self {
564        self.max_iterations = max.clamp(1, 5);
565        self
566    }
567
568    /// Set the quality threshold
569    pub fn with_quality_threshold(mut self, threshold: f64) -> Self {
570        self.quality_threshold = threshold.clamp(0.0, 1.0);
571        self
572    }
573
574    /// Include reasoning chain context
575    pub fn with_chain(mut self) -> Self {
576        self.include_chain = true;
577        self
578    }
579}
580
581#[cfg(test)]
582mod tests {
583    use super::*;
584
585    // ============================================================================
586    // Default Function Tests
587    // ============================================================================
588
589    #[test]
590    fn test_default_max_iterations() {
591        assert_eq!(default_max_iterations(), 3);
592    }
593
594    #[test]
595    fn test_default_quality_threshold() {
596        assert_eq!(default_quality_threshold(), 0.8);
597    }
598
599    // ============================================================================
600    // ReflectionParams Tests
601    // ============================================================================
602
603    #[test]
604    fn test_reflection_params_for_thought() {
605        let params = ReflectionParams::for_thought("thought-123");
606        assert_eq!(params.thought_id, Some("thought-123".to_string()));
607        assert!(params.content.is_none());
608        assert!(params.session_id.is_none());
609        assert!(params.branch_id.is_none());
610        assert_eq!(params.max_iterations, 3);
611        assert_eq!(params.quality_threshold, 0.8);
612        assert!(!params.include_chain);
613    }
614
615    #[test]
616    fn test_reflection_params_for_content() {
617        let params = ReflectionParams::for_content("Some content to reflect upon");
618        assert!(params.thought_id.is_none());
619        assert_eq!(
620            params.content,
621            Some("Some content to reflect upon".to_string())
622        );
623        assert!(params.session_id.is_none());
624        assert_eq!(params.max_iterations, 3);
625    }
626
627    #[test]
628    fn test_reflection_params_with_session() {
629        let params = ReflectionParams::for_thought("t-1").with_session("sess-123");
630        assert_eq!(params.session_id, Some("sess-123".to_string()));
631    }
632
633    #[test]
634    fn test_reflection_params_with_branch() {
635        let params = ReflectionParams::for_thought("t-1").with_branch("branch-456");
636        assert_eq!(params.branch_id, Some("branch-456".to_string()));
637    }
638
639    #[test]
640    fn test_reflection_params_with_max_iterations() {
641        let params = ReflectionParams::for_thought("t-1").with_max_iterations(4);
642        assert_eq!(params.max_iterations, 4);
643    }
644
645    #[test]
646    fn test_reflection_params_max_iterations_clamped_high() {
647        let params = ReflectionParams::for_thought("t-1").with_max_iterations(10);
648        assert_eq!(params.max_iterations, 5); // max is 5
649    }
650
651    #[test]
652    fn test_reflection_params_max_iterations_clamped_low() {
653        let params = ReflectionParams::for_thought("t-1").with_max_iterations(0);
654        assert_eq!(params.max_iterations, 1); // min is 1
655    }
656
657    #[test]
658    fn test_reflection_params_with_quality_threshold() {
659        let params = ReflectionParams::for_thought("t-1").with_quality_threshold(0.9);
660        assert_eq!(params.quality_threshold, 0.9);
661    }
662
663    #[test]
664    fn test_reflection_params_quality_threshold_clamped_high() {
665        let params = ReflectionParams::for_thought("t-1").with_quality_threshold(1.5);
666        assert_eq!(params.quality_threshold, 1.0);
667    }
668
669    #[test]
670    fn test_reflection_params_quality_threshold_clamped_low() {
671        let params = ReflectionParams::for_thought("t-1").with_quality_threshold(-0.5);
672        assert_eq!(params.quality_threshold, 0.0);
673    }
674
675    #[test]
676    fn test_reflection_params_with_chain() {
677        let params = ReflectionParams::for_thought("t-1").with_chain();
678        assert!(params.include_chain);
679    }
680
681    #[test]
682    fn test_reflection_params_builder_chain() {
683        let params = ReflectionParams::for_thought("t-1")
684            .with_session("my-session")
685            .with_branch("my-branch")
686            .with_max_iterations(4)
687            .with_quality_threshold(0.85)
688            .with_chain();
689
690        assert_eq!(params.thought_id, Some("t-1".to_string()));
691        assert_eq!(params.session_id, Some("my-session".to_string()));
692        assert_eq!(params.branch_id, Some("my-branch".to_string()));
693        assert_eq!(params.max_iterations, 4);
694        assert_eq!(params.quality_threshold, 0.85);
695        assert!(params.include_chain);
696    }
697
698    #[test]
699    fn test_reflection_params_serialize() {
700        let params = ReflectionParams::for_thought("t-1")
701            .with_session("sess-1")
702            .with_max_iterations(3);
703
704        let json = serde_json::to_string(&params).unwrap();
705        assert!(json.contains("t-1"));
706        assert!(json.contains("sess-1"));
707        assert!(json.contains("\"max_iterations\":3"));
708    }
709
710    #[test]
711    fn test_reflection_params_deserialize() {
712        let json = r#"{
713            "thought_id": "t-1",
714            "content": "Some content",
715            "session_id": "s-1",
716            "branch_id": "b-1",
717            "max_iterations": 4,
718            "quality_threshold": 0.9,
719            "include_chain": true
720        }"#;
721        let params: ReflectionParams = serde_json::from_str(json).unwrap();
722
723        assert_eq!(params.thought_id, Some("t-1".to_string()));
724        assert_eq!(params.content, Some("Some content".to_string()));
725        assert_eq!(params.session_id, Some("s-1".to_string()));
726        assert_eq!(params.branch_id, Some("b-1".to_string()));
727        assert_eq!(params.max_iterations, 4);
728        assert_eq!(params.quality_threshold, 0.9);
729        assert!(params.include_chain);
730    }
731
732    #[test]
733    fn test_reflection_params_deserialize_minimal() {
734        let json = r#"{"thought_id": "t-1"}"#;
735        let params: ReflectionParams = serde_json::from_str(json).unwrap();
736
737        assert_eq!(params.thought_id, Some("t-1".to_string()));
738        assert!(params.content.is_none());
739        assert!(params.session_id.is_none());
740        assert_eq!(params.max_iterations, 3); // default
741        assert_eq!(params.quality_threshold, 0.8); // default
742        assert!(!params.include_chain); // default
743    }
744
745    // ============================================================================
746    // ReflectionResponse Tests
747    // ============================================================================
748
749    #[test]
750    fn test_reflection_response_serialize() {
751        let response = ReflectionResponse {
752            analysis: "This is the analysis".to_string(),
753            strengths: vec!["Strength 1".to_string(), "Strength 2".to_string()],
754            weaknesses: vec!["Weakness 1".to_string()],
755            recommendations: vec!["Recommendation 1".to_string()],
756            confidence: 0.85,
757            quality_score: Some(0.9),
758            improved_thought: Some("Improved version".to_string()),
759            metadata: serde_json::json!({"key": "value"}),
760        };
761
762        let json = serde_json::to_string(&response).unwrap();
763        assert!(json.contains("This is the analysis"));
764        assert!(json.contains("Strength 1"));
765        assert!(json.contains("Weakness 1"));
766        assert!(json.contains("0.85"));
767        assert!(json.contains("0.9"));
768        assert!(json.contains("Improved version"));
769    }
770
771    #[test]
772    fn test_reflection_response_deserialize() {
773        let json = r#"{
774            "analysis": "Analysis text",
775            "strengths": ["S1", "S2"],
776            "weaknesses": ["W1"],
777            "recommendations": ["R1", "R2"],
778            "confidence": 0.75,
779            "quality_score": 0.8,
780            "improved_thought": "Better thought"
781        }"#;
782        let response: ReflectionResponse = serde_json::from_str(json).unwrap();
783
784        assert_eq!(response.analysis, "Analysis text");
785        assert_eq!(response.strengths.len(), 2);
786        assert_eq!(response.weaknesses.len(), 1);
787        assert_eq!(response.recommendations.len(), 2);
788        assert_eq!(response.confidence, 0.75);
789        assert_eq!(response.quality_score, Some(0.8));
790        assert_eq!(
791            response.improved_thought,
792            Some("Better thought".to_string())
793        );
794    }
795
796    #[test]
797    fn test_reflection_response_deserialize_minimal() {
798        let json = r#"{
799            "analysis": "Basic analysis",
800            "strengths": [],
801            "weaknesses": [],
802            "recommendations": [],
803            "confidence": 0.5
804        }"#;
805        let response: ReflectionResponse = serde_json::from_str(json).unwrap();
806
807        assert_eq!(response.analysis, "Basic analysis");
808        assert!(response.strengths.is_empty());
809        assert!(response.quality_score.is_none());
810        assert!(response.improved_thought.is_none());
811    }
812
813    // ============================================================================
814    // ImprovedThought Tests
815    // ============================================================================
816
817    #[test]
818    fn test_improved_thought_serialize() {
819        let improved = ImprovedThought {
820            thought_id: "t-improved".to_string(),
821            content: "Improved content".to_string(),
822            confidence: 0.92,
823        };
824
825        let json = serde_json::to_string(&improved).unwrap();
826        assert!(json.contains("t-improved"));
827        assert!(json.contains("Improved content"));
828        assert!(json.contains("0.92"));
829    }
830
831    #[test]
832    fn test_improved_thought_deserialize() {
833        let json = r#"{
834            "thought_id": "t-1",
835            "content": "Better version",
836            "confidence": 0.88
837        }"#;
838        let improved: ImprovedThought = serde_json::from_str(json).unwrap();
839
840        assert_eq!(improved.thought_id, "t-1");
841        assert_eq!(improved.content, "Better version");
842        assert_eq!(improved.confidence, 0.88);
843    }
844
845    // ============================================================================
846    // ReflectionResult Tests
847    // ============================================================================
848
849    #[test]
850    fn test_reflection_result_serialize() {
851        let result = ReflectionResult {
852            session_id: "sess-1".to_string(),
853            reflection_thought_id: "t-refl".to_string(),
854            original_thought_id: Some("t-orig".to_string()),
855            analysis: "Analysis of thought".to_string(),
856            strengths: vec!["Strong point".to_string()],
857            weaknesses: vec!["Weak point".to_string()],
858            recommendations: vec!["Suggestion".to_string()],
859            quality_score: 0.85,
860            improved_thought: Some(ImprovedThought {
861                thought_id: "t-improved".to_string(),
862                content: "Better".to_string(),
863                confidence: 0.9,
864            }),
865            iterations_performed: 2,
866            quality_improved: true,
867            branch_id: Some("branch-1".to_string()),
868        };
869
870        let json = serde_json::to_string(&result).unwrap();
871        assert!(json.contains("sess-1"));
872        assert!(json.contains("t-refl"));
873        assert!(json.contains("t-orig"));
874        assert!(json.contains("Strong point"));
875        assert!(json.contains("branch-1"));
876    }
877
878    #[test]
879    fn test_reflection_result_deserialize() {
880        let json = r#"{
881            "session_id": "s-1",
882            "reflection_thought_id": "t-r",
883            "original_thought_id": "t-o",
884            "analysis": "Analysis",
885            "strengths": ["S"],
886            "weaknesses": ["W"],
887            "recommendations": ["R"],
888            "quality_score": 0.8,
889            "improved_thought": null,
890            "iterations_performed": 3,
891            "quality_improved": false
892        }"#;
893        let result: ReflectionResult = serde_json::from_str(json).unwrap();
894
895        assert_eq!(result.session_id, "s-1");
896        assert_eq!(result.reflection_thought_id, "t-r");
897        assert_eq!(result.original_thought_id, Some("t-o".to_string()));
898        assert_eq!(result.quality_score, 0.8);
899        assert!(result.improved_thought.is_none());
900        assert_eq!(result.iterations_performed, 3);
901        assert!(!result.quality_improved);
902        assert!(result.branch_id.is_none());
903    }
904
905    #[test]
906    fn test_reflection_result_without_branch() {
907        let result = ReflectionResult {
908            session_id: "s-1".to_string(),
909            reflection_thought_id: "t-1".to_string(),
910            original_thought_id: None,
911            analysis: "No branch".to_string(),
912            strengths: vec![],
913            weaknesses: vec![],
914            recommendations: vec![],
915            quality_score: 0.5,
916            improved_thought: None,
917            iterations_performed: 1,
918            quality_improved: false,
919            branch_id: None,
920        };
921
922        let json = serde_json::to_string(&result).unwrap();
923        // branch_id should be omitted due to skip_serializing_if
924        assert!(!json.contains("branch_id"));
925    }
926
927    // ============================================================================
928    // SessionEvaluation Tests
929    // ============================================================================
930
931    #[test]
932    fn test_session_evaluation_serialize() {
933        let mut mode_dist = std::collections::HashMap::new();
934        mode_dist.insert("linear".to_string(), 5);
935        mode_dist.insert("tree".to_string(), 3);
936
937        let eval = SessionEvaluation {
938            session_id: "sess-eval".to_string(),
939            total_thoughts: 8,
940            average_confidence: 0.75,
941            mode_distribution: mode_dist,
942            coherence_score: 0.82,
943            recommendation: "Reasoning quality is acceptable".to_string(),
944        };
945
946        let json = serde_json::to_string(&eval).unwrap();
947        assert!(json.contains("sess-eval"));
948        assert!(json.contains("8"));
949        assert!(json.contains("0.75"));
950        assert!(json.contains("linear"));
951        assert!(json.contains("0.82"));
952    }
953
954    #[test]
955    fn test_session_evaluation_deserialize() {
956        let json = r#"{
957            "session_id": "s-1",
958            "total_thoughts": 10,
959            "average_confidence": 0.7,
960            "mode_distribution": {"linear": 6, "divergent": 4},
961            "coherence_score": 0.9,
962            "recommendation": "Good quality"
963        }"#;
964        let eval: SessionEvaluation = serde_json::from_str(json).unwrap();
965
966        assert_eq!(eval.session_id, "s-1");
967        assert_eq!(eval.total_thoughts, 10);
968        assert_eq!(eval.average_confidence, 0.7);
969        assert_eq!(eval.mode_distribution.get("linear"), Some(&6));
970        assert_eq!(eval.coherence_score, 0.9);
971        assert_eq!(eval.recommendation, "Good quality");
972    }
973
974    // ============================================================================
975    // Serialization Round-Trip Tests
976    // ============================================================================
977
978    #[test]
979    fn test_reflection_params_roundtrip() {
980        let original = ReflectionParams::for_thought("t-1")
981            .with_session("sess-1")
982            .with_branch("branch-1")
983            .with_max_iterations(4)
984            .with_quality_threshold(0.85)
985            .with_chain();
986
987        let json = serde_json::to_string(&original).unwrap();
988        let deserialized: ReflectionParams = serde_json::from_str(&json).unwrap();
989
990        assert_eq!(original.thought_id, deserialized.thought_id);
991        assert_eq!(original.session_id, deserialized.session_id);
992        assert_eq!(original.branch_id, deserialized.branch_id);
993        assert_eq!(original.max_iterations, deserialized.max_iterations);
994        assert_eq!(original.quality_threshold, deserialized.quality_threshold);
995        assert_eq!(original.include_chain, deserialized.include_chain);
996    }
997
998    #[test]
999    fn test_reflection_response_roundtrip() {
1000        let original = ReflectionResponse {
1001            analysis: "Deep analysis".to_string(),
1002            strengths: vec!["S1".to_string(), "S2".to_string()],
1003            weaknesses: vec!["W1".to_string()],
1004            recommendations: vec!["R1".to_string(), "R2".to_string()],
1005            confidence: 0.87,
1006            quality_score: Some(0.92),
1007            improved_thought: Some("Improved version".to_string()),
1008            metadata: serde_json::json!({"extra": "data"}),
1009        };
1010
1011        let json = serde_json::to_string(&original).unwrap();
1012        let deserialized: ReflectionResponse = serde_json::from_str(&json).unwrap();
1013
1014        assert_eq!(original.analysis, deserialized.analysis);
1015        assert_eq!(original.strengths, deserialized.strengths);
1016        assert_eq!(original.weaknesses, deserialized.weaknesses);
1017        assert_eq!(original.recommendations, deserialized.recommendations);
1018        assert_eq!(original.confidence, deserialized.confidence);
1019        assert_eq!(original.quality_score, deserialized.quality_score);
1020        assert_eq!(original.improved_thought, deserialized.improved_thought);
1021    }
1022
1023    #[test]
1024    fn test_reflection_result_roundtrip() {
1025        let original = ReflectionResult {
1026            session_id: "s-123".to_string(),
1027            reflection_thought_id: "t-refl".to_string(),
1028            original_thought_id: Some("t-orig".to_string()),
1029            analysis: "Complete analysis".to_string(),
1030            strengths: vec!["Strength".to_string()],
1031            weaknesses: vec!["Weakness".to_string()],
1032            recommendations: vec!["Recommendation".to_string()],
1033            quality_score: 0.88,
1034            improved_thought: Some(ImprovedThought {
1035                thought_id: "t-imp".to_string(),
1036                content: "Better".to_string(),
1037                confidence: 0.91,
1038            }),
1039            iterations_performed: 3,
1040            quality_improved: true,
1041            branch_id: Some("br-1".to_string()),
1042        };
1043
1044        let json = serde_json::to_string(&original).unwrap();
1045        let deserialized: ReflectionResult = serde_json::from_str(&json).unwrap();
1046
1047        assert_eq!(original.session_id, deserialized.session_id);
1048        assert_eq!(
1049            original.reflection_thought_id,
1050            deserialized.reflection_thought_id
1051        );
1052        assert_eq!(
1053            original.original_thought_id,
1054            deserialized.original_thought_id
1055        );
1056        assert_eq!(original.quality_score, deserialized.quality_score);
1057        assert_eq!(
1058            original.iterations_performed,
1059            deserialized.iterations_performed
1060        );
1061        assert_eq!(original.quality_improved, deserialized.quality_improved);
1062        assert_eq!(original.branch_id, deserialized.branch_id);
1063    }
1064
1065    #[test]
1066    fn test_session_evaluation_roundtrip() {
1067        let mut mode_dist = std::collections::HashMap::new();
1068        mode_dist.insert("linear".to_string(), 7);
1069        mode_dist.insert("tree".to_string(), 3);
1070        mode_dist.insert("reflection".to_string(), 2);
1071
1072        let original = SessionEvaluation {
1073            session_id: "eval-session".to_string(),
1074            total_thoughts: 12,
1075            average_confidence: 0.73,
1076            mode_distribution: mode_dist,
1077            coherence_score: 0.85,
1078            recommendation: "Continue with current approach".to_string(),
1079        };
1080
1081        let json = serde_json::to_string(&original).unwrap();
1082        let deserialized: SessionEvaluation = serde_json::from_str(&json).unwrap();
1083
1084        assert_eq!(original.session_id, deserialized.session_id);
1085        assert_eq!(original.total_thoughts, deserialized.total_thoughts);
1086        assert_eq!(original.average_confidence, deserialized.average_confidence);
1087        assert_eq!(original.coherence_score, deserialized.coherence_score);
1088        assert_eq!(original.recommendation, deserialized.recommendation);
1089        assert_eq!(
1090            original.mode_distribution.len(),
1091            deserialized.mode_distribution.len()
1092        );
1093    }
1094
1095    // ============================================================================
1096    // Edge Cases Tests
1097    // ============================================================================
1098
1099    #[test]
1100    fn test_reflection_params_empty_strings() {
1101        let params = ReflectionParams::for_content("");
1102        assert_eq!(params.content, Some("".to_string()));
1103    }
1104
1105    #[test]
1106    fn test_reflection_params_builder_empty_session() {
1107        let params = ReflectionParams::for_thought("t-1").with_session("");
1108        assert_eq!(params.session_id, Some("".to_string()));
1109    }
1110
1111    #[test]
1112    fn test_reflection_params_builder_empty_branch() {
1113        let params = ReflectionParams::for_thought("t-1").with_branch("");
1114        assert_eq!(params.branch_id, Some("".to_string()));
1115    }
1116
1117    #[test]
1118    fn test_reflection_params_max_iterations_boundary() {
1119        // Test boundary values
1120        let params1 = ReflectionParams::for_thought("t-1").with_max_iterations(1);
1121        assert_eq!(params1.max_iterations, 1);
1122
1123        let params5 = ReflectionParams::for_thought("t-1").with_max_iterations(5);
1124        assert_eq!(params5.max_iterations, 5);
1125    }
1126
1127    #[test]
1128    fn test_reflection_params_quality_threshold_boundary() {
1129        // Test boundary values
1130        let params0 = ReflectionParams::for_thought("t-1").with_quality_threshold(0.0);
1131        assert_eq!(params0.quality_threshold, 0.0);
1132
1133        let params1 = ReflectionParams::for_thought("t-1").with_quality_threshold(1.0);
1134        assert_eq!(params1.quality_threshold, 1.0);
1135    }
1136
1137    #[test]
1138    fn test_reflection_response_empty_arrays() {
1139        let response = ReflectionResponse {
1140            analysis: "Analysis".to_string(),
1141            strengths: vec![],
1142            weaknesses: vec![],
1143            recommendations: vec![],
1144            confidence: 0.5,
1145            quality_score: None,
1146            improved_thought: None,
1147            metadata: serde_json::Value::Null,
1148        };
1149
1150        let json = serde_json::to_string(&response).unwrap();
1151        let deserialized: ReflectionResponse = serde_json::from_str(&json).unwrap();
1152
1153        assert!(deserialized.strengths.is_empty());
1154        assert!(deserialized.weaknesses.is_empty());
1155        assert!(deserialized.recommendations.is_empty());
1156    }
1157
1158    #[test]
1159    fn test_improved_thought_roundtrip() {
1160        let original = ImprovedThought {
1161            thought_id: "imp-123".to_string(),
1162            content: "Significantly improved reasoning".to_string(),
1163            confidence: 0.95,
1164        };
1165
1166        let json = serde_json::to_string(&original).unwrap();
1167        let deserialized: ImprovedThought = serde_json::from_str(&json).unwrap();
1168
1169        assert_eq!(original.thought_id, deserialized.thought_id);
1170        assert_eq!(original.content, deserialized.content);
1171        assert_eq!(original.confidence, deserialized.confidence);
1172    }
1173
1174    #[test]
1175    fn test_reflection_params_deserialize_with_defaults() {
1176        // Test that missing fields get default values
1177        let json = r#"{"content": "Test content"}"#;
1178        let params: ReflectionParams = serde_json::from_str(json).unwrap();
1179
1180        assert_eq!(params.max_iterations, 3);
1181        assert_eq!(params.quality_threshold, 0.8);
1182        assert!(!params.include_chain);
1183    }
1184
1185    #[test]
1186    fn test_reflection_response_quality_score_none() {
1187        let json = r#"{
1188            "analysis": "Test",
1189            "strengths": [],
1190            "weaknesses": [],
1191            "recommendations": [],
1192            "confidence": 0.6
1193        }"#;
1194        let response: ReflectionResponse = serde_json::from_str(json).unwrap();
1195
1196        assert!(response.quality_score.is_none());
1197        assert!(response.improved_thought.is_none());
1198    }
1199
1200    #[test]
1201    fn test_reflection_params_very_long_content() {
1202        let long_content = "x".repeat(10000);
1203        let params = ReflectionParams::for_content(&long_content);
1204        assert_eq!(params.content.as_ref().unwrap().len(), 10000);
1205    }
1206
1207    #[test]
1208    fn test_reflection_params_special_characters() {
1209        let special = "Test with \n newlines \t tabs and \"quotes\" and 'apostrophes'";
1210        let params = ReflectionParams::for_content(special);
1211        assert_eq!(params.content, Some(special.to_string()));
1212    }
1213
1214    #[test]
1215    fn test_reflection_params_unicode() {
1216        let unicode = "Unicode test: 你好世界 🌍 مرحبا";
1217        let params = ReflectionParams::for_content(unicode);
1218        assert_eq!(params.content, Some(unicode.to_string()));
1219    }
1220
1221    #[test]
1222    fn test_reflection_result_none_values() {
1223        let result = ReflectionResult {
1224            session_id: "s-1".to_string(),
1225            reflection_thought_id: "t-r".to_string(),
1226            original_thought_id: None,
1227            analysis: "Analysis".to_string(),
1228            strengths: vec![],
1229            weaknesses: vec![],
1230            recommendations: vec![],
1231            quality_score: 0.5,
1232            improved_thought: None,
1233            iterations_performed: 1,
1234            quality_improved: false,
1235            branch_id: None,
1236        };
1237
1238        assert!(result.original_thought_id.is_none());
1239        assert!(result.improved_thought.is_none());
1240        assert!(result.branch_id.is_none());
1241    }
1242
1243    #[test]
1244    fn test_session_evaluation_empty_mode_distribution() {
1245        let eval = SessionEvaluation {
1246            session_id: "s-1".to_string(),
1247            total_thoughts: 0,
1248            average_confidence: 0.0,
1249            mode_distribution: std::collections::HashMap::new(),
1250            coherence_score: 0.0,
1251            recommendation: "No data".to_string(),
1252        };
1253
1254        assert!(eval.mode_distribution.is_empty());
1255        assert_eq!(eval.total_thoughts, 0);
1256    }
1257
1258    // ============================================================================
1259    // Additional Integration Tests (without build_messages - tested via integration tests)
1260    // ============================================================================
1261
1262    #[test]
1263    fn test_default_values_consistency() {
1264        // Ensure default functions match struct defaults
1265        let params_thought = ReflectionParams::for_thought("t-1");
1266        let params_content = ReflectionParams::for_content("content");
1267
1268        assert_eq!(params_thought.max_iterations, default_max_iterations());
1269        assert_eq!(
1270            params_thought.quality_threshold,
1271            default_quality_threshold()
1272        );
1273        assert_eq!(params_content.max_iterations, default_max_iterations());
1274        assert_eq!(
1275            params_content.quality_threshold,
1276            default_quality_threshold()
1277        );
1278    }
1279
1280    #[test]
1281    fn test_clamp_values_negative() {
1282        // Test that negative values are properly clamped
1283        let params = ReflectionParams::for_thought("t-1")
1284            .with_max_iterations(0)
1285            .with_quality_threshold(-1.0);
1286
1287        assert_eq!(params.max_iterations, 1);
1288        assert_eq!(params.quality_threshold, 0.0);
1289    }
1290
1291    #[test]
1292    fn test_clamp_values_very_high() {
1293        // Test that very high values are properly clamped
1294        let params = ReflectionParams::for_thought("t-1")
1295            .with_max_iterations(100)
1296            .with_quality_threshold(5.0);
1297
1298        assert_eq!(params.max_iterations, 5);
1299        assert_eq!(params.quality_threshold, 1.0);
1300    }
1301
1302    #[test]
1303    fn test_reflection_result_quality_improved_logic() {
1304        // Test different quality_improved scenarios
1305        let result_improved = ReflectionResult {
1306            session_id: "s-1".to_string(),
1307            reflection_thought_id: "t-1".to_string(),
1308            original_thought_id: Some("t-orig".to_string()),
1309            analysis: "A".to_string(),
1310            strengths: vec![],
1311            weaknesses: vec![],
1312            recommendations: vec![],
1313            quality_score: 0.9,
1314            improved_thought: None,
1315            iterations_performed: 1,
1316            quality_improved: true,
1317            branch_id: None,
1318        };
1319
1320        assert!(result_improved.quality_improved);
1321        assert!(result_improved.quality_score > 0.5);
1322    }
1323
1324    // ============================================================================
1325    // Additional Builder Pattern Tests
1326    // ============================================================================
1327
1328    #[test]
1329    fn test_reflection_params_multiple_with_calls() {
1330        let params = ReflectionParams::for_thought("t-1")
1331            .with_session("s1")
1332            .with_session("s2") // Should override
1333            .with_max_iterations(2)
1334            .with_max_iterations(4); // Should override
1335
1336        assert_eq!(params.session_id, Some("s2".to_string()));
1337        assert_eq!(params.max_iterations, 4);
1338    }
1339
1340    #[test]
1341    fn test_reflection_params_content_builder_full_chain() {
1342        let params = ReflectionParams::for_content("My content")
1343            .with_session("session-abc")
1344            .with_branch("branch-xyz")
1345            .with_max_iterations(2)
1346            .with_quality_threshold(0.75)
1347            .with_chain();
1348
1349        assert!(params.thought_id.is_none());
1350        assert_eq!(params.content, Some("My content".to_string()));
1351        assert_eq!(params.session_id, Some("session-abc".to_string()));
1352        assert_eq!(params.branch_id, Some("branch-xyz".to_string()));
1353        assert_eq!(params.max_iterations, 2);
1354        assert_eq!(params.quality_threshold, 0.75);
1355        assert!(params.include_chain);
1356    }
1357
1358    #[test]
1359    fn test_reflection_params_default_include_chain_false() {
1360        let params1 = ReflectionParams::for_thought("t-1");
1361        let params2 = ReflectionParams::for_content("content");
1362
1363        assert!(!params1.include_chain);
1364        assert!(!params2.include_chain);
1365    }
1366
1367    #[test]
1368    fn test_reflection_response_metadata_default() {
1369        let json = r#"{
1370            "analysis": "Test",
1371            "strengths": [],
1372            "weaknesses": [],
1373            "recommendations": [],
1374            "confidence": 0.5
1375        }"#;
1376        let response: ReflectionResponse = serde_json::from_str(json).unwrap();
1377
1378        // metadata should default to null
1379        assert_eq!(response.metadata, serde_json::Value::Null);
1380    }
1381
1382    #[test]
1383    fn test_reflection_params_skip_serializing_none() {
1384        let params = ReflectionParams::for_content("content");
1385        let json = serde_json::to_string(&params).unwrap();
1386
1387        // Fields that are None should be omitted
1388        assert!(!json.contains("thought_id"));
1389        assert!(!json.contains("session_id"));
1390        assert!(!json.contains("branch_id"));
1391    }
1392
1393    #[test]
1394    fn test_reflection_result_skip_serializing_branch_none() {
1395        let result = ReflectionResult {
1396            session_id: "s-1".to_string(),
1397            reflection_thought_id: "t-1".to_string(),
1398            original_thought_id: None,
1399            analysis: "A".to_string(),
1400            strengths: vec![],
1401            weaknesses: vec![],
1402            recommendations: vec![],
1403            quality_score: 0.5,
1404            improved_thought: None,
1405            iterations_performed: 1,
1406            quality_improved: false,
1407            branch_id: None,
1408        };
1409
1410        let json = serde_json::to_string(&result).unwrap();
1411        assert!(!json.contains("branch_id"));
1412    }
1413
1414    #[test]
1415    fn test_reflection_result_with_all_fields() {
1416        let result = ReflectionResult {
1417            session_id: "s-1".to_string(),
1418            reflection_thought_id: "t-refl".to_string(),
1419            original_thought_id: Some("t-orig".to_string()),
1420            analysis: "Full analysis".to_string(),
1421            strengths: vec!["S1".to_string(), "S2".to_string()],
1422            weaknesses: vec!["W1".to_string()],
1423            recommendations: vec!["R1".to_string(), "R2".to_string(), "R3".to_string()],
1424            quality_score: 0.88,
1425            improved_thought: Some(ImprovedThought {
1426                thought_id: "t-imp".to_string(),
1427                content: "Improved".to_string(),
1428                confidence: 0.92,
1429            }),
1430            iterations_performed: 4,
1431            quality_improved: true,
1432            branch_id: Some("b-1".to_string()),
1433        };
1434
1435        assert_eq!(result.strengths.len(), 2);
1436        assert_eq!(result.weaknesses.len(), 1);
1437        assert_eq!(result.recommendations.len(), 3);
1438        assert!(result.improved_thought.is_some());
1439        assert!(result.branch_id.is_some());
1440    }
1441
1442    #[test]
1443    fn test_session_evaluation_single_mode() {
1444        let mut mode_dist = std::collections::HashMap::new();
1445        mode_dist.insert("reflection".to_string(), 1);
1446
1447        let eval = SessionEvaluation {
1448            session_id: "s-1".to_string(),
1449            total_thoughts: 1,
1450            average_confidence: 0.9,
1451            mode_distribution: mode_dist,
1452            coherence_score: 1.0,
1453            recommendation: "Single thought".to_string(),
1454        };
1455
1456        assert_eq!(eval.mode_distribution.len(), 1);
1457        assert_eq!(eval.total_thoughts, 1);
1458    }
1459
1460    #[test]
1461    fn test_improved_thought_zero_confidence() {
1462        let improved = ImprovedThought {
1463            thought_id: "t-1".to_string(),
1464            content: "Low confidence improvement".to_string(),
1465            confidence: 0.0,
1466        };
1467
1468        assert_eq!(improved.confidence, 0.0);
1469    }
1470
1471    #[test]
1472    fn test_improved_thought_full_confidence() {
1473        let improved = ImprovedThought {
1474            thought_id: "t-1".to_string(),
1475            content: "Perfect improvement".to_string(),
1476            confidence: 1.0,
1477        };
1478
1479        assert_eq!(improved.confidence, 1.0);
1480    }
1481
1482    #[test]
1483    fn test_reflection_response_with_complex_metadata() {
1484        let response = ReflectionResponse {
1485            analysis: "Complex".to_string(),
1486            strengths: vec![],
1487            weaknesses: vec![],
1488            recommendations: vec![],
1489            confidence: 0.5,
1490            quality_score: None,
1491            improved_thought: None,
1492            metadata: serde_json::json!({
1493                "nested": {
1494                    "field": "value",
1495                    "array": [1, 2, 3]
1496                },
1497                "boolean": true,
1498                "number": 42
1499            }),
1500        };
1501
1502        let json = serde_json::to_string(&response).unwrap();
1503        let deserialized: ReflectionResponse = serde_json::from_str(&json).unwrap();
1504
1505        assert_eq!(response.metadata["nested"]["field"], "value");
1506        assert_eq!(deserialized.metadata["boolean"], true);
1507    }
1508
1509    // ============================================================================
1510    // ReflectionMode Constructor Tests
1511    // ============================================================================
1512
1513    fn create_test_config() -> Config {
1514        use crate::config::{
1515            DatabaseConfig, ErrorHandlingConfig, LangbaseConfig, LogFormat, LoggingConfig,
1516            PipeConfig,
1517        };
1518        use std::path::PathBuf;
1519
1520        Config {
1521            langbase: LangbaseConfig {
1522                api_key: "test-key".to_string(),
1523                base_url: "https://api.langbase.com".to_string(),
1524            },
1525            database: DatabaseConfig {
1526                path: PathBuf::from(":memory:"),
1527                max_connections: 5,
1528            },
1529            logging: LoggingConfig {
1530                level: "info".to_string(),
1531                format: LogFormat::Pretty,
1532            },
1533            request: crate::config::RequestConfig::default(),
1534            pipes: PipeConfig::default(),
1535            error_handling: ErrorHandlingConfig::default(),
1536        }
1537    }
1538
1539    #[test]
1540    fn test_reflection_mode_new() {
1541        let config = create_test_config();
1542        let rt = tokio::runtime::Runtime::new().unwrap();
1543        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
1544        let langbase =
1545            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
1546
1547        let mode = ReflectionMode::new(storage, langbase, &config);
1548        assert_eq!(mode.pipe_name, config.pipes.reflection);
1549    }
1550
1551    #[test]
1552    fn test_reflection_mode_new_with_custom_pipe_name() {
1553        let mut config = create_test_config();
1554        config.pipes.reflection = "custom-reflection-pipe".to_string();
1555
1556        let rt = tokio::runtime::Runtime::new().unwrap();
1557        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
1558        let langbase =
1559            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
1560
1561        let mode = ReflectionMode::new(storage, langbase, &config);
1562        assert_eq!(mode.pipe_name, "custom-reflection-pipe");
1563    }
1564
1565    // ============================================================================
1566    // build_messages() Tests
1567    // ============================================================================
1568
1569    #[test]
1570    fn test_build_messages_simple_content() {
1571        use crate::langbase::MessageRole;
1572
1573        let config = create_test_config();
1574        let rt = tokio::runtime::Runtime::new().unwrap();
1575        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
1576        let langbase =
1577            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
1578
1579        let mode = ReflectionMode::new(storage, langbase, &config);
1580        let messages = mode.build_messages("Test content", &[], 0);
1581
1582        assert_eq!(messages.len(), 2);
1583        assert!(matches!(messages[0].role, MessageRole::System));
1584        assert!(messages[0].content.contains("meta-cognitive"));
1585        assert!(matches!(messages[1].role, MessageRole::User));
1586        assert!(messages[1].content.contains("Test content"));
1587    }
1588
1589    #[test]
1590    fn test_build_messages_with_iteration() {
1591        let config = create_test_config();
1592        let rt = tokio::runtime::Runtime::new().unwrap();
1593        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
1594        let langbase =
1595            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
1596
1597        let mode = ReflectionMode::new(storage, langbase, &config);
1598        let messages = mode.build_messages("Test content", &[], 2);
1599
1600        assert_eq!(messages.len(), 2);
1601        assert!(messages[0].content.contains("iteration 3"));
1602        assert!(messages[0]
1603            .content
1604            .contains("previously identified weaknesses"));
1605    }
1606
1607    #[test]
1608    fn test_build_messages_with_empty_chain() {
1609        let config = create_test_config();
1610        let rt = tokio::runtime::Runtime::new().unwrap();
1611        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
1612        let langbase =
1613            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
1614
1615        let mode = ReflectionMode::new(storage, langbase, &config);
1616        let chain: Vec<Thought> = vec![];
1617        let messages = mode.build_messages("Content", &chain, 0);
1618
1619        assert_eq!(messages.len(), 2);
1620        assert!(!messages
1621            .iter()
1622            .any(|m| m.content.contains("Reasoning chain")));
1623    }
1624
1625    #[test]
1626    fn test_build_messages_with_reasoning_chain() {
1627        use crate::langbase::MessageRole;
1628
1629        let config = create_test_config();
1630        let rt = tokio::runtime::Runtime::new().unwrap();
1631        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
1632        let langbase =
1633            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
1634
1635        let mode = ReflectionMode::new(storage, langbase, &config);
1636
1637        let thought1 = Thought::new("sess-1", "First thought", "linear").with_confidence(0.7);
1638        let thought2 = Thought::new("sess-1", "Second thought", "tree").with_confidence(0.8);
1639        let chain = vec![thought1, thought2];
1640
1641        let messages = mode.build_messages("Final thought", &chain, 0);
1642
1643        assert_eq!(messages.len(), 3);
1644        assert!(matches!(messages[0].role, MessageRole::System));
1645        assert!(matches!(messages[1].role, MessageRole::User));
1646        assert!(messages[1].content.contains("Reasoning chain"));
1647        assert!(messages[1].content.contains("First thought"));
1648        assert!(messages[1].content.contains("Second thought"));
1649        assert!(messages[1].content.contains("0.70"));
1650        assert!(messages[1].content.contains("0.80"));
1651        assert!(matches!(messages[2].role, MessageRole::User));
1652        assert!(messages[2].content.contains("Final thought"));
1653    }
1654
1655    #[test]
1656    fn test_build_messages_chain_formatting() {
1657        let config = create_test_config();
1658        let rt = tokio::runtime::Runtime::new().unwrap();
1659        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
1660        let langbase =
1661            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
1662
1663        let mode = ReflectionMode::new(storage, langbase, &config);
1664
1665        let thought = Thought::new("sess-1", "Content", "divergent").with_confidence(0.65);
1666        let chain = vec![thought];
1667
1668        let messages = mode.build_messages("Test", &chain, 0);
1669
1670        let chain_message = &messages[1];
1671        assert!(chain_message.content.contains("[divergent]"));
1672        assert!(chain_message.content.contains("confidence: 0.65"));
1673        assert!(chain_message.content.contains("Content"));
1674    }
1675
1676    #[test]
1677    fn test_build_messages_empty_content() {
1678        let config = create_test_config();
1679        let rt = tokio::runtime::Runtime::new().unwrap();
1680        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
1681        let langbase =
1682            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
1683
1684        let mode = ReflectionMode::new(storage, langbase, &config);
1685        let messages = mode.build_messages("", &[], 0);
1686
1687        assert_eq!(messages.len(), 2);
1688        assert!(messages[1].content.contains("Thought to reflect upon"));
1689    }
1690
1691    #[test]
1692    fn test_build_messages_unicode_content() {
1693        let config = create_test_config();
1694        let rt = tokio::runtime::Runtime::new().unwrap();
1695        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
1696        let langbase =
1697            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
1698
1699        let mode = ReflectionMode::new(storage, langbase, &config);
1700        let unicode_content = "Test with unicode: 你好 🌍 مرحبا";
1701        let messages = mode.build_messages(unicode_content, &[], 0);
1702
1703        assert!(messages[1].content.contains(unicode_content));
1704    }
1705
1706    #[test]
1707    fn test_build_messages_special_characters() {
1708        let config = create_test_config();
1709        let rt = tokio::runtime::Runtime::new().unwrap();
1710        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
1711        let langbase =
1712            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
1713
1714        let mode = ReflectionMode::new(storage, langbase, &config);
1715        let special = "Content with\nnewlines\tand\ttabs and \"quotes\"";
1716        let messages = mode.build_messages(special, &[], 0);
1717
1718        assert!(messages[1].content.contains(special));
1719    }
1720
1721    #[test]
1722    fn test_build_messages_large_chain() {
1723        let config = create_test_config();
1724        let rt = tokio::runtime::Runtime::new().unwrap();
1725        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
1726        let langbase =
1727            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
1728
1729        let mode = ReflectionMode::new(storage, langbase, &config);
1730
1731        let mut chain = Vec::new();
1732        for i in 0..5 {
1733            chain.push(Thought::new("sess-1", format!("Thought {}", i), "linear"));
1734        }
1735
1736        let messages = mode.build_messages("Final", &chain, 0);
1737
1738        assert_eq!(messages.len(), 3);
1739        let chain_msg = &messages[1];
1740        assert!(chain_msg.content.contains("Thought 0"));
1741        assert!(chain_msg.content.contains("Thought 4"));
1742    }
1743
1744    // ============================================================================
1745    // parse_response() Tests
1746    // ============================================================================
1747
1748    #[test]
1749    fn test_parse_response_valid_json() {
1750        let config = create_test_config();
1751        let rt = tokio::runtime::Runtime::new().unwrap();
1752        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
1753        let langbase =
1754            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
1755
1756        let mode = ReflectionMode::new(storage, langbase, &config);
1757
1758        let completion = r#"{
1759            "analysis": "This is the analysis",
1760            "strengths": ["Strength 1", "Strength 2"],
1761            "weaknesses": ["Weakness 1"],
1762            "recommendations": ["Recommendation 1"],
1763            "confidence": 0.85
1764        }"#;
1765
1766        let response = mode.parse_response(completion).unwrap();
1767        assert_eq!(response.analysis, "This is the analysis");
1768        assert_eq!(response.strengths.len(), 2);
1769        assert_eq!(response.weaknesses.len(), 1);
1770        assert_eq!(response.recommendations.len(), 1);
1771        assert_eq!(response.confidence, 0.85);
1772    }
1773
1774    #[test]
1775    fn test_parse_response_with_quality_score() {
1776        let config = create_test_config();
1777        let rt = tokio::runtime::Runtime::new().unwrap();
1778        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
1779        let langbase =
1780            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
1781
1782        let mode = ReflectionMode::new(storage, langbase, &config);
1783
1784        let completion = r#"{
1785            "analysis": "Analysis",
1786            "strengths": [],
1787            "weaknesses": [],
1788            "recommendations": [],
1789            "confidence": 0.7,
1790            "quality_score": 0.9
1791        }"#;
1792
1793        let response = mode.parse_response(completion).unwrap();
1794        assert_eq!(response.quality_score, Some(0.9));
1795    }
1796
1797    #[test]
1798    fn test_parse_response_with_improved_thought() {
1799        let config = create_test_config();
1800        let rt = tokio::runtime::Runtime::new().unwrap();
1801        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
1802        let langbase =
1803            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
1804
1805        let mode = ReflectionMode::new(storage, langbase, &config);
1806
1807        let completion = r#"{
1808            "analysis": "Analysis",
1809            "strengths": [],
1810            "weaknesses": [],
1811            "recommendations": [],
1812            "confidence": 0.8,
1813            "improved_thought": "This is the improved version"
1814        }"#;
1815
1816        let response = mode.parse_response(completion).unwrap();
1817        assert_eq!(
1818            response.improved_thought,
1819            Some("This is the improved version".to_string())
1820        );
1821    }
1822
1823    #[test]
1824    fn test_parse_response_with_metadata() {
1825        let config = create_test_config();
1826        let rt = tokio::runtime::Runtime::new().unwrap();
1827        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
1828        let langbase =
1829            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
1830
1831        let mode = ReflectionMode::new(storage, langbase, &config);
1832
1833        let completion = r#"{
1834            "analysis": "Analysis",
1835            "strengths": [],
1836            "weaknesses": [],
1837            "recommendations": [],
1838            "confidence": 0.6,
1839            "metadata": {"key": "value", "number": 42}
1840        }"#;
1841
1842        let response = mode.parse_response(completion).unwrap();
1843        assert_eq!(response.metadata["key"], "value");
1844        assert_eq!(response.metadata["number"], 42);
1845    }
1846
1847    #[test]
1848    fn test_parse_response_json_with_markdown() {
1849        let config = create_test_config();
1850        let rt = tokio::runtime::Runtime::new().unwrap();
1851        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
1852        let langbase =
1853            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
1854
1855        let mode = ReflectionMode::new(storage, langbase, &config);
1856
1857        let completion = r#"Here's my analysis:
1858
1859```json
1860{
1861    "analysis": "Extracted from markdown",
1862    "strengths": ["S1"],
1863    "weaknesses": ["W1"],
1864    "recommendations": ["R1"],
1865    "confidence": 0.75
1866}
1867```"#;
1868
1869        let response = mode.parse_response(completion).unwrap();
1870        assert_eq!(response.analysis, "Extracted from markdown");
1871        assert_eq!(response.confidence, 0.75);
1872    }
1873
1874    #[test]
1875    fn test_parse_response_invalid_json() {
1876        let config = create_test_config();
1877        let rt = tokio::runtime::Runtime::new().unwrap();
1878        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
1879        let langbase =
1880            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
1881
1882        let mode = ReflectionMode::new(storage, langbase, &config);
1883
1884        let completion = "This is not JSON at all";
1885        let result = mode.parse_response(completion);
1886        assert!(result.is_err());
1887    }
1888
1889    #[test]
1890    fn test_parse_response_missing_required_fields() {
1891        let config = create_test_config();
1892        let rt = tokio::runtime::Runtime::new().unwrap();
1893        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
1894        let langbase =
1895            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
1896
1897        let mode = ReflectionMode::new(storage, langbase, &config);
1898
1899        let completion = r#"{"analysis": "Missing other fields"}"#;
1900        let result = mode.parse_response(completion);
1901        assert!(result.is_err());
1902    }
1903
1904    #[test]
1905    fn test_parse_response_empty_arrays() {
1906        let config = create_test_config();
1907        let rt = tokio::runtime::Runtime::new().unwrap();
1908        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
1909        let langbase =
1910            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
1911
1912        let mode = ReflectionMode::new(storage, langbase, &config);
1913
1914        let completion = r#"{
1915            "analysis": "Test",
1916            "strengths": [],
1917            "weaknesses": [],
1918            "recommendations": [],
1919            "confidence": 0.5
1920        }"#;
1921
1922        let response = mode.parse_response(completion).unwrap();
1923        assert!(response.strengths.is_empty());
1924        assert!(response.weaknesses.is_empty());
1925        assert!(response.recommendations.is_empty());
1926    }
1927
1928    #[test]
1929    fn test_parse_response_unicode_in_analysis() {
1930        let config = create_test_config();
1931        let rt = tokio::runtime::Runtime::new().unwrap();
1932        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
1933        let langbase =
1934            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
1935
1936        let mode = ReflectionMode::new(storage, langbase, &config);
1937
1938        let completion = r#"{
1939            "analysis": "Unicode: 你好世界 🌍",
1940            "strengths": [],
1941            "weaknesses": [],
1942            "recommendations": [],
1943            "confidence": 0.5
1944        }"#;
1945
1946        let response = mode.parse_response(completion).unwrap();
1947        assert!(response.analysis.contains("你好世界"));
1948        assert!(response.analysis.contains("🌍"));
1949    }
1950
1951    // ============================================================================
1952    // calculate_coherence() Tests
1953    // ============================================================================
1954
1955    #[test]
1956    fn test_calculate_coherence_empty_thoughts() {
1957        let config = create_test_config();
1958        let rt = tokio::runtime::Runtime::new().unwrap();
1959        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
1960        let langbase =
1961            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
1962
1963        let mode = ReflectionMode::new(storage, langbase, &config);
1964        let thoughts: Vec<Thought> = vec![];
1965        let coherence = mode.calculate_coherence(&thoughts);
1966
1967        // Empty array should have perfect coherence (no inconsistency)
1968        assert_eq!(coherence, 1.0);
1969    }
1970
1971    #[test]
1972    fn test_calculate_coherence_single_thought() {
1973        let config = create_test_config();
1974        let rt = tokio::runtime::Runtime::new().unwrap();
1975        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
1976        let langbase =
1977            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
1978
1979        let mode = ReflectionMode::new(storage, langbase, &config);
1980        let thought = Thought::new("sess-1", "Single thought", "linear");
1981        let coherence = mode.calculate_coherence(&[thought]);
1982
1983        assert_eq!(coherence, 1.0);
1984    }
1985
1986    #[test]
1987    fn test_calculate_coherence_all_linked() {
1988        let config = create_test_config();
1989        let rt = tokio::runtime::Runtime::new().unwrap();
1990        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
1991        let langbase =
1992            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
1993
1994        let mode = ReflectionMode::new(storage, langbase, &config);
1995
1996        let thought1 = Thought::new("sess-1", "First", "linear").with_confidence(0.8);
1997        let thought2 = Thought::new("sess-1", "Second", "linear")
1998            .with_confidence(0.8)
1999            .with_parent(&thought1.id);
2000        let thought3 = Thought::new("sess-1", "Third", "linear")
2001            .with_confidence(0.8)
2002            .with_parent(&thought2.id);
2003
2004        let coherence = mode.calculate_coherence(&[thought1, thought2, thought3]);
2005
2006        // All linked + stable confidence = high coherence
2007        assert!(coherence > 0.9);
2008    }
2009
2010    #[test]
2011    fn test_calculate_coherence_no_links() {
2012        let config = create_test_config();
2013        let rt = tokio::runtime::Runtime::new().unwrap();
2014        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
2015        let langbase =
2016            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
2017
2018        let mode = ReflectionMode::new(storage, langbase, &config);
2019
2020        let thought1 = Thought::new("sess-1", "First", "linear").with_confidence(0.8);
2021        let thought2 = Thought::new("sess-1", "Second", "linear").with_confidence(0.8);
2022        let thought3 = Thought::new("sess-1", "Third", "linear").with_confidence(0.8);
2023
2024        let coherence = mode.calculate_coherence(&[thought1, thought2, thought3]);
2025
2026        // No links = poor link ratio, but stable confidence helps
2027        assert!(coherence < 0.7);
2028    }
2029
2030    #[test]
2031    fn test_calculate_coherence_unstable_confidence() {
2032        let config = create_test_config();
2033        let rt = tokio::runtime::Runtime::new().unwrap();
2034        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
2035        let langbase =
2036            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
2037
2038        let mode = ReflectionMode::new(storage, langbase, &config);
2039
2040        let thought1 = Thought::new("sess-1", "First", "linear").with_confidence(0.9);
2041        let thought2 = Thought::new("sess-1", "Second", "linear").with_confidence(0.1);
2042        let thought3 = Thought::new("sess-1", "Third", "linear").with_confidence(0.9);
2043
2044        let coherence = mode.calculate_coherence(&[thought1, thought2, thought3]);
2045
2046        // Large confidence swings reduce coherence
2047        assert!(coherence < 0.7);
2048    }
2049
2050    #[test]
2051    fn test_calculate_coherence_partial_links() {
2052        let config = create_test_config();
2053        let rt = tokio::runtime::Runtime::new().unwrap();
2054        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
2055        let langbase =
2056            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
2057
2058        let mode = ReflectionMode::new(storage, langbase, &config);
2059
2060        let thought1 = Thought::new("sess-1", "First", "linear").with_confidence(0.7);
2061        let thought2 = Thought::new("sess-1", "Second", "linear")
2062            .with_confidence(0.75)
2063            .with_parent(&thought1.id);
2064        let thought3 = Thought::new("sess-1", "Third", "linear").with_confidence(0.7);
2065
2066        let coherence = mode.calculate_coherence(&[thought1, thought2, thought3]);
2067
2068        // 50% linked, stable confidence = medium coherence
2069        assert!(coherence > 0.5 && coherence < 0.9);
2070    }
2071
2072    #[test]
2073    fn test_calculate_coherence_two_thoughts_linked() {
2074        let config = create_test_config();
2075        let rt = tokio::runtime::Runtime::new().unwrap();
2076        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
2077        let langbase =
2078            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
2079
2080        let mode = ReflectionMode::new(storage, langbase, &config);
2081
2082        let thought1 = Thought::new("sess-1", "First", "linear").with_confidence(0.8);
2083        let thought2 = Thought::new("sess-1", "Second", "linear")
2084            .with_confidence(0.8)
2085            .with_parent(&thought1.id);
2086
2087        let coherence = mode.calculate_coherence(&[thought1, thought2]);
2088
2089        // Perfect link ratio, stable confidence
2090        assert!(coherence > 0.9);
2091    }
2092
2093    #[test]
2094    fn test_calculate_coherence_two_thoughts_unlinked() {
2095        let config = create_test_config();
2096        let rt = tokio::runtime::Runtime::new().unwrap();
2097        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
2098        let langbase =
2099            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
2100
2101        let mode = ReflectionMode::new(storage, langbase, &config);
2102
2103        let thought1 = Thought::new("sess-1", "First", "linear").with_confidence(0.8);
2104        let thought2 = Thought::new("sess-1", "Second", "linear").with_confidence(0.8);
2105
2106        let coherence = mode.calculate_coherence(&[thought1, thought2]);
2107
2108        // No links but stable confidence
2109        assert!(coherence < 0.7);
2110    }
2111
2112    #[test]
2113    fn test_calculate_coherence_varying_confidence() {
2114        let config = create_test_config();
2115        let rt = tokio::runtime::Runtime::new().unwrap();
2116        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
2117        let langbase =
2118            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
2119
2120        let mode = ReflectionMode::new(storage, langbase, &config);
2121
2122        let thought1 = Thought::new("sess-1", "First", "linear").with_confidence(0.5);
2123        let thought2 = Thought::new("sess-1", "Second", "linear")
2124            .with_confidence(0.6)
2125            .with_parent(&thought1.id);
2126        let thought3 = Thought::new("sess-1", "Third", "linear")
2127            .with_confidence(0.7)
2128            .with_parent(&thought2.id);
2129
2130        let coherence = mode.calculate_coherence(&[thought1, thought2, thought3]);
2131
2132        // Good links, gradually improving confidence
2133        assert!(coherence > 0.8);
2134    }
2135
2136    // ============================================================================
2137    // Additional Edge Case Tests
2138    // ============================================================================
2139
2140    #[test]
2141    fn test_reflection_params_for_thought_with_empty_id() {
2142        let params = ReflectionParams::for_thought("");
2143        assert_eq!(params.thought_id, Some("".to_string()));
2144    }
2145
2146    #[test]
2147    fn test_reflection_params_for_content_with_whitespace() {
2148        let params = ReflectionParams::for_content("   \n\t  ");
2149        assert_eq!(params.content, Some("   \n\t  ".to_string()));
2150    }
2151
2152    #[test]
2153    fn test_reflection_response_zero_confidence() {
2154        let response = ReflectionResponse {
2155            analysis: "Low confidence".to_string(),
2156            strengths: vec![],
2157            weaknesses: vec!["Many issues".to_string()],
2158            recommendations: vec![],
2159            confidence: 0.0,
2160            quality_score: Some(0.0),
2161            improved_thought: None,
2162            metadata: serde_json::Value::Null,
2163        };
2164
2165        assert_eq!(response.confidence, 0.0);
2166        assert_eq!(response.quality_score, Some(0.0));
2167    }
2168
2169    #[test]
2170    fn test_reflection_response_perfect_confidence() {
2171        let response = ReflectionResponse {
2172            analysis: "Perfect".to_string(),
2173            strengths: vec!["Everything".to_string()],
2174            weaknesses: vec![],
2175            recommendations: vec![],
2176            confidence: 1.0,
2177            quality_score: Some(1.0),
2178            improved_thought: None,
2179            metadata: serde_json::Value::Null,
2180        };
2181
2182        assert_eq!(response.confidence, 1.0);
2183        assert_eq!(response.quality_score, Some(1.0));
2184    }
2185
2186    #[test]
2187    fn test_reflection_result_iterations_zero() {
2188        let result = ReflectionResult {
2189            session_id: "s-1".to_string(),
2190            reflection_thought_id: "t-1".to_string(),
2191            original_thought_id: None,
2192            analysis: "Quick".to_string(),
2193            strengths: vec![],
2194            weaknesses: vec![],
2195            recommendations: vec![],
2196            quality_score: 0.95,
2197            improved_thought: None,
2198            iterations_performed: 0,
2199            quality_improved: true,
2200            branch_id: None,
2201        };
2202
2203        assert_eq!(result.iterations_performed, 0);
2204    }
2205
2206    #[test]
2207    fn test_session_evaluation_high_confidence_low_coherence() {
2208        let mut mode_dist = std::collections::HashMap::new();
2209        mode_dist.insert("linear".to_string(), 5);
2210
2211        let eval = SessionEvaluation {
2212            session_id: "s-1".to_string(),
2213            total_thoughts: 5,
2214            average_confidence: 0.9,
2215            mode_distribution: mode_dist,
2216            coherence_score: 0.3,
2217            recommendation: "Reasoning chain may have logical gaps - consider reflection mode"
2218                .to_string(),
2219        };
2220
2221        assert!(eval.average_confidence > 0.6);
2222        assert!(eval.coherence_score < 0.5);
2223        assert!(eval.recommendation.contains("logical gaps"));
2224    }
2225
2226    #[test]
2227    fn test_session_evaluation_low_confidence_high_coherence() {
2228        let mut mode_dist = std::collections::HashMap::new();
2229        mode_dist.insert("linear".to_string(), 3);
2230
2231        let eval = SessionEvaluation {
2232            session_id: "s-1".to_string(),
2233            total_thoughts: 3,
2234            average_confidence: 0.4,
2235            mode_distribution: mode_dist,
2236            coherence_score: 0.9,
2237            recommendation: "Consider reviewing and refining low-confidence thoughts".to_string(),
2238        };
2239
2240        assert!(eval.average_confidence < 0.6);
2241        assert!(eval.coherence_score > 0.5);
2242        assert!(eval.recommendation.contains("low-confidence"));
2243    }
2244
2245    #[test]
2246    fn test_reflection_params_with_all_options_none() {
2247        let params = ReflectionParams {
2248            thought_id: None,
2249            content: None,
2250            session_id: None,
2251            branch_id: None,
2252            max_iterations: 1,
2253            quality_threshold: 0.5,
2254            include_chain: false,
2255        };
2256
2257        assert!(params.thought_id.is_none());
2258        assert!(params.content.is_none());
2259        assert!(params.session_id.is_none());
2260        assert!(params.branch_id.is_none());
2261    }
2262
2263    #[test]
2264    fn test_improved_thought_empty_content() {
2265        let improved = ImprovedThought {
2266            thought_id: "t-1".to_string(),
2267            content: "".to_string(),
2268            confidence: 0.5,
2269        };
2270
2271        assert_eq!(improved.content, "");
2272    }
2273
2274    #[test]
2275    fn test_reflection_response_large_arrays() {
2276        let strengths: Vec<String> = (0..100).map(|i| format!("Strength {}", i)).collect();
2277        let weaknesses: Vec<String> = (0..50).map(|i| format!("Weakness {}", i)).collect();
2278        let recommendations: Vec<String> = (0..75).map(|i| format!("Rec {}", i)).collect();
2279
2280        let response = ReflectionResponse {
2281            analysis: "Large arrays".to_string(),
2282            strengths: strengths.clone(),
2283            weaknesses: weaknesses.clone(),
2284            recommendations: recommendations.clone(),
2285            confidence: 0.5,
2286            quality_score: None,
2287            improved_thought: None,
2288            metadata: serde_json::Value::Null,
2289        };
2290
2291        assert_eq!(response.strengths.len(), 100);
2292        assert_eq!(response.weaknesses.len(), 50);
2293        assert_eq!(response.recommendations.len(), 75);
2294    }
2295
2296    #[test]
2297    fn test_reflection_params_extreme_quality_threshold() {
2298        let params1 = ReflectionParams::for_thought("t-1").with_quality_threshold(-100.0);
2299        assert_eq!(params1.quality_threshold, 0.0);
2300
2301        let params2 = ReflectionParams::for_thought("t-1").with_quality_threshold(100.0);
2302        assert_eq!(params2.quality_threshold, 1.0);
2303    }
2304
2305    #[test]
2306    fn test_reflection_params_extreme_max_iterations() {
2307        let params1 = ReflectionParams::for_thought("t-1").with_max_iterations(usize::MAX);
2308        assert_eq!(params1.max_iterations, 5);
2309
2310        let params2 = ReflectionParams::for_thought("t-1").with_max_iterations(0);
2311        assert_eq!(params2.max_iterations, 1);
2312    }
2313
2314    #[test]
2315    fn test_session_evaluation_many_modes() {
2316        let mut mode_dist = std::collections::HashMap::new();
2317        mode_dist.insert("linear".to_string(), 10);
2318        mode_dist.insert("tree".to_string(), 8);
2319        mode_dist.insert("divergent".to_string(), 5);
2320        mode_dist.insert("reflection".to_string(), 3);
2321        mode_dist.insert("backtracking".to_string(), 2);
2322
2323        let eval = SessionEvaluation {
2324            session_id: "s-complex".to_string(),
2325            total_thoughts: 28,
2326            average_confidence: 0.72,
2327            mode_distribution: mode_dist.clone(),
2328            coherence_score: 0.68,
2329            recommendation: "Reasoning quality is acceptable".to_string(),
2330        };
2331
2332        assert_eq!(eval.mode_distribution.len(), 5);
2333        assert_eq!(eval.total_thoughts, 28);
2334        assert_eq!(eval.mode_distribution.get("linear"), Some(&10));
2335    }
2336
2337    #[test]
2338    fn test_reflection_result_with_very_long_analysis() {
2339        let long_analysis = "a".repeat(10000);
2340        let result = ReflectionResult {
2341            session_id: "s-1".to_string(),
2342            reflection_thought_id: "t-1".to_string(),
2343            original_thought_id: None,
2344            analysis: long_analysis.clone(),
2345            strengths: vec![],
2346            weaknesses: vec![],
2347            recommendations: vec![],
2348            quality_score: 0.5,
2349            improved_thought: None,
2350            iterations_performed: 1,
2351            quality_improved: false,
2352            branch_id: None,
2353        };
2354
2355        assert_eq!(result.analysis.len(), 10000);
2356    }
2357
2358    #[test]
2359    fn test_parse_response_with_nested_json_arrays() {
2360        let config = create_test_config();
2361        let rt = tokio::runtime::Runtime::new().unwrap();
2362        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
2363        let langbase =
2364            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
2365
2366        let mode = ReflectionMode::new(storage, langbase, &config);
2367
2368        let completion = r#"{
2369            "analysis": "Complex",
2370            "strengths": ["S1", "S2", "S3"],
2371            "weaknesses": ["W1", "W2"],
2372            "recommendations": ["R1", "R2", "R3", "R4"],
2373            "confidence": 0.65,
2374            "metadata": {
2375                "nested": {
2376                    "deep": {
2377                        "array": [1, 2, 3]
2378                    }
2379                }
2380            }
2381        }"#;
2382
2383        let response = mode.parse_response(completion).unwrap();
2384        assert_eq!(response.strengths.len(), 3);
2385        assert_eq!(response.weaknesses.len(), 2);
2386        assert_eq!(response.recommendations.len(), 4);
2387        assert_eq!(response.metadata["nested"]["deep"]["array"][0], 1);
2388    }
2389
2390    #[test]
2391    fn test_reflection_params_quality_threshold_precision() {
2392        let params = ReflectionParams::for_thought("t-1").with_quality_threshold(0.123456789);
2393        assert!((params.quality_threshold - 0.123456789).abs() < 1e-9);
2394    }
2395
2396    #[test]
2397    fn test_build_messages_iteration_zero() {
2398        let config = create_test_config();
2399        let rt = tokio::runtime::Runtime::new().unwrap();
2400        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
2401        let langbase =
2402            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
2403
2404        let mode = ReflectionMode::new(storage, langbase, &config);
2405        let messages = mode.build_messages("Content", &[], 0);
2406
2407        assert!(!messages[0].content.contains("iteration"));
2408    }
2409
2410    #[test]
2411    fn test_build_messages_iteration_one() {
2412        let config = create_test_config();
2413        let rt = tokio::runtime::Runtime::new().unwrap();
2414        let storage = rt.block_on(SqliteStorage::new_in_memory()).unwrap();
2415        let langbase =
2416            LangbaseClient::new(&config.langbase, crate::config::RequestConfig::default()).unwrap();
2417
2418        let mode = ReflectionMode::new(storage, langbase, &config);
2419        let messages = mode.build_messages("Content", &[], 1);
2420
2421        assert!(messages[0].content.contains("iteration 2"));
2422    }
2423}