use std::sync::Arc;
use crate::error::{AgentError, AgentResult};
use crate::openai::Model;
use crate::tool::Tool;
use crate::types::{Context, RunContext};
pub struct Agent {
name: String,
instructions: Option<String>,
model: Arc<dyn Model>,
tools: Vec<Arc<dyn Tool>>,
}
impl Agent {
pub fn new(
name: impl Into<String>,
instructions: Option<String>,
model: Arc<dyn Model>,
tools: Vec<Arc<dyn Tool>>,
) -> Self {
Self {
name: name.into(),
instructions,
model,
tools,
}
}
pub async fn run(&self, input: impl Into<String>, context: Context) -> AgentResult<String> {
let mut run_context = RunContext::new(context);
if let Some(instructions) = &self.instructions {
run_context.add_message("system", instructions);
}
run_context.add_message("user", input);
let tools: Vec<&dyn Tool> = self.tools.iter().map(|tool| tool.as_ref()).collect();
self.model.generate_response(&mut run_context, &tools).await
}
pub fn name(&self) -> &str {
&self.name
}
pub fn instructions(&self) -> Option<&str> {
self.instructions.as_deref()
}
pub fn tools(&self) -> &[Arc<dyn Tool>] {
&self.tools
}
}
pub struct AgentBuilder {
name: String,
instructions: Option<String>,
model: Option<Arc<dyn Model>>,
tools: Vec<Arc<dyn Tool>>,
}
impl AgentBuilder {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
instructions: None,
model: None,
tools: Vec::new(),
}
}
pub fn instructions(mut self, instructions: impl Into<String>) -> Self {
self.instructions = Some(instructions.into());
self
}
pub fn model(mut self, model: Arc<dyn Model>) -> Self {
self.model = Some(model);
self
}
pub fn add_tool(mut self, tool: Arc<dyn Tool>) -> Self {
self.tools.push(tool);
self
}
pub fn build(self) -> AgentResult<Agent> {
let model = self
.model
.ok_or_else(|| AgentError::ConfigurationError("Model not set".into()))?;
Ok(Agent::new(self.name, self.instructions, model, self.tools))
}
}