1//! Agent management and representation.
2//!
3//! This module defines the `Agent` struct, which represents an AI agent,
4//! its configuration, and its associated tools.
56use crate::core::Tool;
7use crate::models::AgentDefinition;
8use anyhow::Result;
9use std::collections::HashMap;
10use std::path::{Path, PathBuf};
1112/// Represents an AI agent, including its definition, tools, and configuration.
13///
14/// An agent is a fundamental concept in this framework, encapsulating the logic
15/// and capabilities needed to perform tasks.
16#[derive(Debug, Clone)]
17pub struct Agent {
18/// A unique name for the agent.
19pub name: String,
2021/// The file system path to the agent's directory.
22pub path: PathBuf,
2324/// The agent's definition, loaded from its `index.yaml` file.
25pub definition: AgentDefinition,
2627/// A list of tools that are specific to this agent.
28pub tools: Vec<Tool>,
2930/// A list of names of shared tools that this agent can use.
31pub shared_tools: Vec<String>,
3233/// A map of variables and their values for this agent.
34pub variables: HashMap<String, String>,
35}
3637impl Agent {
38/// Loads an agent from a specified directory.
39 ///
40 /// This function reads the agent's definition from `index.yaml`, loads its
41 /// agent-specific tools from a `tools` subdirectory, and reads the list of
42 /// shared tools from `tools.txt`.
43pub async fn from_directory<P: AsRef<Path>>(path: P) -> Result<Self> {
44let path = path.as_ref().to_path_buf();
45let name = path
46 .file_name()
47 .ok_or_else(|| anyhow::anyhow!("Invalid agent directory"))?
48.to_string_lossy()
49 .to_string();
5051let index_path = path.join("index.yaml");
52let index_content = tokio::fs::read_to_string(&index_path).await?;
53let definition: AgentDefinition = serde_yaml::from_str(&index_content)?;
5455// Load agent-specific tools from a 'tools' subdirectory
56let mut tools = Vec::new();
57let agent_tools_dir = path.join("tools");
58if agent_tools_dir.is_dir() {
59let mut entries = tokio::fs::read_dir(agent_tools_dir).await?;
60while let Some(entry) = entries.next_entry().await? {
61let tool_path = entry.path();
62if tool_path.is_file() {
63match Tool::from_file(&tool_path).await {
64Ok(tool) => tools.push(tool),
65Err(e) => tracing::warn!(
66"Failed to load agent-specific tool {}: {}",
67 tool_path.display(),
68 e
69 ),
70 }
71 }
72 }
73 }
7475let shared_tools = if path.join("tools.txt").exists() {
76let content = tokio::fs::read_to_string(path.join("tools.txt")).await?;
77 content
78 .lines()
79 .filter(|line| !line.trim().is_empty() && !line.starts_with('#'))
80 .map(|s| s.to_string())
81 .collect()
82 } else {
83 Vec::new()
84 };
8586let mut variables = HashMap::new();
87for var in &definition.variables {
88if let Some(default) = &var.default {
89 variables.insert(var.name.clone(), default.clone());
90 }
91 }
9293Ok(Self {
94 name,
95 path,
96 definition,
97 tools,
98 shared_tools,
99 variables,
100 })
101 }
102103/// Retrieves all tools available to this agent, including its own tools and shared ones.
104 ///
105 /// # Arguments
106 ///
107 /// * `registry` - A reference to the `Registry` where shared tools are stored.
108pub fn get_all_tools<'a>(
109&'a self,
110 registry: &'a crate::core::Registry,
111 ) -> Result<Vec<&'a Tool>> {
112let mut all_tools: Vec<&'a Tool> = self.tools.iter().collect();
113114for tool_name in &self.shared_tools {
115if let Some(tool) = registry.get_tool(tool_name) {
116 all_tools.push(tool);
117 } else {
118tracing::warn!(
119"Shared tool '{}' for agent '{}' not found in registry.",
120 tool_name,
121self.name
122 );
123 }
124 }
125126Ok(all_tools)
127 }
128}