use anyhow::{Context, Result};
use async_trait::async_trait;
use std::sync::Arc;
use crate::tools::toolproxy::{ProxyToolExecutor, ProxyToolDef};
use crate::workflow::context::WorkflowContext;
use crate::workflow::def::NodeDef;
use crate::workflow::template::TemplateRenderer;
use super::node_executor::NodeExecutor;
pub struct ProxyExecutor {
executor: Arc<dyn ProxyToolExecutor>,
tool_defs: Vec<ProxyToolDef>,
template_renderer: TemplateRenderer,
}
impl ProxyExecutor {
pub fn new(executor: Arc<dyn ProxyToolExecutor>, tool_defs: Vec<ProxyToolDef>) -> Self {
Self {
executor,
tool_defs,
template_renderer: TemplateRenderer::new(),
}
}
pub fn has_tool(&self, name: &str) -> bool {
self.tool_defs.iter().any(|t| t.definition.name == name)
}
pub fn get_timeout(&self, name: &str) -> u64 {
self.tool_defs
.iter()
.find(|t| t.definition.name == name)
.map(|t| t.timeout_ms)
.unwrap_or(30000)
}
}
#[async_trait]
impl NodeExecutor for ProxyExecutor {
async fn execute(
&self,
node: &NodeDef,
context: &mut WorkflowContext,
) -> Result<serde_json::Value> {
let tool_name = node.task.as_ref()
.ok_or_else(|| anyhow::anyhow!("Proxy executor requires a task name"))?;
if !self.has_tool(tool_name) {
return Err(anyhow::anyhow!("Proxy tool '{}' not found", tool_name));
}
let params = self.template_renderer.render_params(&node.params, &context.variables)?;
let result = self.executor.exec(tool_name, params.clone()).await
.with_context(|| format!("Proxy tool '{}' execution failed", tool_name))?;
let output = if let Ok(json) = serde_json::from_str::<serde_json::Value>(&result) {
json
} else {
serde_json::json!({
"result": result,
"tool": tool_name,
})
};
if let serde_json::Value::Object(map) = &output {
for (key, value) in map {
context.set_variable(key.clone(), value.clone());
}
}
Ok(output)
}
fn name(&self) -> &str {
"proxy_executor"
}
}