use std::sync::Arc;
use serde::{Deserialize, Serialize};
use fluers_core::{Model, ThinkingLevel, Tool};
use crate::env::Limits;
use crate::error::{RuntimeError, RuntimeResult};
use crate::sandbox::Sandbox;
use crate::skill::Skill;
#[derive(Clone)]
pub struct AgentProfile {
pub model: Model,
pub instructions: String,
pub tools: Vec<Arc<dyn Tool>>,
pub skills: Vec<Arc<Skill>>,
pub sandbox: Arc<dyn Sandbox>,
pub thinking: ThinkingLevel,
pub limits: Limits,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentSpec {
pub model: String,
#[serde(default)]
pub instructions: String,
#[serde(default)]
pub tools: Vec<String>,
#[serde(default)]
pub skills: Vec<String>,
#[serde(default = "default_sandbox")]
pub sandbox: String,
#[serde(default)]
pub thinking: ThinkingLevel,
}
fn default_sandbox() -> String {
"local".to_string()
}
pub struct Agent {
pub profile: AgentProfile,
}
pub async fn define_agent<F>(build: F) -> RuntimeResult<Agent>
where
F: FnOnce(&mut AgentBuilder) -> RuntimeResult<()>,
{
let mut b = AgentBuilder::default();
build(&mut b)?;
let profile = b.finish()?;
Ok(Agent { profile })
}
#[derive(Default)]
pub struct AgentBuilder {
pub model: Option<Model>,
pub instructions: Option<String>,
pub tools: Vec<Arc<dyn Tool>>,
pub skills: Vec<Arc<Skill>>,
pub sandbox: Option<Arc<dyn Sandbox>>,
pub thinking: ThinkingLevel,
}
impl AgentBuilder {
pub fn model(&mut self, model: impl Into<String>) -> &mut Self {
self.model = Some(Model::new(model));
self
}
pub fn instructions(&mut self, text: impl Into<String>) -> &mut Self {
self.instructions = Some(text.into());
self
}
pub fn tool(&mut self, tool: Arc<dyn Tool>) -> &mut Self {
self.tools.push(tool);
self
}
pub fn skill(&mut self, skill: Arc<Skill>) -> &mut Self {
self.skills.push(skill);
self
}
pub fn sandbox(&mut self, sandbox: Arc<dyn Sandbox>) -> &mut Self {
self.sandbox = Some(sandbox);
self
}
fn finish(self) -> RuntimeResult<AgentProfile> {
let model = self
.model
.ok_or_else(|| RuntimeError::InvalidSkill("agent requires a model".into()))?;
let sandbox = self
.sandbox
.unwrap_or_else(|| Arc::new(crate::sandbox::local()));
Ok(AgentProfile {
model,
instructions: self.instructions.unwrap_or_default(),
tools: self.tools,
skills: self.skills,
sandbox,
thinking: self.thinking,
limits: Limits::default(),
})
}
}