use crate::executors::{SkillCall, registry};
use anyhow::Result;
use serde_json::Value;
#[derive(Debug, Clone)]
pub struct Executor;
impl Executor {
pub fn new() -> Self {
Self
}
pub fn parse_skill_call(&self, json_str: &str) -> Result<SkillCall> {
Ok(serde_json::from_str(json_str)?)
}
pub fn parse_skill_call_from_value(&self, json_value: &Value) -> Result<SkillCall> {
Ok(serde_json::from_value(json_value.clone())?)
}
pub async fn execute(&self, call: &SkillCall) -> Result<String> {
let skill = registry::get_skill(&call.action)
.ok_or_else(|| anyhow::anyhow!("Unknown skill: {}", call.action))?;
skill.execute(&call.parameters).await
}
}
impl Default for Executor {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[tokio::test]
async fn test_execute_helloworld_from_llm_json() {
let executor = Executor::new();
let llm_response = r#"{"action": "helloworld", "parameters": {"name": "Alice"}}"#;
let call = executor.parse_skill_call(llm_response).unwrap();
let result = executor.execute(&call).await.unwrap();
assert_eq!(result, "Hello, Alice!");
}
#[tokio::test]
async fn test_execute_helloworld_from_llm_json_without_parameters() {
let executor = Executor::new();
let llm_response = r#"{"action": "helloworld"}"#;
let call = executor.parse_skill_call(llm_response).unwrap();
let result = executor.execute(&call).await.unwrap();
assert_eq!(result, "Hello, World!");
}
#[tokio::test]
async fn test_unknown_skill_from_llm() {
let executor = Executor::new();
let llm_response = r#"{"action": "nonexistent_skill", "parameters": {}}"#;
let call = executor.parse_skill_call(llm_response).unwrap();
let result = executor.execute(&call).await;
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("Unknown skill"));
}
#[tokio::test]
async fn test_invalid_json_from_llm() {
let executor = Executor::new();
let invalid_json = "not a json";
let result = executor.parse_skill_call(invalid_json);
assert!(result.is_err());
}
}