use crate::types::{AgentFinish, AgentOutput, AgentStep};
use async_trait::async_trait;
use lc_core::language_models::TokenUsage;
use std::collections::HashMap;
use std::future::Future;
use std::pin::Pin;
use std::sync::atomic::AtomicUsize;
static CACHE_NS: AtomicUsize = AtomicUsize::new(0);
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum AgentError {
#[error("Output parsing error: {0}")]
OutputParsingError(String),
#[error("Tool not found: {0}")]
ToolNotFound(String),
#[error("Tool execution error: {0}")]
ToolExecutionError(String),
#[error("Max iterations reached")]
MaxIterationsReached,
#[error("Budget exceeded: {0:?}")]
BudgetExceeded(BudgetExceeded),
#[error("Agent error: {0}")]
Other(String),
}
#[async_trait]
pub trait BaseAgent: Send + Sync {
async fn plan(
&self,
intermediate_steps: &[AgentStep],
inputs: &HashMap<String, String>,
) -> Result<AgentOutput, AgentError>;
async fn plan_stream(
&self,
intermediate_steps: &[AgentStep],
inputs: &HashMap<String, String>,
on_token: &mut (dyn FnMut(String) -> Pin<Box<dyn Future<Output = ()> + Send>> + Send),
) -> Result<AgentOutput, AgentError> {
let output = self.plan(intermediate_steps, inputs).await?;
if let AgentOutput::Finish(finish) = &output {
on_token(finish.output().unwrap_or("").to_string()).await;
}
Ok(output)
}
fn input_keys(&self) -> Vec<&str> {
vec!["input"]
}
fn get_allowed_tools(&self) -> Option<Vec<&str>> {
None
}
fn return_stopped_response(&self, _intermediate_steps: &[AgentStep]) -> AgentFinish {
AgentFinish::new(
"Agent stopped due to iteration limit or time limit.".to_string(),
String::new(),
)
}
fn last_token_usage(&self) -> Option<TokenUsage> {
None
}
}
const MIN_MAX_ITERATIONS: usize = 1;
const MAX_MAX_ITERATIONS: usize = 100;
const DEFAULT_MAX_CONCURRENCY: usize = 8;
mod agent_loop;
mod budget;
mod engine;
mod hooks;
#[cfg(test)]
mod tests;
mod tools;
pub use budget::{BudgetConfig, BudgetExceeded};
pub use engine::AgentExecutor;