Skip to main content

agent_base/tool/
auto_continue.rs

1use async_trait::async_trait;
2use serde_json::{Value, json};
3
4use crate::tool::{Content, Tool, ToolContext};
5use crate::types::AgentResult;
6
7/// Pure orchestration signal tool with zero domain dependency.
8///
9/// When the agent encounters an error in the previous tool execution and has
10/// found a solution or retry strategy, or when it needs to execute multiple
11/// long tasks in sequence, it can call this tool to request the system to
12/// automatically continue to the next turn without waiting for user reply.
13#[derive(Clone, Debug, Default)]
14pub struct AutoContinueTool;
15
16impl AutoContinueTool {
17    pub fn new() -> Self {
18        Self
19    }
20}
21
22#[async_trait]
23impl Tool for AutoContinueTool {
24    fn name(&self) -> &'static str {
25        "request_auto_continue"
26    }
27
28    fn description(&self) -> &'static str {
29        "When you encounter an error in the previous tool execution and have found a solution or retry strategy, or when you need to execute multiple long tasks in sequence, call this tool to request the system to automatically continue to the next turn instead of stopping and waiting for user reply. This tool is only for making the request; you still need to describe your solution in the prompt."
30    }
31
32    fn schema(&self) -> Value {
33        json!({
34            "type": "object",
35            "properties": {
36                "reason": {
37                    "type": "string",
38                    "description": "A brief reason for requesting auto-continue, e.g. 'network error, trying alternative source'"
39                }
40            },
41            "required": ["reason"]
42        })
43    }
44
45    fn metadata(&self) -> crate::tool::ToolMetadata {
46        crate::tool::ToolMetadata {
47            name: self.name().to_string(),
48            description:
49                "Request automatic continuation to the next turn without waiting for user input."
50                    .to_string(),
51            origin: "agent-base".to_string(),
52            version: env!("CARGO_PKG_VERSION").to_string(),
53            requirements: vec![],
54        }
55    }
56
57    async fn call(&self, args: &Value, _ctx: &ToolContext) -> AgentResult<Vec<Content>> {
58        let reason = args
59            .get("reason")
60            .and_then(Value::as_str)
61            .unwrap_or("no reason provided");
62
63        Ok(vec![Content::text(format!(
64            "Auto-continue request received. Reason: {}",
65            reason
66        ))])
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73    use crate::tool::content_text;
74    use serde_json::json;
75
76    #[test]
77    fn name_is_stable() {
78        assert_eq!(AutoContinueTool::new().name(), "request_auto_continue");
79    }
80
81    #[test]
82    fn schema_requires_reason() {
83        let schema = AutoContinueTool::new().schema();
84        assert_eq!(schema["type"], "object");
85        assert!(schema["properties"]["reason"].is_object());
86        assert_eq!(schema["required"], json!(["reason"]));
87    }
88
89    #[test]
90    fn metadata_origin_is_agent_base() {
91        let m = AutoContinueTool::new().metadata();
92        assert_eq!(m.origin, "agent-base");
93        assert_eq!(m.name, "request_auto_continue");
94    }
95
96    #[tokio::test]
97    async fn call_with_reason_echoes_reason() {
98        let tool = AutoContinueTool::new();
99        let ctx = ToolContext::for_test();
100        let out = tool
101            .call(&json!({"reason": "retry after network error"}), &ctx)
102            .await
103            .unwrap();
104        assert!(content_text(&out).contains("retry after network error"));
105    }
106
107    #[tokio::test]
108    async fn call_without_reason_uses_default() {
109        let tool = AutoContinueTool::new();
110        let ctx = ToolContext::for_test();
111        let out = tool.call(&json!({}), &ctx).await.unwrap();
112        assert!(content_text(&out).contains("no reason provided"));
113    }
114}