reasonkit/mcp/
thinktool_tools.rs

1//! ThinkTool MCP Handlers
2//!
3//! MCP tool implementations for ReasonKit ThinkTools, exposing
4//! structured reasoning capabilities to AI agents via MCP.
5//!
6//! ## Available Tools
7//!
8//! | Tool | Description | Profile |
9//! |------|-------------|---------|
10//! | `gigathink` | Expansive creative thinking (10+ perspectives) | `--creative` |
11//! | `laserlogic` | Precision deductive reasoning with fallacy detection | `--balanced` |
12//! | `bedrock` | First principles decomposition | `--deep` |
13//! | `proofguard` | Multi-source verification (3+ sources) | `--paranoid` |
14//! | `brutalhonesty` | Adversarial self-critique | `--paranoid` |
15//!
16//! ## Usage
17//!
18//! ### Quick Registration (Recommended)
19//!
20//! Use `register_thinktools()` to register all 5 tools at once:
21//!
22//! ```rust,ignore
23//! use reasonkit::mcp::{McpServer, register_thinktools};
24//!
25//! let server = McpServer::new(...);
26//! register_thinktools(&server).await;  // Registers all 5 ThinkTools
27//! ```
28//!
29//! ### Individual Handler Registration
30//!
31//! Register specific tools using individual handlers:
32//!
33//! ```rust,ignore
34//! use reasonkit::mcp::{ThinkToolHandler, GigaThinkHandler, McpServer};
35//! use std::sync::Arc;
36//!
37//! let server = McpServer::new(...);
38//!
39//! // Register only GigaThink
40//! server.register_tool(
41//!     ThinkToolHandler::gigathink_tool(),
42//!     Arc::new(GigaThinkHandler::new())
43//! ).await;
44//! ```
45//!
46//! ### Combined Handler (Legacy)
47//!
48//! For backward compatibility, use `ThinkToolHandler` with `_tool` routing:
49//!
50//! ```rust,ignore
51//! use reasonkit::mcp::{ThinkToolHandler, ToolHandler};
52//!
53//! let handler = ThinkToolHandler::new();
54//! let tools = handler.tool_definitions();
55//!
56//! // Register with MCP server
57//! for tool in tools {
58//!     server.register_tool(tool, Arc::new(handler.clone()));
59//! }
60//! ```
61
62use crate::error::{Error, Result};
63use crate::mcp::tools::{Tool, ToolHandler, ToolResult};
64use crate::thinktool::modules::{
65    BedRock, BrutalHonesty, GigaThink, LaserLogic, ProofGuard, ThinkToolContext, ThinkToolModule,
66};
67use async_trait::async_trait;
68use serde_json::{json, Value};
69use std::collections::HashMap;
70use std::sync::Arc;
71use tracing::{debug, error, info, instrument};
72
73/// ThinkTool MCP Handler
74///
75/// Provides MCP tool interface for all 5 core ThinkTools:
76/// - GigaThink: Expansive creative thinking
77/// - LaserLogic: Precision deductive reasoning
78/// - BedRock: First principles decomposition
79/// - ProofGuard: Multi-source verification
80/// - BrutalHonesty: Adversarial self-critique
81///
82/// # Example
83///
84/// ```rust,ignore
85/// let handler = ThinkToolHandler::new();
86/// let args = HashMap::from([("query".to_string(), json!("Should we migrate to microservices?"))]);
87/// let result = handler.call_tool("gigathink", args).await?;
88/// ```
89pub struct ThinkToolHandler {
90    /// GigaThink module instance
91    gigathink: Arc<GigaThink>,
92    /// LaserLogic module instance
93    laserlogic: Arc<LaserLogic>,
94    /// BedRock module instance
95    bedrock: Arc<BedRock>,
96    /// ProofGuard module instance
97    proofguard: Arc<ProofGuard>,
98    /// BrutalHonesty module instance
99    brutalhonesty: Arc<BrutalHonesty>,
100}
101
102impl Default for ThinkToolHandler {
103    fn default() -> Self {
104        Self::new()
105    }
106}
107
108impl ThinkToolHandler {
109    /// Create a new ThinkToolHandler with default configurations
110    pub fn new() -> Self {
111        Self {
112            gigathink: Arc::new(GigaThink::new()),
113            laserlogic: Arc::new(LaserLogic::new()),
114            bedrock: Arc::new(BedRock::new()),
115            proofguard: Arc::new(ProofGuard::new()),
116            brutalhonesty: Arc::new(BrutalHonesty::new()),
117        }
118    }
119
120    /// Get all ThinkTool definitions for MCP registration
121    ///
122    /// Returns a vector of Tool definitions with JSON schemas for input validation.
123    pub fn tool_definitions() -> Vec<Tool> {
124        vec![
125            Self::gigathink_tool(),
126            Self::laserlogic_tool(),
127            Self::bedrock_tool(),
128            Self::proofguard_tool(),
129            Self::brutalhonesty_tool(),
130        ]
131    }
132
133    /// GigaThink tool definition
134    fn gigathink_tool() -> Tool {
135        Tool::with_schema(
136            "gigathink",
137            "Expansive creative thinking - generates 10+ diverse perspectives across \
138            multiple analytical dimensions (economic, technological, social, environmental, \
139            political, psychological, ethical, historical, competitive, user experience, \
140            risk/opportunity, strategic). Use for brainstorming, exploring problem spaces, \
141            or generating comprehensive viewpoints on complex issues.",
142            json!({
143                "type": "object",
144                "properties": {
145                    "query": {
146                        "type": "string",
147                        "description": "The question, problem, or topic to analyze from multiple perspectives",
148                        "minLength": 10
149                    },
150                    "context": {
151                        "type": "array",
152                        "items": { "type": "string" },
153                        "description": "Optional previous reasoning steps for chained execution",
154                        "default": []
155                    },
156                    "min_perspectives": {
157                        "type": "integer",
158                        "description": "Minimum number of perspectives to generate",
159                        "minimum": 5,
160                        "maximum": 20,
161                        "default": 10
162                    }
163                },
164                "required": ["query"],
165                "additionalProperties": false
166            }),
167        )
168    }
169
170    /// LaserLogic tool definition
171    fn laserlogic_tool() -> Tool {
172        Tool::with_schema(
173            "laserlogic",
174            "Precision deductive reasoning with fallacy detection - validates logical \
175            arguments, identifies formal fallacies (affirming consequent, denying antecedent, \
176            undistributed middle, illicit major/minor), detects contradictions, and assesses \
177            argument soundness. Use for analyzing claims, validating reasoning chains, or \
178            checking logical consistency.",
179            json!({
180                "type": "object",
181                "properties": {
182                    "query": {
183                        "type": "string",
184                        "description": "The argument or statement to analyze logically"
185                    },
186                    "context": {
187                        "type": "array",
188                        "items": { "type": "string" },
189                        "description": "Optional previous reasoning steps",
190                        "default": []
191                    },
192                    "detect_fallacies": {
193                        "type": "boolean",
194                        "description": "Enable formal fallacy detection",
195                        "default": true
196                    },
197                    "check_contradictions": {
198                        "type": "boolean",
199                        "description": "Enable contradiction detection",
200                        "default": true
201                    }
202                },
203                "required": ["query"],
204                "additionalProperties": false
205            }),
206        )
207    }
208
209    /// BedRock tool definition
210    fn bedrock_tool() -> Tool {
211        Tool::with_schema(
212            "bedrock",
213            "First principles decomposition - breaks down complex problems into \
214            fundamental axioms, surfaces hidden assumptions, and identifies core \
215            building blocks. Use for understanding root causes, challenging assumptions, \
216            or building understanding from foundational concepts.",
217            json!({
218                "type": "object",
219                "properties": {
220                    "query": {
221                        "type": "string",
222                        "description": "The problem or concept to decompose to first principles"
223                    },
224                    "context": {
225                        "type": "array",
226                        "items": { "type": "string" },
227                        "description": "Optional previous reasoning steps",
228                        "default": []
229                    },
230                    "decomposition_depth": {
231                        "type": "integer",
232                        "description": "Maximum depth of decomposition (levels of 'why')",
233                        "minimum": 1,
234                        "maximum": 5,
235                        "default": 3
236                    }
237                },
238                "required": ["query"],
239                "additionalProperties": false
240            }),
241        )
242    }
243
244    /// ProofGuard tool definition
245    fn proofguard_tool() -> Tool {
246        Tool::with_schema(
247            "proofguard",
248            "Multi-source verification - validates claims through triangulation \
249            of evidence from multiple independent sources. Implements 3-source minimum \
250            requirement, source credibility tiers (primary, secondary, tertiary), and \
251            confidence scoring based on source agreement. Use for fact-checking, \
252            verifying claims, or assessing evidence quality.",
253            json!({
254                "type": "object",
255                "properties": {
256                    "query": {
257                        "type": "string",
258                        "description": "The claim or statement to verify"
259                    },
260                    "context": {
261                        "type": "array",
262                        "items": { "type": "string" },
263                        "description": "Optional previous reasoning steps",
264                        "default": []
265                    },
266                    "min_sources": {
267                        "type": "integer",
268                        "description": "Minimum number of independent sources required",
269                        "minimum": 2,
270                        "maximum": 10,
271                        "default": 3
272                    },
273                    "verification_strategy": {
274                        "type": "string",
275                        "description": "Strategy for source verification",
276                        "enum": ["triangulation", "consensus", "hierarchical"],
277                        "default": "triangulation"
278                    }
279                },
280                "required": ["query"],
281                "additionalProperties": false
282            }),
283        )
284    }
285
286    /// BrutalHonesty tool definition
287    fn brutalhonesty_tool() -> Tool {
288        Tool::with_schema(
289            "brutalhonesty",
290            "Adversarial self-critique - identifies weaknesses, biases, blind spots, \
291            and implicit assumptions in arguments or plans. Generates devil's advocate \
292            counterarguments, detects cognitive biases, and provides ruthless assessment \
293            of claims. Use for stress-testing ideas, challenging assumptions, or getting \
294            honest feedback on proposals.",
295            json!({
296                "type": "object",
297                "properties": {
298                    "query": {
299                        "type": "string",
300                        "description": "The argument, plan, or idea to critique"
301                    },
302                    "context": {
303                        "type": "array",
304                        "items": { "type": "string" },
305                        "description": "Optional previous reasoning steps",
306                        "default": []
307                    },
308                    "severity": {
309                        "type": "string",
310                        "description": "Critique intensity level",
311                        "enum": ["gentle", "moderate", "harsh", "ruthless"],
312                        "default": "moderate"
313                    },
314                    "enable_devil_advocate": {
315                        "type": "boolean",
316                        "description": "Enable devil's advocate mode",
317                        "default": true
318                    },
319                    "detect_cognitive_biases": {
320                        "type": "boolean",
321                        "description": "Enable cognitive bias detection",
322                        "default": true
323                    }
324                },
325                "required": ["query"],
326                "additionalProperties": false
327            }),
328        )
329    }
330
331    /// Execute a ThinkTool by name
332    ///
333    /// Dispatches to the appropriate tool handler based on the tool name.
334    #[instrument(skip(self, arguments), fields(tool = %name))]
335    pub async fn call_tool(
336        &self,
337        name: &str,
338        arguments: HashMap<String, Value>,
339    ) -> Result<ToolResult> {
340        info!(tool = %name, "Executing ThinkTool");
341
342        match name {
343            "gigathink" => self.handle_gigathink(arguments).await,
344            "laserlogic" => self.handle_laserlogic(arguments).await,
345            "bedrock" => self.handle_bedrock(arguments).await,
346            "proofguard" => self.handle_proofguard(arguments).await,
347            "brutalhonesty" => self.handle_brutalhonesty(arguments).await,
348            _ => {
349                error!(tool = %name, "Unknown tool requested");
350                Ok(ToolResult::error(format!("Unknown ThinkTool: {}", name)))
351            }
352        }
353    }
354
355    /// Handle GigaThink tool execution
356    async fn handle_gigathink(&self, args: HashMap<String, Value>) -> Result<ToolResult> {
357        let query = extract_required_string(&args, "query")?;
358        let context = extract_context(&args);
359
360        debug!(query = %query, context_len = context.len(), "Executing GigaThink");
361
362        let think_context = ThinkToolContext::with_previous_steps(query, context);
363        let output = self.gigathink.execute(&think_context)?;
364
365        format_output(output)
366    }
367
368    /// Handle LaserLogic tool execution
369    async fn handle_laserlogic(&self, args: HashMap<String, Value>) -> Result<ToolResult> {
370        let query = extract_required_string(&args, "query")?;
371        let context = extract_context(&args);
372
373        debug!(query = %query, "Executing LaserLogic");
374
375        let think_context = ThinkToolContext::with_previous_steps(query, context);
376        let output = self.laserlogic.execute(&think_context)?;
377
378        format_output(output)
379    }
380
381    /// Handle BedRock tool execution
382    async fn handle_bedrock(&self, args: HashMap<String, Value>) -> Result<ToolResult> {
383        let query = extract_required_string(&args, "query")?;
384        let context = extract_context(&args);
385
386        debug!(query = %query, "Executing BedRock");
387
388        let think_context = ThinkToolContext::with_previous_steps(query, context);
389        let output = self.bedrock.execute(&think_context)?;
390
391        format_output(output)
392    }
393
394    /// Handle ProofGuard tool execution
395    async fn handle_proofguard(&self, args: HashMap<String, Value>) -> Result<ToolResult> {
396        let query = extract_required_string(&args, "query")?;
397        let context = extract_context(&args);
398
399        debug!(query = %query, "Executing ProofGuard");
400
401        let think_context = ThinkToolContext::with_previous_steps(query, context);
402        let output = self.proofguard.execute(&think_context)?;
403
404        format_output(output)
405    }
406
407    /// Handle BrutalHonesty tool execution
408    async fn handle_brutalhonesty(&self, args: HashMap<String, Value>) -> Result<ToolResult> {
409        let query = extract_required_string(&args, "query")?;
410        let context = extract_context(&args);
411
412        debug!(query = %query, "Executing BrutalHonesty");
413
414        let think_context = ThinkToolContext::with_previous_steps(query, context);
415        let output = self.brutalhonesty.execute(&think_context)?;
416
417        format_output(output)
418    }
419}
420
421/// Implement ToolHandler trait for integration with MCP server
422#[async_trait]
423impl ToolHandler for ThinkToolHandler {
424    async fn call(&self, arguments: HashMap<String, Value>) -> Result<ToolResult> {
425        // Extract tool name from arguments
426        let tool_name = arguments
427            .get("_tool")
428            .and_then(|v| v.as_str())
429            .map(|s| s.to_string())
430            .ok_or_else(|| Error::Mcp("Missing _tool identifier in arguments".into()))?;
431
432        self.call_tool(&tool_name, arguments).await
433    }
434}
435
436// ============================================================================
437// INDIVIDUAL TOOL HANDLERS (for per-tool MCP registration)
438// ============================================================================
439
440/// GigaThink MCP Handler
441///
442/// Provides expansive creative thinking with 10+ diverse perspectives.
443/// Ideal for brainstorming, strategic planning, and exploring solution spaces.
444///
445/// # MCP Tool Parameters
446/// - `query` (required): The topic or question to analyze
447/// - `context` (optional): Array of previous reasoning steps for context
448///
449/// # Example
450/// ```json
451/// { "query": "Should we migrate to microservices?", "context": [] }
452/// ```
453pub struct GigaThinkHandler {
454    module: Arc<GigaThink>,
455}
456
457impl Default for GigaThinkHandler {
458    fn default() -> Self {
459        Self::new()
460    }
461}
462
463impl GigaThinkHandler {
464    pub fn new() -> Self {
465        Self {
466            module: Arc::new(GigaThink::new()),
467        }
468    }
469}
470
471#[async_trait]
472impl ToolHandler for GigaThinkHandler {
473    async fn call(&self, arguments: HashMap<String, Value>) -> Result<ToolResult> {
474        let query = extract_required_string(&arguments, "query")?;
475        let context = extract_context(&arguments);
476        let think_context = ThinkToolContext::with_previous_steps(query, context);
477        let output = self.module.execute(&think_context)?;
478        format_output(output)
479    }
480}
481
482/// LaserLogic MCP Handler
483///
484/// Provides precision deductive reasoning with fallacy detection.
485/// Ideal for argument validation, logical analysis, and formal reasoning.
486///
487/// # MCP Tool Parameters
488/// - `query` (required): The logical argument to analyze (format: "Premise 1. Premise 2. Therefore, Conclusion.")
489/// - `context` (optional): Array of previous reasoning steps for context
490///
491/// # Example
492/// ```json
493/// { "query": "All birds can fly. Penguins are birds. Therefore, penguins can fly.", "context": [] }
494/// ```
495pub struct LaserLogicHandler {
496    module: Arc<LaserLogic>,
497}
498
499impl Default for LaserLogicHandler {
500    fn default() -> Self {
501        Self::new()
502    }
503}
504
505impl LaserLogicHandler {
506    pub fn new() -> Self {
507        Self {
508            module: Arc::new(LaserLogic::new()),
509        }
510    }
511}
512
513#[async_trait]
514impl ToolHandler for LaserLogicHandler {
515    async fn call(&self, arguments: HashMap<String, Value>) -> Result<ToolResult> {
516        let query = extract_required_string(&arguments, "query")?;
517        let context = extract_context(&arguments);
518        let think_context = ThinkToolContext::with_previous_steps(query, context);
519        let output = self.module.execute(&think_context)?;
520        format_output(output)
521    }
522}
523
524/// BedRock MCP Handler
525///
526/// Provides first principles decomposition for fundamental analysis.
527/// Ideal for breaking down complex problems to their foundational truths.
528///
529/// # MCP Tool Parameters
530/// - `query` (required): The problem or concept to decompose
531/// - `context` (optional): Array of previous reasoning steps for context
532///
533/// # Example
534/// ```json
535/// { "query": "Why are electric vehicles becoming popular?", "context": [] }
536/// ```
537pub struct BedRockHandler {
538    module: Arc<BedRock>,
539}
540
541impl Default for BedRockHandler {
542    fn default() -> Self {
543        Self::new()
544    }
545}
546
547impl BedRockHandler {
548    pub fn new() -> Self {
549        Self {
550            module: Arc::new(BedRock::new()),
551        }
552    }
553}
554
555#[async_trait]
556impl ToolHandler for BedRockHandler {
557    async fn call(&self, arguments: HashMap<String, Value>) -> Result<ToolResult> {
558        let query = extract_required_string(&arguments, "query")?;
559        let context = extract_context(&arguments);
560        let think_context = ThinkToolContext::with_previous_steps(query, context);
561        let output = self.module.execute(&think_context)?;
562        format_output(output)
563    }
564}
565
566/// ProofGuard MCP Handler
567///
568/// Provides multi-source verification (3+ sources minimum).
569/// Ideal for fact-checking, claim validation, and research verification.
570///
571/// # MCP Tool Parameters
572/// - `query` (required): The claim or assertion to verify
573/// - `context` (optional): Array of previous reasoning steps for context
574///
575/// # Example
576/// ```json
577/// { "query": "Python is the most popular programming language in 2024", "context": [] }
578/// ```
579pub struct ProofGuardHandler {
580    module: Arc<ProofGuard>,
581}
582
583impl Default for ProofGuardHandler {
584    fn default() -> Self {
585        Self::new()
586    }
587}
588
589impl ProofGuardHandler {
590    pub fn new() -> Self {
591        Self {
592            module: Arc::new(ProofGuard::new()),
593        }
594    }
595}
596
597#[async_trait]
598impl ToolHandler for ProofGuardHandler {
599    async fn call(&self, arguments: HashMap<String, Value>) -> Result<ToolResult> {
600        let query = extract_required_string(&arguments, "query")?;
601        let context = extract_context(&arguments);
602        let think_context = ThinkToolContext::with_previous_steps(query, context);
603        let output = self.module.execute(&think_context)?;
604        format_output(output)
605    }
606}
607
608/// BrutalHonesty MCP Handler
609///
610/// Provides adversarial self-critique for identifying weaknesses.
611/// Ideal for stress-testing ideas, uncovering blind spots, and ensuring rigor.
612///
613/// # MCP Tool Parameters
614/// - `query` (required): The idea, plan, or argument to critique
615/// - `context` (optional): Array of previous reasoning steps for context
616///
617/// # Example
618/// ```json
619/// { "query": "Our startup will succeed because we have a great product", "context": [] }
620/// ```
621pub struct BrutalHonestyHandler {
622    module: Arc<BrutalHonesty>,
623}
624
625impl Default for BrutalHonestyHandler {
626    fn default() -> Self {
627        Self::new()
628    }
629}
630
631impl BrutalHonestyHandler {
632    pub fn new() -> Self {
633        Self {
634            module: Arc::new(BrutalHonesty::new()),
635        }
636    }
637}
638
639#[async_trait]
640impl ToolHandler for BrutalHonestyHandler {
641    async fn call(&self, arguments: HashMap<String, Value>) -> Result<ToolResult> {
642        let query = extract_required_string(&arguments, "query")?;
643        let context = extract_context(&arguments);
644        let think_context = ThinkToolContext::with_previous_steps(query, context);
645        let output = self.module.execute(&think_context)?;
646        format_output(output)
647    }
648}
649
650/// Register all ThinkTools with an MCP server
651///
652/// This helper function registers all 5 ThinkTools with their handlers.
653///
654/// # Example
655///
656/// ```rust,ignore
657/// use reasonkit::mcp::{McpServer, register_thinktools};
658///
659/// let server = McpServer::new(...);
660/// register_thinktools(&server).await;
661/// ```
662pub async fn register_thinktools<T: crate::mcp::McpServerTrait + ?Sized>(server: &T) {
663    // Register GigaThink
664    server
665        .register_tool(
666            ThinkToolHandler::gigathink_tool(),
667            Arc::new(GigaThinkHandler::new()),
668        )
669        .await;
670
671    // Register LaserLogic
672    server
673        .register_tool(
674            ThinkToolHandler::laserlogic_tool(),
675            Arc::new(LaserLogicHandler::new()),
676        )
677        .await;
678
679    // Register BedRock
680    server
681        .register_tool(
682            ThinkToolHandler::bedrock_tool(),
683            Arc::new(BedRockHandler::new()),
684        )
685        .await;
686
687    // Register ProofGuard
688    server
689        .register_tool(
690            ThinkToolHandler::proofguard_tool(),
691            Arc::new(ProofGuardHandler::new()),
692        )
693        .await;
694
695    // Register BrutalHonesty
696    server
697        .register_tool(
698            ThinkToolHandler::brutalhonesty_tool(),
699            Arc::new(BrutalHonestyHandler::new()),
700        )
701        .await;
702
703    tracing::info!(
704        "Registered 5 ThinkTools: gigathink, laserlogic, bedrock, proofguard, brutalhonesty"
705    );
706}
707
708// ============================================================================
709// HELPER FUNCTIONS
710// ============================================================================
711
712/// Extract required string argument
713fn extract_required_string(args: &HashMap<String, Value>, key: &str) -> Result<String> {
714    args.get(key)
715        .and_then(|v| v.as_str())
716        .map(|s| s.to_string())
717        .ok_or_else(|| Error::Mcp(format!("Missing required argument: {}", key)))
718}
719
720/// Extract optional context array
721fn extract_context(args: &HashMap<String, Value>) -> Vec<String> {
722    args.get("context")
723        .and_then(|v| v.as_array())
724        .map(|arr| {
725            arr.iter()
726                .filter_map(|v| v.as_str().map(String::from))
727                .collect()
728        })
729        .unwrap_or_default()
730}
731
732/// Format ThinkToolOutput as ToolResult
733fn format_output(output: crate::thinktool::modules::ThinkToolOutput) -> Result<ToolResult> {
734    let formatted = json!({
735        "module": output.module,
736        "confidence": output.confidence,
737        "result": output.output
738    });
739
740    Ok(ToolResult::text(serde_json::to_string_pretty(&formatted)?))
741}
742
743// ============================================================================
744// TESTS
745// ============================================================================
746
747#[cfg(test)]
748mod tests {
749    use super::*;
750
751    #[test]
752    fn test_handler_creation() {
753        let handler = ThinkToolHandler::new();
754        assert!(Arc::strong_count(&handler.gigathink) > 0);
755    }
756
757    #[test]
758    fn test_tool_definitions_count() {
759        let tools = ThinkToolHandler::tool_definitions();
760        assert_eq!(tools.len(), 5, "Should have 5 ThinkTool definitions");
761    }
762
763    #[test]
764    fn test_tool_definitions_names() {
765        let tools = ThinkToolHandler::tool_definitions();
766        let names: Vec<&str> = tools.iter().map(|t| t.name.as_str()).collect();
767
768        assert!(names.contains(&"gigathink"));
769        assert!(names.contains(&"laserlogic"));
770        assert!(names.contains(&"bedrock"));
771        assert!(names.contains(&"proofguard"));
772        assert!(names.contains(&"brutalhonesty"));
773    }
774
775    #[test]
776    fn test_tool_definitions_have_descriptions() {
777        let tools = ThinkToolHandler::tool_definitions();
778        for tool in tools {
779            assert!(
780                tool.description.is_some(),
781                "Tool {} should have description",
782                tool.name
783            );
784        }
785    }
786
787    #[test]
788    fn test_tool_definitions_have_schemas() {
789        let tools = ThinkToolHandler::tool_definitions();
790        for tool in tools {
791            assert!(
792                tool.input_schema.is_object(),
793                "Tool {} should have JSON schema",
794                tool.name
795            );
796
797            // All tools should require "query" argument
798            let required = tool.input_schema.get("required").unwrap();
799            assert!(
800                required.as_array().unwrap().contains(&json!("query")),
801                "Tool {} should require 'query' argument",
802                tool.name
803            );
804        }
805    }
806
807    #[test]
808    fn test_extract_required_string_success() {
809        let mut args = HashMap::new();
810        args.insert("query".to_string(), json!("test query"));
811
812        let result = extract_required_string(&args, "query");
813        assert!(result.is_ok());
814        assert_eq!(result.unwrap(), "test query");
815    }
816
817    #[test]
818    fn test_extract_required_string_missing() {
819        let args = HashMap::new();
820        let result = extract_required_string(&args, "query");
821        assert!(result.is_err());
822    }
823
824    #[test]
825    fn test_extract_context_present() {
826        let mut args = HashMap::new();
827        args.insert("context".to_string(), json!(["step 1", "step 2"]));
828
829        let context = extract_context(&args);
830        assert_eq!(context.len(), 2);
831        assert_eq!(context[0], "step 1");
832    }
833
834    #[test]
835    fn test_extract_context_missing() {
836        let args = HashMap::new();
837        let context = extract_context(&args);
838        assert!(context.is_empty());
839    }
840
841    #[tokio::test]
842    async fn test_gigathink_execution() {
843        let handler = ThinkToolHandler::new();
844        let mut args = HashMap::new();
845        args.insert(
846            "query".to_string(),
847            json!("What are the implications of AI in healthcare?"),
848        );
849
850        let result = handler.handle_gigathink(args).await;
851        assert!(result.is_ok());
852
853        let tool_result = result.unwrap();
854        assert!(tool_result.is_error.is_none() || !tool_result.is_error.unwrap());
855    }
856
857    #[tokio::test]
858    async fn test_laserlogic_execution() {
859        let handler = ThinkToolHandler::new();
860        let mut args = HashMap::new();
861        args.insert(
862            "query".to_string(),
863            json!("All birds can fly. Penguins are birds. Therefore, penguins can fly."),
864        );
865
866        let result = handler.handle_laserlogic(args).await;
867        assert!(result.is_ok());
868    }
869
870    #[tokio::test]
871    async fn test_bedrock_execution() {
872        let handler = ThinkToolHandler::new();
873        let mut args = HashMap::new();
874        args.insert(
875            "query".to_string(),
876            json!("Why do companies need to innovate?"),
877        );
878
879        let result = handler.handle_bedrock(args).await;
880        assert!(result.is_ok());
881    }
882
883    #[tokio::test]
884    async fn test_proofguard_execution() {
885        let handler = ThinkToolHandler::new();
886        let mut args = HashMap::new();
887        args.insert(
888            "query".to_string(),
889            json!("Climate change is primarily caused by human activity"),
890        );
891
892        let result = handler.handle_proofguard(args).await;
893        assert!(result.is_ok());
894    }
895
896    #[tokio::test]
897    async fn test_brutalhonesty_execution() {
898        let handler = ThinkToolHandler::new();
899        let mut args = HashMap::new();
900        args.insert(
901            "query".to_string(),
902            json!("Our startup will succeed because we have the best team"),
903        );
904
905        let result = handler.handle_brutalhonesty(args).await;
906        assert!(result.is_ok());
907    }
908
909    #[tokio::test]
910    async fn test_unknown_tool() {
911        let handler = ThinkToolHandler::new();
912        let args = HashMap::new();
913
914        let result = handler.call_tool("nonexistent", args).await;
915        assert!(result.is_ok());
916
917        let tool_result = result.unwrap();
918        assert_eq!(tool_result.is_error, Some(true));
919    }
920
921    #[tokio::test]
922    async fn test_missing_query_argument() {
923        let handler = ThinkToolHandler::new();
924        let args = HashMap::new(); // No query
925
926        let result = handler.handle_gigathink(args).await;
927        assert!(result.is_err());
928    }
929}