1use crate::errors::Result;
4use crate::result::RunResult;
5use crate::runner::{RunConfig, Runner};
6use crate::tool::Tool;
7use crate::types::ModelSettings;
8use std::sync::Arc;
9
10#[derive(Debug, Clone)]
12pub enum Instructions {
13 Static(String),
15
16 Dynamic(String),
19}
20
21impl Instructions {
22 pub fn as_str(&self) -> &str {
24 match self {
25 Instructions::Static(s) | Instructions::Dynamic(s) => s,
26 }
27 }
28}
29
30impl From<String> for Instructions {
31 fn from(s: String) -> Self {
32 Instructions::Static(s)
33 }
34}
35
36impl From<&str> for Instructions {
37 fn from(s: &str) -> Self {
38 Instructions::Static(s.to_string())
39 }
40}
41
42#[derive(Clone)]
47pub struct Agent {
48 pub name: String,
50
51 pub instructions: Option<Instructions>,
53
54 pub model: String,
56
57 pub tools: Vec<Arc<dyn Tool>>,
59
60 pub handoffs: Vec<Agent>,
62
63 pub model_settings: ModelSettings,
65
66 pub handoff_description: Option<String>,
68}
69
70impl Agent {
71 pub fn new(name: impl Into<String>) -> Self {
73 Self {
74 name: name.into(),
75 instructions: None,
76 model: "gpt-4".to_string(),
77 tools: Vec::new(),
78 handoffs: Vec::new(),
79 model_settings: ModelSettings::default(),
80 handoff_description: None,
81 }
82 }
83
84 pub fn builder(name: impl Into<String>) -> AgentBuilder {
86 AgentBuilder::new(name)
87 }
88
89 pub fn clone_with(&self) -> AgentBuilder {
91 AgentBuilder {
92 name: self.name.clone(),
93 instructions: self.instructions.clone(),
94 model: self.model.clone(),
95 tools: self.tools.clone(),
96 handoffs: self.handoffs.clone(),
97 model_settings: self.model_settings.clone(),
98 handoff_description: self.handoff_description.clone(),
99 }
100 }
101
102 pub fn system_prompt(&self) -> Option<&str> {
104 self.instructions.as_ref().map(|i| i.as_str())
105 }
106
107 pub async fn run(&self, input: impl Into<String>, config: &RunConfig) -> Result<RunResult> {
112 Runner::run(self, input.into(), config).await
113 }
114
115 pub fn with_tool(mut self, tool: impl Tool + 'static) -> Self {
117 self.tools.push(Arc::new(tool));
118 self
119 }
120
121 pub fn with_handoff(mut self, agent: Agent) -> Self {
123 self.handoffs.push(agent);
124 self
125 }
126}
127
128impl std::fmt::Debug for Agent {
129 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130 f.debug_struct("Agent")
131 .field("name", &self.name)
132 .field("model", &self.model)
133 .field("tools", &self.tools.len())
134 .field("handoffs", &self.handoffs.len())
135 .finish()
136 }
137}
138
139pub struct AgentBuilder {
141 name: String,
142 instructions: Option<Instructions>,
143 model: String,
144 tools: Vec<Arc<dyn Tool>>,
145 handoffs: Vec<Agent>,
146 model_settings: ModelSettings,
147 handoff_description: Option<String>,
148}
149
150impl AgentBuilder {
151 pub fn new(name: impl Into<String>) -> Self {
153 Self {
154 name: name.into(),
155 instructions: None,
156 model: "gpt-4".to_string(),
157 tools: Vec::new(),
158 handoffs: Vec::new(),
159 model_settings: ModelSettings::default(),
160 handoff_description: None,
161 }
162 }
163
164 pub fn instructions(mut self, instructions: impl Into<Instructions>) -> Self {
166 self.instructions = Some(instructions.into());
167 self
168 }
169
170 pub fn model(mut self, model: impl Into<String>) -> Self {
172 self.model = model.into();
173 self
174 }
175
176 pub fn tool(mut self, tool: impl Tool + 'static) -> Self {
178 self.tools.push(Arc::new(tool));
179 self
180 }
181
182 pub fn tools(mut self, tools: Vec<Arc<dyn Tool>>) -> Self {
184 self.tools.extend(tools);
185 self
186 }
187
188 pub fn handoff(mut self, agent: Agent) -> Self {
190 self.handoffs.push(agent);
191 self
192 }
193
194 pub fn model_settings(mut self, settings: ModelSettings) -> Self {
196 self.model_settings = settings;
197 self
198 }
199
200 pub fn handoff_description(mut self, desc: impl Into<String>) -> Self {
202 self.handoff_description = Some(desc.into());
203 self
204 }
205
206 pub fn build(self) -> Agent {
208 Agent {
209 name: self.name,
210 instructions: self.instructions,
211 model: self.model,
212 tools: self.tools,
213 handoffs: self.handoffs,
214 model_settings: self.model_settings,
215 handoff_description: self.handoff_description,
216 }
217 }
218}
219
220#[cfg(test)]
221mod tests {
222 use super::*;
223
224 #[test]
225 fn test_agent_builder() {
226 let agent = Agent::builder("test")
227 .instructions("You are a helpful assistant")
228 .model("gpt-4")
229 .build();
230
231 assert_eq!(agent.name, "test");
232 assert_eq!(agent.model, "gpt-4");
233 assert!(agent.system_prompt().is_some());
234 }
235
236 #[test]
237 fn test_agent_clone_with() {
238 let agent = Agent::builder("test")
239 .instructions("Original instructions")
240 .build();
241
242 let modified = agent.clone_with().instructions("New instructions").build();
243
244 assert_eq!(modified.name, "test");
245 assert_eq!(modified.system_prompt(), Some("New instructions"));
246 }
247}