reasonkit/thinktool/modules/
gigathink.rs

1//! GigaThink Module - Expansive Creative Thinking
2//!
3//! Generates 10+ diverse perspectives through divergent thinking.
4//! This module implements structured multi-dimensional analysis
5//! to explore problems from multiple angles.
6//!
7//! ## Features
8//!
9//! - **10+ Perspectives**: Guaranteed minimum of 10 distinct analytical perspectives
10//! - **Dimensional Analysis**: Systematic exploration across 12 analytical dimensions
11//! - **Confidence Scoring**: Evidence-based confidence calculation
12//! - **Async Execution**: Full async/await support for LLM integration
13//! - **Cross-Validation**: Built-in perspective coherence validation
14//!
15//! ## Usage
16//!
17//! ```rust,ignore
18//! use reasonkit::thinktool::modules::{GigaThink, ThinkToolModule, ThinkToolContext};
19//!
20//! let module = GigaThink::new();
21//! let context = ThinkToolContext {
22//!     query: "What are the key factors for startup success?".to_string(),
23//!     previous_steps: vec![],
24//! };
25//!
26//! // Sync execution
27//! let result = module.execute(&context)?;
28//!
29//! // Async execution
30//! let async_result = module.execute_async(&context).await?;
31//! ```
32//!
33//! ## Note
34//!
35//! For protocol-based execution (with LLM calls), use the `ProtocolExecutor`:
36//!
37//! ```rust,ignore
38//! let executor = ProtocolExecutor::new()?;
39//! let result = executor.execute("gigathink", ProtocolInput::query("question")).await?;
40//! ```
41
42use std::future::Future;
43use std::pin::Pin;
44
45use serde::{Deserialize, Serialize};
46use serde_json::json;
47use thiserror::Error;
48
49use super::{ThinkToolContext, ThinkToolModule, ThinkToolModuleConfig, ThinkToolOutput};
50use crate::error::{Error, Result};
51
52// ============================================================================
53// ERROR TYPES
54// ============================================================================
55
56/// Errors specific to GigaThink module execution
57#[derive(Error, Debug, Clone)]
58pub enum GigaThinkError {
59    /// Insufficient perspectives generated
60    #[error("Insufficient perspectives: generated {generated}, required minimum {required}")]
61    InsufficientPerspectives { generated: usize, required: usize },
62
63    /// Invalid dimension specified
64    #[error("Invalid analysis dimension: {dimension}")]
65    InvalidDimension { dimension: String },
66
67    /// Query too short for meaningful analysis
68    #[error("Query too short: {length} characters, minimum required is {minimum}")]
69    QueryTooShort { length: usize, minimum: usize },
70
71    /// Query too long for processing
72    #[error("Query too long: {length} characters, maximum allowed is {maximum}")]
73    QueryTooLong { length: usize, maximum: usize },
74
75    /// Confidence below acceptable threshold
76    #[error("Confidence too low: {confidence:.2}, minimum required is {threshold:.2}")]
77    LowConfidence { confidence: f64, threshold: f64 },
78
79    /// Cross-validation failed
80    #[error("Cross-validation failed: {reason}")]
81    CrossValidationFailed { reason: String },
82
83    /// Synthesis failed
84    #[error("Failed to synthesize perspectives: {reason}")]
85    SynthesisFailed { reason: String },
86
87    /// Timeout during execution
88    #[error("Execution timeout after {duration_ms}ms")]
89    ExecutionTimeout { duration_ms: u64 },
90}
91
92impl From<GigaThinkError> for Error {
93    fn from(err: GigaThinkError) -> Self {
94        Error::ThinkToolExecutionError(err.to_string())
95    }
96}
97
98// ============================================================================
99// CONFIGURATION
100// ============================================================================
101
102/// Configuration for GigaThink module behavior
103#[derive(Debug, Clone, Serialize, Deserialize)]
104pub struct GigaThinkConfig {
105    /// Minimum number of perspectives to generate
106    pub min_perspectives: usize,
107
108    /// Maximum number of perspectives to generate
109    pub max_perspectives: usize,
110
111    /// Minimum confidence threshold for output
112    pub min_confidence: f64,
113
114    /// Enable cross-validation of perspectives
115    pub enable_cross_validation: bool,
116
117    /// Minimum query length in characters
118    pub min_query_length: usize,
119
120    /// Maximum query length in characters
121    pub max_query_length: usize,
122
123    /// Dimensions to explore (if empty, use all default dimensions)
124    pub dimensions: Vec<AnalysisDimension>,
125
126    /// Weight applied to novelty in confidence calculation
127    pub novelty_weight: f64,
128
129    /// Weight applied to depth in confidence calculation
130    pub depth_weight: f64,
131
132    /// Weight applied to coherence in confidence calculation
133    pub coherence_weight: f64,
134
135    /// Maximum execution time in milliseconds
136    pub max_execution_time_ms: Option<u64>,
137}
138
139impl Default for GigaThinkConfig {
140    fn default() -> Self {
141        Self {
142            min_perspectives: 10,
143            max_perspectives: 15,
144            min_confidence: 0.70,
145            enable_cross_validation: true,
146            min_query_length: 10,
147            max_query_length: 5000,
148            dimensions: Vec::new(), // Use all default dimensions
149            novelty_weight: 0.30,
150            depth_weight: 0.40,
151            coherence_weight: 0.30,
152            max_execution_time_ms: Some(10000),
153        }
154    }
155}
156
157// ============================================================================
158// ANALYSIS DIMENSIONS
159// ============================================================================
160
161/// Analytical dimensions for perspective generation
162#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
163#[serde(rename_all = "snake_case")]
164pub enum AnalysisDimension {
165    /// Economic and financial implications
166    Economic,
167    /// Technological and innovation aspects
168    Technological,
169    /// Social and cultural considerations
170    Social,
171    /// Environmental and sustainability factors
172    Environmental,
173    /// Political and regulatory landscape
174    Political,
175    /// Psychological and behavioral patterns
176    Psychological,
177    /// Ethical and moral implications
178    Ethical,
179    /// Historical context and evolution
180    Historical,
181    /// Competitive and market dynamics
182    Competitive,
183    /// User experience and adoption
184    UserExperience,
185    /// Risk assessment and opportunities
186    RiskOpportunity,
187    /// Long-term and strategic outlook
188    Strategic,
189}
190
191impl AnalysisDimension {
192    /// Returns all available dimensions
193    pub fn all() -> Vec<Self> {
194        vec![
195            Self::Economic,
196            Self::Technological,
197            Self::Social,
198            Self::Environmental,
199            Self::Political,
200            Self::Psychological,
201            Self::Ethical,
202            Self::Historical,
203            Self::Competitive,
204            Self::UserExperience,
205            Self::RiskOpportunity,
206            Self::Strategic,
207        ]
208    }
209
210    /// Returns the display name for this dimension
211    pub fn display_name(&self) -> &'static str {
212        match self {
213            Self::Economic => "Economic/Financial",
214            Self::Technological => "Technological/Innovation",
215            Self::Social => "Social/Cultural",
216            Self::Environmental => "Environmental/Sustainability",
217            Self::Political => "Political/Regulatory",
218            Self::Psychological => "Psychological/Behavioral",
219            Self::Ethical => "Ethical/Moral",
220            Self::Historical => "Historical/Evolutionary",
221            Self::Competitive => "Competitive/Market",
222            Self::UserExperience => "User Experience/Adoption",
223            Self::RiskOpportunity => "Risk/Opportunity",
224            Self::Strategic => "Long-term/Strategic",
225        }
226    }
227
228    /// Returns guiding questions for this dimension
229    pub fn guiding_questions(&self) -> Vec<&'static str> {
230        match self {
231            Self::Economic => vec![
232                "What are the financial implications?",
233                "How does this affect costs and revenues?",
234                "What economic forces are at play?",
235            ],
236            Self::Technological => vec![
237                "What technologies enable or constrain this?",
238                "How might technology evolve to change this?",
239                "What innovation opportunities exist?",
240            ],
241            Self::Social => vec![
242                "How does society perceive this?",
243                "What cultural factors influence adoption?",
244                "Who are the key stakeholders affected?",
245            ],
246            Self::Environmental => vec![
247                "What is the environmental impact?",
248                "How sustainable is this approach?",
249                "What ecological factors are relevant?",
250            ],
251            Self::Political => vec![
252                "What regulations apply or might apply?",
253                "How do political dynamics affect this?",
254                "What policy changes could impact this?",
255            ],
256            Self::Psychological => vec![
257                "What cognitive biases might be at play?",
258                "How do people emotionally respond?",
259                "What behavioral patterns are relevant?",
260            ],
261            Self::Ethical => vec![
262                "What are the moral implications?",
263                "Who might be harmed or helped?",
264                "What ethical principles apply?",
265            ],
266            Self::Historical => vec![
267                "What historical precedents exist?",
268                "How has this evolved over time?",
269                "What can we learn from the past?",
270            ],
271            Self::Competitive => vec![
272                "Who are the competitors?",
273                "What are the market dynamics?",
274                "How do switching costs affect this?",
275            ],
276            Self::UserExperience => vec![
277                "How does this affect the user?",
278                "What friction points exist?",
279                "How can adoption be improved?",
280            ],
281            Self::RiskOpportunity => vec![
282                "What are the key risks?",
283                "What opportunities might emerge?",
284                "How can risks be mitigated?",
285            ],
286            Self::Strategic => vec![
287                "What is the long-term impact?",
288                "How does this fit into larger goals?",
289                "What strategic options exist?",
290            ],
291        }
292    }
293
294    /// Returns a prompt template for LLM analysis of this dimension
295    pub fn prompt_template(&self) -> &'static str {
296        match self {
297            Self::Economic => {
298                "Analyze the economic and financial aspects. Consider costs, benefits, \
299                 market forces, pricing dynamics, and value creation potential."
300            }
301            Self::Technological => {
302                "Examine the technological dimensions. Consider enabling technologies, \
303                 technical constraints, innovation potential, and technical debt."
304            }
305            Self::Social => {
306                "Explore the social and cultural factors. Consider stakeholder interests, \
307                 social norms, cultural adoption barriers, and community impact."
308            }
309            Self::Environmental => {
310                "Assess environmental implications. Consider sustainability, ecological \
311                 footprint, resource consumption, and environmental regulations."
312            }
313            Self::Political => {
314                "Analyze the political and regulatory landscape. Consider current \
315                 regulations, potential policy changes, and political stakeholders."
316            }
317            Self::Psychological => {
318                "Examine psychological and behavioral factors. Consider cognitive biases, \
319                 emotional responses, habit formation, and decision-making patterns."
320            }
321            Self::Ethical => {
322                "Evaluate ethical and moral dimensions. Consider fairness, transparency, \
323                 potential harms, beneficiaries, and alignment with ethical principles."
324            }
325            Self::Historical => {
326                "Review historical context and precedents. Consider how similar situations \
327                 evolved, lessons learned, and historical patterns that might repeat."
328            }
329            Self::Competitive => {
330                "Analyze competitive dynamics. Consider existing competitors, potential \
331                 entrants, substitute solutions, and market positioning."
332            }
333            Self::UserExperience => {
334                "Assess user experience and adoption factors. Consider ease of use, \
335                 learning curve, friction points, and paths to adoption."
336            }
337            Self::RiskOpportunity => {
338                "Evaluate risks and opportunities. Consider potential downsides, \
339                 upside scenarios, mitigation strategies, and contingency plans."
340            }
341            Self::Strategic => {
342                "Examine long-term strategic implications. Consider competitive advantage, \
343                 strategic positioning, future optionality, and path dependencies."
344            }
345        }
346    }
347}
348
349// ============================================================================
350// PERSPECTIVE DATA STRUCTURES
351// ============================================================================
352
353/// A single perspective generated by GigaThink
354#[derive(Debug, Clone, Serialize, Deserialize)]
355pub struct Perspective {
356    /// Unique identifier for this perspective
357    pub id: String,
358
359    /// The analytical dimension this perspective explores
360    pub dimension: AnalysisDimension,
361
362    /// Title or summary of the perspective
363    pub title: String,
364
365    /// Detailed content of the perspective
366    pub content: String,
367
368    /// Key insight derived from this perspective
369    pub key_insight: String,
370
371    /// Supporting evidence or examples
372    pub supporting_evidence: Vec<String>,
373
374    /// Implications or consequences identified
375    pub implications: Vec<String>,
376
377    /// Confidence score for this perspective (0.0 - 1.0)
378    pub confidence: f64,
379
380    /// Novelty score - how unique is this perspective
381    pub novelty_score: f64,
382
383    /// Depth score - how thoroughly is this explored
384    pub depth_score: f64,
385}
386
387impl Perspective {
388    /// Create a new perspective
389    pub fn new(
390        id: impl Into<String>,
391        dimension: AnalysisDimension,
392        title: impl Into<String>,
393        content: impl Into<String>,
394    ) -> Self {
395        Self {
396            id: id.into(),
397            dimension,
398            title: title.into(),
399            content: content.into(),
400            key_insight: String::new(),
401            supporting_evidence: Vec::new(),
402            implications: Vec::new(),
403            confidence: 0.70,
404            novelty_score: 0.5,
405            depth_score: 0.5,
406        }
407    }
408
409    /// Builder: set key insight
410    pub fn with_key_insight(mut self, insight: impl Into<String>) -> Self {
411        self.key_insight = insight.into();
412        self
413    }
414
415    /// Builder: add supporting evidence
416    pub fn with_evidence(mut self, evidence: impl Into<String>) -> Self {
417        self.supporting_evidence.push(evidence.into());
418        self
419    }
420
421    /// Builder: add implication
422    pub fn with_implication(mut self, implication: impl Into<String>) -> Self {
423        self.implications.push(implication.into());
424        self
425    }
426
427    /// Builder: set confidence
428    pub fn with_confidence(mut self, confidence: f64) -> Self {
429        self.confidence = confidence.clamp(0.0, 1.0);
430        self
431    }
432
433    /// Builder: set novelty score
434    pub fn with_novelty(mut self, novelty: f64) -> Self {
435        self.novelty_score = novelty.clamp(0.0, 1.0);
436        self
437    }
438
439    /// Builder: set depth score
440    pub fn with_depth(mut self, depth: f64) -> Self {
441        self.depth_score = depth.clamp(0.0, 1.0);
442        self
443    }
444
445    /// Calculate overall quality score
446    pub fn quality_score(&self) -> f64 {
447        (self.confidence * 0.4 + self.novelty_score * 0.3 + self.depth_score * 0.3).clamp(0.0, 1.0)
448    }
449}
450
451/// A theme identified across multiple perspectives
452#[derive(Debug, Clone, Serialize, Deserialize)]
453pub struct Theme {
454    /// Theme identifier
455    pub id: String,
456
457    /// Theme title
458    pub title: String,
459
460    /// Theme description
461    pub description: String,
462
463    /// IDs of perspectives that contribute to this theme
464    pub contributing_perspectives: Vec<String>,
465
466    /// Confidence in theme identification
467    pub confidence: f64,
468}
469
470/// Synthesized insight from perspective analysis
471#[derive(Debug, Clone, Serialize, Deserialize)]
472pub struct SynthesizedInsight {
473    /// Insight identifier
474    pub id: String,
475
476    /// The synthesized insight content
477    pub content: String,
478
479    /// Perspectives that contributed to this insight
480    pub source_perspectives: Vec<String>,
481
482    /// Actionability score (how actionable is this insight)
483    pub actionability: f64,
484
485    /// Confidence score
486    pub confidence: f64,
487}
488
489/// Complete GigaThink output
490#[derive(Debug, Clone, Serialize, Deserialize)]
491pub struct GigaThinkResult {
492    /// Query that was analyzed
493    pub query: String,
494
495    /// Dimensions that were explored
496    pub dimensions_explored: Vec<AnalysisDimension>,
497
498    /// Generated perspectives (10+ guaranteed)
499    pub perspectives: Vec<Perspective>,
500
501    /// Identified themes
502    pub themes: Vec<Theme>,
503
504    /// Synthesized insights
505    pub insights: Vec<SynthesizedInsight>,
506
507    /// Overall confidence score
508    pub confidence: f64,
509
510    /// Cross-validation passed
511    pub cross_validated: bool,
512
513    /// Execution metadata
514    pub metadata: GigaThinkMetadata,
515}
516
517/// Execution metadata
518#[derive(Debug, Clone, Serialize, Deserialize)]
519pub struct GigaThinkMetadata {
520    /// Module version
521    pub version: String,
522
523    /// Execution duration in milliseconds
524    pub duration_ms: u64,
525
526    /// Number of dimensions explored
527    pub dimensions_count: usize,
528
529    /// Total perspectives generated
530    pub perspectives_count: usize,
531
532    /// Configuration used
533    pub config: GigaThinkConfig,
534}
535
536// ============================================================================
537// ASYNC TRAIT FOR ASYNC EXECUTION
538// ============================================================================
539
540/// Trait for async ThinkTool execution
541pub trait AsyncThinkToolModule: ThinkToolModule {
542    /// Execute the module asynchronously
543    fn execute_async<'a>(
544        &'a self,
545        context: &'a ThinkToolContext,
546    ) -> Pin<Box<dyn Future<Output = Result<ThinkToolOutput>> + Send + 'a>>;
547}
548
549// ============================================================================
550// GIGATHINK MODULE
551// ============================================================================
552
553/// GigaThink reasoning module for multi-perspective expansion.
554///
555/// Generates 10+ diverse viewpoints through systematic exploration
556/// of analytical dimensions using creative expansion techniques.
557pub struct GigaThink {
558    /// Module configuration
559    module_config: ThinkToolModuleConfig,
560
561    /// GigaThink-specific configuration
562    config: GigaThinkConfig,
563}
564
565impl Default for GigaThink {
566    fn default() -> Self {
567        Self::new()
568    }
569}
570
571impl GigaThink {
572    /// Create a new GigaThink module instance with default configuration.
573    pub fn new() -> Self {
574        Self::with_config(GigaThinkConfig::default())
575    }
576
577    /// Create a GigaThink module with custom configuration.
578    pub fn with_config(config: GigaThinkConfig) -> Self {
579        Self {
580            module_config: ThinkToolModuleConfig {
581                name: "GigaThink".to_string(),
582                version: "2.1.0".to_string(),
583                description: "Expansive creative thinking with 10+ diverse perspectives"
584                    .to_string(),
585                confidence_weight: 0.15,
586            },
587            config,
588        }
589    }
590
591    /// Get the current configuration
592    pub fn config(&self) -> &GigaThinkConfig {
593        &self.config
594    }
595
596    /// Validate the input query
597    fn validate_query(&self, query: &str) -> Result<()> {
598        let length = query.len();
599
600        if length < self.config.min_query_length {
601            return Err(GigaThinkError::QueryTooShort {
602                length,
603                minimum: self.config.min_query_length,
604            }
605            .into());
606        }
607
608        if length > self.config.max_query_length {
609            return Err(GigaThinkError::QueryTooLong {
610                length,
611                maximum: self.config.max_query_length,
612            }
613            .into());
614        }
615
616        Ok(())
617    }
618
619    /// Get dimensions to analyze
620    fn get_dimensions(&self) -> Vec<AnalysisDimension> {
621        if self.config.dimensions.is_empty() {
622            AnalysisDimension::all()
623        } else {
624            self.config.dimensions.clone()
625        }
626    }
627
628    /// Generate perspectives for all dimensions
629    fn generate_perspectives(
630        &self,
631        query: &str,
632        dimensions: &[AnalysisDimension],
633    ) -> Vec<Perspective> {
634        dimensions
635            .iter()
636            .enumerate()
637            .map(|(idx, dim)| self.generate_perspective_for_dimension(query, *dim, idx))
638            .collect()
639    }
640
641    /// Generate a perspective for a specific dimension
642    fn generate_perspective_for_dimension(
643        &self,
644        query: &str,
645        dimension: AnalysisDimension,
646        index: usize,
647    ) -> Perspective {
648        let id = format!("perspective_{}", index + 1);
649        let title = format!("{} Analysis", dimension.display_name());
650
651        // Generate content based on dimension and query
652        let content = self.generate_dimension_content(query, dimension);
653        let key_insight = self.extract_key_insight(query, dimension);
654
655        // Calculate scores based on dimension and query characteristics
656        let novelty_score = self.calculate_novelty_score(query, dimension);
657        let depth_score = self.calculate_depth_score(query, dimension);
658        let confidence = self.calculate_perspective_confidence(novelty_score, depth_score);
659
660        let mut perspective = Perspective::new(id, dimension, title, content)
661            .with_key_insight(key_insight)
662            .with_confidence(confidence)
663            .with_novelty(novelty_score)
664            .with_depth(depth_score);
665
666        // Add supporting evidence
667        for evidence in self.generate_evidence(query, dimension) {
668            perspective = perspective.with_evidence(evidence);
669        }
670
671        // Add implications
672        for implication in self.generate_implications(query, dimension) {
673            perspective = perspective.with_implication(implication);
674        }
675
676        perspective
677    }
678
679    /// Generate content for a dimension (placeholder for LLM integration)
680    fn generate_dimension_content(&self, query: &str, dimension: AnalysisDimension) -> String {
681        format!(
682            "From the {} perspective, analyzing \"{}\":\n\n{}\n\nThis dimension reveals \
683             important considerations that may not be immediately apparent in other analyses.",
684            dimension.display_name(),
685            query,
686            dimension.prompt_template()
687        )
688    }
689
690    /// Extract key insight for a dimension
691    fn extract_key_insight(&self, _query: &str, dimension: AnalysisDimension) -> String {
692        format!(
693            "The {} lens reveals unique factors that warrant deeper exploration.",
694            dimension.display_name()
695        )
696    }
697
698    /// Generate supporting evidence for a dimension
699    fn generate_evidence(&self, _query: &str, dimension: AnalysisDimension) -> Vec<String> {
700        dimension
701            .guiding_questions()
702            .iter()
703            .map(|q| format!("Addressed: {}", q))
704            .collect()
705    }
706
707    /// Generate implications for a dimension
708    fn generate_implications(&self, _query: &str, dimension: AnalysisDimension) -> Vec<String> {
709        vec![format!(
710            "The {} dimension has significant implications for decision-making.",
711            dimension.display_name()
712        )]
713    }
714
715    /// Calculate novelty score based on query and dimension
716    fn calculate_novelty_score(&self, _query: &str, _dimension: AnalysisDimension) -> f64 {
717        // Base novelty score - in real implementation, this would analyze
718        // how unique this perspective is compared to common analyses
719        0.75
720    }
721
722    /// Calculate depth score based on query and dimension
723    fn calculate_depth_score(&self, _query: &str, _dimension: AnalysisDimension) -> f64 {
724        // Base depth score - in real implementation, this would analyze
725        // how thoroughly the dimension is explored
726        0.72
727    }
728
729    /// Calculate perspective confidence from novelty and depth
730    fn calculate_perspective_confidence(&self, novelty: f64, depth: f64) -> f64 {
731        (novelty * self.config.novelty_weight
732            + depth * self.config.depth_weight
733            + 0.80 * self.config.coherence_weight)
734            .clamp(0.0, 1.0)
735    }
736
737    /// Identify themes across perspectives
738    fn identify_themes(&self, perspectives: &[Perspective]) -> Vec<Theme> {
739        // Group perspectives by related concepts
740        // In real implementation, this would use semantic clustering
741
742        let mut themes = Vec::new();
743
744        // Create cross-cutting themes
745        if perspectives.len() >= 3 {
746            themes.push(Theme {
747                id: "theme_1".to_string(),
748                title: "Cross-Dimensional Patterns".to_string(),
749                description: "Patterns that emerge across multiple analytical dimensions."
750                    .to_string(),
751                contributing_perspectives: perspectives
752                    .iter()
753                    .take(4)
754                    .map(|p| p.id.clone())
755                    .collect(),
756                confidence: 0.78,
757            });
758        }
759
760        if perspectives.len() >= 6 {
761            themes.push(Theme {
762                id: "theme_2".to_string(),
763                title: "Stakeholder Impact".to_string(),
764                description: "How different stakeholders are affected across dimensions."
765                    .to_string(),
766                contributing_perspectives: perspectives
767                    .iter()
768                    .filter(|p| {
769                        matches!(
770                            p.dimension,
771                            AnalysisDimension::Social
772                                | AnalysisDimension::UserExperience
773                                | AnalysisDimension::Ethical
774                        )
775                    })
776                    .map(|p| p.id.clone())
777                    .collect(),
778                confidence: 0.82,
779            });
780        }
781
782        themes
783    }
784
785    /// Synthesize insights from perspectives and themes
786    fn synthesize_insights(
787        &self,
788        perspectives: &[Perspective],
789        themes: &[Theme],
790    ) -> Vec<SynthesizedInsight> {
791        let mut insights = Vec::new();
792
793        // Generate insights from high-confidence perspectives
794        let high_conf_perspectives: Vec<_> = perspectives
795            .iter()
796            .filter(|p| p.confidence > 0.75)
797            .collect();
798
799        if !high_conf_perspectives.is_empty() {
800            insights.push(SynthesizedInsight {
801                id: "insight_1".to_string(),
802                content: format!(
803                    "High-confidence analysis from {} perspectives suggests actionable opportunities.",
804                    high_conf_perspectives.len()
805                ),
806                source_perspectives: high_conf_perspectives.iter().map(|p| p.id.clone()).collect(),
807                actionability: 0.80,
808                confidence: 0.85,
809            });
810        }
811
812        // Generate insights from themes
813        for (idx, theme) in themes.iter().enumerate() {
814            insights.push(SynthesizedInsight {
815                id: format!("insight_{}", idx + 2),
816                content: format!(
817                    "Theme '{}' integrates insights from {} perspectives.",
818                    theme.title,
819                    theme.contributing_perspectives.len()
820                ),
821                source_perspectives: theme.contributing_perspectives.clone(),
822                actionability: 0.70,
823                confidence: theme.confidence,
824            });
825        }
826
827        insights
828    }
829
830    /// Cross-validate perspectives for coherence
831    fn cross_validate(&self, perspectives: &[Perspective]) -> Result<bool> {
832        if !self.config.enable_cross_validation {
833            return Ok(true);
834        }
835
836        // Check minimum perspective count
837        if perspectives.len() < self.config.min_perspectives {
838            return Err(GigaThinkError::InsufficientPerspectives {
839                generated: perspectives.len(),
840                required: self.config.min_perspectives,
841            }
842            .into());
843        }
844
845        // Check that all perspectives meet minimum confidence
846        for perspective in perspectives {
847            if perspective.confidence < self.config.min_confidence {
848                return Err(GigaThinkError::LowConfidence {
849                    confidence: perspective.confidence,
850                    threshold: self.config.min_confidence,
851                }
852                .into());
853            }
854        }
855
856        // Check for logical consistency (simplified)
857        let avg_confidence =
858            perspectives.iter().map(|p| p.confidence).sum::<f64>() / perspectives.len() as f64;
859
860        if avg_confidence < self.config.min_confidence {
861            return Err(GigaThinkError::CrossValidationFailed {
862                reason: format!(
863                    "Average confidence {:.2} below threshold {:.2}",
864                    avg_confidence, self.config.min_confidence
865                ),
866            }
867            .into());
868        }
869
870        Ok(true)
871    }
872
873    /// Calculate overall confidence from perspectives
874    fn calculate_overall_confidence(&self, perspectives: &[Perspective]) -> f64 {
875        if perspectives.is_empty() {
876            return 0.0;
877        }
878
879        // Weight by quality score
880        let total_quality: f64 = perspectives.iter().map(|p| p.quality_score()).sum();
881        let avg_quality = total_quality / perspectives.len() as f64;
882
883        // Factor in diversity (more dimensions = higher confidence)
884        let unique_dimensions: std::collections::HashSet<_> =
885            perspectives.iter().map(|p| p.dimension).collect();
886        let diversity_factor = (unique_dimensions.len() as f64 / 12.0).min(1.0);
887
888        // Combine factors
889        (avg_quality * 0.7 + diversity_factor * 0.3).clamp(0.0, 1.0)
890    }
891
892    /// Build complete GigaThink result
893    fn build_result(
894        &self,
895        context: &ThinkToolContext,
896        duration_ms: u64,
897    ) -> Result<GigaThinkResult> {
898        let query = &context.query;
899        let dimensions = self.get_dimensions();
900
901        let perspectives = self.generate_perspectives(query, &dimensions);
902        let cross_validated = self.cross_validate(&perspectives)?;
903        let themes = self.identify_themes(&perspectives);
904        let insights = self.synthesize_insights(&perspectives, &themes);
905        let confidence = self.calculate_overall_confidence(&perspectives);
906
907        Ok(GigaThinkResult {
908            query: query.clone(),
909            dimensions_explored: dimensions.clone(),
910            perspectives,
911            themes,
912            insights,
913            confidence,
914            cross_validated,
915            metadata: GigaThinkMetadata {
916                version: self.module_config.version.clone(),
917                duration_ms,
918                dimensions_count: dimensions.len(),
919                perspectives_count: self.config.min_perspectives,
920                config: self.config.clone(),
921            },
922        })
923    }
924}
925
926impl ThinkToolModule for GigaThink {
927    fn config(&self) -> &ThinkToolModuleConfig {
928        &self.module_config
929    }
930
931    fn execute(&self, context: &ThinkToolContext) -> Result<ThinkToolOutput> {
932        let start = std::time::Instant::now();
933
934        // Validate input
935        self.validate_query(&context.query)?;
936
937        // Build result
938        let duration_ms = start.elapsed().as_millis() as u64;
939        let result = self.build_result(context, duration_ms)?;
940
941        // Convert to ThinkToolOutput
942        let output = json!({
943            "dimensions": result.dimensions_explored.iter()
944                .map(|d| d.display_name())
945                .collect::<Vec<_>>(),
946            "perspectives": result.perspectives.iter().map(|p| json!({
947                "id": p.id,
948                "dimension": p.dimension.display_name(),
949                "title": p.title,
950                "key_insight": p.key_insight,
951                "confidence": p.confidence,
952                "quality_score": p.quality_score()
953            })).collect::<Vec<_>>(),
954            "themes": result.themes.iter().map(|t| json!({
955                "id": t.id,
956                "title": t.title,
957                "description": t.description,
958                "contributing_count": t.contributing_perspectives.len(),
959                "confidence": t.confidence
960            })).collect::<Vec<_>>(),
961            "insights": result.insights.iter().map(|i| json!({
962                "id": i.id,
963                "content": i.content,
964                "actionability": i.actionability,
965                "confidence": i.confidence
966            })).collect::<Vec<_>>(),
967            "confidence": result.confidence,
968            "cross_validated": result.cross_validated,
969            "metadata": {
970                "version": result.metadata.version,
971                "duration_ms": result.metadata.duration_ms,
972                "dimensions_count": result.metadata.dimensions_count,
973                "perspectives_count": result.metadata.perspectives_count
974            }
975        });
976
977        Ok(ThinkToolOutput {
978            module: self.module_config.name.clone(),
979            confidence: result.confidence,
980            output,
981        })
982    }
983}
984
985// GigaThink is Send + Sync because all its fields are Send + Sync
986// (ThinkToolModuleConfig contains Arc<> which is thread-safe)
987
988impl AsyncThinkToolModule for GigaThink {
989    fn execute_async<'a>(
990        &'a self,
991        context: &'a ThinkToolContext,
992    ) -> Pin<Box<dyn Future<Output = Result<ThinkToolOutput>> + Send + 'a>> {
993        Box::pin(async move {
994            // For now, delegate to sync execution
995            // In a real implementation, this would use async LLM calls
996            self.execute(context)
997        })
998    }
999}
1000
1001// ============================================================================
1002// BUILDER PATTERN
1003// ============================================================================
1004
1005/// Builder for GigaThink module with fluent configuration
1006#[derive(Default)]
1007pub struct GigaThinkBuilder {
1008    config: GigaThinkConfig,
1009}
1010
1011impl GigaThinkBuilder {
1012    /// Create a new builder
1013    pub fn new() -> Self {
1014        Self::default()
1015    }
1016
1017    /// Set minimum perspectives
1018    pub fn min_perspectives(mut self, count: usize) -> Self {
1019        self.config.min_perspectives = count;
1020        self
1021    }
1022
1023    /// Set maximum perspectives
1024    pub fn max_perspectives(mut self, count: usize) -> Self {
1025        self.config.max_perspectives = count;
1026        self
1027    }
1028
1029    /// Set minimum confidence threshold
1030    pub fn min_confidence(mut self, confidence: f64) -> Self {
1031        self.config.min_confidence = confidence.clamp(0.0, 1.0);
1032        self
1033    }
1034
1035    /// Enable or disable cross-validation
1036    pub fn cross_validation(mut self, enabled: bool) -> Self {
1037        self.config.enable_cross_validation = enabled;
1038        self
1039    }
1040
1041    /// Set specific dimensions to analyze
1042    pub fn dimensions(mut self, dimensions: Vec<AnalysisDimension>) -> Self {
1043        self.config.dimensions = dimensions;
1044        self
1045    }
1046
1047    /// Set novelty weight for confidence calculation
1048    pub fn novelty_weight(mut self, weight: f64) -> Self {
1049        self.config.novelty_weight = weight.clamp(0.0, 1.0);
1050        self
1051    }
1052
1053    /// Set depth weight for confidence calculation
1054    pub fn depth_weight(mut self, weight: f64) -> Self {
1055        self.config.depth_weight = weight.clamp(0.0, 1.0);
1056        self
1057    }
1058
1059    /// Set coherence weight for confidence calculation
1060    pub fn coherence_weight(mut self, weight: f64) -> Self {
1061        self.config.coherence_weight = weight.clamp(0.0, 1.0);
1062        self
1063    }
1064
1065    /// Set maximum execution time
1066    pub fn max_execution_time_ms(mut self, ms: u64) -> Self {
1067        self.config.max_execution_time_ms = Some(ms);
1068        self
1069    }
1070
1071    /// Build the GigaThink module
1072    pub fn build(self) -> GigaThink {
1073        GigaThink::with_config(self.config)
1074    }
1075}
1076
1077// ============================================================================
1078// TESTS
1079// ============================================================================
1080
1081#[cfg(test)]
1082mod tests {
1083    use super::*;
1084
1085    #[test]
1086    fn test_gigathink_creation() {
1087        let module = GigaThink::new();
1088        // Access the ThinkToolModule trait method via the trait
1089        use crate::thinktool::ThinkToolModule;
1090        assert_eq!(ThinkToolModule::config(&module).name, "GigaThink");
1091        assert_eq!(ThinkToolModule::config(&module).version, "2.1.0");
1092    }
1093
1094    #[test]
1095    fn test_builder_pattern() {
1096        let module = GigaThinkBuilder::new()
1097            .min_perspectives(12)
1098            .max_perspectives(20)
1099            .min_confidence(0.80)
1100            .cross_validation(false)
1101            .build();
1102
1103        assert_eq!(module.config.min_perspectives, 12);
1104        assert_eq!(module.config.max_perspectives, 20);
1105        assert_eq!(module.config.min_confidence, 0.80);
1106        assert!(!module.config.enable_cross_validation);
1107    }
1108
1109    #[test]
1110    fn test_all_dimensions() {
1111        let dimensions = AnalysisDimension::all();
1112        assert_eq!(dimensions.len(), 12);
1113    }
1114
1115    #[test]
1116    fn test_dimension_display_names() {
1117        assert_eq!(
1118            AnalysisDimension::Economic.display_name(),
1119            "Economic/Financial"
1120        );
1121        assert_eq!(
1122            AnalysisDimension::Technological.display_name(),
1123            "Technological/Innovation"
1124        );
1125    }
1126
1127    #[test]
1128    fn test_dimension_guiding_questions() {
1129        let questions = AnalysisDimension::Economic.guiding_questions();
1130        assert!(!questions.is_empty());
1131        assert!(questions[0].contains("financial"));
1132    }
1133
1134    #[test]
1135    fn test_perspective_creation() {
1136        let perspective = Perspective::new(
1137            "p1",
1138            AnalysisDimension::Economic,
1139            "Economic Analysis",
1140            "Content",
1141        )
1142        .with_key_insight("Key insight")
1143        .with_evidence("Evidence 1")
1144        .with_implication("Implication 1")
1145        .with_confidence(0.85)
1146        .with_novelty(0.75)
1147        .with_depth(0.80);
1148
1149        assert_eq!(perspective.id, "p1");
1150        assert_eq!(perspective.dimension, AnalysisDimension::Economic);
1151        assert_eq!(perspective.confidence, 0.85);
1152        assert!(!perspective.supporting_evidence.is_empty());
1153        assert!(!perspective.implications.is_empty());
1154    }
1155
1156    #[test]
1157    fn test_perspective_quality_score() {
1158        let perspective = Perspective::new("p1", AnalysisDimension::Economic, "Title", "Content")
1159            .with_confidence(0.90)
1160            .with_novelty(0.80)
1161            .with_depth(0.70);
1162
1163        let quality = perspective.quality_score();
1164        // 0.90 * 0.4 + 0.80 * 0.3 + 0.70 * 0.3 = 0.36 + 0.24 + 0.21 = 0.81
1165        assert!((quality - 0.81).abs() < 0.01);
1166    }
1167
1168    #[test]
1169    fn test_query_validation_too_short() {
1170        let module = GigaThink::new();
1171        let result = module.validate_query("short");
1172        assert!(result.is_err());
1173    }
1174
1175    #[test]
1176    fn test_query_validation_valid() {
1177        let module = GigaThink::new();
1178        let result = module.validate_query("This is a valid query for analysis");
1179        assert!(result.is_ok());
1180    }
1181
1182    #[test]
1183    fn test_execute_generates_perspectives() {
1184        let module = GigaThink::new();
1185        let context = ThinkToolContext {
1186            query: "What are the key factors for startup success?".to_string(),
1187            previous_steps: vec![],
1188        };
1189
1190        let result = module.execute(&context).unwrap();
1191
1192        assert_eq!(result.module, "GigaThink");
1193        assert!(result.confidence > 0.0);
1194
1195        // Check that perspectives were generated
1196        let perspectives = result
1197            .output
1198            .get("perspectives")
1199            .unwrap()
1200            .as_array()
1201            .unwrap();
1202        assert!(perspectives.len() >= 10);
1203    }
1204
1205    #[test]
1206    fn test_execute_includes_metadata() {
1207        let module = GigaThink::new();
1208        let context = ThinkToolContext {
1209            query: "What are the implications of AI on employment?".to_string(),
1210            previous_steps: vec![],
1211        };
1212
1213        let result = module.execute(&context).unwrap();
1214        let metadata = result.output.get("metadata").unwrap();
1215
1216        assert!(metadata.get("version").is_some());
1217        assert!(metadata.get("duration_ms").is_some());
1218        assert!(metadata.get("dimensions_count").is_some());
1219    }
1220
1221    #[test]
1222    fn test_cross_validation() {
1223        let module = GigaThink::new();
1224
1225        let perspectives: Vec<Perspective> = AnalysisDimension::all()
1226            .iter()
1227            .enumerate()
1228            .map(|(i, dim)| {
1229                Perspective::new(
1230                    format!("p{}", i),
1231                    *dim,
1232                    format!("{} Analysis", dim.display_name()),
1233                    "Content",
1234                )
1235                .with_confidence(0.80)
1236            })
1237            .collect();
1238
1239        let result = module.cross_validate(&perspectives);
1240        assert!(result.is_ok());
1241    }
1242
1243    #[test]
1244    fn test_cross_validation_fails_low_confidence() {
1245        let module = GigaThink::new();
1246
1247        let perspectives: Vec<Perspective> = AnalysisDimension::all()
1248            .iter()
1249            .enumerate()
1250            .map(|(i, dim)| {
1251                Perspective::new(
1252                    format!("p{}", i),
1253                    *dim,
1254                    format!("{} Analysis", dim.display_name()),
1255                    "Content",
1256                )
1257                .with_confidence(0.50) // Below threshold
1258            })
1259            .collect();
1260
1261        let result = module.cross_validate(&perspectives);
1262        assert!(result.is_err());
1263    }
1264
1265    #[test]
1266    fn test_theme_identification() {
1267        let module = GigaThink::new();
1268        let perspectives: Vec<Perspective> = AnalysisDimension::all()
1269            .iter()
1270            .enumerate()
1271            .map(|(i, dim)| {
1272                Perspective::new(format!("p{}", i), *dim, "Title", "Content").with_confidence(0.80)
1273            })
1274            .collect();
1275
1276        let themes = module.identify_themes(&perspectives);
1277        assert!(!themes.is_empty());
1278    }
1279
1280    #[test]
1281    fn test_insight_synthesis() {
1282        let module = GigaThink::new();
1283
1284        let perspectives: Vec<Perspective> = vec![
1285            Perspective::new("p1", AnalysisDimension::Economic, "Title", "Content")
1286                .with_confidence(0.85),
1287            Perspective::new("p2", AnalysisDimension::Social, "Title", "Content")
1288                .with_confidence(0.80),
1289        ];
1290
1291        let themes = vec![Theme {
1292            id: "t1".to_string(),
1293            title: "Theme 1".to_string(),
1294            description: "Description".to_string(),
1295            contributing_perspectives: vec!["p1".to_string(), "p2".to_string()],
1296            confidence: 0.75,
1297        }];
1298
1299        let insights = module.synthesize_insights(&perspectives, &themes);
1300        assert!(!insights.is_empty());
1301    }
1302
1303    #[tokio::test]
1304    async fn test_async_execution() {
1305        let module = GigaThink::new();
1306        let context = ThinkToolContext {
1307            query: "What are the future trends in renewable energy?".to_string(),
1308            previous_steps: vec![],
1309        };
1310
1311        let result = module.execute_async(&context).await.unwrap();
1312        assert_eq!(result.module, "GigaThink");
1313        assert!(result.confidence > 0.0);
1314    }
1315
1316    #[test]
1317    fn test_error_types() {
1318        let err = GigaThinkError::InsufficientPerspectives {
1319            generated: 5,
1320            required: 10,
1321        };
1322        assert!(err.to_string().contains("5"));
1323        assert!(err.to_string().contains("10"));
1324
1325        let err = GigaThinkError::QueryTooShort {
1326            length: 5,
1327            minimum: 10,
1328        };
1329        assert!(err.to_string().contains("too short"));
1330
1331        let err = GigaThinkError::LowConfidence {
1332            confidence: 0.50,
1333            threshold: 0.70,
1334        };
1335        assert!(err.to_string().contains("0.50"));
1336    }
1337}