1use super::{ThinkToolContext, ThinkToolModule, ThinkToolModuleConfig, ThinkToolOutput};
32use serde::{Deserialize, Serialize};
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct BedRockConfig {
37 pub max_depth: usize,
39 pub axiom_threshold: f64,
41 pub branching_factor: usize,
43 pub min_confidence: f64,
45 pub strict_assumptions: bool,
47 pub max_principles: usize,
49}
50
51impl Default for BedRockConfig {
52 fn default() -> Self {
53 Self {
54 max_depth: 3,
55 axiom_threshold: 0.85,
56 branching_factor: 3,
57 min_confidence: 0.5,
58 strict_assumptions: true,
59 max_principles: 20,
60 }
61 }
62}
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
66pub enum PrincipleType {
67 Axiom,
69 Derived,
71 Assumption,
73 Empirical,
75 Definition,
77 Contested,
79}
80
81impl PrincipleType {
82 pub fn reliability_weight(&self) -> f64 {
84 match self {
85 PrincipleType::Axiom => 1.0,
86 PrincipleType::Definition => 0.95,
87 PrincipleType::Empirical => 0.80,
88 PrincipleType::Derived => 0.75,
89 PrincipleType::Assumption => 0.50,
90 PrincipleType::Contested => 0.30,
91 }
92 }
93}
94
95#[derive(Debug, Clone, Serialize, Deserialize)]
97pub struct Principle {
98 pub id: usize,
100 pub statement: String,
102 pub principle_type: PrincipleType,
104 pub fundamentality: f64,
106 pub confidence: f64,
108 pub parent_id: Option<usize>,
110 pub child_ids: Vec<usize>,
112 pub evidence: Vec<String>,
114 pub challenges: Vec<String>,
116 pub depth: usize,
118}
119
120impl Principle {
121 pub fn effective_weight(&self) -> f64 {
123 self.fundamentality * self.confidence * self.principle_type.reliability_weight()
124 }
125
126 pub fn is_axiomatic(&self, threshold: f64) -> bool {
128 self.principle_type == PrincipleType::Axiom && self.fundamentality >= threshold
129 }
130}
131
132#[derive(Debug, Clone, Serialize, Deserialize)]
134pub struct ReconstructionPath {
135 pub principle_chain: Vec<usize>,
137 pub connectives: Vec<String>,
139 pub confidence: f64,
141 pub is_complete: bool,
143 pub gaps: Vec<String>,
145}
146
147#[derive(Debug, Clone, Serialize, Deserialize)]
149pub struct AnalysisGap {
150 pub description: String,
152 pub severity: f64,
154 pub suggestion: Option<String>,
156 pub affected_principles: Vec<usize>,
158}
159
160#[derive(Debug, Clone, Serialize, Deserialize)]
162pub struct BedRockResult {
163 pub query: String,
165 pub principles: Vec<Principle>,
167 pub reconstructions: Vec<ReconstructionPath>,
169 pub gaps: Vec<AnalysisGap>,
171 pub insights: Vec<String>,
173 pub confidence: f64,
175 pub metadata: BedRockMetadata,
177}
178
179#[derive(Debug, Clone, Serialize, Deserialize)]
181pub struct BedRockMetadata {
182 pub max_depth_reached: usize,
184 pub total_principles: usize,
186 pub axiom_count: usize,
188 pub assumption_count: usize,
190 pub contested_count: usize,
192 pub completeness: f64,
194}
195
196impl BedRockResult {
197 pub fn axioms(&self) -> Vec<&Principle> {
199 self.principles
200 .iter()
201 .filter(|p| p.principle_type == PrincipleType::Axiom)
202 .collect()
203 }
204
205 pub fn assumptions(&self) -> Vec<&Principle> {
207 self.principles
208 .iter()
209 .filter(|p| p.principle_type == PrincipleType::Assumption)
210 .collect()
211 }
212
213 pub fn contested(&self) -> Vec<&Principle> {
215 self.principles
216 .iter()
217 .filter(|p| p.principle_type == PrincipleType::Contested)
218 .collect()
219 }
220
221 pub fn at_depth(&self, depth: usize) -> Vec<&Principle> {
223 self.principles
224 .iter()
225 .filter(|p| p.depth == depth)
226 .collect()
227 }
228
229 pub fn is_complete(&self, threshold: f64) -> bool {
231 self.metadata.completeness >= threshold && self.gaps.iter().all(|g| g.severity < 0.8)
232 }
233
234 pub fn to_json(&self) -> serde_json::Value {
236 serde_json::json!({
237 "query": self.query,
238 "axioms": self.axioms().iter().map(|p| {
239 serde_json::json!({
240 "id": p.id,
241 "statement": p.statement,
242 "fundamentality": p.fundamentality,
243 "confidence": p.confidence,
244 "evidence": p.evidence
245 })
246 }).collect::<Vec<_>>(),
247 "assumptions": self.assumptions().iter().map(|p| {
248 serde_json::json!({
249 "id": p.id,
250 "statement": p.statement,
251 "confidence": p.confidence,
252 "challenges": p.challenges
253 })
254 }).collect::<Vec<_>>(),
255 "decomposition": self.principles.iter().map(|p| {
256 serde_json::json!({
257 "id": p.id,
258 "statement": p.statement,
259 "type": format!("{:?}", p.principle_type),
260 "fundamentality": p.fundamentality,
261 "confidence": p.confidence,
262 "depth": p.depth,
263 "parent_id": p.parent_id
264 })
265 }).collect::<Vec<_>>(),
266 "reconstruction": self.reconstructions.iter().map(|r| {
267 serde_json::json!({
268 "path": r.principle_chain,
269 "confidence": r.confidence,
270 "complete": r.is_complete,
271 "gaps": r.gaps
272 })
273 }).collect::<Vec<_>>(),
274 "gaps": self.gaps.iter().map(|g| {
275 serde_json::json!({
276 "description": g.description,
277 "severity": g.severity,
278 "suggestion": g.suggestion
279 })
280 }).collect::<Vec<_>>(),
281 "insights": self.insights,
282 "confidence": self.confidence,
283 "metadata": {
284 "max_depth": self.metadata.max_depth_reached,
285 "total_principles": self.metadata.total_principles,
286 "axioms": self.metadata.axiom_count,
287 "assumptions": self.metadata.assumption_count,
288 "contested": self.metadata.contested_count,
289 "completeness": self.metadata.completeness
290 }
291 })
292 }
293}
294
295pub struct BedRock {
300 config: ThinkToolModuleConfig,
302 analysis_config: BedRockConfig,
304}
305
306impl Default for BedRock {
307 fn default() -> Self {
308 Self::new()
309 }
310}
311
312impl BedRock {
313 pub fn new() -> Self {
315 Self {
316 config: ThinkToolModuleConfig {
317 name: "BedRock".to_string(),
318 version: "3.0.0".to_string(),
319 description: "First principles decomposition with Tree-of-Thoughts reconstruction"
320 .to_string(),
321 confidence_weight: 0.25,
322 },
323 analysis_config: BedRockConfig::default(),
324 }
325 }
326
327 pub fn with_config(analysis_config: BedRockConfig) -> Self {
329 Self {
330 config: ThinkToolModuleConfig {
331 name: "BedRock".to_string(),
332 version: "3.0.0".to_string(),
333 description: "First principles decomposition with Tree-of-Thoughts reconstruction"
334 .to_string(),
335 confidence_weight: 0.25,
336 },
337 analysis_config,
338 }
339 }
340
341 pub fn analysis_config(&self) -> &BedRockConfig {
343 &self.analysis_config
344 }
345
346 pub fn decompose(&self, query: &str, previous_steps: &[String]) -> BedRockResult {
354 let mut principles = Vec::new();
355 let mut next_id = 0;
356
357 let root_principle = self.create_root_principle(query, &mut next_id);
359 principles.push(root_principle);
360
361 self.decompose_recursive(&mut principles, 0, 0, &mut next_id);
363
364 self.incorporate_context(&mut principles, previous_steps, &mut next_id);
366
367 self.classify_principles(&mut principles);
369
370 let reconstructions = self.build_reconstructions(&principles);
372
373 let gaps = self.identify_gaps(&principles, &reconstructions);
375
376 let insights = self.extract_insights(&principles, &gaps);
378
379 let confidence = self.calculate_confidence(&principles, &gaps);
381
382 let metadata = BedRockMetadata {
384 max_depth_reached: principles.iter().map(|p| p.depth).max().unwrap_or(0),
385 total_principles: principles.len(),
386 axiom_count: principles
387 .iter()
388 .filter(|p| p.principle_type == PrincipleType::Axiom)
389 .count(),
390 assumption_count: principles
391 .iter()
392 .filter(|p| p.principle_type == PrincipleType::Assumption)
393 .count(),
394 contested_count: principles
395 .iter()
396 .filter(|p| p.principle_type == PrincipleType::Contested)
397 .count(),
398 completeness: self.calculate_completeness(&principles, &gaps),
399 };
400
401 BedRockResult {
402 query: query.to_string(),
403 principles,
404 reconstructions,
405 gaps,
406 insights,
407 confidence,
408 metadata,
409 }
410 }
411
412 fn create_root_principle(&self, query: &str, next_id: &mut usize) -> Principle {
414 let id = *next_id;
415 *next_id += 1;
416
417 let principle_type = self.classify_query(query);
419
420 Principle {
421 id,
422 statement: query.to_string(),
423 principle_type,
424 fundamentality: 0.0, confidence: 1.0, parent_id: None,
427 child_ids: Vec::new(),
428 evidence: Vec::new(),
429 challenges: Vec::new(),
430 depth: 0,
431 }
432 }
433
434 fn classify_query(&self, query: &str) -> PrincipleType {
436 let lower = query.to_lowercase();
437
438 if lower.contains("what is")
440 || lower.contains("define")
441 || lower.contains("meaning of")
442 || lower.contains("definition")
443 {
444 return PrincipleType::Definition;
445 }
446
447 if lower.contains("how many")
449 || lower.contains("when did")
450 || lower.contains("data shows")
451 || lower.contains("research")
452 || lower.contains("study")
453 || lower.contains("evidence")
454 {
455 return PrincipleType::Empirical;
456 }
457
458 if lower.contains("always true")
460 || lower.contains("by definition")
461 || lower.contains("necessarily")
462 || lower.contains("logically")
463 || lower.contains("mathematically")
464 {
465 return PrincipleType::Axiom;
466 }
467
468 if lower.contains("assume")
470 || lower.contains("suppose")
471 || lower.contains("if we")
472 || lower.contains("given that")
473 {
474 return PrincipleType::Assumption;
475 }
476
477 if lower.contains("better")
479 || lower.contains("worse")
480 || lower.contains("should")
481 || lower.contains("ought")
482 || lower.contains("believe")
483 || lower.contains("think")
484 {
485 return PrincipleType::Contested;
486 }
487
488 PrincipleType::Derived
490 }
491
492 fn decompose_recursive(
494 &self,
495 principles: &mut Vec<Principle>,
496 parent_idx: usize,
497 current_depth: usize,
498 next_id: &mut usize,
499 ) {
500 if current_depth >= self.analysis_config.max_depth {
501 return;
502 }
503
504 if principles.len() >= self.analysis_config.max_principles {
505 return;
506 }
507
508 let parent_statement = principles[parent_idx].statement.clone();
509 let sub_principles = self.extract_sub_principles(&parent_statement, current_depth);
510
511 let mut child_ids = Vec::new();
512
513 for (statement, principle_type, fundamentality) in sub_principles {
514 if principles.len() >= self.analysis_config.max_principles {
515 break;
516 }
517
518 let id = *next_id;
519 *next_id += 1;
520 child_ids.push(id);
521
522 let confidence = self.estimate_confidence(&statement, principle_type);
523
524 let principle = Principle {
525 id,
526 statement,
527 principle_type,
528 fundamentality,
529 confidence,
530 parent_id: Some(principles[parent_idx].id),
531 child_ids: Vec::new(),
532 evidence: Vec::new(),
533 challenges: self.identify_challenges(principle_type),
534 depth: current_depth + 1,
535 };
536
537 let new_idx = principles.len();
538 principles.push(principle);
539
540 if principle_type != PrincipleType::Axiom
542 && fundamentality < self.analysis_config.axiom_threshold
543 {
544 self.decompose_recursive(principles, new_idx, current_depth + 1, next_id);
545 }
546 }
547
548 principles[parent_idx].child_ids = child_ids;
549 }
550
551 fn extract_sub_principles(
553 &self,
554 statement: &str,
555 depth: usize,
556 ) -> Vec<(String, PrincipleType, f64)> {
557 let mut sub_principles = Vec::new();
558 let lower = statement.to_lowercase();
559
560 if lower.contains("better") || lower.contains("worse") || lower.contains("more") {
562 sub_principles.push((
563 "Comparison requires a defined metric or criterion".to_string(),
564 PrincipleType::Definition,
565 0.9,
566 ));
567 sub_principles.push((
568 "Both alternatives must be well-understood".to_string(),
569 PrincipleType::Assumption,
570 0.7,
571 ));
572 }
573
574 if lower.contains("because") || lower.contains("causes") || lower.contains("leads to") {
576 sub_principles.push((
577 "Causal relationships require evidence of mechanism".to_string(),
578 PrincipleType::Empirical,
579 0.6,
580 ));
581 sub_principles.push((
582 "Correlation does not imply causation".to_string(),
583 PrincipleType::Axiom,
584 1.0,
585 ));
586 }
587
588 if lower.contains("all")
590 || lower.contains("every")
591 || lower.contains("none")
592 || lower.contains("never")
593 {
594 sub_principles.push((
595 "Universal claims require exhaustive verification".to_string(),
596 PrincipleType::Axiom,
597 1.0,
598 ));
599 sub_principles.push((
600 "A single counterexample disproves a universal claim".to_string(),
601 PrincipleType::Axiom,
602 1.0,
603 ));
604 }
605
606 if lower.contains("good")
608 || lower.contains("bad")
609 || lower.contains("right")
610 || lower.contains("wrong")
611 {
612 sub_principles.push((
613 "Value judgments require a defined value framework".to_string(),
614 PrincipleType::Definition,
615 0.85,
616 ));
617 sub_principles.push((
618 "Different stakeholders may have different values".to_string(),
619 PrincipleType::Assumption,
620 0.75,
621 ));
622 }
623
624 if lower.contains("will") || lower.contains("future") || lower.contains("predict") {
626 sub_principles.push((
627 "Future predictions carry inherent uncertainty".to_string(),
628 PrincipleType::Axiom,
629 1.0,
630 ));
631 sub_principles.push((
632 "Past patterns may not continue".to_string(),
633 PrincipleType::Assumption,
634 0.6,
635 ));
636 }
637
638 if sub_principles.is_empty() && depth < self.analysis_config.max_depth {
640 sub_principles.push((
641 "The claim contains implicit assumptions".to_string(),
642 PrincipleType::Assumption,
643 0.5,
644 ));
645 sub_principles.push((
646 "Terms used may have multiple interpretations".to_string(),
647 PrincipleType::Definition,
648 0.6,
649 ));
650 }
651
652 sub_principles
653 }
654
655 fn estimate_confidence(&self, _statement: &str, principle_type: PrincipleType) -> f64 {
657 match principle_type {
658 PrincipleType::Axiom => 0.95,
659 PrincipleType::Definition => 0.90,
660 PrincipleType::Empirical => 0.75,
661 PrincipleType::Derived => 0.70,
662 PrincipleType::Assumption => 0.55,
663 PrincipleType::Contested => 0.40,
664 }
665 }
666
667 fn identify_challenges(&self, principle_type: PrincipleType) -> Vec<String> {
669 match principle_type {
670 PrincipleType::Axiom => vec![],
671 PrincipleType::Definition => {
672 vec!["Alternative definitions may exist".to_string()]
673 }
674 PrincipleType::Empirical => vec![
675 "Data may be outdated".to_string(),
676 "Sample may not be representative".to_string(),
677 ],
678 PrincipleType::Derived => vec![
679 "Derivation logic may have flaws".to_string(),
680 "Missing intermediate steps".to_string(),
681 ],
682 PrincipleType::Assumption => vec![
683 "Assumption may not hold in all contexts".to_string(),
684 "Implicit bias may be present".to_string(),
685 ],
686 PrincipleType::Contested => vec![
687 "Subject to debate".to_string(),
688 "Evidence may support opposing views".to_string(),
689 ],
690 }
691 }
692
693 fn incorporate_context(
695 &self,
696 principles: &mut Vec<Principle>,
697 previous_steps: &[String],
698 next_id: &mut usize,
699 ) {
700 for step in previous_steps {
701 if principles.len() >= self.analysis_config.max_principles {
702 break;
703 }
704
705 let principle_type = self.classify_query(step);
706 let id = *next_id;
707 *next_id += 1;
708
709 let principle = Principle {
710 id,
711 statement: format!("Prior context: {}", step),
712 principle_type,
713 fundamentality: 0.3, confidence: 0.7, parent_id: None,
716 child_ids: Vec::new(),
717 evidence: vec!["From previous reasoning step".to_string()],
718 challenges: vec!["May need re-evaluation in new context".to_string()],
719 depth: 0, };
721
722 principles.push(principle);
723 }
724 }
725
726 fn classify_principles(&self, principles: &mut [Principle]) {
728 for principle in principles.iter_mut() {
729 if principle.fundamentality >= self.analysis_config.axiom_threshold
731 && principle.principle_type != PrincipleType::Axiom
732 && principle.principle_type != PrincipleType::Contested
733 {
734 principle.principle_type = PrincipleType::Axiom;
735 principle.challenges.clear();
736 }
737
738 if principle.evidence.is_empty() && principle.principle_type == PrincipleType::Empirical
740 {
741 principle.principle_type = PrincipleType::Assumption;
742 principle.confidence *= 0.8;
743 }
744 }
745 }
746
747 fn build_reconstructions(&self, principles: &[Principle]) -> Vec<ReconstructionPath> {
749 let mut reconstructions = Vec::new();
750
751 let axioms: Vec<_> = principles
753 .iter()
754 .filter(|p| p.principle_type == PrincipleType::Axiom)
755 .collect();
756
757 for axiom in axioms {
759 let mut path = vec![axiom.id];
760 let mut connectives = Vec::new();
761 let mut current_id = axiom.id;
762 let mut gaps = Vec::new();
763
764 while let Some(principle) = principles.iter().find(|p| p.id == current_id) {
766 if let Some(parent_idx) = principles.iter().position(|p| {
767 p.child_ids.contains(¤t_id) || Some(p.id) == principle.parent_id
768 }) {
769 let parent = &principles[parent_idx];
770 path.push(parent.id);
771 connectives.push("implies".to_string());
772 current_id = parent.id;
773 } else {
774 break;
775 }
776
777 if path.len() > principles.len() {
779 gaps.push("Circular dependency detected".to_string());
780 break;
781 }
782 }
783
784 let is_complete = principles
786 .iter()
787 .any(|p| path.contains(&p.id) && p.depth == 0);
788
789 if !is_complete {
790 gaps.push("Path does not reach the original claim".to_string());
791 }
792
793 let confidence = if is_complete && gaps.is_empty() {
794 axiom.confidence * 0.9
795 } else {
796 axiom.confidence * 0.5
797 };
798
799 reconstructions.push(ReconstructionPath {
800 principle_chain: path,
801 connectives,
802 confidence,
803 is_complete,
804 gaps,
805 });
806 }
807
808 reconstructions
809 }
810
811 fn identify_gaps(
813 &self,
814 principles: &[Principle],
815 reconstructions: &[ReconstructionPath],
816 ) -> Vec<AnalysisGap> {
817 let mut gaps = Vec::new();
818
819 if reconstructions.is_empty() {
821 gaps.push(AnalysisGap {
822 description: "No axiomatic foundation identified".to_string(),
823 severity: 0.9,
824 suggestion: Some("Decompose further to find self-evident truths".to_string()),
825 affected_principles: principles.iter().map(|p| p.id).collect(),
826 });
827 }
828
829 let incomplete_paths: Vec<_> = reconstructions.iter().filter(|r| !r.is_complete).collect();
831
832 if !incomplete_paths.is_empty() {
833 gaps.push(AnalysisGap {
834 description: format!(
835 "{} reconstruction path(s) do not reach the root claim",
836 incomplete_paths.len()
837 ),
838 severity: 0.7,
839 suggestion: Some("Add intermediate principles to complete the chain".to_string()),
840 affected_principles: incomplete_paths
841 .iter()
842 .flat_map(|r| r.principle_chain.clone())
843 .collect(),
844 });
845 }
846
847 let unsupported_assumptions: Vec<_> = principles
849 .iter()
850 .filter(|p| p.principle_type == PrincipleType::Assumption && p.evidence.is_empty())
851 .collect();
852
853 if !unsupported_assumptions.is_empty() {
854 gaps.push(AnalysisGap {
855 description: format!(
856 "{} assumption(s) lack supporting evidence",
857 unsupported_assumptions.len()
858 ),
859 severity: 0.6,
860 suggestion: Some("Provide evidence or acknowledge as unverified".to_string()),
861 affected_principles: unsupported_assumptions.iter().map(|p| p.id).collect(),
862 });
863 }
864
865 let low_confidence: Vec<_> = principles
867 .iter()
868 .filter(|p| p.confidence < self.analysis_config.min_confidence)
869 .collect();
870
871 if !low_confidence.is_empty() {
872 gaps.push(AnalysisGap {
873 description: format!(
874 "{} principle(s) have confidence below threshold",
875 low_confidence.len()
876 ),
877 severity: 0.5,
878 suggestion: Some("Verify or remove low-confidence principles".to_string()),
879 affected_principles: low_confidence.iter().map(|p| p.id).collect(),
880 });
881 }
882
883 let unresolved_contested: Vec<_> = principles
885 .iter()
886 .filter(|p| p.principle_type == PrincipleType::Contested && !p.challenges.is_empty())
887 .collect();
888
889 if !unresolved_contested.is_empty() {
890 gaps.push(AnalysisGap {
891 description: format!(
892 "{} contested claim(s) require resolution",
893 unresolved_contested.len()
894 ),
895 severity: 0.8,
896 suggestion: Some("Provide evidence to resolve contested claims".to_string()),
897 affected_principles: unresolved_contested.iter().map(|p| p.id).collect(),
898 });
899 }
900
901 gaps
902 }
903
904 fn extract_insights(&self, principles: &[Principle], gaps: &[AnalysisGap]) -> Vec<String> {
906 let mut insights = Vec::new();
907
908 let axiom_count = principles
910 .iter()
911 .filter(|p| p.principle_type == PrincipleType::Axiom)
912 .count();
913
914 if axiom_count > 0 {
915 insights.push(format!(
916 "Analysis rests on {} axiomatic foundation(s)",
917 axiom_count
918 ));
919 } else {
920 insights.push(
921 "No self-evident axioms identified - claim relies on assumptions".to_string(),
922 );
923 }
924
925 let assumption_count = principles
927 .iter()
928 .filter(|p| p.principle_type == PrincipleType::Assumption)
929 .count();
930
931 if assumption_count > 0 {
932 insights.push(format!(
933 "{} hidden assumption(s) identified that could be challenged",
934 assumption_count
935 ));
936 }
937
938 let critical_gaps: Vec<_> = gaps.iter().filter(|g| g.severity >= 0.8).collect();
940
941 if !critical_gaps.is_empty() {
942 insights.push(format!(
943 "{} critical gap(s) in reasoning require attention",
944 critical_gaps.len()
945 ));
946 }
947
948 let max_depth = principles.iter().map(|p| p.depth).max().unwrap_or(0);
950 if max_depth > 0 {
951 insights.push(format!(
952 "Decomposition reached {} level(s) of depth",
953 max_depth
954 ));
955 }
956
957 let contested_count = principles
959 .iter()
960 .filter(|p| p.principle_type == PrincipleType::Contested)
961 .count();
962
963 if contested_count > 0 {
964 insights.push(format!(
965 "{} contested claim(s) identified - these are debatable",
966 contested_count
967 ));
968 }
969
970 insights
971 }
972
973 fn calculate_confidence(&self, principles: &[Principle], gaps: &[AnalysisGap]) -> f64 {
975 if principles.is_empty() {
976 return 0.0;
977 }
978
979 let principle_confidence: f64 =
981 principles.iter().map(|p| p.effective_weight()).sum::<f64>() / principles.len() as f64;
982
983 let gap_penalty: f64 = gaps.iter().map(|g| g.severity * 0.1).sum();
985
986 let axiom_count = principles
988 .iter()
989 .filter(|p| p.principle_type == PrincipleType::Axiom)
990 .count();
991 let axiom_bonus = (axiom_count as f64 * 0.05).min(0.2);
992
993 (principle_confidence + axiom_bonus - gap_penalty).clamp(0.0, 1.0)
994 }
995
996 fn calculate_completeness(&self, principles: &[Principle], gaps: &[AnalysisGap]) -> f64 {
998 if principles.is_empty() {
999 return 0.0;
1000 }
1001
1002 let has_axiom = principles
1004 .iter()
1005 .any(|p| p.principle_type == PrincipleType::Axiom);
1006 let has_definitions = principles
1007 .iter()
1008 .any(|p| p.principle_type == PrincipleType::Definition);
1009 let assumptions_identified = principles
1010 .iter()
1011 .any(|p| p.principle_type == PrincipleType::Assumption);
1012
1013 let mut completeness = 0.0;
1014
1015 if has_axiom {
1016 completeness += 0.3;
1017 }
1018 if has_definitions {
1019 completeness += 0.2;
1020 }
1021 if assumptions_identified {
1022 completeness += 0.2;
1023 }
1024
1025 let max_depth = principles.iter().map(|p| p.depth).max().unwrap_or(0);
1027 completeness += (max_depth as f64 * 0.1).min(0.2);
1028
1029 let critical_gaps = gaps.iter().filter(|g| g.severity >= 0.8).count();
1031 completeness -= critical_gaps as f64 * 0.1;
1032
1033 completeness.clamp(0.0, 1.0)
1034 }
1035}
1036
1037impl ThinkToolModule for BedRock {
1038 fn config(&self) -> &ThinkToolModuleConfig {
1039 &self.config
1040 }
1041
1042 fn execute(&self, context: &ThinkToolContext) -> Result<ThinkToolOutput, crate::error::Error> {
1043 let result = self.decompose(&context.query, &context.previous_steps);
1045
1046 Ok(ThinkToolOutput {
1047 module: self.config.name.clone(),
1048 confidence: result.confidence,
1049 output: result.to_json(),
1050 })
1051 }
1052}
1053
1054#[cfg(test)]
1055mod tests {
1056 use super::*;
1057
1058 #[test]
1059 fn test_bedrock_new() {
1060 let bedrock = BedRock::new();
1061 assert_eq!(bedrock.config().name, "BedRock");
1062 assert_eq!(bedrock.config().version, "3.0.0");
1063 }
1064
1065 #[test]
1066 fn test_bedrock_with_config() {
1067 let config = BedRockConfig {
1068 max_depth: 5,
1069 axiom_threshold: 0.9,
1070 ..Default::default()
1071 };
1072 let bedrock = BedRock::with_config(config);
1073 assert_eq!(bedrock.analysis_config().max_depth, 5);
1074 assert_eq!(bedrock.analysis_config().axiom_threshold, 0.9);
1075 }
1076
1077 #[test]
1078 fn test_principle_type_reliability() {
1079 assert_eq!(PrincipleType::Axiom.reliability_weight(), 1.0);
1080 assert_eq!(PrincipleType::Contested.reliability_weight(), 0.30);
1081 assert!(
1082 PrincipleType::Assumption.reliability_weight()
1083 < PrincipleType::Derived.reliability_weight()
1084 );
1085 }
1086
1087 #[test]
1088 fn test_decompose_simple_query() {
1089 let bedrock = BedRock::new();
1090 let result = bedrock.decompose("Electric vehicles are better than gas cars", &[]);
1091
1092 assert!(!result.principles.is_empty());
1093 assert_eq!(result.query, "Electric vehicles are better than gas cars");
1094 assert!(result.confidence > 0.0);
1095 assert!(!result.insights.is_empty());
1096 }
1097
1098 #[test]
1099 fn test_decompose_with_comparison() {
1100 let bedrock = BedRock::new();
1101 let result = bedrock.decompose("Python is better than JavaScript for data science", &[]);
1102
1103 let has_definition = result
1105 .principles
1106 .iter()
1107 .any(|p| p.principle_type == PrincipleType::Definition);
1108 assert!(has_definition, "Should identify need for comparison metric");
1109 }
1110
1111 #[test]
1112 fn test_decompose_with_causation() {
1113 let bedrock = BedRock::new();
1114 let result = bedrock.decompose("Smoking causes cancer", &[]);
1115
1116 let has_axiom = result
1118 .principles
1119 .iter()
1120 .any(|p| p.principle_type == PrincipleType::Axiom);
1121 assert!(
1122 has_axiom,
1123 "Should identify axiomatic principles about causation"
1124 );
1125 }
1126
1127 #[test]
1128 fn test_execute_trait() {
1129 let bedrock = BedRock::new();
1130 let context = ThinkToolContext {
1131 query: "What is the best programming language?".into(),
1132 previous_steps: vec!["Prior analysis: Consider use case".into()],
1133 };
1134
1135 let output = bedrock.execute(&context).expect("Execution should succeed");
1136
1137 assert_eq!(output.module, "BedRock");
1138 assert!(output.confidence > 0.0);
1139 assert!(output.output.get("axioms").is_some());
1140 assert!(output.output.get("assumptions").is_some());
1141 assert!(output.output.get("decomposition").is_some());
1142 assert!(output.output.get("insights").is_some());
1143 }
1144
1145 #[test]
1146 fn test_classify_query() {
1147 let bedrock = BedRock::new();
1148
1149 let def_type = bedrock.classify_query("What is machine learning?");
1151 assert_eq!(def_type, PrincipleType::Definition);
1152
1153 let emp_type = bedrock.classify_query("Research shows that exercise improves health");
1155 assert_eq!(emp_type, PrincipleType::Empirical);
1156
1157 let contested_type = bedrock.classify_query("Rust is better than C++");
1159 assert_eq!(contested_type, PrincipleType::Contested);
1160 }
1161
1162 #[test]
1163 fn test_result_accessors() {
1164 let bedrock = BedRock::new();
1165 let result = bedrock.decompose("All birds can fly", &[]);
1166
1167 let _axioms = result.axioms();
1169 let _assumptions = result.assumptions();
1170
1171 let root_principles = result.at_depth(0);
1173 assert!(!root_principles.is_empty());
1174
1175 assert!(result.metadata.completeness >= 0.0);
1177 assert!(result.metadata.completeness <= 1.0);
1178 }
1179
1180 #[test]
1181 fn test_principle_effective_weight() {
1182 let principle = Principle {
1183 id: 0,
1184 statement: "Test axiom".into(),
1185 principle_type: PrincipleType::Axiom,
1186 fundamentality: 1.0,
1187 confidence: 0.95,
1188 parent_id: None,
1189 child_ids: vec![],
1190 evidence: vec![],
1191 challenges: vec![],
1192 depth: 0,
1193 };
1194
1195 let weight = principle.effective_weight();
1196 assert_eq!(weight, 0.95); assert!(principle.is_axiomatic(0.85));
1198 }
1199
1200 #[test]
1201 fn test_gap_identification() {
1202 let bedrock = BedRock::new();
1203 let result = bedrock.decompose("This is a vague statement", &[]);
1204
1205 let _ = &result.gaps;
1210 }
1211
1212 #[test]
1213 fn test_max_principles_limit() {
1214 let config = BedRockConfig {
1215 max_principles: 5,
1216 ..Default::default()
1217 };
1218 let bedrock = BedRock::with_config(config);
1219 let result = bedrock.decompose("Complex multi-part query about many things", &[]);
1220
1221 assert!(result.principles.len() <= 5);
1222 }
1223
1224 #[test]
1225 fn test_json_output_structure() {
1226 let bedrock = BedRock::new();
1227 let result = bedrock.decompose("Test query for JSON", &[]);
1228 let json = result.to_json();
1229
1230 assert!(json.get("query").is_some());
1231 assert!(json.get("axioms").is_some());
1232 assert!(json.get("assumptions").is_some());
1233 assert!(json.get("decomposition").is_some());
1234 assert!(json.get("reconstruction").is_some());
1235 assert!(json.get("gaps").is_some());
1236 assert!(json.get("insights").is_some());
1237 assert!(json.get("confidence").is_some());
1238 assert!(json.get("metadata").is_some());
1239 }
1240}