stakpak_shared/models/
subagent.rs1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3use std::path::Path;
4
5#[derive(Debug, Clone, Deserialize, Serialize)]
6pub struct WardenConfig {
7 pub enabled: bool,
8 #[serde(default)]
9 pub volumes: Vec<String>,
10}
11
12#[derive(Debug, Clone, Deserialize, Serialize)]
13pub struct SubagentConfig {
14 pub description: String,
15 pub max_steps: usize,
16 pub allowed_tools: Vec<String>,
17 #[serde(default)]
18 pub warden: Option<WardenConfig>,
19}
20
21#[derive(Debug, Clone, Deserialize, Serialize)]
22pub struct SubagentConfigs {
23 pub subagents: HashMap<String, SubagentConfig>,
24}
25
26impl SubagentConfigs {
27 pub fn load_from_file<P: AsRef<Path>>(path: P) -> Result<Self, Box<dyn std::error::Error>> {
28 let content = std::fs::read_to_string(path)?;
29 Self::load_from_str(&content)
30 }
31
32 pub fn load_from_str(content: &str) -> Result<Self, Box<dyn std::error::Error>> {
33 let config: SubagentConfigs = toml::from_str(content)?;
34 Ok(config)
35 }
36
37 pub fn get_available_types(&self) -> Vec<String> {
38 self.subagents.keys().cloned().collect()
39 }
40
41 pub fn get_config(&self, subagent_type: &str) -> Option<&SubagentConfig> {
42 self.subagents.get(subagent_type)
43 }
44
45 pub fn format_for_context(&self) -> String {
46 if self.subagents.is_empty() {
47 "# No Subagents Available".to_string()
48 } else {
49 let subagents_text = self
50 .subagents
51 .iter()
52 .map(|(name, config)| {
53 format!(
54 " - Name: {}\n Description: {}\n Tools: {}",
55 name,
56 config.description,
57 config.allowed_tools.join(", ")
58 )
59 })
60 .collect::<Vec<String>>()
61 .join("\n");
62
63 format!("# Available Subagents:\n\n{}", subagents_text)
64 }
65 }
66}