openfunctions_rs/core/
agent.rs1use crate::core::Tool;
7use crate::models::AgentDefinition;
8use anyhow::Result;
9use std::collections::HashMap;
10use std::path::{Path, PathBuf};
11
12#[derive(Debug, Clone)]
17pub struct Agent {
18 pub name: String,
20
21 pub path: PathBuf,
23
24 pub definition: AgentDefinition,
26
27 pub tools: Vec<Tool>,
29
30 pub shared_tools: Vec<String>,
32
33 pub variables: HashMap<String, String>,
35}
36
37impl Agent {
38 pub async fn from_directory<P: AsRef<Path>>(path: P) -> Result<Self> {
44 let path = path.as_ref().to_path_buf();
45 let name = path
46 .file_name()
47 .ok_or_else(|| anyhow::anyhow!("Invalid agent directory"))?
48 .to_string_lossy()
49 .to_string();
50
51 let index_path = path.join("index.yaml");
52 let index_content = tokio::fs::read_to_string(&index_path).await?;
53 let definition: AgentDefinition = serde_yaml::from_str(&index_content)?;
54
55 let mut tools = Vec::new();
57 let agent_tools_dir = path.join("tools");
58 if agent_tools_dir.is_dir() {
59 let mut entries = tokio::fs::read_dir(agent_tools_dir).await?;
60 while let Some(entry) = entries.next_entry().await? {
61 let tool_path = entry.path();
62 if tool_path.is_file() {
63 match Tool::from_file(&tool_path).await {
64 Ok(tool) => tools.push(tool),
65 Err(e) => tracing::warn!(
66 "Failed to load agent-specific tool {}: {}",
67 tool_path.display(),
68 e
69 ),
70 }
71 }
72 }
73 }
74
75 let shared_tools = if path.join("tools.txt").exists() {
76 let 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 };
85
86 let mut variables = HashMap::new();
87 for var in &definition.variables {
88 if let Some(default) = &var.default {
89 variables.insert(var.name.clone(), default.clone());
90 }
91 }
92
93 Ok(Self {
94 name,
95 path,
96 definition,
97 tools,
98 shared_tools,
99 variables,
100 })
101 }
102
103 pub fn get_all_tools<'a>(
109 &'a self,
110 registry: &'a crate::core::Registry,
111 ) -> Result<Vec<&'a Tool>> {
112 let mut all_tools: Vec<&'a Tool> = self.tools.iter().collect();
113
114 for tool_name in &self.shared_tools {
115 if let Some(tool) = registry.get_tool(tool_name) {
116 all_tools.push(tool);
117 } else {
118 tracing::warn!(
119 "Shared tool '{}' for agent '{}' not found in registry.",
120 tool_name,
121 self.name
122 );
123 }
124 }
125
126 Ok(all_tools)
127 }
128}