Skip to main content

claude_rust_tools/infrastructure/
task_manager.rs

1use std::sync::Arc;
2use std::sync::atomic::{AtomicU64, Ordering};
3
4use claude_rust_errors::{AppError, AppResult};
5use serde_json::Value;
6
7#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
8pub struct TaskInfo {
9    pub id: String,
10    pub subject: String,
11    pub description: String,
12    pub status: TaskStatus,
13    pub owner: Option<String>,
14    pub blocked_by: Vec<String>,
15    pub metadata: Value,
16}
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
19#[serde(rename_all = "snake_case")]
20pub enum TaskStatus {
21    Pending,
22    InProgress,
23    Completed,
24    Deleted,
25}
26
27impl std::fmt::Display for TaskStatus {
28    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29        match self {
30            Self::Pending => write!(f, "pending"),
31            Self::InProgress => write!(f, "in_progress"),
32            Self::Completed => write!(f, "completed"),
33            Self::Deleted => write!(f, "deleted"),
34        }
35    }
36}
37
38#[async_trait::async_trait]
39pub trait TaskManager: Send + Sync {
40    async fn create(&self, subject: &str, description: &str) -> AppResult<TaskInfo>;
41    async fn get(&self, task_id: &str) -> AppResult<TaskInfo>;
42    async fn list(&self) -> AppResult<Vec<TaskInfo>>;
43    async fn update(&self, task_id: &str, updates: Value) -> AppResult<TaskInfo>;
44    async fn stop(&self, task_id: &str) -> AppResult<()>;
45    async fn output(&self, task_id: &str) -> AppResult<String>;
46}
47
48pub struct InMemoryTaskManager {
49    tasks: tokio::sync::RwLock<Vec<TaskInfo>>,
50    next_id: AtomicU64,
51}
52
53impl InMemoryTaskManager {
54    pub fn new() -> Arc<Self> {
55        Arc::new(Self {
56            tasks: tokio::sync::RwLock::new(Vec::new()),
57            next_id: AtomicU64::new(1),
58        })
59    }
60}
61
62#[async_trait::async_trait]
63impl TaskManager for InMemoryTaskManager {
64    async fn create(&self, subject: &str, description: &str) -> AppResult<TaskInfo> {
65        let id = self.next_id.fetch_add(1, Ordering::SeqCst);
66        let task = TaskInfo {
67            id: id.to_string(),
68            subject: subject.to_string(),
69            description: description.to_string(),
70            status: TaskStatus::Pending,
71            owner: None,
72            blocked_by: Vec::new(),
73            metadata: Value::Null,
74        };
75        self.tasks.write().await.push(task.clone());
76        Ok(task)
77    }
78
79    async fn get(&self, task_id: &str) -> AppResult<TaskInfo> {
80        self.tasks
81            .read()
82            .await
83            .iter()
84            .find(|t| t.id == task_id)
85            .cloned()
86            .ok_or_else(|| AppError::Tool(format!("task not found: {task_id}")))
87    }
88
89    async fn list(&self) -> AppResult<Vec<TaskInfo>> {
90        let tasks = self.tasks.read().await;
91        Ok(tasks
92            .iter()
93            .filter(|t| t.status != TaskStatus::Deleted)
94            .cloned()
95            .collect())
96    }
97
98    async fn update(&self, task_id: &str, updates: Value) -> AppResult<TaskInfo> {
99        let mut tasks = self.tasks.write().await;
100        let task = tasks
101            .iter_mut()
102            .find(|t| t.id == task_id)
103            .ok_or_else(|| AppError::Tool(format!("task not found: {task_id}")))?;
104
105        if let Some(s) = updates.get("status").and_then(|v| v.as_str()) {
106            task.status = match s {
107                "pending" => TaskStatus::Pending,
108                "in_progress" => TaskStatus::InProgress,
109                "completed" => TaskStatus::Completed,
110                "deleted" => TaskStatus::Deleted,
111                other => return Err(AppError::Tool(format!("invalid status: {other}"))),
112            };
113        }
114        if let Some(s) = updates.get("subject").and_then(|v| v.as_str()) {
115            task.subject = s.to_string();
116        }
117        if let Some(s) = updates.get("description").and_then(|v| v.as_str()) {
118            task.description = s.to_string();
119        }
120        if let Some(s) = updates.get("owner").and_then(|v| v.as_str()) {
121            task.owner = Some(s.to_string());
122        }
123        if let Some(m) = updates.get("metadata") {
124            task.metadata = m.clone();
125        }
126
127        Ok(task.clone())
128    }
129
130    async fn stop(&self, task_id: &str) -> AppResult<()> {
131        let mut tasks = self.tasks.write().await;
132        let task = tasks
133            .iter_mut()
134            .find(|t| t.id == task_id)
135            .ok_or_else(|| AppError::Tool(format!("task not found: {task_id}")))?;
136        task.status = TaskStatus::Deleted;
137        Ok(())
138    }
139
140    async fn output(&self, task_id: &str) -> AppResult<String> {
141        // Verify the task exists
142        self.tasks
143            .read()
144            .await
145            .iter()
146            .find(|t| t.id == task_id)
147            .ok_or_else(|| AppError::Tool(format!("task not found: {task_id}")))?;
148        // In-memory implementation has no subprocess output
149        Ok(String::new())
150    }
151}