use std::sync::Arc;
use crate::{DriverCall, DriverCallback, DriverContext, get_driver_by_name};
use anyhow::Result;
use serde_json::Value;
#[derive(Debug, Clone)]
pub struct Executor;
impl Executor {
pub fn new() -> Self {
Self
}
pub fn parse_driver_call(&self, json_str: &str) -> Result<DriverCall> {
Ok(serde_json::from_str(json_str)?)
}
pub fn parse_driver_call_from_value(&self, json_value: &Value) -> Result<DriverCall> {
Ok(serde_json::from_value(json_value.clone())?)
}
pub async fn execute(
&self,
call: &DriverCall,
callback: Option<&dyn DriverCallback>,
context: Option<&DriverContext>,
) -> Result<String> {
let driver = get_driver_by_name(&call.action)
.ok_or_else(|| anyhow::anyhow!("Unknown driver: {}", call.action))?;
driver.execute(&call.parameters, callback, context).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_driver_call(llm_response).unwrap();
let result = executor.execute(&call, None, None).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_driver_call(llm_response).unwrap();
let result = executor.execute(&call, None, None).await.unwrap();
assert_eq!(result, "Hello, World!");
}
#[tokio::test]
async fn test_unknown_driver_from_llm() {
let executor = Executor::new();
let llm_response = r#"{"action": "nonexistent_driver", "parameters": {}}"#;
let call = executor.parse_driver_call(llm_response).unwrap();
let result = executor.execute(&call, None, None).await;
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("Unknown driver"));
}
#[tokio::test]
async fn test_invalid_json_from_llm() {
let executor = Executor::new();
let invalid_json = "not a json";
let result = executor.parse_driver_call(invalid_json);
assert!(result.is_err());
}
#[tokio::test]
async fn test_parse_driver_call_from_value() {
let executor = Executor::new();
let json_value = json!({
"action": "helloworld",
"parameters": {
"name": "TestUser"
}
});
let call = executor.parse_driver_call_from_value(&json_value).unwrap();
assert_eq!(call.action, "helloworld");
assert!(!call.parameters.is_empty());
let result = executor.execute(&call, None, None).await.unwrap();
assert_eq!(result, "Hello, TestUser!");
}
#[tokio::test]
async fn test_parse_driver_call_from_value_without_parameters() {
let executor = Executor::new();
let json_value = json!({
"action": "helloworld"
});
let call = executor.parse_driver_call_from_value(&json_value).unwrap();
assert_eq!(call.action, "helloworld");
assert!(call.parameters.is_empty());
let result = executor.execute(&call, None, None).await.unwrap();
assert_eq!(result, "Hello, World!");
}
#[tokio::test]
async fn test_parse_driver_call_with_empty_parameters_object() {
let executor = Executor::new();
let llm_response = r#"{"action": "helloworld", "parameters": {}}"#;
let call = executor.parse_driver_call(llm_response).unwrap();
assert_eq!(call.action, "helloworld");
assert!(!call.parameters.is_empty());
let result = executor.execute(&call, None, None).await.unwrap();
assert_eq!(result, "Hello, World!");
}
}