Skip to main content

synaptic_lark/tools/
task.rs

1use async_trait::async_trait;
2use serde_json::{json, Value};
3use synaptic_core::{SynapticError, Tool};
4
5use crate::{api::task::TaskApi, LarkConfig};
6
7/// Create and manage Feishu/Lark Tasks as an Agent tool.
8///
9/// # Actions
10///
11/// | Action     | Description                                    |
12/// |------------|------------------------------------------------|
13/// | `list`     | List all tasks (paginated)                     |
14/// | `get`      | Get details of a specific task                 |
15/// | `create`   | Create a new task                              |
16/// | `update`   | Update an existing task                        |
17/// | `complete` | Mark a task as complete                        |
18/// | `delete`   | Delete a task                                  |
19pub struct LarkTaskTool {
20    api: TaskApi,
21}
22
23impl LarkTaskTool {
24    /// Create a new task tool.
25    pub fn new(config: LarkConfig) -> Self {
26        Self {
27            api: TaskApi::new(config),
28        }
29    }
30}
31
32#[async_trait]
33impl Tool for LarkTaskTool {
34    fn name(&self) -> &'static str {
35        "lark_task"
36    }
37
38    fn description(&self) -> &'static str {
39        "Create and manage Feishu/Lark Tasks. \
40         Use action='list' to list tasks; \
41         action='get' to get a task by GUID; \
42         action='create' to create a new task; \
43         action='update' to update task fields; \
44         action='complete' to mark a task as complete; \
45         action='delete' to delete a task."
46    }
47
48    fn parameters(&self) -> Option<Value> {
49        Some(json!({
50            "type": "object",
51            "properties": {
52                "action": {
53                    "type": "string",
54                    "description": "Operation: list | get | create | update | complete | delete",
55                    "enum": ["list", "get", "create", "update", "complete", "delete"]
56                },
57                "task_guid": {
58                    "type": "string",
59                    "description": "Task GUID — required for get, update, complete, delete"
60                },
61                "summary": {
62                    "type": "string",
63                    "description": "For 'create': task title (required); for 'update': new title"
64                },
65                "description": {
66                    "type": "string",
67                    "description": "For 'create'/'update': task description"
68                },
69                "due_timestamp": {
70                    "type": "string",
71                    "description": "For 'create'/'update': due date as Unix timestamp string (seconds)"
72                },
73                "page_token": {
74                    "type": "string",
75                    "description": "For 'list': pagination token from previous response"
76                }
77            },
78            "required": ["action"]
79        }))
80    }
81
82    async fn call(&self, args: Value) -> Result<Value, SynapticError> {
83        let action = args["action"]
84            .as_str()
85            .ok_or_else(|| SynapticError::Tool("missing 'action'".to_string()))?;
86
87        match action {
88            "list" => {
89                let page_token = args["page_token"].as_str();
90                let (tasks, next_token) = self.api.list_tasks(page_token).await?;
91                let mut result = json!({ "tasks": tasks });
92                if let Some(t) = next_token {
93                    result["next_page_token"] = json!(t);
94                }
95                Ok(result)
96            }
97
98            "get" => {
99                let task_guid = args["task_guid"]
100                    .as_str()
101                    .ok_or_else(|| SynapticError::Tool("missing 'task_guid'".to_string()))?;
102                let task = self.api.get_task(task_guid).await?;
103                Ok(json!({ "task": task }))
104            }
105
106            "create" => {
107                let summary = args["summary"]
108                    .as_str()
109                    .ok_or_else(|| SynapticError::Tool("missing 'summary'".to_string()))?;
110                let due_timestamp = args["due_timestamp"].as_str();
111                let description = args["description"].as_str();
112                let task_guid = self
113                    .api
114                    .create_task(summary, due_timestamp, description)
115                    .await?;
116                Ok(json!({ "task_guid": task_guid }))
117            }
118
119            "update" => {
120                let task_guid = args["task_guid"]
121                    .as_str()
122                    .ok_or_else(|| SynapticError::Tool("missing 'task_guid'".to_string()))?;
123                let mut fields = json!({});
124                let mut update_fields: Vec<String> = Vec::new();
125                if let Some(s) = args["summary"].as_str() {
126                    fields["summary"] = json!(s);
127                    update_fields.push("summary".to_string());
128                }
129                if let Some(d) = args["description"].as_str() {
130                    fields["description"] = json!(d);
131                    update_fields.push("description".to_string());
132                }
133                if let Some(ts) = args["due_timestamp"].as_str() {
134                    fields["due"] = json!({ "timestamp": ts });
135                    update_fields.push("due".to_string());
136                }
137                self.api
138                    .update_task(task_guid, fields, update_fields)
139                    .await?;
140                Ok(json!({ "task_guid": task_guid, "status": "updated" }))
141            }
142
143            "complete" => {
144                let task_guid = args["task_guid"]
145                    .as_str()
146                    .ok_or_else(|| SynapticError::Tool("missing 'task_guid'".to_string()))?;
147                self.api.complete_task(task_guid).await?;
148                Ok(json!({ "task_guid": task_guid, "status": "completed" }))
149            }
150
151            "delete" => {
152                let task_guid = args["task_guid"]
153                    .as_str()
154                    .ok_or_else(|| SynapticError::Tool("missing 'task_guid'".to_string()))?;
155                self.api.delete_task(task_guid).await?;
156                Ok(json!({ "task_guid": task_guid, "status": "deleted" }))
157            }
158
159            other => Err(SynapticError::Tool(format!(
160                "unknown action '{other}': expected list | get | create | update | complete | delete"
161            ))),
162        }
163    }
164}