//! Examples demonstrating the `#[tool]` procedural macro. //! //! The macro eliminates boilerplate for defining tools: //! Instead of manually building `ToolDefinition` + `ToolSchema` + serde structures, //! you write a typed Rust function and derive everything automatically. //! //! # Manual way (without macro) //! //! ``` //! use agent::{ToolDefinition, ToolParam, ToolRegistry, ToolSchema}; //! use serde_json::json; //! //! fn register_manual(registry: &mut ToolRegistry) { //! registry.register_fn("search_issues", |_ctx, args| { //! async move { //! let args: serde_json::Value = args; //! let title = args["title"].as_str().unwrap_or(""); //! Ok(json!([{ "title": title, "status": "open" }])) //! }.boxed() //! }); //! } //! ``` //! //! # With `#[tool]` macro (recommended) //! //! ``` //! use agent_tool_derive::tool; //! use agent::{ToolDefinition, ToolRegistry, ToolError}; //! //! #[tool(description = "Search issues by title", params( //! title = "Issue title to search for", //! status = "Filter by status (open/closed/all)" //! ))] //! async fn search_issues( //! title: String, //! status: Option, //! ) -> Result, String> { //! Ok(vec![serde_json::json!({ //! "title": title, //! "status": status.unwrap_or_else(|| "open".to_string()) //! })]) //! } //! //! fn register_with_macro(registry: &mut ToolRegistry) { //! register_search_issues(registry); // Generated by #[tool] //! } //! ``` //! //! The macro generates: //! - `SearchIssuesParameters` struct (serde Deserialize) //! - `SEARCH_ISSUES_DEFINITION: ToolDefinition` constant //! - `register_search_issues(registry: &mut ToolRegistry)` helper #[cfg(test)] mod tests { use crate::{ToolDefinition, ToolError, ToolRegistry}; // Example: using the manual approach (without macro) // This demonstrates the baseline — how it looks without #[tool] #[test] fn manual_tool_registration_shows_boilerplate() { use futures::FutureExt; let mut registry = ToolRegistry::new(); registry.register_fn("echo", |_ctx, args| { async move { let text: serde_json::Value = serde_json::from_value(args) .map_err(|e| ToolError::ParseError(e.to_string()))?; Ok(text) } .boxed() }); assert_eq!(registry.len(), 1); assert!(registry.get("echo").is_some()); } // NOTE: To use #[tool], the `agent-tool-derive` crate must be a dependency. // Since proc-macro crates cannot be conditionally compiled via cfg_attr, // the macro usage example is documented above in the module doc comment. // // Full working example (requires agent-tool-derive dependency): // // ```ignore // use agent_tool_derive::tool; // // #[tool(description = "Echo back the input text", params( // text = "The text to echo back" // ))] // async fn echo(text: String) -> Result { // Ok(text) // } // // #[test] // fn test_macro_generates_definition() { // let def = ECHO_DEFINITION; // assert_eq!(def.name, "echo"); // assert!(def.description.is_some()); // assert!(def.parameters.is_some()); // // let schema = def.parameters.unwrap(); // assert_eq!(schema.schema_type, "object"); // let props = schema.properties.unwrap(); // assert!(props.contains_key("text")); // } // // #[test] // fn test_macro_registers_tool() { // let mut registry = ToolRegistry::new(); // register_echo(&mut registry); // assert!(registry.get("echo").is_some()); // } // ``` }