use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum AgentRole {
General,
Planner,
Explorer,
Builder,
Reviewer,
}
impl AgentRole {
pub fn system_prompt(&self) -> &str {
match self {
Self::General => "You are a helpful coding assistant with access to all tools.",
Self::Planner => "You are a planning agent. Reason carefully and produce structured plans. Do not execute code.",
Self::Explorer => "You are an exploration agent. Read files and search the codebase to answer questions. Do not write or execute.",
Self::Builder => "You are a builder agent. Implement the specified changes using the available tools.",
Self::Reviewer => "You are a code reviewer. Analyze diffs and files to provide actionable feedback. Do not write files.",
}
}
pub fn allowed_tools(&self) -> Vec<&'static str> {
match self {
Self::General | Self::Builder => vec![],
Self::Planner => vec!["read_file", "glob", "grep"],
Self::Explorer => vec!["read_file", "glob", "grep", "fetch_url"],
Self::Reviewer => vec!["read_file", "glob", "grep"],
}
}
}
#[derive(Debug, Clone)]
pub struct AgentDef {
pub id: String,
pub name: String,
pub role: AgentRole,
pub model_override: Option<String>,
}
impl AgentDef {
pub fn new(name: impl Into<String>, role: AgentRole) -> Self {
Self {
id: uuid::Uuid::new_v4().to_string(),
name: name.into(),
role,
model_override: None,
}
}
pub fn with_model(mut self, model: impl Into<String>) -> Self {
self.model_override = Some(model.into());
self
}
pub fn builtins() -> Vec<AgentDef> {
vec![
AgentDef::new("planner", AgentRole::Planner),
AgentDef::new("explorer", AgentRole::Explorer),
AgentDef::new("builder", AgentRole::Builder),
AgentDef::new("reviewer", AgentRole::Reviewer),
]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn planner_has_no_exec_tools() {
let tools = AgentRole::Planner.allowed_tools();
assert!(!tools.contains(&"bash"));
assert!(!tools.contains(&"write_file"));
}
#[test]
fn builder_has_all_tools() {
let tools = AgentRole::Builder.allowed_tools();
assert!(tools.is_empty(), "empty means all tools allowed");
}
#[test]
fn builtins_are_four_agents() {
assert_eq!(AgentDef::builtins().len(), 4);
}
#[test]
fn agent_def_new_has_unique_id() {
let a = AgentDef::new("test", AgentRole::General);
let b = AgentDef::new("test", AgentRole::General);
assert_ne!(a.id, b.id);
}
}