feat: Add Tool trait definition and tool_registry macro skeleton

This commit is contained in:
2026-01-06 13:52:32 +09:00
parent 9a7acb74c8
commit a4e2795e56
7 changed files with 440 additions and 33 deletions
+103 -30
View File
@@ -1,41 +1,114 @@
//! worker-macros - LLMワーカー用のProcedural Macros
//!
//! このクレートはTools/Hooksを定義するためのマクロを提供する予定です。
//!
//! TODO: Tool定義マクロの実装
//! TODO: Hook定義マクロの実装
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, ImplItem, ItemImpl};
/// ツール定義マクロ(未実装)
/// `impl` ブロックに付与し、内部の `#[tool]` 属性がついたメソッドからツールを生成するマクロ。
///
/// # Example
/// ```ignore
/// #[tool(
/// name = "get_weather",
/// description = "Get weather information for a city"
/// )]
/// fn get_weather(city: String) -> Result<WeatherInfo, ToolError> {
/// // ...
/// #[tool_registry]
/// impl MyApp {
/// #[tool]
/// async fn my_function(&self, arg: String) -> Result<String, Error> { ... }
/// }
/// ```
#[proc_macro_attribute]
pub fn tool_registry(_attr: TokenStream, item: TokenStream) -> TokenStream {
let mut impl_block = parse_macro_input!(item as ItemImpl);
let self_ty = &impl_block.self_ty;
let mut generated_items = Vec::new();
for item in &mut impl_block.items {
if let ImplItem::Fn(method) = item {
// #[tool] 属性を探す
let mut is_tool = false;
let mut _description = String::new();
// 属性を走査してtoolがあるか確認し、削除する
// 同時にドキュメントコメントから説明を取得
method.attrs.retain(|attr| {
if attr.path().is_ident("tool") {
is_tool = true;
false // 属性を削除
} else if attr.path().is_ident("doc") {
// TODO: docコメントのパース
true
} else {
true
}
});
if is_tool {
let sig = &method.sig;
let method_name = &sig.ident;
let tool_name = method_name.to_string();
let tool_struct_name = syn::Ident::new(
&format!("Tool_{}", method_name),
method_name.span(),
);
let factory_name = syn::Ident::new(
&format!("{}_tool", method_name),
method_name.span(),
);
// TODO: 引数の解析とArgs構造体の生成
// TODO: descriptionの取得
// 仮の実装: Contextを抱えるTool構造体を作成
let tool_impl = quote! {
#[derive(Clone)]
pub struct #tool_struct_name {
ctx: #self_ty,
}
#[async_trait::async_trait]
impl worker_types::Tool for #tool_struct_name {
fn name(&self) -> &str {
#tool_name
}
fn description(&self) -> &str {
"TODO: description from doc comments"
}
fn input_schema(&self) -> serde_json::Value {
serde_json::json!({}) // TODO: schemars
}
async fn execute(&self, input_json: &str) -> Result<String, worker_types::ToolError> {
// TODO: Deserialize args and call check
// self.ctx.#method_name(...)
Ok("Not implemented yet".to_string())
}
}
impl #self_ty {
pub fn #factory_name(&self) -> #tool_struct_name {
#tool_struct_name {
ctx: self.clone()
}
}
}
};
generated_items.push(tool_impl);
}
}
}
let expanded = quote! {
#impl_block
#(#generated_items)*
};
TokenStream::from(expanded)
}
/// マーカー属性。`tool_registry` によって処理されるため、ここでは何もしない。
#[proc_macro_attribute]
pub fn tool(_attr: TokenStream, item: TokenStream) -> TokenStream {
// TODO: 実装
item
}
/// フック定義マクロ(未実装)
///
/// # Example
/// ```ignore
/// #[hook(on = "before_tool_call")]
/// fn log_tool_call(tool_name: &str) {
/// println!("Calling tool: {}", tool_name);
/// }
/// ```
#[proc_macro_attribute]
pub fn hook(_attr: TokenStream, item: TokenStream) -> TokenStream {
// TODO: 実装
item
}