1use crate::error::{WorkflowError, WorkflowResult};
6use crate::models::{AgentStep, Workflow, WorkflowState};
7use crate::state::StateManager;
8use std::time::Instant;
9
10pub struct AgentExecutor;
12
13impl AgentExecutor {
14 pub fn execute_agent_step(
30 workflow: &Workflow,
31 state: &mut WorkflowState,
32 step_id: &str,
33 agent_step: &AgentStep,
34 ) -> WorkflowResult<()> {
35 StateManager::start_step(state, step_id.to_string());
37
38 let start_time = Instant::now();
39
40 let agent_output = Self::execute_agent_internal(workflow, state, step_id, agent_step)?;
49
50 let duration_ms = start_time.elapsed().as_millis() as u64;
51
52 StateManager::complete_step(state, step_id.to_string(), Some(agent_output), duration_ms);
54
55 Ok(())
56 }
57
58 fn execute_agent_internal(
63 _workflow: &Workflow,
64 _state: &WorkflowState,
65 _step_id: &str,
66 agent_step: &AgentStep,
67 ) -> WorkflowResult<serde_json::Value> {
68 Ok(serde_json::json!({
76 "agent_id": agent_step.agent_id,
77 "task": agent_step.task,
78 "status": "completed",
79 "output": {
80 "findings": [],
81 "suggestions": []
82 }
83 }))
84 }
85
86 pub fn execute_agent_step_with_timeout(
104 workflow: &Workflow,
105 state: &mut WorkflowState,
106 step_id: &str,
107 agent_step: &AgentStep,
108 timeout_ms: u64,
109 ) -> WorkflowResult<()> {
110 StateManager::start_step(state, step_id.to_string());
112
113 let start_time = Instant::now();
114
115 let agent_output = Self::execute_agent_internal(workflow, state, step_id, agent_step)?;
118
119 let elapsed_ms = start_time.elapsed().as_millis() as u64;
120
121 if elapsed_ms > timeout_ms {
123 StateManager::fail_step(
124 state,
125 step_id.to_string(),
126 format!("Agent execution timed out after {}ms", timeout_ms),
127 elapsed_ms,
128 );
129 return Err(WorkflowError::StepFailed(format!(
130 "Agent step {} timed out after {}ms",
131 step_id, timeout_ms
132 )));
133 }
134
135 StateManager::complete_step(state, step_id.to_string(), Some(agent_output), elapsed_ms);
137
138 Ok(())
139 }
140
141 pub fn get_agent_id(agent_step: &AgentStep) -> &str {
143 &agent_step.agent_id
144 }
145
146 pub fn get_task(agent_step: &AgentStep) -> &str {
148 &agent_step.task
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155 use crate::models::{
156 ErrorAction, RiskFactors, StepConfig, StepStatus, StepType, WorkflowConfig, WorkflowStep,
157 };
158
159 fn create_workflow_with_agent_step() -> Workflow {
160 Workflow {
161 id: "test-workflow".to_string(),
162 name: "Test Workflow".to_string(),
163 description: "A test workflow".to_string(),
164 parameters: vec![],
165 steps: vec![WorkflowStep {
166 id: "agent-step".to_string(),
167 name: "Agent Step".to_string(),
168 step_type: StepType::Agent(AgentStep {
169 agent_id: "test-agent".to_string(),
170 task: "test-task".to_string(),
171 }),
172 config: StepConfig {
173 config: serde_json::json!({"param": "value"}),
174 },
175 dependencies: vec![],
176 approval_required: false,
177 on_error: ErrorAction::Fail,
178 risk_score: None,
179 risk_factors: RiskFactors::default(),
180 }],
181 config: WorkflowConfig {
182 timeout_ms: None,
183 max_parallel: None,
184 },
185 }
186 }
187
188 #[test]
189 fn test_execute_agent_step() {
190 let workflow = create_workflow_with_agent_step();
191 let mut state = StateManager::create_state(&workflow);
192 let agent_step = AgentStep {
193 agent_id: "test-agent".to_string(),
194 task: "test-task".to_string(),
195 };
196
197 let result =
198 AgentExecutor::execute_agent_step(&workflow, &mut state, "agent-step", &agent_step);
199 assert!(result.is_ok());
200
201 let step_result = state.step_results.get("agent-step");
203 assert!(step_result.is_some());
204 assert_eq!(step_result.unwrap().status, StepStatus::Completed);
205 }
206
207 #[test]
208 fn test_execute_agent_step_with_timeout() {
209 let workflow = create_workflow_with_agent_step();
210 let mut state = StateManager::create_state(&workflow);
211 let agent_step = AgentStep {
212 agent_id: "test-agent".to_string(),
213 task: "test-task".to_string(),
214 };
215
216 let result = AgentExecutor::execute_agent_step_with_timeout(
217 &workflow,
218 &mut state,
219 "agent-step",
220 &agent_step,
221 5000, );
223 assert!(result.is_ok());
224
225 let step_result = state.step_results.get("agent-step");
227 assert!(step_result.is_some());
228 assert_eq!(step_result.unwrap().status, StepStatus::Completed);
229 }
230
231 #[test]
232 fn test_get_agent_id() {
233 let agent_step = AgentStep {
234 agent_id: "my-agent".to_string(),
235 task: "my-task".to_string(),
236 };
237
238 assert_eq!(AgentExecutor::get_agent_id(&agent_step), "my-agent");
239 }
240
241 #[test]
242 fn test_get_task() {
243 let agent_step = AgentStep {
244 agent_id: "my-agent".to_string(),
245 task: "my-task".to_string(),
246 };
247
248 assert_eq!(AgentExecutor::get_task(&agent_step), "my-task");
249 }
250}