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}