1use std::collections::HashMap;
4use std::sync::Arc;
5use std::time::Instant;
6
7use serde::{Deserialize, Serialize};
8
9use crate::ast::{ActionNode, CollectionExpr, ConditionExpr, ParamExpr};
10use crate::compiler::CompiledAction;
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct ExecutionResult {
15 pub compiled_id: String,
16 pub signature: String,
17 pub success: bool,
18 pub tokens_used: u64,
19 pub duration_ms: u64,
20 pub steps_executed: u32,
21 pub results: Vec<StepResult>,
22 pub error: Option<String>,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct StepResult {
27 pub tool: String,
28 pub params: HashMap<String, serde_json::Value>,
29 pub result: serde_json::Value,
30 pub success: bool,
31}
32
33pub type CompiledToolDispatcher = Arc<
36 dyn Fn(&str, &HashMap<String, serde_json::Value>) -> Result<serde_json::Value, String>
37 + Send
38 + Sync,
39>;
40
41pub struct CompiledExecutor {
43 variables: HashMap<String, serde_json::Value>,
45 stored_results: HashMap<String, serde_json::Value>,
47 tool_dispatcher: Option<CompiledToolDispatcher>,
49}
50
51impl CompiledExecutor {
52 pub fn new() -> Self {
53 Self {
54 variables: HashMap::new(),
55 stored_results: HashMap::new(),
56 tool_dispatcher: None,
57 }
58 }
59
60 pub fn with_variables(variables: HashMap<String, serde_json::Value>) -> Self {
61 Self {
62 variables,
63 stored_results: HashMap::new(),
64 tool_dispatcher: None,
65 }
66 }
67
68 pub fn with_dispatcher(mut self, dispatcher: CompiledToolDispatcher) -> Self {
71 self.tool_dispatcher = Some(dispatcher);
72 self
73 }
74
75 pub fn execute(&mut self, compiled: &CompiledAction) -> ExecutionResult {
77 let start = Instant::now();
78 let mut results = Vec::new();
79
80 let success = self.execute_node(&compiled.ast, &mut results);
81
82 ExecutionResult {
83 compiled_id: compiled.id.clone(),
84 signature: compiled.signature.clone(),
85 success,
86 tokens_used: 0, duration_ms: start.elapsed().as_millis() as u64,
88 steps_executed: results.len() as u32,
89 results,
90 error: if success {
91 None
92 } else {
93 Some("Step failed".into())
94 },
95 }
96 }
97
98 fn execute_node(&mut self, node: &ActionNode, results: &mut Vec<StepResult>) -> bool {
99 match node {
100 ActionNode::Action { tool, params } => {
101 let resolved = self.resolve_params(params);
102
103 let (result, success) = if let Some(ref dispatcher) = self.tool_dispatcher {
104 match dispatcher(tool, &resolved) {
106 Ok(val) => (val, true),
107 Err(err) => (serde_json::json!({ "error": err }), false),
108 }
109 } else {
110 (serde_json::json!({ "status": "ok", "tool": tool }), true)
112 };
113
114 results.push(StepResult {
115 tool: tool.clone(),
116 params: resolved,
117 result: result.clone(),
118 success,
119 });
120 success
121 }
122 ActionNode::Sequence(nodes) => {
123 for node in nodes {
124 if !self.execute_node(node, results) {
125 return false;
126 }
127 }
128 true
129 }
130 ActionNode::If {
131 condition,
132 then,
133 else_,
134 } => {
135 if self.evaluate_condition(condition) {
136 self.execute_node(then, results)
137 } else if let Some(else_node) = else_ {
138 self.execute_node(else_node, results)
139 } else {
140 true
141 }
142 }
143 ActionNode::ForEach {
144 variable,
145 collection,
146 body,
147 } => {
148 let items = self.resolve_collection(collection);
149 for item in items {
150 self.variables.insert(variable.clone(), item);
151 if !self.execute_node(body, results) {
152 return false;
153 }
154 }
155 true
156 }
157 ActionNode::StoreResult { key, action } => {
158 let prev_len = results.len();
159 let success = self.execute_node(action, results);
160 if success {
161 if let Some(last) = results.get(prev_len) {
162 self.stored_results.insert(key.clone(), last.result.clone());
163 }
164 }
165 success
166 }
167 }
168 }
169
170 fn resolve_params(
171 &self,
172 params: &HashMap<String, ParamExpr>,
173 ) -> HashMap<String, serde_json::Value> {
174 params
175 .iter()
176 .map(|(k, v)| (k.clone(), self.resolve_param(v)))
177 .collect()
178 }
179
180 fn resolve_param(&self, expr: &ParamExpr) -> serde_json::Value {
181 match expr {
182 ParamExpr::Literal(v) => v.clone(),
183 ParamExpr::Variable(name) => self
184 .variables
185 .get(name)
186 .cloned()
187 .unwrap_or(serde_json::Value::Null),
188 ParamExpr::PreviousResult(key) => self
189 .stored_results
190 .get(key)
191 .cloned()
192 .unwrap_or(serde_json::Value::Null),
193 ParamExpr::Computed(_) => {
194 serde_json::Value::Null
196 }
197 }
198 }
199
200 fn evaluate_condition(&self, condition: &ConditionExpr) -> bool {
201 match condition {
202 ConditionExpr::Exists(key) => {
203 self.stored_results.contains_key(key) || self.variables.contains_key(key)
204 }
205 ConditionExpr::Success(key) => self
206 .stored_results
207 .get(key)
208 .and_then(|v| v.get("status"))
209 .and_then(|s| s.as_str())
210 .map(|s| s == "ok")
211 .unwrap_or(false),
212 ConditionExpr::Equals { left, right } => {
213 let left_val = self
214 .variables
215 .get(left)
216 .or_else(|| self.stored_results.get(left));
217 left_val.map(|v| v == right).unwrap_or(false)
218 }
219 ConditionExpr::And(conditions) => conditions.iter().all(|c| self.evaluate_condition(c)),
220 ConditionExpr::Or(conditions) => conditions.iter().any(|c| self.evaluate_condition(c)),
221 ConditionExpr::Not(inner) => !self.evaluate_condition(inner),
222 }
223 }
224
225 fn resolve_collection(&self, collection: &CollectionExpr) -> Vec<serde_json::Value> {
226 match collection {
227 CollectionExpr::Literal(items) => items.clone(),
228 CollectionExpr::FromResult(key) => self
229 .stored_results
230 .get(key)
231 .and_then(|v| v.as_array())
232 .cloned()
233 .unwrap_or_default(),
234 CollectionExpr::FromVariable(key) => self
235 .variables
236 .get(key)
237 .and_then(|v| v.as_array())
238 .cloned()
239 .unwrap_or_default(),
240 }
241 }
242}
243
244impl Default for CompiledExecutor {
245 fn default() -> Self {
246 Self::new()
247 }
248}
249
250#[cfg(test)]
251#[path = "executor_tests.rs"]
252mod executor_tests;