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/// # Macro Expansion
54///
55/// ## Transform a Function
56///
57/// Input function:
58/// ```ignore
59/// /// Fetch a URL.
60/// #[tool]
61/// pub async fn fetch(
62///     /// URL to fetch
63///     url: String,
64/// ) -> String {
65///     todo!()
66/// }
67/// ```
68///
69/// Expands to:
70/// ```ignore
71/// /// Arguments for the `fetch` tool.
72/// #[derive(serde::Deserialize, schemars::JsonSchema)]
73/// pub struct FetchArgs {
74///     /// URL to fetch
75///     pub url: String,
76/// }
77///
78/// impl tiny_loop::tool::ToolArgs for FetchArgs {
79///     const TOOL_NAME: &'static str = "fetch";
80///     const TOOL_DESCRIPTION: &'static str = "Fetch a URL.";
81/// }
82///
83/// /// Fetch a URL.
84/// pub async fn fetch(args: FetchArgs) -> String {
85///     let FetchArgs { url } = args;
86///     todo!()
87/// }
88/// ```
89///
90/// ## Transform Methods
91///
92/// Input method:
93/// ```ignore
94/// impl Database {
95///     /// Query database
96///     #[tool]
97///     pub async fn query(
98///         self,
99///         /// SQL query
100///         sql: String,
101///     ) -> String {
102///         todo!()
103///     }
104/// }
105/// ```
106///
107/// Expands to:
108/// ```ignore
109/// /// Arguments for the `query` tool.
110/// #[derive(serde::Deserialize, schemars::JsonSchema)]
111/// pub struct QueryArgs {
112///     /// SQL query
113///     pub sql: String,
114/// }
115///
116/// impl tiny_loop::tool::ToolArgs for QueryArgs {
117///     const TOOL_NAME: &'static str = "query";
118///     const TOOL_DESCRIPTION: &'static str = "Query database";
119/// }
120///
121/// impl Database {
122///     /// Query database
123///     pub async fn query(self, args: QueryArgs) -> String {
124///         let QueryArgs { sql } = args;
125///         todo!()
126///     }
127/// }
128/// ```
129#[proc_macro_attribute]
130pub fn tool(_attr: TokenStream, item: TokenStream) -> TokenStream {
131    tool_impl(item, quote!(tiny_loop::tool::ToolArgs))
132}
133
134/// Same as `#[tool]` but uses internal `ToolArgs` path for use within the `tiny-loop` crate.
135#[doc(hidden)]
136#[proc_macro_attribute]
137pub fn tool_internal(_attr: TokenStream, item: TokenStream) -> TokenStream {
138    tool_impl(item, quote!(crate::tool::ToolArgs))
139}