Skip to main content

tmai_core/agents/
subagent.rs

1use std::fmt;
2
3use serde::{Deserialize, Serialize};
4
5/// Type of subagent (Task tool agent types in Claude Code)
6#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
7pub enum SubagentType {
8    Explore,
9    Plan,
10    Bash,
11    GeneralPurpose,
12    Custom(String),
13}
14
15impl SubagentType {
16    /// Parse subagent type from string
17    pub fn parse(s: &str) -> Self {
18        let lower = s.to_lowercase();
19        match lower.as_str() {
20            "explore" => SubagentType::Explore,
21            "plan" => SubagentType::Plan,
22            "bash" => SubagentType::Bash,
23            "general-purpose" | "generalpurpose" => SubagentType::GeneralPurpose,
24            _ => SubagentType::Custom(s.to_string()),
25        }
26    }
27
28    /// Get display name
29    pub fn display_name(&self) -> &str {
30        match self {
31            SubagentType::Explore => "Explore",
32            SubagentType::Plan => "Plan",
33            SubagentType::Bash => "Bash",
34            SubagentType::GeneralPurpose => "General",
35            SubagentType::Custom(name) => name,
36        }
37    }
38}
39
40impl fmt::Display for SubagentType {
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        write!(f, "{}", self.display_name())
43    }
44}
45
46/// Status of a subagent
47#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
48pub enum SubagentStatus {
49    #[default]
50    Running,
51    Completed,
52    Failed,
53}
54
55/// A subagent spawned by the main agent
56#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct Subagent {
58    /// Unique identifier
59    pub id: String,
60    /// Type of subagent
61    pub subagent_type: SubagentType,
62    /// Description/task
63    pub description: String,
64    /// Current status
65    pub status: SubagentStatus,
66}
67
68impl Subagent {
69    /// Create a new subagent
70    pub fn new(id: String, subagent_type: SubagentType, description: String) -> Self {
71        Self {
72            id,
73            subagent_type,
74            description,
75            status: SubagentStatus::Running,
76        }
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83
84    #[test]
85    fn test_subagent_type_parse() {
86        assert_eq!(SubagentType::parse("Explore"), SubagentType::Explore);
87        assert_eq!(SubagentType::parse("EXPLORE"), SubagentType::Explore);
88        assert_eq!(SubagentType::parse("plan"), SubagentType::Plan);
89        assert_eq!(
90            SubagentType::parse("general-purpose"),
91            SubagentType::GeneralPurpose
92        );
93        assert_eq!(
94            SubagentType::parse("custom-type"),
95            SubagentType::Custom("custom-type".to_string())
96        );
97    }
98}