Skip to main content

cersei_tools/
sleep.rs

1//! Sleep tool: delay execution for a specified duration.
2
3use super::*;
4use serde::Deserialize;
5
6pub struct SleepTool;
7
8#[async_trait]
9impl Tool for SleepTool {
10    fn name(&self) -> &str {
11        "Sleep"
12    }
13    fn description(&self) -> &str {
14        "Pause execution for the specified number of milliseconds."
15    }
16    fn permission_level(&self) -> PermissionLevel {
17        PermissionLevel::None
18    }
19
20    fn input_schema(&self) -> Value {
21        serde_json::json!({
22            "type": "object",
23            "properties": {
24                "duration_ms": { "type": "integer", "description": "Duration to sleep in milliseconds (max 60000)" }
25            },
26            "required": ["duration_ms"]
27        })
28    }
29
30    async fn execute(&self, input: Value, _ctx: &ToolContext) -> ToolResult {
31        #[derive(Deserialize)]
32        struct Input {
33            duration_ms: u64,
34        }
35
36        let input: Input = match serde_json::from_value(input) {
37            Ok(i) => i,
38            Err(e) => return ToolResult::error(format!("Invalid input: {}", e)),
39        };
40
41        let duration = input.duration_ms.min(60_000);
42        tokio::time::sleep(std::time::Duration::from_millis(duration)).await;
43        ToolResult::success(format!("Slept for {}ms", duration))
44    }
45}
46
47#[cfg(test)]
48mod tests {
49    use super::*;
50    use crate::permissions::AllowAll;
51    use std::sync::Arc;
52
53    fn test_ctx() -> ToolContext {
54        ToolContext {
55            working_dir: std::env::temp_dir(),
56            session_id: "test".into(),
57            permissions: Arc::new(AllowAll),
58            cost_tracker: Arc::new(CostTracker::new()),
59            mcp_manager: None,
60            extensions: Extensions::default(),
61        }
62    }
63
64    #[tokio::test]
65    async fn test_sleep_100ms() {
66        let tool = SleepTool;
67        let start = std::time::Instant::now();
68        let result = tool
69            .execute(serde_json::json!({"duration_ms": 100}), &test_ctx())
70            .await;
71        assert!(!result.is_error);
72        assert!(start.elapsed().as_millis() >= 90);
73    }
74
75    #[tokio::test]
76    async fn test_sleep_capped() {
77        let tool = SleepTool;
78        // Should cap at 60000ms, not actually sleep that long in test
79        let result = tool
80            .execute(serde_json::json!({"duration_ms": 1}), &test_ctx())
81            .await;
82        assert!(result.content.contains("1ms"));
83    }
84}