1use chrono::{DateTime, Utc};
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9use uuid::Uuid;
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct SubTask {
14 pub id: String,
16
17 pub name: String,
19
20 pub instruction: String,
22
23 pub specialty: Option<String>,
25
26 pub dependencies: Vec<String>,
28
29 pub priority: i32,
31
32 pub max_steps: usize,
34
35 pub context: SubTaskContext,
37
38 pub status: SubTaskStatus,
40
41 pub assigned_agent: Option<String>,
43
44 pub created_at: DateTime<Utc>,
46
47 pub completed_at: Option<DateTime<Utc>>,
49
50 pub stage: usize,
52}
53
54impl SubTask {
55 pub fn new(name: impl Into<String>, instruction: impl Into<String>) -> Self {
57 Self {
58 id: Uuid::new_v4().to_string(),
59 name: name.into(),
60 instruction: instruction.into(),
61 specialty: None,
62 dependencies: Vec::new(),
63 priority: 0,
64 max_steps: 100,
65 context: SubTaskContext::default(),
66 status: SubTaskStatus::Pending,
67 assigned_agent: None,
68 created_at: Utc::now(),
69 completed_at: None,
70 stage: 0,
71 }
72 }
73
74 pub fn with_specialty(mut self, specialty: impl Into<String>) -> Self {
76 self.specialty = Some(specialty.into());
77 self
78 }
79
80 pub fn with_dependencies(mut self, deps: Vec<String>) -> Self {
82 self.dependencies = deps;
83 self
84 }
85
86 pub fn with_priority(mut self, priority: i32) -> Self {
88 self.priority = priority;
89 self
90 }
91
92 pub fn with_max_steps(mut self, max_steps: usize) -> Self {
94 self.max_steps = max_steps;
95 self
96 }
97
98 pub fn with_context(mut self, context: SubTaskContext) -> Self {
100 self.context = context;
101 self
102 }
103
104 pub fn can_run(&self, completed: &[String]) -> bool {
106 self.dependencies.iter().all(|dep| completed.contains(dep))
107 }
108
109 pub fn start(&mut self, agent_id: &str) {
111 self.status = SubTaskStatus::Running;
112 self.assigned_agent = Some(agent_id.to_string());
113 }
114
115 pub fn complete(&mut self, success: bool) {
117 self.status = if success {
118 SubTaskStatus::Completed
119 } else {
120 SubTaskStatus::Failed
121 };
122 self.completed_at = Some(Utc::now());
123 }
124}
125
126#[derive(Debug, Clone, Default, Serialize, Deserialize)]
128pub struct SubTaskContext {
129 pub parent_task: Option<String>,
131
132 pub dependency_results: HashMap<String, String>,
134
135 pub shared_resources: Vec<String>,
137
138 pub metadata: HashMap<String, serde_json::Value>,
140}
141
142#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
144#[serde(rename_all = "snake_case")]
145pub enum SubTaskStatus {
146 Pending,
148
149 Blocked,
151
152 Running,
154
155 Completed,
157
158 Failed,
160
161 Cancelled,
163
164 TimedOut,
166}
167
168#[derive(Debug, Clone, Serialize, Deserialize)]
170pub struct SubAgent {
171 pub id: String,
173
174 pub name: String,
176
177 pub specialty: String,
179
180 pub subtask_id: String,
182
183 pub status: SubAgentStatus,
185
186 pub steps: usize,
188
189 pub tool_calls: Vec<ToolCallRecord>,
191
192 pub output: String,
194
195 pub model: String,
197
198 pub provider: String,
200
201 pub created_at: DateTime<Utc>,
203
204 pub last_active: DateTime<Utc>,
206}
207
208impl SubAgent {
209 pub fn new(
211 name: impl Into<String>,
212 specialty: impl Into<String>,
213 subtask_id: impl Into<String>,
214 model: impl Into<String>,
215 provider: impl Into<String>,
216 ) -> Self {
217 let now = Utc::now();
218 Self {
219 id: Uuid::new_v4().to_string(),
220 name: name.into(),
221 specialty: specialty.into(),
222 subtask_id: subtask_id.into(),
223 status: SubAgentStatus::Initializing,
224 steps: 0,
225 tool_calls: Vec::new(),
226 output: String::new(),
227 model: model.into(),
228 provider: provider.into(),
229 created_at: now,
230 last_active: now,
231 }
232 }
233
234 pub fn record_tool_call(&mut self, name: &str, success: bool) {
236 self.tool_calls.push(ToolCallRecord {
237 name: name.to_string(),
238 timestamp: Utc::now(),
239 success,
240 });
241 self.steps += 1;
242 self.last_active = Utc::now();
243 }
244
245 pub fn append_output(&mut self, text: &str) {
247 self.output.push_str(text);
248 self.last_active = Utc::now();
249 }
250
251 pub fn set_status(&mut self, status: SubAgentStatus) {
253 self.status = status;
254 self.last_active = Utc::now();
255 }
256}
257
258#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
260#[serde(rename_all = "snake_case")]
261pub enum SubAgentStatus {
262 Initializing,
264
265 Working,
267
268 Waiting,
270
271 Completed,
273
274 Failed,
276
277 Terminated,
279}
280
281#[derive(Debug, Clone, Serialize, Deserialize)]
283pub struct ToolCallRecord {
284 pub name: String,
285 pub timestamp: DateTime<Utc>,
286 pub success: bool,
287}
288
289#[derive(Debug, Clone, Serialize, Deserialize)]
291pub struct SubTaskResult {
292 pub subtask_id: String,
294
295 pub subagent_id: String,
297
298 pub success: bool,
300
301 pub result: String,
303
304 pub steps: usize,
306
307 pub tool_calls: usize,
309
310 pub execution_time_ms: u64,
312
313 pub error: Option<String>,
315
316 pub artifacts: Vec<String>,
318}