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}