act_sdk_macros/lib.rs
1mod component;
2mod tool;
3
4use proc_macro::TokenStream;
5
6/// Attribute macro for ACT component modules. Takes no arguments.
7///
8/// Transforms a module of `#[act_tool]` functions into a complete WIT component
9/// implementation (wit-bindgen world, `Guest` impl, `list_tools`/`call_tool`
10/// dispatch, plus session-provider when `#[session_open]`/`#[session_close]` are
11/// present). Component metadata and skills are embedded by `act-build pack`, not
12/// this macro.
13#[proc_macro_attribute]
14pub fn act_component(attr: TokenStream, item: TokenStream) -> TokenStream {
15 let attr_stream: proc_macro2::TokenStream = attr.into();
16 if !attr_stream.is_empty() {
17 return syn::Error::new_spanned(
18 &attr_stream,
19 "#[act_component] takes no arguments; component metadata comes from act.toml via `act-build pack`",
20 )
21 .to_compile_error()
22 .into();
23 }
24 let module = match syn::parse::<syn::ItemMod>(item) {
25 Ok(m) => m,
26 Err(e) => return e.to_compile_error().into(),
27 };
28 match component::generate(&module) {
29 Ok(tokens) => tokens.into(),
30 Err(e) => e.to_compile_error().into(),
31 }
32}
33
34/// Attribute macro for ACT tool functions.
35///
36/// When used inside an `#[act_component]` module, marks a function as a tool.
37/// The `#[act_component]` macro processes these attributes during code generation.
38///
39/// When used standalone (outside `#[act_component]`), this is a no-op pass-through.
40///
41/// # Attributes
42///
43/// - `description = "..."` (required) — Tool description
44/// - `read_only` — Mark tool as read-only
45/// - `idempotent` — Mark tool as idempotent
46/// - `destructive` — Mark tool as destructive
47/// - `streaming` — Mark tool as streaming (auto-detected if ActContext param present)
48/// - `timeout_ms = N` — Set timeout in milliseconds
49#[proc_macro_attribute]
50pub fn act_tool(_attr: TokenStream, item: TokenStream) -> TokenStream {
51 // When used standalone, pass through unchanged.
52 // When inside #[act_component], the component macro processes this.
53 item
54}
55
56/// Mark a function as `act:sessions/session-provider.open-session`.
57///
58/// Inside `#[act_component]`, the component macro picks up this annotation,
59/// generates the `session-provider` Guest impl, and derives the
60/// `get-open-session-args-schema` JSON Schema from the function's argument
61/// type via `schemars::JsonSchema`.
62///
63/// Signature: `fn open(args: T) -> ActResult<String>` (sync or async). `T`
64/// must implement `serde::Deserialize` and `schemars::JsonSchema`. The
65/// returned `String` is the session-id the host will use in subsequent
66/// capability calls.
67///
68/// Outside `#[act_component]`, this attribute is a no-op pass-through.
69#[proc_macro_attribute]
70pub fn session_open(_attr: TokenStream, item: TokenStream) -> TokenStream {
71 item
72}
73
74/// Mark a function as `act:sessions/session-provider.close-session`.
75///
76/// Signature: `fn close(session_id: String)`. Synchronous, no return value
77/// (matches the WIT close-session signature).
78///
79/// Outside `#[act_component]`, this attribute is a no-op pass-through.
80#[proc_macro_attribute]
81pub fn session_close(_attr: TokenStream, item: TokenStream) -> TokenStream {
82 item
83}