neuromance_tools/
bool_tool.rs1use 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
10pub 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 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 }
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}