reasonkit/thinktool/modules/
mod.rs1use crate::error::Result;
52use serde::{Deserialize, Serialize};
53
54pub mod bedrock;
59pub mod brutalhonesty;
60pub mod brutalhonesty_enhanced;
61pub mod gigathink;
62pub mod laserlogic;
63pub mod proofguard;
64
65pub use bedrock::BedRock;
67pub use brutalhonesty::BrutalHonesty;
68pub use brutalhonesty_enhanced::BrutalHonestyEnhanced;
69pub use gigathink::GigaThink;
70pub use laserlogic::LaserLogic;
71pub use proofguard::ProofGuard;
72
73pub use gigathink::{
75 AnalysisDimension, AsyncThinkToolModule, GigaThinkBuilder, GigaThinkConfig, GigaThinkError,
76 GigaThinkMetadata, GigaThinkResult, Perspective, SynthesizedInsight, Theme,
77};
78
79pub use laserlogic::{
81 Argument, ArgumentForm, Contradiction, ContradictionType, DetectedFallacy, Fallacy,
82 LaserLogicConfig, LaserLogicResult, Premise, PremiseType, SoundnessStatus, ValidityStatus,
83};
84
85pub use brutalhonesty::{
87 BrutalHonestyBuilder, BrutalHonestyConfig, CritiqueSeverity, CritiqueVerdict, DetectedFlaw,
88 FlawCategory, FlawSeverity, IdentifiedStrength, ImplicitAssumption,
89};
90
91pub use brutalhonesty_enhanced::{
93 ArgumentMap, BiasCategory, CognitiveBias, CognitiveBiasDepth, CulturalAssumption,
94 EnhancedBuilder, EnhancedConfig, SteelmanArgument,
95};
96
97#[derive(Debug, Clone, Serialize, Deserialize)]
105pub struct ThinkToolModuleConfig {
106 pub name: String,
108
109 pub version: String,
111
112 pub description: String,
114
115 pub confidence_weight: f64,
118}
119
120impl ThinkToolModuleConfig {
121 pub fn new(
123 name: impl Into<String>,
124 version: impl Into<String>,
125 description: impl Into<String>,
126 ) -> Self {
127 Self {
128 name: name.into(),
129 version: version.into(),
130 description: description.into(),
131 confidence_weight: 0.20, }
133 }
134
135 pub fn with_confidence_weight(mut self, weight: f64) -> Self {
137 self.confidence_weight = weight.clamp(0.0, 1.0);
138 self
139 }
140}
141
142#[derive(Debug, Clone, Serialize, Deserialize)]
146pub struct ThinkToolContext {
147 pub query: String,
149
150 pub previous_steps: Vec<String>,
152}
153
154impl ThinkToolContext {
155 pub fn new(query: impl Into<String>) -> Self {
157 Self {
158 query: query.into(),
159 previous_steps: Vec::new(),
160 }
161 }
162
163 pub fn with_previous_steps(query: impl Into<String>, steps: Vec<String>) -> Self {
165 Self {
166 query: query.into(),
167 previous_steps: steps,
168 }
169 }
170
171 pub fn add_previous_step(&mut self, step: impl Into<String>) {
173 self.previous_steps.push(step.into());
174 }
175
176 pub fn has_previous_steps(&self) -> bool {
178 !self.previous_steps.is_empty()
179 }
180
181 pub fn previous_step_count(&self) -> usize {
183 self.previous_steps.len()
184 }
185}
186
187#[derive(Debug, Clone, Serialize, Deserialize)]
191pub struct ThinkToolOutput {
192 pub module: String,
194
195 pub confidence: f64,
197
198 pub output: serde_json::Value,
200}
201
202impl ThinkToolOutput {
203 pub fn new(module: impl Into<String>, confidence: f64, output: serde_json::Value) -> Self {
205 Self {
206 module: module.into(),
207 confidence: confidence.clamp(0.0, 1.0),
208 output,
209 }
210 }
211
212 pub fn get(&self, field: &str) -> Option<&serde_json::Value> {
214 self.output.get(field)
215 }
216
217 pub fn get_str(&self, field: &str) -> Option<&str> {
219 self.output.get(field).and_then(|v| v.as_str())
220 }
221
222 pub fn get_array(&self, field: &str) -> Option<&Vec<serde_json::Value>> {
224 self.output.get(field).and_then(|v| v.as_array())
225 }
226
227 pub fn is_high_confidence(&self) -> bool {
229 self.confidence >= 0.80
230 }
231
232 pub fn meets_threshold(&self, threshold: f64) -> bool {
234 self.confidence >= threshold
235 }
236}
237
238pub trait ThinkToolModule: Send + Sync {
249 fn config(&self) -> &ThinkToolModuleConfig;
251
252 fn execute(&self, context: &ThinkToolContext) -> Result<ThinkToolOutput>;
261
262 fn name(&self) -> &str {
264 &self.config().name
265 }
266
267 fn version(&self) -> &str {
269 &self.config().version
270 }
271
272 fn description(&self) -> &str {
274 &self.config().description
275 }
276
277 fn confidence_weight(&self) -> f64 {
279 self.config().confidence_weight
280 }
281}
282
283#[cfg(test)]
288mod tests {
289 use super::*;
290
291 #[test]
292 fn test_module_config_creation() {
293 let config = ThinkToolModuleConfig::new("TestModule", "1.0.0", "A test module");
294 assert_eq!(config.name, "TestModule");
295 assert_eq!(config.version, "1.0.0");
296 assert_eq!(config.confidence_weight, 0.20);
297 }
298
299 #[test]
300 fn test_module_config_with_weight() {
301 let config = ThinkToolModuleConfig::new("TestModule", "1.0.0", "A test module")
302 .with_confidence_weight(0.35);
303 assert_eq!(config.confidence_weight, 0.35);
304 }
305
306 #[test]
307 fn test_context_creation() {
308 let context = ThinkToolContext::new("Test query");
309 assert_eq!(context.query, "Test query");
310 assert!(context.previous_steps.is_empty());
311 }
312
313 #[test]
314 fn test_context_with_previous_steps() {
315 let context =
316 ThinkToolContext::with_previous_steps("Query", vec!["Step 1".into(), "Step 2".into()]);
317 assert!(context.has_previous_steps());
318 assert_eq!(context.previous_step_count(), 2);
319 }
320
321 #[test]
322 fn test_output_creation() {
323 let output =
324 ThinkToolOutput::new("TestModule", 0.85, serde_json::json!({"result": "success"}));
325 assert_eq!(output.module, "TestModule");
326 assert_eq!(output.confidence, 0.85);
327 assert!(output.is_high_confidence());
328 }
329
330 #[test]
331 fn test_output_threshold() {
332 let output =
333 ThinkToolOutput::new("TestModule", 0.75, serde_json::json!({"result": "success"}));
334 assert!(output.meets_threshold(0.70));
335 assert!(!output.meets_threshold(0.80));
336 }
337
338 #[test]
339 fn test_output_field_access() {
340 let output = ThinkToolOutput::new(
341 "TestModule",
342 0.85,
343 serde_json::json!({
344 "name": "test",
345 "values": [1, 2, 3]
346 }),
347 );
348
349 assert_eq!(output.get_str("name"), Some("test"));
350 assert!(output.get_array("values").is_some());
351 }
352
353 #[test]
354 fn test_gigathink_module() {
355 let module = GigaThink::new();
356 assert_eq!(module.name(), "GigaThink");
357 assert_eq!(module.version(), "2.1.0");
358 }
359
360 #[test]
361 fn test_gigathink_execution() {
362 let module = GigaThink::new();
363 let context = ThinkToolContext::new("What are the implications of AI adoption?");
364
365 let result = module.execute(&context).unwrap();
366 assert_eq!(result.module, "GigaThink");
367 assert!(result.confidence > 0.0);
368
369 let perspectives = result.get_array("perspectives").unwrap();
371 assert!(perspectives.len() >= 10);
372 }
373
374 #[test]
375 fn test_laserlogic_module() {
376 let module = LaserLogic::new();
377 assert_eq!(module.name(), "LaserLogic");
378 assert_eq!(module.version(), "3.0.0");
379 }
380
381 #[test]
382 fn test_laserlogic_analyze_argument() {
383 let module = LaserLogic::new();
384 let result = module
385 .analyze_argument(
386 &["All humans are mortal", "Socrates is human"],
387 "Socrates is mortal",
388 )
389 .unwrap();
390
391 assert_eq!(
393 result.argument_form,
394 Some(ArgumentForm::CategoricalSyllogism)
395 );
396 assert!(result.confidence > 0.0);
397 }
398
399 #[test]
400 fn test_laserlogic_fallacy_detection() {
401 let module = LaserLogic::new();
402 let result = module
403 .analyze_argument(
404 &["If it rains, then the ground is wet", "The ground is wet"],
405 "It rained",
406 )
407 .unwrap();
408
409 assert!(result.has_fallacies());
411 assert!(result
412 .fallacies
413 .iter()
414 .any(|f| f.fallacy == Fallacy::AffirmingConsequent));
415 }
416
417 #[test]
418 fn test_brutalhonesty_module() {
419 let module = BrutalHonesty::new();
420 assert_eq!(module.name(), "BrutalHonesty");
421 assert_eq!(module.version(), "3.0.0");
422 }
423
424 #[test]
425 fn test_brutalhonesty_execution() {
426 let module = BrutalHonesty::new();
427 let context =
428 ThinkToolContext::new("Our startup will succeed because we have the best team");
429
430 let result = module.execute(&context).unwrap();
431 assert_eq!(result.module, "BrutalHonesty");
432 assert!(result.confidence > 0.0);
433 assert!(result.confidence <= 0.95);
434
435 assert!(result.get("verdict").is_some());
437 assert!(result.get("analysis").is_some());
438 assert!(result.get("devils_advocate").is_some());
439 }
440
441 #[test]
442 fn test_brutalhonesty_enhanced_module() {
443 let module = BrutalHonestyEnhanced::new();
444 assert_eq!(module.name(), "BrutalHonestyEnhanced");
445 assert_eq!(module.version(), "3.0.0");
446 }
447
448 #[test]
449 fn test_brutalhonesty_enhanced_execution() {
450 let module = BrutalHonestyEnhanced::new();
451 let context = ThinkToolContext::new(
452 "We're certain this will succeed because everyone agrees it's the best approach.",
453 );
454
455 let result = module.execute(&context).unwrap();
456 assert_eq!(result.module, "BrutalHonestyEnhanced");
457 assert!(result.confidence > 0.0);
458 assert!(result.confidence <= 0.90);
459
460 assert!(result.get("enhanced_analysis").is_some());
462 assert!(result.get("base_analysis").is_some());
463 }
464
465 #[test]
466 fn test_brutalhonesty_builder() {
467 let module = BrutalHonesty::builder()
468 .severity(CritiqueSeverity::Ruthless)
469 .enable_devil_advocate(true)
470 .build();
471
472 assert_eq!(module.brutal_config().severity, CritiqueSeverity::Ruthless);
473 assert!(module.brutal_config().enable_devil_advocate);
474 }
475
476 #[test]
477 fn test_brutalhonesty_enhanced_builder() {
478 let module = BrutalHonestyEnhanced::builder()
479 .severity(CritiqueSeverity::Harsh)
480 .cognitive_bias_depth(CognitiveBiasDepth::Deep)
481 .enable_cultural_analysis(true)
482 .build();
483
484 assert_eq!(
485 module.enhanced_config().base_config.severity,
486 CritiqueSeverity::Harsh
487 );
488 assert_eq!(
489 module.enhanced_config().cognitive_bias_depth,
490 CognitiveBiasDepth::Deep
491 );
492 }
493}