use adk_core::{AdkError, Tool};
use adk_core as adk_tool;
use adk_rust_macros::tool;
use schemars::JsonSchema;
use serde::Deserialize;
use serde_json::{Value, json};
use std::sync::Arc;
#[derive(Deserialize, JsonSchema)]
struct WeatherArgs {
city: String,
}
#[tool]
async fn get_weather(args: WeatherArgs) -> Result<Value, AdkError> {
Ok(json!({ "temp": 72, "city": args.city }))
}
#[test]
fn tool_has_correct_name() {
let tool = GetWeather;
assert_eq!(tool.name(), "get_weather");
}
#[test]
fn tool_has_doc_description() {
let tool = GetWeather;
assert_eq!(tool.description(), "Get the current weather for a city.");
}
#[test]
fn tool_has_schema() {
let tool = GetWeather;
let schema = tool.parameters_schema();
assert!(schema.is_some());
let schema = schema.unwrap();
assert!(schema.get("properties").is_some());
}
#[tool]
async fn calculator(
_ctx: Arc<dyn adk_core::ToolContext>,
args: CalcArgs,
) -> Result<Value, AdkError> {
Ok(json!({ "result": args.a + args.b }))
}
#[derive(Deserialize, JsonSchema)]
struct CalcArgs {
a: f64,
b: f64,
}
#[test]
fn tool_with_context_has_correct_name() {
let tool = Calculator;
assert_eq!(tool.name(), "calculator");
}
#[test]
fn tool_with_context_has_schema() {
let tool = Calculator;
let schema = tool.parameters_schema().unwrap();
let props = schema.get("properties").unwrap();
assert!(props.get("a").is_some());
assert!(props.get("b").is_some());
}
#[tool]
async fn my_cool_tool(args: WeatherArgs) -> Result<Value, AdkError> {
Ok(json!({ "city": args.city }))
}
#[test]
fn tool_without_doc_gets_auto_description() {
let tool = MyCoolTool;
assert_eq!(tool.description(), "my cool tool");
}
#[tool(read_only)]
async fn read_only_lookup(args: WeatherArgs) -> Result<Value, AdkError> {
Ok(json!({ "city": args.city }))
}
#[test]
fn tool_read_only_attribute() {
let tool = ReadOnlyLookup;
assert!(tool.is_read_only(), "read_only attribute should set is_read_only() to true");
assert!(!tool.is_concurrency_safe(), "concurrency_safe should remain false");
assert!(!tool.is_long_running(), "long_running should remain false");
}
#[tool(read_only, concurrency_safe)]
async fn concurrent_lookup(args: WeatherArgs) -> Result<Value, AdkError> {
Ok(json!({ "city": args.city }))
}
#[test]
fn tool_multiple_attributes() {
let tool = ConcurrentLookup;
assert!(tool.is_read_only());
assert!(tool.is_concurrency_safe());
assert!(!tool.is_long_running());
}
#[tool(long_running)]
async fn background_task(args: WeatherArgs) -> Result<Value, AdkError> {
Ok(json!({ "city": args.city }))
}
#[test]
fn tool_long_running_attribute() {
let tool = BackgroundTask;
assert!(!tool.is_read_only());
assert!(!tool.is_concurrency_safe());
assert!(tool.is_long_running());
}
#[tool(read_only, concurrency_safe, long_running)]
async fn fully_attributed(args: WeatherArgs) -> Result<Value, AdkError> {
Ok(json!({ "city": args.city }))
}
#[test]
fn tool_all_attributes() {
let tool = FullyAttributed;
assert!(tool.is_read_only());
assert!(tool.is_concurrency_safe());
assert!(tool.is_long_running());
}
#[test]
fn tool_no_attributes_defaults_false() {
let tool = GetWeather;
assert!(!tool.is_read_only());
assert!(!tool.is_concurrency_safe());
assert!(!tool.is_long_running());
}
#[derive(Deserialize, JsonSchema)]
struct ArchReviewArgs {
rps: u32,
}
#[tool]
async fn review_architecture(args: ArchReviewArgs) -> Result<Value, AdkError> {
Ok(json!({ "rps": args.rps }))
}
#[test]
fn tool_arg_type_name_containing_arc_is_not_skipped() {
let tool = ReviewArchitecture;
let schema = tool.parameters_schema().unwrap();
let props = schema.get("properties").unwrap();
assert!(props.get("rps").is_some());
}