1use std::sync::Arc;
8
9use serde::{Deserialize, Serialize};
10
11use fluers_core::{Model, ThinkingLevel, Tool};
12
13use crate::env::Limits;
14use crate::error::{RuntimeError, RuntimeResult};
15use crate::sandbox::Sandbox;
16use crate::skill::Skill;
17
18#[derive(Clone)]
23pub struct AgentProfile {
24 pub model: Model,
26 pub instructions: String,
28 pub tools: Vec<Arc<dyn Tool>>,
30 pub skills: Vec<Arc<Skill>>,
32 pub sandbox: Arc<dyn Sandbox>,
34 pub thinking: ThinkingLevel,
36 pub limits: Limits,
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
45pub struct AgentSpec {
46 pub model: String,
48 #[serde(default)]
50 pub instructions: String,
51 #[serde(default)]
53 pub tools: Vec<String>,
54 #[serde(default)]
56 pub skills: Vec<String>,
57 #[serde(default = "default_sandbox")]
59 pub sandbox: String,
60 #[serde(default)]
62 pub thinking: ThinkingLevel,
63}
64
65fn default_sandbox() -> String {
66 "local".to_string()
67}
68
69pub struct Agent {
71 pub profile: AgentProfile,
73}
74
75pub async fn define_agent<F>(build: F) -> RuntimeResult<Agent>
81where
82 F: FnOnce(&mut AgentBuilder) -> RuntimeResult<()>,
83{
84 let mut b = AgentBuilder::default();
85 build(&mut b)?;
86 let profile = b.finish()?;
87 Ok(Agent { profile })
88}
89
90#[derive(Default)]
92pub struct AgentBuilder {
93 pub model: Option<Model>,
95 pub instructions: Option<String>,
97 pub tools: Vec<Arc<dyn Tool>>,
99 pub skills: Vec<Arc<Skill>>,
101 pub sandbox: Option<Arc<dyn Sandbox>>,
103 pub thinking: ThinkingLevel,
105}
106
107impl AgentBuilder {
108 pub fn model(&mut self, model: impl Into<String>) -> &mut Self {
110 self.model = Some(Model::new(model));
111 self
112 }
113
114 pub fn instructions(&mut self, text: impl Into<String>) -> &mut Self {
116 self.instructions = Some(text.into());
117 self
118 }
119
120 pub fn tool(&mut self, tool: Arc<dyn Tool>) -> &mut Self {
122 self.tools.push(tool);
123 self
124 }
125
126 pub fn skill(&mut self, skill: Arc<Skill>) -> &mut Self {
128 self.skills.push(skill);
129 self
130 }
131
132 pub fn sandbox(&mut self, sandbox: Arc<dyn Sandbox>) -> &mut Self {
134 self.sandbox = Some(sandbox);
135 self
136 }
137
138 fn finish(self) -> RuntimeResult<AgentProfile> {
139 let model = self
140 .model
141 .ok_or_else(|| RuntimeError::InvalidSkill("agent requires a model".into()))?;
142 let sandbox = self
143 .sandbox
144 .unwrap_or_else(|| Arc::new(crate::sandbox::local()));
145 Ok(AgentProfile {
146 model,
147 instructions: self.instructions.unwrap_or_default(),
148 tools: self.tools,
149 skills: self.skills,
150 sandbox,
151 thinking: self.thinking,
152 limits: Limits::default(),
153 })
154 }
155}