everruns_core/capabilities/
current_time.rs1use super::{Capability, CapabilityStatus};
4use crate::tool_types::ToolHints;
5use crate::tools::{Tool, ToolExecutionResult};
6use async_trait::async_trait;
7use serde_json::Value;
8
9pub struct CurrentTimeCapability;
11
12impl Capability for CurrentTimeCapability {
13 fn id(&self) -> &str {
14 "current_time"
15 }
16
17 fn name(&self) -> &str {
18 "Current Time"
19 }
20
21 fn description(&self) -> &str {
22 "Adds a tool to get the current date and time in various formats and timezones."
23 }
24
25 fn status(&self) -> CapabilityStatus {
26 CapabilityStatus::Available
27 }
28
29 fn icon(&self) -> Option<&str> {
30 Some("clock")
31 }
32
33 fn category(&self) -> Option<&str> {
34 Some("Utilities")
35 }
36
37 fn tools(&self) -> Vec<Box<dyn Tool>> {
38 vec![Box::new(GetCurrentTimeTool)]
39 }
40}
41
42pub struct GetCurrentTimeTool;
48
49#[async_trait]
50impl Tool for GetCurrentTimeTool {
51 fn name(&self) -> &str {
52 "get_current_time"
53 }
54
55 fn display_name(&self) -> Option<&str> {
56 Some("Get Current Time")
57 }
58
59 fn description(&self) -> &str {
60 "Get the current date and time. Can return time in different formats and timezones."
61 }
62
63 fn parameters_schema(&self) -> Value {
64 serde_json::json!({
65 "type": "object",
66 "properties": {
67 "timezone": {
68 "type": "string",
69 "description": "Timezone to return the time in (e.g., 'UTC', 'America/New_York', 'Europe/London'). Defaults to UTC."
70 },
71 "format": {
72 "type": "string",
73 "enum": ["iso8601", "unix", "human"],
74 "description": "Output format: 'iso8601' for ISO 8601 format, 'unix' for Unix timestamp, 'human' for human-readable format. Defaults to 'iso8601'."
75 }
76 },
77 "additionalProperties": false
78 })
79 }
80
81 fn hints(&self) -> ToolHints {
82 ToolHints::default()
83 .with_readonly(true)
84 .with_idempotent(true)
85 }
86
87 async fn execute(&self, arguments: Value) -> ToolExecutionResult {
88 let format = arguments
89 .get("format")
90 .and_then(|v| v.as_str())
91 .unwrap_or("iso8601");
92
93 let _timezone = arguments
94 .get("timezone")
95 .and_then(|v| v.as_str())
96 .unwrap_or("UTC");
97
98 let now = chrono::Utc::now();
101
102 let result = match format {
103 "unix" => serde_json::json!({
104 "timestamp": now.timestamp(),
105 "format": "unix",
106 "timezone": "UTC"
107 }),
108 "human" => serde_json::json!({
109 "datetime": now.format("%A, %B %d, %Y at %H:%M:%S UTC").to_string(),
110 "format": "human",
111 "timezone": "UTC"
112 }),
113 _ => serde_json::json!({
114 "datetime": now.to_rfc3339(),
115 "format": "iso8601",
116 "timezone": "UTC"
117 }),
118 };
119
120 ToolExecutionResult::success(result)
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127 use crate::capabilities::CapabilityRegistry;
128
129 #[test]
130 fn test_capability_metadata() {
131 let cap = CurrentTimeCapability;
132
133 assert_eq!(cap.id(), "current_time");
134 assert_eq!(cap.name(), "Current Time");
135 assert_eq!(cap.icon(), Some("clock"));
136 assert_eq!(cap.category(), Some("Utilities"));
137 assert_eq!(cap.status(), CapabilityStatus::Available);
138 }
139
140 #[test]
141 fn test_capability_has_tools() {
142 let cap = CurrentTimeCapability;
143 let tools = cap.tools();
144
145 assert_eq!(tools.len(), 1);
146 assert_eq!(tools[0].name(), "get_current_time");
147 }
148
149 #[test]
150 fn test_capability_no_system_prompt() {
151 let cap = CurrentTimeCapability;
152 assert!(cap.system_prompt_addition().is_none());
153 }
154
155 #[test]
156 fn test_capability_in_registry() {
157 let registry = CapabilityRegistry::with_builtins();
158 let cap = registry.get("current_time").unwrap();
159
160 assert_eq!(cap.id(), "current_time");
161 assert_eq!(cap.tools().len(), 1);
162 }
163
164 #[tokio::test]
165 async fn test_get_current_time_iso8601() {
166 let tool = GetCurrentTimeTool;
167 let result = tool.execute(serde_json::json!({})).await;
168
169 if let ToolExecutionResult::Success(value) = result {
170 assert!(value.get("datetime").is_some());
171 assert_eq!(value.get("format").unwrap().as_str().unwrap(), "iso8601");
172 assert_eq!(value.get("timezone").unwrap().as_str().unwrap(), "UTC");
173 } else {
174 panic!("Expected success");
175 }
176 }
177
178 #[tokio::test]
179 async fn test_get_current_time_unix() {
180 let tool = GetCurrentTimeTool;
181 let result = tool.execute(serde_json::json!({"format": "unix"})).await;
182
183 if let ToolExecutionResult::Success(value) = result {
184 assert!(value.get("timestamp").is_some());
185 assert_eq!(value.get("format").unwrap().as_str().unwrap(), "unix");
186 } else {
187 panic!("Expected success");
188 }
189 }
190
191 #[tokio::test]
192 async fn test_get_current_time_human() {
193 let tool = GetCurrentTimeTool;
194 let result = tool.execute(serde_json::json!({"format": "human"})).await;
195
196 if let ToolExecutionResult::Success(value) = result {
197 assert!(value.get("datetime").is_some());
198 assert_eq!(value.get("format").unwrap().as_str().unwrap(), "human");
199 let datetime = value.get("datetime").unwrap().as_str().unwrap();
200 assert!(datetime.contains("at"));
201 } else {
202 panic!("Expected success");
203 }
204 }
205}