use std::path::PathBuf;
use super::types::{ExecutionMode, SubagentDefinition, SubagentKind};
pub struct SubagentBuilder {
definition: SubagentDefinition,
}
impl SubagentBuilder {
pub fn new(name: impl Into<String>) -> Self {
Self {
definition: SubagentDefinition {
name: name.into(),
description: String::new(),
kind: SubagentKind::BuiltIn,
execution_mode: ExecutionMode::Sync,
model: None,
system_prompt: None,
tool_filter: None,
max_iterations: None,
token_limit: None,
inherit_history: None,
inherit_memory: false,
timeout_secs: 0,
can_delegate: false,
tags: Vec::new(),
},
}
}
pub fn description(mut self, desc: impl Into<String>) -> Self {
self.definition.description = desc.into();
self
}
pub fn kind(mut self, kind: SubagentKind) -> Self {
self.definition.kind = kind;
self
}
pub fn custom(mut self, path: impl Into<PathBuf>) -> Self {
self.definition.kind = SubagentKind::Custom { path: path.into() };
self
}
pub fn plugin(mut self, source: impl Into<String>) -> Self {
self.definition.kind = SubagentKind::Plugin {
source: source.into(),
};
self
}
pub fn sync_mode(mut self) -> Self {
self.definition.execution_mode = ExecutionMode::Sync;
self
}
pub fn fork_mode(mut self) -> Self {
self.definition.execution_mode = ExecutionMode::Fork;
self.definition.inherit_history = Some(10);
self.definition.inherit_memory = true;
self
}
pub fn teammate_mode(mut self) -> Self {
self.definition.execution_mode = ExecutionMode::Teammate;
self
}
pub fn model(mut self, model: impl Into<String>) -> Self {
self.definition.model = Some(model.into());
self
}
pub fn system_prompt(mut self, prompt: impl Into<String>) -> Self {
self.definition.system_prompt = Some(prompt.into());
self
}
pub fn tools(mut self, tools: Vec<impl Into<String>>) -> Self {
self.definition.tool_filter = Some(tools.into_iter().map(Into::into).collect());
self
}
pub fn max_iterations(mut self, max: usize) -> Self {
self.definition.max_iterations = Some(max);
self
}
pub fn token_limit(mut self, limit: usize) -> Self {
self.definition.token_limit = Some(limit);
self
}
pub fn inherit_history(mut self, count: usize) -> Self {
self.definition.inherit_history = Some(count);
self
}
pub fn inherit_memory(mut self) -> Self {
self.definition.inherit_memory = true;
self
}
pub fn timeout(mut self, secs: u64) -> Self {
self.definition.timeout_secs = secs;
self
}
pub fn can_delegate(mut self) -> Self {
self.definition.can_delegate = true;
self
}
pub fn tag(mut self, tag: impl Into<String>) -> Self {
self.definition.tags.push(tag.into());
self
}
pub fn tags(mut self, tags: Vec<impl Into<String>>) -> Self {
self.definition
.tags
.extend(tags.into_iter().map(Into::into));
self
}
pub fn build(self) -> SubagentDefinition {
let mut def = self.definition;
if def.description.is_empty() {
def.description = format!("Subagent '{}'", def.name);
}
def
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_builder_sync() {
let def = SubagentBuilder::new("worker")
.description("Does work")
.sync_mode()
.timeout(60)
.build();
assert_eq!(def.name, "worker");
assert_eq!(def.execution_mode, ExecutionMode::Sync);
assert_eq!(def.timeout_secs, 60);
assert!(def.inherit_history.is_none());
}
#[test]
fn test_builder_fork() {
let def = SubagentBuilder::new("researcher")
.description("Researches")
.fork_mode()
.model("qwen3")
.system_prompt("You are a researcher")
.tools(vec!["search", "read"])
.inherit_history(10)
.timeout(120)
.tag("research")
.can_delegate()
.build();
assert_eq!(def.execution_mode, ExecutionMode::Fork);
assert_eq!(def.model.as_deref(), Some("qwen3"));
assert_eq!(def.inherit_history, Some(10));
assert!(def.can_delegate);
assert_eq!(def.tags, vec!["research"]);
assert_eq!(
def.tool_filter.as_deref(),
Some(["search".to_string(), "read".to_string()].as_slice())
);
}
#[test]
fn test_builder_teammate() {
let def = SubagentBuilder::new("tm").teammate_mode().build();
assert_eq!(def.execution_mode, ExecutionMode::Teammate);
assert!(def.inherit_history.is_none());
}
#[test]
fn test_builder_auto_description() {
let def = SubagentBuilder::new("auto").build();
assert!(def.description.contains("auto"));
}
#[test]
fn test_builder_custom_kind() {
let def = SubagentBuilder::new("custom")
.custom("/path/to/agent.md")
.build();
assert!(matches!(def.kind, SubagentKind::Custom { .. }));
}
#[test]
fn test_builder_plugin_kind() {
let def = SubagentBuilder::new("plugin")
.plugin("remote://registry")
.build();
assert!(matches!(def.kind, SubagentKind::Plugin { .. }));
}
}