telos_agent/tools/builtin/
team_delete.rs1use async_trait::async_trait;
7use serde_json::{Value, json};
8
9use crate::error::AgentError;
10use crate::orchestration::team::{self, has_active_members, load_team_config};
11use crate::tools::api::{Tool, ToolContext, ToolDefinition, ToolOutput};
12
13use super::team_create::SharedTeamContext;
14
15pub struct TeamDeleteTool {
17 team_ctx: SharedTeamContext,
18}
19
20impl TeamDeleteTool {
21 pub fn new(team_ctx: SharedTeamContext) -> Self {
22 Self { team_ctx }
23 }
24}
25
26#[async_trait]
27impl Tool for TeamDeleteTool {
28 fn definition(&self) -> ToolDefinition {
29 ToolDefinition {
30 name: "TeamDelete".into(),
31 description: "Clean up the current collaboration team. Removes team config and \
32shared task directory. Fails if teammates are still active — ask them to finish \
33or stop them first. Use this when the team's work is complete."
34 .into(),
35 input_schema: json!({"type": "object", "properties": {}, "additionalProperties": false}),
36 }
37 }
38
39 fn prompt_text(&self) -> Option<&'static str> {
40 Some(TEAM_DELETE_PROMPT)
41 }
42
43 async fn invoke(
44 &self,
45 _arguments: Value,
46 _context: ToolContext,
47 ) -> Result<ToolOutput, AgentError> {
48 let team_name = {
49 let ctx = self.team_ctx.lock().unwrap();
50 match &ctx.team_name {
51 Some(name) => name.clone(),
52 None => {
53 return Ok(ToolOutput::json(json!({
54 "success": true,
55 "message": "No active team to clean up."
56 })));
57 }
58 }
59 };
60
61 match load_team_config(&team_name) {
63 Ok(config) => {
64 if has_active_members(&config) {
65 let active: Vec<_> = config
66 .members
67 .iter()
68 .filter(|m| m.is_active && m.agent_id != config.lead_agent_id)
69 .map(|m| m.name.clone())
70 .collect();
71 return Err(AgentError::Validation(format!(
72 "Cannot clean up team with {} active member(s): {}. \
73Stop or wait for them to finish, then retry.",
74 active.len(),
75 active.join(", ")
76 )));
77 }
78 }
79 Err(_) => {
80 }
82 }
83
84 team::cleanup_team(&team_name)?;
85
86 {
87 let mut ctx = self.team_ctx.lock().unwrap();
88 ctx.team_name = None;
89 ctx.lead_agent_id = None;
90 }
91
92 Ok(ToolOutput::json(json!({
93 "success": true,
94 "team_name": team_name,
95 "message": format!("Team '{team_name}' cleaned up successfully.")
96 })))
97 }
98
99 fn is_concurrency_safe(&self, _: &Value) -> bool {
100 true
101 }
102}
103
104const TEAM_DELETE_PROMPT: &str = r#"TeamDelete cleans up a completed collaboration team.
105
106Use when all tasks are done or the user signals completion. Fails if active teammates remain — stop them first. Removes team config and shared task directory."#;