1use serde::{Deserialize, Serialize};
2use snafu::{ResultExt, Snafu};
3use std::collections::HashMap;
4
5#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
7#[serde(untagged)]
8pub enum Tool {
9 Function {
11 function_declarations: Vec<FunctionDeclaration>,
13 },
14 GoogleSearch {
16 google_search: GoogleSearchConfig,
18 },
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
23pub struct GoogleSearchConfig {}
24
25impl Tool {
26 pub fn new(function_declaration: FunctionDeclaration) -> Self {
28 Self::Function {
29 function_declarations: vec![function_declaration],
30 }
31 }
32
33 pub fn with_functions(function_declarations: Vec<FunctionDeclaration>) -> Self {
35 Self::Function {
36 function_declarations,
37 }
38 }
39
40 pub fn google_search() -> Self {
42 Self::GoogleSearch {
43 google_search: GoogleSearchConfig {},
44 }
45 }
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
50pub struct FunctionDeclaration {
51 pub name: String,
53 pub description: String,
55 pub parameters: FunctionParameters,
57}
58
59impl FunctionDeclaration {
60 pub fn new(
62 name: impl Into<String>,
63 description: impl Into<String>,
64 parameters: FunctionParameters,
65 ) -> Self {
66 Self {
67 name: name.into(),
68 description: description.into(),
69 parameters,
70 }
71 }
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
76pub struct FunctionParameters {
77 #[serde(rename = "type")]
79 pub param_type: String,
80 #[serde(skip_serializing_if = "Option::is_none")]
82 pub properties: Option<HashMap<String, PropertyDetails>>,
83 #[serde(skip_serializing_if = "Option::is_none")]
85 pub required: Option<Vec<String>>,
86}
87
88impl FunctionParameters {
89 pub fn object() -> Self {
91 Self {
92 param_type: "object".to_string(),
93 properties: Some(HashMap::new()),
94 required: Some(Vec::new()),
95 }
96 }
97
98 pub fn with_property(
100 mut self,
101 name: impl Into<String>,
102 details: PropertyDetails,
103 required: bool,
104 ) -> Self {
105 let name = name.into();
106 if let Some(props) = &mut self.properties {
107 props.insert(name.clone(), details);
108 }
109 if required {
110 if let Some(req) = &mut self.required {
111 req.push(name);
112 }
113 }
114 self
115 }
116}
117
118#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
120pub struct PropertyDetails {
121 #[serde(rename = "type")]
123 pub property_type: String,
124 #[serde(skip_serializing_if = "Option::is_none")]
126 pub description: Option<String>,
127 #[serde(rename = "enum", skip_serializing_if = "Option::is_none")]
129 pub enum_values: Option<Vec<String>>,
130 #[serde(skip_serializing_if = "Option::is_none")]
132 pub items: Option<Box<PropertyDetails>>,
133}
134
135impl PropertyDetails {
136 pub fn string(description: impl Into<String>) -> Self {
138 Self {
139 property_type: "string".to_string(),
140 description: Some(description.into()),
141 enum_values: None,
142 items: None,
143 }
144 }
145
146 pub fn number(description: impl Into<String>) -> Self {
148 Self {
149 property_type: "number".to_string(),
150 description: Some(description.into()),
151 enum_values: None,
152 items: None,
153 }
154 }
155
156 pub fn integer(description: impl Into<String>) -> Self {
158 Self {
159 property_type: "integer".to_string(),
160 description: Some(description.into()),
161 enum_values: None,
162 items: None,
163 }
164 }
165
166 pub fn boolean(description: impl Into<String>) -> Self {
168 Self {
169 property_type: "boolean".to_string(),
170 description: Some(description.into()),
171 enum_values: None,
172 items: None,
173 }
174 }
175
176 pub fn array(description: impl Into<String>, items: PropertyDetails) -> Self {
178 Self {
179 property_type: "array".to_string(),
180 description: Some(description.into()),
181 enum_values: None,
182 items: Some(Box::new(items)),
183 }
184 }
185
186 pub fn enum_type(
188 description: impl Into<String>,
189 enum_values: impl IntoIterator<Item = impl Into<String>>,
190 ) -> Self {
191 Self {
192 property_type: "string".to_string(),
193 description: Some(description.into()),
194 enum_values: Some(enum_values.into_iter().map(|s| s.into()).collect()),
195 items: None,
196 }
197 }
198}
199#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
201pub struct FunctionCall {
202 pub name: String,
204 pub args: serde_json::Value,
206 #[serde(skip_serializing_if = "Option::is_none")]
208 pub thought_signature: Option<String>,
209}
210
211#[derive(Debug, Snafu)]
212pub enum FunctionCallError {
213 #[snafu(display("failed to deserialize parameter '{key}'"))]
214 Deserialization {
215 source: serde_json::Error,
216 key: String,
217 },
218
219 #[snafu(display("parameter '{key}' is missing in arguments '{args}'"))]
220 MissingParameter {
221 key: String,
222 args: serde_json::Value,
223 },
224
225 #[snafu(display("arguments should be an object; actual: {actual}"))]
226 ArgumentTypeMismatch { actual: String },
227}
228
229impl FunctionCall {
230 pub fn new(name: impl Into<String>, args: serde_json::Value) -> Self {
232 Self {
233 name: name.into(),
234 args,
235 thought_signature: None,
236 }
237 }
238
239 pub fn with_thought_signature(
241 name: impl Into<String>,
242 args: serde_json::Value,
243 thought_signature: impl Into<String>,
244 ) -> Self {
245 Self {
246 name: name.into(),
247 args,
248 thought_signature: Some(thought_signature.into()),
249 }
250 }
251
252 pub fn get<T: serde::de::DeserializeOwned>(&self, key: &str) -> Result<T, FunctionCallError> {
254 match &self.args {
255 serde_json::Value::Object(obj) => {
256 if let Some(value) = obj.get(key) {
257 serde_json::from_value(value.clone()).with_context(|_| DeserializationSnafu {
258 key: key.to_string(),
259 })
260 } else {
261 Err(MissingParameterSnafu {
262 key: key.to_string(),
263 args: self.args.clone(),
264 }
265 .build())
266 }
267 }
268 _ => Err(ArgumentTypeMismatchSnafu {
269 actual: self.args.to_string(),
270 }
271 .build()),
272 }
273 }
274}
275
276#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
278pub struct FunctionResponse {
279 pub name: String,
281 #[serde(skip_serializing_if = "Option::is_none")]
284 pub response: Option<serde_json::Value>,
285}
286
287impl FunctionResponse {
288 pub fn new(name: impl Into<String>, response: serde_json::Value) -> Self {
290 Self {
291 name: name.into(),
292 response: Some(response),
293 }
294 }
295
296 pub fn from_str(
298 name: impl Into<String>,
299 response: impl Into<String>,
300 ) -> Result<Self, serde_json::Error> {
301 let json = serde_json::from_str(&response.into())?;
302 Ok(Self {
303 name: name.into(),
304 response: Some(json),
305 })
306 }
307}
308
309#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
311pub struct ToolConfig {
312 #[serde(skip_serializing_if = "Option::is_none")]
314 pub function_calling_config: Option<FunctionCallingConfig>,
315}
316
317#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
319pub struct FunctionCallingConfig {
320 pub mode: FunctionCallingMode,
322}
323
324#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
326#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
327pub enum FunctionCallingMode {
328 Auto,
330 Any,
332 None,
334}