Skip to main content

tiny_loop_macros/
lib.rs

1mod tool;
2
3use crate::tool::tool_impl;
4use proc_macro::TokenStream;
5use quote::quote;
6
7/// Transforms a function or method into a tool with generated args struct and `ToolArgs` implementation.
8///
9/// # Usage
10///
11/// ## Transform a Function
12///
13/// ```ignore
14/// use tiny_loop::{Agent, tool::tool, llm::OpenAIProvider};
15///
16/// #[tool]
17/// async fn get_weather(
18///     /// City name
19///     city: String,
20/// ) -> String {
21///     format!("Weather in {}: Sunny", city)
22/// }
23///
24/// let agent = Agent::new(OpenAIProvider::new())
25///     .tool(get_weather);
26/// ```
27///
28/// ## Transform Methods
29///
30/// For methods, use `.bind()`:
31///
32/// ```ignore
33/// #[derive(Clone)]
34/// struct Database;
35///
36/// #[tool]
37/// impl Database {
38///     /// Query the database
39///     async fn query(
40///         self,
41///         /// SQL query
42///         sql: String,
43///     ) -> String {
44///         format!("Results for: {}", sql)
45///     }
46/// }
47///
48/// let db = Database;
49/// let agent = Agent::new(OpenAIProvider::new())
50///     .bind(db, Database::query);
51/// ```
52///
53/// ## Custom Tool Name
54///
55/// ```ignore
56/// #[tool(name = "weather_api")]
57/// async fn get_weather(
58///     /// City name
59///     city: String,
60/// ) -> String {
61///     todo!()
62/// }
63///
64/// #[tool]
65/// impl Database {
66///     #[name = "db_query"]
67///     async fn query(self, sql: String) -> String {
68///         todo!()
69///     }
70/// }
71/// ```
72///
73/// ## Serde Attributes
74///
75/// Serde attributes like `#[serde(rename = "...")]` can be applied to parameters:
76///
77/// ```ignore
78/// #[tool]
79/// async fn fetch(
80///     #[serde(rename = "URL")]
81///     url: String,
82/// ) -> String {
83///     todo!()
84/// }
85/// ```
86///
87/// # Macro Expansion
88///
89/// ## Transform a Function
90///
91/// Input function:
92/// ```ignore
93/// /// Fetch a URL.
94/// #[tool]
95/// pub async fn fetch(
96///     /// URL to fetch
97///     url: String,
98/// ) -> String {
99///     todo!()
100/// }
101/// ```
102///
103/// Expands to:
104/// ```ignore
105/// /// Arguments for the `fetch` tool.
106/// #[derive(serde::Deserialize, schemars::JsonSchema)]
107/// pub struct FetchArgs {
108///     /// URL to fetch
109///     pub url: String,
110/// }
111///
112/// impl tiny_loop::tool::ToolArgs for FetchArgs {
113///     const TOOL_NAME: &'static str = "fetch";
114///     const TOOL_DESCRIPTION: &'static str = "Fetch a URL.";
115/// }
116///
117/// /// Fetch a URL.
118/// pub async fn fetch(args: FetchArgs) -> String {
119///     let FetchArgs { url } = args;
120///     todo!()
121/// }
122/// ```
123///
124/// ## Transform Methods
125///
126/// Input method:
127/// ```ignore
128/// impl Database {
129///     /// Query database
130///     #[tool]
131///     pub async fn query(
132///         self,
133///         /// SQL query
134///         sql: String,
135///     ) -> String {
136///         todo!()
137///     }
138/// }
139/// ```
140///
141/// Expands to:
142/// ```ignore
143/// /// Arguments for the `query` tool.
144/// #[derive(serde::Deserialize, schemars::JsonSchema)]
145/// pub struct QueryArgs {
146///     /// SQL query
147///     pub sql: String,
148/// }
149///
150/// impl tiny_loop::tool::ToolArgs for QueryArgs {
151///     const TOOL_NAME: &'static str = "query";
152///     const TOOL_DESCRIPTION: &'static str = "Query database";
153/// }
154///
155/// impl Database {
156///     /// Query database
157///     pub async fn query(self, args: QueryArgs) -> String {
158///         let QueryArgs { sql } = args;
159///         todo!()
160///     }
161/// }
162/// ```
163#[proc_macro_attribute]
164pub fn tool(attr: TokenStream, item: TokenStream) -> TokenStream {
165    tool_impl(attr, item, quote!(tiny_loop::tool::ToolArgs))
166}
167
168/// Same as `#[tool]` but uses internal `ToolArgs` path for use within the `tiny-loop` crate.
169#[doc(hidden)]
170#[proc_macro_attribute]
171pub fn tool_internal(attr: TokenStream, item: TokenStream) -> TokenStream {
172    tool_impl(attr, item, quote!(crate::tool::ToolArgs))
173}