openfunctions_rs/core/
mod.rs

1//! Core functionality for OpenFunctions.
2//!
3//! This module provides the central components of the framework, including the
4//! structures for tools, agents, configuration, and execution. It also contains
5//! core utilities like the `Registry` for managing tools and agents, and the
6//! `TestRunner` for quality assurance.
7
8use anyhow::Result;
9use std::collections::HashMap;
10use tracing::{error, info};
11
12pub mod agent;
13pub mod builder;
14pub mod checker;
15pub mod config;
16pub mod function;
17pub mod loader;
18pub mod registry;
19pub mod tool;
20
21pub use agent::Agent;
22pub use builder::Builder;
23pub use checker::Checker;
24pub use config::Config;
25pub use function::FunctionDeclaration;
26pub use loader::Loader;
27pub use registry::Registry;
28pub use tool::Tool;
29
30/// A test runner for executing tests on tools and agents.
31///
32/// `TestRunner` discovers and runs tests, reporting the results.
33pub struct TestRunner {
34    config: Config,
35    registry: Registry,
36}
37
38impl TestRunner {
39    /// Creates a new `TestRunner` with the given configuration.
40    pub fn new(config: &Config) -> Self {
41        Self {
42            config: config.clone(),
43            registry: Registry::new(),
44        }
45    }
46
47    /// Runs all tests for all registered tools and agents.
48    pub async fn run_all(&mut self) -> Result<TestResults> {
49        info!("Running all tests...");
50        self.registry.load_tools(&self.config.tool_dirs).await?;
51        self.registry.load_agents(&self.config.agent_dirs).await?;
52
53        let mut results = TestResults::default();
54
55        // Run tool tests
56        for tool_name in self.registry.list_tools() {
57            let result = self.run_tool_test(&tool_name).await?;
58            results.add_tool_result(tool_name, result);
59        }
60
61        // Run agent tests
62        for agent_name in self.registry.list_agents() {
63            let result = self.run_agent_test(&agent_name).await?;
64            results.add_agent_result(agent_name, result);
65        }
66
67        Ok(results)
68    }
69
70    /// Run tests for a specific suite.
71    pub async fn run_suite(&mut self, suite: &str) -> Result<TestResults> {
72        match suite {
73            "tools" => self.run_tool_tests().await,
74            "agents" => self.run_agent_tests().await,
75            "integration" => self.run_integration_tests().await,
76            _ => anyhow::bail!("Unknown test suite: {}", suite),
77        }
78    }
79
80    async fn run_tool_tests(&mut self) -> Result<TestResults> {
81        self.registry.load_tools(&self.config.tool_dirs).await?;
82        let mut results = TestResults::default();
83        for tool_name in self.registry.list_tools() {
84            let result = self.run_tool_test(&tool_name).await?;
85            results.add_tool_result(tool_name, result);
86        }
87        Ok(results)
88    }
89
90    async fn run_agent_tests(&mut self) -> Result<TestResults> {
91        self.registry.load_agents(&self.config.agent_dirs).await?;
92        let mut results = TestResults::default();
93        for agent_name in self.registry.list_agents() {
94            let result = self.run_agent_test(&agent_name).await?;
95            results.add_agent_result(agent_name, result);
96        }
97        Ok(results)
98    }
99
100    async fn run_integration_tests(&self) -> Result<TestResults> {
101        info!("Running integration tests...");
102        // TODO: Implement integration tests.
103        Ok(TestResults::default())
104    }
105
106    async fn run_tool_test(&self, tool: &str) -> Result<TestResult> {
107        info!(tool = %tool, "Running test for tool");
108        // TODO: Implement actual test execution logic for tools.
109        Ok(TestResult {
110            passed: true,
111            duration: std::time::Duration::from_millis(100),
112            output: format!("Tool {} test passed", tool),
113        })
114    }
115
116    async fn run_agent_test(&self, agent: &str) -> Result<TestResult> {
117        info!(agent = %agent, "Running test for agent");
118        // TODO: Implement actual test execution logic for agents.
119        Ok(TestResult {
120            passed: true,
121            duration: std::time::Duration::from_millis(200),
122            output: format!("Agent {} test passed", agent),
123        })
124    }
125}
126
127/// A container for the results of a test run.
128#[derive(Debug, Default)]
129pub struct TestResults {
130    tool_results: HashMap<String, TestResult>,
131    agent_results: HashMap<String, TestResult>,
132}
133
134impl TestResults {
135    /// Adds a tool test result.
136    pub fn add_tool_result(&mut self, tool_name: String, result: TestResult) {
137        self.tool_results.insert(tool_name, result);
138    }
139
140    /// Adds an agent test result.
141    pub fn add_agent_result(&mut self, agent_name: String, result: TestResult) {
142        self.agent_results.insert(agent_name, result);
143    }
144
145    /// Prints a summary of the test results to the console.
146    pub fn print_summary(&self) {
147        info!("Test Results Summary:");
148
149        let total_tools = self.tool_results.len();
150        let passed_tools = self.tool_results.values().filter(|r| r.passed).count();
151        info!("Tools: {}/{} passed", passed_tools, total_tools);
152
153        let total_agents = self.agent_results.len();
154        let passed_agents = self.agent_results.values().filter(|r| r.passed).count();
155        info!("Agents: {}/{} passed", passed_agents, total_agents);
156
157        if passed_tools < total_tools || passed_agents < total_agents {
158            error!("Failed tests:");
159            for (tool, result) in &self.tool_results {
160                if !result.passed {
161                    error!("  Tool '{}': {}", tool, result.output);
162                }
163            }
164            for (agent, result) in &self.agent_results {
165                if !result.passed {
166                    error!("  Agent '{}': {}", agent, result.output);
167                }
168            }
169        }
170    }
171}
172
173/// Represents the result of a single test case.
174#[derive(Debug)]
175pub struct TestResult {
176    /// Whether the test passed
177    pub passed: bool,
178    /// Duration of the test execution
179    pub duration: std::time::Duration,
180    /// Test output
181    pub output: String,
182}