anthropic_async/types/
tools.rs1use serde::{Deserialize, Serialize};
44
45use super::common::CacheControl;
46
47#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
49pub struct Tool {
50 pub name: String,
52 #[serde(skip_serializing_if = "Option::is_none")]
54 pub description: Option<String>,
55 pub input_schema: serde_json::Value,
57 #[serde(skip_serializing_if = "Option::is_none")]
59 pub cache_control: Option<CacheControl>,
60 #[serde(skip_serializing_if = "Option::is_none")]
65 pub strict: Option<bool>,
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
70#[serde(tag = "type", rename_all = "snake_case")]
71pub enum ToolChoice {
72 Auto {
74 #[serde(skip_serializing_if = "Option::is_none")]
76 disable_parallel_tool_use: Option<bool>,
77 },
78 Any {
80 #[serde(skip_serializing_if = "Option::is_none")]
82 disable_parallel_tool_use: Option<bool>,
83 },
84 #[serde(rename = "none")]
86 None,
87 Tool {
89 name: String,
91 #[serde(skip_serializing_if = "Option::is_none")]
93 disable_parallel_tool_use: Option<bool>,
94 },
95}
96
97impl Default for ToolChoice {
98 fn default() -> Self {
99 Self::Auto {
100 disable_parallel_tool_use: None,
101 }
102 }
103}
104
105#[cfg(feature = "schemars")]
107pub mod schema {
108 use schemars::JsonSchema;
109
110 use super::Tool;
111
112 #[must_use]
132 pub fn tool_from_schema<T: JsonSchema>(name: &str, description: Option<&str>) -> Tool {
133 let schema = schemars::schema_for!(T);
134 let schema_value = serde_json::to_value(&schema).expect("valid schema");
135 Tool {
136 name: name.to_string(),
137 description: description.map(std::string::ToString::to_string),
138 input_schema: schema_value,
139 cache_control: None,
140 strict: None,
141 }
142 }
143
144 pub fn try_parse_tool_use<T: serde::de::DeserializeOwned>(
149 name: &str,
150 input: &serde_json::Value,
151 ) -> serde_json::Result<T> {
152 let wrapped = serde_json::json!({
153 "action": name,
154 "params": input
155 });
156 serde_json::from_value(wrapped)
157 }
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163
164 #[test]
165 fn tool_choice_auto_ser() {
166 let tc = ToolChoice::Auto {
167 disable_parallel_tool_use: None,
168 };
169 let s = serde_json::to_string(&tc).unwrap();
170 assert!(s.contains(r#""type":"auto""#));
171 }
172
173 #[test]
174 fn tool_choice_any_ser() {
175 let tc = ToolChoice::Any {
176 disable_parallel_tool_use: Some(true),
177 };
178 let s = serde_json::to_string(&tc).unwrap();
179 assert!(s.contains(r#""type":"any""#));
180 assert!(s.contains(r#""disable_parallel_tool_use":true"#));
181 }
182
183 #[test]
184 fn tool_choice_none_ser() {
185 let tc = ToolChoice::None;
186 let s = serde_json::to_string(&tc).unwrap();
187 assert_eq!(s, r#"{"type":"none"}"#);
188 }
189
190 #[test]
191 fn tool_choice_tool_ser() {
192 let tc = ToolChoice::Tool {
193 name: "get_weather".into(),
194 disable_parallel_tool_use: None,
195 };
196 let s = serde_json::to_string(&tc).unwrap();
197 assert!(s.contains(r#""type":"tool""#));
198 assert!(s.contains(r#""name":"get_weather""#));
199 }
200
201 #[test]
202 fn tool_ser() {
203 let tool = Tool {
204 name: "calculator".into(),
205 description: Some("Math tool".into()),
206 input_schema: serde_json::json!({
207 "type": "object",
208 "properties": {
209 "expression": { "type": "string" }
210 }
211 }),
212 cache_control: None,
213 strict: None,
214 };
215 let s = serde_json::to_string(&tool).unwrap();
216 assert!(s.contains(r#""name":"calculator""#));
217 assert!(s.contains(r#""description":"Math tool""#));
218 assert!(s.contains(r#""input_schema""#));
219 assert!(!s.contains("strict"));
221 }
222
223 #[cfg(feature = "schemars")]
224 #[test]
225 fn schema_tool_generation() {
226 use schemars::JsonSchema;
227
228 #[derive(serde::Serialize, serde::Deserialize, JsonSchema)]
229 #[serde(tag = "action", content = "params")]
230 enum TestTools {
231 Echo { message: String },
232 }
233
234 let tool = schema::tool_from_schema::<TestTools>("test", Some("Test tool"));
235 assert_eq!(tool.name, "test");
236 assert_eq!(tool.description, Some("Test tool".into()));
237 assert!(tool.input_schema.is_object());
238 }
239}