ai_agent/tools/remote_trigger/
mod.rs1use crate::error::AgentError;
3use crate::types::*;
4
5pub const REMOTE_TRIGGER_TOOL_NAME: &str = "RemoteTrigger";
6
7pub const DESCRIPTION: &str =
8 "Manage scheduled remote Claude Code agents (triggers) via the claude.ai CCR API";
9
10pub struct RemoteTriggerTool;
12
13impl RemoteTriggerTool {
14 pub fn new() -> Self {
15 Self
16 }
17
18 pub fn name(&self) -> &str {
19 REMOTE_TRIGGER_TOOL_NAME
20 }
21
22 pub fn description(&self) -> &str {
23 DESCRIPTION
24 }
25
26 pub fn user_facing_name(&self, _input: Option<&serde_json::Value>) -> String {
27 "RemoteTrigger".to_string()
28 }
29
30 pub fn get_tool_use_summary(&self, input: Option<&serde_json::Value>) -> Option<String> {
31 input.and_then(|inp| inp["action"].as_str().map(String::from))
32 }
33
34 pub fn render_tool_result_message(
35 &self,
36 content: &serde_json::Value,
37 ) -> Option<String> {
38 content["content"].as_str().map(|s| s.to_string())
39 }
40
41 pub fn input_schema(&self) -> ToolInputSchema {
42 ToolInputSchema {
43 schema_type: "object".to_string(),
44 properties: serde_json::json!({
45 "action": {
46 "type": "string",
47 "enum": ["list", "get", "create", "update", "run"],
48 "description": "The action to perform"
49 },
50 "trigger_id": {
51 "type": "string",
52 "description": "Required for get, update, and run"
53 },
54 "body": {
55 "type": "object",
56 "description": "JSON body for create and update"
57 }
58 }),
59 required: Some(vec!["action".to_string()]),
60 }
61 }
62
63 pub async fn execute(
64 &self,
65 input: serde_json::Value,
66 _context: &ToolContext,
67 ) -> Result<ToolResult, AgentError> {
68 let action = input["action"]
69 .as_str()
70 .ok_or_else(|| AgentError::Tool("Missing action parameter".to_string()))?;
71
72 let trigger_id = input["trigger_id"].as_str();
73 let body = input.get("body");
74
75 let base_url = "https://api.claude.ai/v1/code/triggers";
77 let (method, url, request_body) = match action {
78 "list" => ("GET", base_url.to_string(), None),
79 "get" => {
80 let tid = trigger_id.ok_or_else(|| {
81 AgentError::Tool("get action requires trigger_id".to_string())
82 })?;
83 ("GET", format!("{}/{}", base_url, tid), None)
84 }
85 "create" => {
86 let b = body
87 .ok_or_else(|| AgentError::Tool("create action requires body".to_string()))?;
88 ("POST", base_url.to_string(), Some(b.clone()))
89 }
90 "update" => {
91 let tid = trigger_id.ok_or_else(|| {
92 AgentError::Tool("update action requires trigger_id".to_string())
93 })?;
94 let b = body
95 .ok_or_else(|| AgentError::Tool("update action requires body".to_string()))?;
96 ("POST", format!("{}/{}", base_url, tid), Some(b.clone()))
97 }
98 "run" => {
99 let tid = trigger_id.ok_or_else(|| {
100 AgentError::Tool("run action requires trigger_id".to_string())
101 })?;
102 (
103 "POST",
104 format!("{}/run", base_url),
105 Some(serde_json::json!({})),
106 )
107 }
108 _ => return Err(AgentError::Tool(format!("Unknown action: {}", action))),
109 };
110
111 let result = serde_json::json!({
114 "status": 501,
115 "json": {
116 "message": "RemoteTrigger tool requires OAuth authentication with claude.ai. This feature is not available in the current build.",
117 "action": action,
118 "url": url,
119 "method": method
120 }
121 });
122
123 Ok(ToolResult {
124 result_type: "text".to_string(),
125 tool_use_id: "".to_string(),
126 content: serde_json::to_string_pretty(&result).unwrap_or_default(),
127 is_error: None,
128 was_persisted: None,
129 })
130 }
131}
132
133impl Default for RemoteTriggerTool {
134 fn default() -> Self {
135 Self::new()
136 }
137}
138
139#[cfg(test)]
140mod tests {
141 use super::*;
142
143 #[test]
144 fn test_remote_trigger_tool_name() {
145 let tool = RemoteTriggerTool::new();
146 assert_eq!(tool.name(), REMOTE_TRIGGER_TOOL_NAME);
147 }
148
149 #[test]
150 fn test_remote_trigger_tool_schema() {
151 let tool = RemoteTriggerTool::new();
152 let schema = tool.input_schema();
153 assert_eq!(schema.schema_type, "object");
154 assert_eq!(schema.required, Some(vec!["action".to_string()]));
155 }
156}