Skip to main content

lellm_derive/
lib.rs

1//! lellm-derive — 派生宏与属性宏。
2//!
3//! # 三级 API
4//!
5//! ## Level 1: `#[tool]` 函数宏(推荐,95% 用户)
6//!
7//! ```ignore
8//! use lellm_agent::ToolResult;
9//! use lellm_derive::tool;
10//!
11//! #[tool(name = "search", description = "搜索互联网信息")]
12//! async fn search(query: String, limit: Option<u32>) -> ToolResult {
13//!     // 实现逻辑
14//!     Ok(format!("搜索结果: {}", query))
15//! }
16//!
17//! // 无依赖 — 直接调用生成的工厂函数:
18//! builder.tool(search_tool());
19//!
20//! // 有依赖 — 使用 _with 后缀工厂函数:
21//! let client = SearchClient::new();
22//! builder.tool(search_tool_with({
23//!     let client = client.clone();
24//!     move |args| async move {
25//!         client.search(&args.query, args.limit).await
26//!     }
27//! }));
28//! ```
29//!
30//! ## Level 2: `#[derive(Tool)]` struct 宏(高级用户)
31//!
32//! ```ignore
33//! use lellm_agent::ToolResult;
34//! use lellm_derive::Tool;
35//!
36//! #[derive(Tool, JsonSchema)]
37//! #[tool(name = "search", description = "搜索互联网信息")]
38//! struct SearchArgs {
39//!     /// 搜索关键词
40//!     query: String,
41//!     /// 返回数量
42//!     limit: Option<u32>,
43//! }
44//!
45//! // 注册:
46//! let reg = SearchArgs::safe(|args| async move {
47//!     Ok(format!("搜索结果: {}", args.query))
48//! });
49//! ```
50//!
51//! ## Level 3: `ToolRegistration::safe()`(框架开发者)
52//!
53//! ```ignore
54//! use lellm_agent::{ToolDefinition, ToolRegistration};
55//!
56//! let reg = ToolRegistration::safe(
57//!     ToolDefinition {
58//!         name: "search".to_string(),
59//!         description: "搜索".to_string(),
60//!         parameters: serde_json::json!({
61//!             "type": "object",
62//!             "properties": { "query": { "type": "string" } }
63//!         }),
64//!     },
65//!     |args| async { Ok(args["query"].as_str().unwrap().to_string()) }
66//! );
67//! ```
68
69mod codegen;
70mod fn_expand;
71mod helpers;
72mod struct_expand;
73
74use proc_macro::TokenStream;
75use proc_macro2::Span;
76use syn::{DeriveInput, Item, parse_macro_input};
77
78// ─────────────────────────────────────────────────────────────────
79// Entry: #[tool] attribute macro (handles both fn and struct)
80// ─────────────────────────────────────────────────────────────────
81
82#[proc_macro_attribute]
83pub fn tool(args: TokenStream, input: TokenStream) -> TokenStream {
84    let parsed: Item = parse_macro_input!(input as Item);
85
86    match parsed {
87        Item::Fn(func) => {
88            // Level 1: function → generate Args struct + factory functions
89            match fn_expand::expand_tool_for_fn(args.into(), func) {
90                Ok(out) => out.into(),
91                Err(e) => e.to_compile_error().into(),
92            }
93        }
94        Item::Struct(s) => {
95            // Level 2: struct → generate ToolArgs impl
96            match struct_expand::expand_tool_for_struct(args.into(), s) {
97                Ok(out) => out.into(),
98                Err(e) => e.to_compile_error().into(),
99            }
100        }
101        other => {
102            syn::Error::new_spanned(other, "#[tool] can only be applied to functions or structs")
103                .to_compile_error()
104                .into()
105        }
106    }
107}
108
109// ─────────────────────────────────────────────────────────────────
110// Entry: #[derive(Tool)] derive macro
111// ─────────────────────────────────────────────────────────────────
112
113#[proc_macro_derive(Tool, attributes(tool))]
114pub fn derive_tool(input: TokenStream) -> TokenStream {
115    let input = parse_macro_input!(input as DeriveInput);
116
117    match &input.data {
118        syn::Data::Struct(data) => struct_expand::generate_tool_for_struct(&input, data),
119        _ => {
120            let error = syn::Error::new(Span::call_site(), "Tool only supports struct types");
121            error.to_compile_error().into()
122        }
123    }
124}
125
126// ─────────────────────────────────────────────────────────────────
127// Backward compatibility: ToolDefinition alias
128// ─────────────────────────────────────────────────────────────────
129
130#[proc_macro_derive(ToolDefinition, attributes(tool))]
131#[deprecated(since = "0.2.0", note = "Use `Tool` instead of `ToolDefinition`")]
132pub fn derive_tool_definition(input: TokenStream) -> TokenStream {
133    derive_tool(input)
134}