neuromance_tools/
bool_tool.rs

1use std::collections::HashMap;
2
3use anyhow::Result;
4use async_trait::async_trait;
5use serde_json::Value;
6
7use crate::ToolImplementation;
8use neuromance_common::tools::{Function, Property, Tool};
9
10/// A tool that returns a boolean result based on the agent's analysis
11/// Used for binary decisions like goal verification
12pub struct BooleanTool;
13
14#[async_trait]
15impl ToolImplementation for BooleanTool {
16    fn get_definition(&self) -> Tool {
17        let mut properties = HashMap::new();
18        properties.insert(
19            "result".to_string(),
20            Property {
21                prop_type: "boolean".to_string(),
22                description: "The boolean result (true or false)".to_string(),
23            },
24        );
25        properties.insert(
26            "reason".to_string(),
27            Property {
28                prop_type: "string".to_string(),
29                description: "A brief explanation for the boolean result".to_string(),
30            },
31        );
32
33        Tool {
34            r#type: "function".to_string(),
35            function: Function {
36                name: "return_bool".to_string(),
37                description: "Return a boolean result (true/false) with an explanation. Use this to provide definitive yes/no answers.".to_string(),
38                parameters: serde_json::json!({
39                    "type": "object",
40                    "properties": properties,
41                    "required": vec!["result".to_string(), "reason".to_string()],
42                }),
43            },
44        }
45    }
46
47    async fn execute(&self, args: &Value) -> Result<String> {
48        let obj = args
49            .as_object()
50            .ok_or_else(|| anyhow::anyhow!("Expected object arguments"))?;
51
52        let result = obj
53            .get("result")
54            .and_then(|v| v.as_bool())
55            .ok_or_else(|| anyhow::anyhow!("Missing or invalid 'result' parameter"))?;
56
57        let reason = obj
58            .get("reason")
59            .and_then(|v| v.as_str())
60            .ok_or_else(|| anyhow::anyhow!("Missing or invalid 'reason' parameter"))?;
61
62        // Format the result in a structured way
63        Ok(format!(
64            "RESULT: {}\nREASON: {}",
65            if result { "TRUE" } else { "FALSE" },
66            reason
67        ))
68    }
69
70    fn is_auto_approved(&self) -> bool {
71        true // Bool tool is safe and can be auto-approved
72    }
73}
74
75#[cfg(test)]
76mod tests {
77    use super::*;
78    use serde_json::json;
79
80    #[tokio::test]
81    async fn test_bool_tool_true() {
82        let tool = BooleanTool;
83
84        let args = json!({
85            "result": true,
86            "reason": "The goal was successfully achieved"
87        });
88
89        let result = tool.execute(&args).await.unwrap();
90        assert!(result.contains("RESULT: TRUE"));
91        assert!(result.contains("REASON: The goal was successfully achieved"));
92    }
93
94    #[tokio::test]
95    async fn test_bool_tool_false() {
96        let tool = BooleanTool;
97
98        let args = json!({
99            "result": false,
100            "reason": "The task failed due to missing dependencies"
101        });
102
103        let result = tool.execute(&args).await.unwrap();
104        assert!(result.contains("RESULT: FALSE"));
105        assert!(result.contains("REASON: The task failed due to missing dependencies"));
106    }
107
108    #[tokio::test]
109    async fn test_bool_tool_missing_result() {
110        let tool = BooleanTool;
111
112        let args = json!({
113            "reason": "Some reason"
114        });
115
116        let result = tool.execute(&args).await;
117        assert!(result.is_err());
118        assert!(
119            result
120                .unwrap_err()
121                .to_string()
122                .contains("Missing or invalid 'result' parameter")
123        );
124    }
125
126    #[tokio::test]
127    async fn test_bool_tool_missing_reason() {
128        let tool = BooleanTool;
129
130        let args = json!({
131            "result": true
132        });
133
134        let result = tool.execute(&args).await;
135        assert!(result.is_err());
136        assert!(
137            result
138                .unwrap_err()
139                .to_string()
140                .contains("Missing or invalid 'reason' parameter")
141        );
142    }
143}