mojentic/llm/tools/
tell_user_tool.rs

1use crate::error::Result;
2use crate::llm::tools::{FunctionDescriptor, LlmTool, ToolDescriptor};
3use serde_json::{json, Value};
4use std::collections::HashMap;
5
6/// Tool for displaying messages to the user without expecting a response
7///
8/// This tool allows the LLM to send important intermediate information to the user
9/// as it works on completing their request. It's useful for providing status updates,
10/// progress information, or other important messages during long-running operations.
11///
12/// # Examples
13///
14/// ```
15/// use mojentic::llm::tools::tell_user_tool::TellUserTool;
16/// use mojentic::llm::tools::LlmTool;
17/// use std::collections::HashMap;
18/// use serde_json::json;
19///
20/// let tool = TellUserTool;
21/// let mut args = HashMap::new();
22/// args.insert("message".to_string(), json!("Processing your request..."));
23///
24/// let result = tool.run(&args).unwrap();
25/// // Prints to stdout:
26/// //
27/// //
28/// //
29/// // MESSAGE FROM ASSISTANT:
30/// // Processing your request...
31/// //
32/// // Returns: "Message delivered to user."
33/// ```
34#[derive(Clone)]
35pub struct TellUserTool;
36
37impl TellUserTool {
38    /// Creates a new TellUserTool instance
39    pub fn new() -> Self {
40        Self
41    }
42}
43
44impl Default for TellUserTool {
45    fn default() -> Self {
46        Self::new()
47    }
48}
49
50impl LlmTool for TellUserTool {
51    fn run(&self, args: &HashMap<String, Value>) -> Result<Value> {
52        let message = args.get("message").and_then(|v| v.as_str()).unwrap_or("");
53
54        println!("\n\n\nMESSAGE FROM ASSISTANT:\n{}", message);
55
56        Ok(json!("Message delivered to user."))
57    }
58
59    fn descriptor(&self) -> ToolDescriptor {
60        ToolDescriptor {
61            r#type: "function".to_string(),
62            function: FunctionDescriptor {
63                name: "tell_user".to_string(),
64                description: "Display a message to the user without expecting a response. Use this to send important intermediate information to the user as you work on completing their request.".to_string(),
65                parameters: json!({
66                    "type": "object",
67                    "properties": {
68                        "message": {
69                            "type": "string",
70                            "description": "The important message you want to display to the user."
71                        }
72                    },
73                    "required": ["message"]
74                }),
75            },
76        }
77    }
78    fn clone_box(&self) -> Box<dyn LlmTool> {
79        Box::new(self.clone())
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86
87    #[test]
88    fn test_descriptor() {
89        let tool = TellUserTool::new();
90        let descriptor = tool.descriptor();
91
92        assert_eq!(descriptor.r#type, "function");
93        assert_eq!(descriptor.function.name, "tell_user");
94        assert!(descriptor.function.description.contains("Display a message to the user"));
95
96        // Verify parameters structure
97        let params = &descriptor.function.parameters;
98        assert_eq!(params["type"], "object");
99        assert!(params["properties"]["message"].is_object());
100        assert_eq!(params["properties"]["message"]["type"], "string");
101        assert!(params["required"].as_array().unwrap().contains(&json!("message")));
102    }
103
104    #[test]
105    fn test_run_with_message() {
106        let tool = TellUserTool::new();
107        let mut args = HashMap::new();
108        args.insert("message".to_string(), json!("This is an important update"));
109
110        let result = tool.run(&args).unwrap();
111
112        assert_eq!(result, json!("Message delivered to user."));
113    }
114
115    #[test]
116    fn test_run_without_message() {
117        let tool = TellUserTool::new();
118        let args = HashMap::new();
119
120        let result = tool.run(&args).unwrap();
121
122        assert_eq!(result, json!("Message delivered to user."));
123    }
124
125    #[test]
126    fn test_tool_matches() {
127        let tool = TellUserTool::new();
128        assert!(tool.matches("tell_user"));
129        assert!(!tool.matches("other_tool"));
130    }
131
132    #[test]
133    fn test_multiline_message() {
134        let tool = TellUserTool::new();
135        let mut args = HashMap::new();
136        args.insert("message".to_string(), json!("Line 1\nLine 2\nLine 3"));
137
138        let result = tool.run(&args).unwrap();
139
140        assert_eq!(result, json!("Message delivered to user."));
141    }
142
143    #[test]
144    fn test_default_implementation() {
145        let tool = TellUserTool;
146        let descriptor = tool.descriptor();
147
148        assert_eq!(descriptor.function.name, "tell_user");
149    }
150}