use std::sync::Arc;
use crate::agents::{AgentError, AgentExecutor, BaseAgent, FunctionCallingAgent};
use crate::language_models::OpenAIChat;
use crate::BaseTool;
use super::plan::StepStatus;
use super::planner::Planner;
#[derive(Debug, thiserror::Error)]
pub enum PlanExecuteError {
#[error("Planning failed: {0}")]
PlanningError(String),
#[error("Step execution failed: {0}")]
StepExecutionError(String),
#[error("Max replans reached: step [{step}] failed: {reason}")]
MaxReplansReached { step: String, reason: String },
#[error("Plan incomplete after all replans")]
PlanIncomplete,
}
impl From<AgentError> for PlanExecuteError {
fn from(e: AgentError) -> Self {
PlanExecuteError::StepExecutionError(e.to_string())
}
}
pub struct PlanExecuteAgent {
llm: OpenAIChat,
tools: Vec<Arc<dyn BaseTool>>,
max_replans: usize,
}
impl PlanExecuteAgent {
pub fn new(llm: OpenAIChat, tools: Vec<Arc<dyn BaseTool>>) -> Self {
Self {
llm,
tools,
max_replans: 2,
}
}
pub fn with_max_replans(mut self, n: usize) -> Self {
self.max_replans = n;
self
}
pub async fn run(&self, objective: &str) -> Result<String, PlanExecuteError> {
let planner = Planner::new(self.llm.clone());
let mut plan = planner
.plan(objective)
.await
.map_err(PlanExecuteError::PlanningError)?;
for replan_count in 0..=self.max_replans {
let pending_ids: Vec<usize> = plan
.steps
.iter()
.filter(|s| s.status == StepStatus::Pending)
.map(|s| s.id)
.collect();
let mut failed = false;
for step_id in pending_ids {
let step = plan.steps.iter_mut().find(|s| s.id == step_id);
let step_desc = match step {
Some(s) => {
s.status = StepStatus::Running;
s.description.clone()
}
None => {
continue;
}
};
match self.execute_step(&step_desc).await {
Ok(result) => plan.mark_completed(step_id, result),
Err(e) => {
let error_msg = e.to_string();
plan.mark_failed(step_id, error_msg.clone());
if replan_count < self.max_replans {
plan = planner
.replan(objective, &step_desc, &error_msg)
.await
.map_err(PlanExecuteError::PlanningError)?;
failed = true;
break;
} else {
return Err(PlanExecuteError::MaxReplansReached {
step: step_desc,
reason: error_msg,
});
}
}
}
}
if !failed && plan.is_complete() {
let summary: Vec<String> = plan
.steps
.iter()
.map(|s| {
format!(
"{}. {}: {}",
s.id + 1,
s.description,
s.result.as_deref().unwrap_or("无结果")
)
})
.collect();
return Ok(summary.join("\n"));
}
}
Err(PlanExecuteError::PlanIncomplete)
}
async fn execute_step(&self, step: &str) -> Result<String, PlanExecuteError> {
let agent = FunctionCallingAgent::new(self.llm.clone(), self.tools.clone(), None);
let executor =
AgentExecutor::new(Arc::new(agent) as Arc<dyn BaseAgent>, self.tools.clone())
.with_max_iterations(5);
executor
.invoke(step.to_string())
.await
.map_err(|e| PlanExecuteError::StepExecutionError(e.to_string()))
}
}