1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//! Provides procedural macros for the [clust](https://github.com/mochi-neko/clust).

use crate::tool::impl_tool;
use proc_macro::TokenStream;

mod check_result;
mod tool;

/// A procedural macro that generates a `clust::messages::Tool` or `clust::messages::AsyncTool`
/// implementation for the annotated function with documentation.
///
/// See also [the official guide](https://docs.anthropic.com/claude/docs/functions-external-tools).
///
/// ## Supported arguments
/// - None
///   - e.g. `fn function() -> T`
/// - A type or types that implement(s) `std::str::FromStr`.
///   - e.g.
///     - `fn function(arg1: u32) -> T`
///     - `fn function(arg1: DefinedStruct) -> T` where `DefinedStruct` implements `std::str::FromStr`.
///
/// ## Supported return values
/// - A type that implements `std::fmt::Display`.
///   - e.g.
///     - `fn function() -> u32`
///     - `fn function() -> DefinedStruct` where `DefinedStruct` implements `std::fmt::Display`.
/// - Result<T, E> where T and E implement `std::fmt::Display`.
///   - e.g.
///     - `fn function() -> Result<u32, Error>`
///     - `fn function() -> Result<DefinedStruct, Error>` where `DefinedStruct` and `Error` implement `std::fmt::Display`.
///
/// ## Supported executions
/// - Synchronous -> implement `clust::messages::Tool`
///   - e.g. `fn function() -> T`
/// - Asynchronous -> implement `clust::messages::AsyncTool`
///   - e.g. `async fn function() -> T`
///
/// ## Supported documentation formats
/// 1. Description block for the function at the top of document.
/// 2. Arguments block for the function with
///   - header: `# Arguments`, `## Arguments`, `# Parameters` or `## Parameters`.
///   - listed items: `- `arg1` - Description for the argument` or `* `arg1` - Description for the argument`.
/// 3. Other blocks are ignored.
///
/// ```rust
/// /// Description for the function.
/// ///
/// /// ## Arguments
/// /// - `arg1` - Description for the argument.
/// fn function(arg1: i32) -> i32 { arg1 }
/// ```
///
/// ## Examples
///
/// Implement a tool by `clust_tool` for a function with documentation:
///
/// ```rust
/// use clust_macros::clust_tool;
/// use std::collections::BTreeMap;
/// use std::iter::FromIterator;
/// use clust::messages::{FunctionCalls, Invoke, Tool};
///
/// /// Increments the argument by 1.
/// ///
/// /// ## Arguments
/// /// - `value` - Target value.
/// #[clust_tool]
/// fn incrementer(value: i32) -> i32 {
///    value + 1
/// }
///
/// let tool = ClustTool_incrementer {};
///
/// let description = tool.description();
///
/// let function_calls = FunctionCalls {
///     invoke: Invoke {
///         tool_name: String::from("incrementer"),
///         parameters: BTreeMap::from_iter(vec![(
///             "value".to_string(),
///             "42".to_string(),
///         )]),
///     },
/// };
///
/// let result = tool.call(function_calls).unwrap();
/// ```
///
/// Generated XML tool description from above implementation is as follows:
///
/// ```xml
/// <tool_description>
///   <tool_name>incrementer</tool_name>
///   <description>Increments the argument by 1.</description>
///   <parameters>
///     <parameter>
///       <name>value</name>
///       <type>i32</type>
///       <description>Target value.</description>
///     </parameter>
///   </parameters>
/// </tool_description>
/// ```
///
/// This tool can be called with a function calls as following XML format:
///
/// ```xml
/// <function_calls>
///   <invoke>
///     <tool_name>incrementer</tool_name>
///     <parameters>
///         <value>42</value>
///     </parameters>
///   </invoke>
/// </function_calls>
/// ```
///
/// Calling result is as following XML format:
///
/// ```xml
/// <function_results>
///   <result>
///     <tool_name>incrementer</tool_name>
///     <stdout>43</stdout>
///   </result>
/// </function_results>
/// ```
#[proc_macro_attribute]
pub fn clust_tool(
    _attr: TokenStream,
    item: TokenStream,
) -> TokenStream {
    let item_func = syn::parse::<syn::ItemFn>(item).unwrap();
    impl_tool(&item_func)
}