use anthropic_async::types::content::ContentBlock;
use anthropic_async::types::content::ContentBlockParam;
use anthropic_async::types::content::MessageParam;
use anthropic_async::types::content::MessageRole;
use anthropic_async::types::messages::MessagesCreateRequest;
use anthropic_async::types::tools::Tool;
use anthropic_async::types::tools::ToolChoice;
#[test]
fn tool_serialization() {
let tool = Tool {
name: "get_weather".into(),
description: Some("Get weather for a city".into()),
input_schema: serde_json::json!({
"type": "object",
"properties": {
"city": { "type": "string" }
},
"required": ["city"]
}),
cache_control: None,
strict: None,
};
let s = serde_json::to_string(&tool).unwrap();
assert!(s.contains(r#""name":"get_weather""#));
assert!(s.contains(r#""description":"Get weather for a city""#));
assert!(s.contains(r#""input_schema""#));
assert!(!s.contains("strict"));
}
#[test]
fn tool_choice_auto() {
let tc = ToolChoice::Auto {
disable_parallel_tool_use: None,
};
let s = serde_json::to_string(&tc).unwrap();
assert!(s.contains(r#""type":"auto""#));
}
#[test]
fn tool_choice_specific() {
let tc = ToolChoice::Tool {
name: "calculator".into(),
disable_parallel_tool_use: Some(true),
};
let s = serde_json::to_string(&tc).unwrap();
assert!(s.contains(r#""type":"tool""#));
assert!(s.contains(r#""name":"calculator""#));
assert!(s.contains(r#""disable_parallel_tool_use":true"#));
}
#[test]
fn message_request_with_tools() {
let tool = Tool {
name: "echo".into(),
description: None,
input_schema: serde_json::json!({
"type": "object",
"properties": {
"message": { "type": "string" }
}
}),
cache_control: None,
strict: None,
};
let req = MessagesCreateRequest {
model: "claude-sonnet-4-6".into(),
max_tokens: 128,
messages: vec![MessageParam {
role: MessageRole::User,
content: "Hello".into(),
}],
tools: Some(vec![tool]),
tool_choice: Some(ToolChoice::Auto {
disable_parallel_tool_use: None,
}),
..Default::default()
};
let s = serde_json::to_string(&req).unwrap();
assert!(s.contains(r#""tools""#));
assert!(s.contains(r#""tool_choice""#));
assert!(s.contains(r#""name":"echo""#));
}
#[test]
fn tool_result_content_block() {
use anthropic_async::types::content::ToolResultContent;
let tool_result = ContentBlockParam::ToolResult {
tool_use_id: "tool_123".into(),
content: Some(ToolResultContent::String("Result content".into())),
is_error: Some(false),
cache_control: None,
};
let s = serde_json::to_string(&tool_result).unwrap();
assert!(s.contains(r#""type":"tool_result""#));
assert!(s.contains(r#""tool_use_id":"tool_123""#));
assert!(s.contains(r#""content":"Result content""#));
assert!(s.contains(r#""is_error":false"#));
}
#[test]
fn tool_use_response_block() {
let tool_use = ContentBlock::ToolUse {
id: "tool_456".into(),
name: "calculator".into(),
input: serde_json::json!({ "expression": "2+2" }),
};
let s = serde_json::to_string(&tool_use).unwrap();
assert!(s.contains(r#""type":"tool_use""#));
assert!(s.contains(r#""id":"tool_456""#));
assert!(s.contains(r#""name":"calculator""#));
assert!(s.contains(r#""expression":"2+2""#));
}
#[test]
fn tool_use_response_deserialization() {
let json = r#"{
"type": "tool_use",
"id": "tool_789",
"name": "weather",
"input": {"city": "Paris"}
}"#;
let block: ContentBlock = serde_json::from_str(json).unwrap();
match block {
ContentBlock::ToolUse { id, name, input } => {
assert_eq!(id, "tool_789");
assert_eq!(name, "weather");
assert_eq!(input["city"], "Paris");
}
_ => panic!("Expected ToolUse variant"),
}
}
#[cfg(feature = "schemars")]
#[test]
fn schema_generation() {
use anthropic_async::types::tools::schema;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
#[derive(Serialize, Deserialize, JsonSchema)]
#[serde(tag = "action", content = "params")]
enum TestActions {
Add { a: i32, b: i32 },
Multiply { a: i32, b: i32 },
}
let tool = schema::tool_from_schema::<TestActions>("math", Some("Math operations"));
assert_eq!(tool.name, "math");
assert_eq!(tool.description, Some("Math operations".into()));
assert!(tool.input_schema.is_object());
}
#[cfg(feature = "schemars")]
#[test]
fn tool_use_parsing() {
use anthropic_async::types::tools::schema;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
#[derive(Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
#[serde(tag = "action", content = "params")]
enum TestActions {
Echo { message: String },
}
let input = serde_json::json!({ "message": "hello" });
let action = schema::try_parse_tool_use::<TestActions>("Echo", &input).unwrap();
match action {
TestActions::Echo { message } => {
assert_eq!(message, "hello");
}
}
}
#[cfg(feature = "schemars")]
#[test]
fn tool_use_parsing_snake_case() {
use anthropic_async::types::tools::schema;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
#[derive(Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
#[serde(tag = "action", content = "params", rename_all = "snake_case")]
enum Actions {
SendEmail { to: String, subject: String },
SearchWeb { query: String },
}
let input_email = serde_json::json!({ "to": "user@example.com", "subject": "Hello" });
let act1: Actions = schema::try_parse_tool_use("send_email", &input_email).unwrap();
assert_eq!(
act1,
Actions::SendEmail {
to: "user@example.com".into(),
subject: "Hello".into()
}
);
let input_search = serde_json::json!({ "query": "rust async runtimes" });
let act2: Actions = schema::try_parse_tool_use("search_web", &input_search).unwrap();
assert_eq!(
act2,
Actions::SearchWeb {
query: "rust async runtimes".into()
}
);
}