| Crates.io | rsai-macros |
| lib.rs | rsai-macros |
| version | 0.2.0 |
| created_at | 2025-10-31 12:53:24.124482+00 |
| updated_at | 2025-12-10 15:17:56.544255+00 |
| description | Macros for the rsai crate providing structured AI generation capabilities |
| homepage | https://rsai.dev |
| repository | https://github.com/caluckenbach/rsai |
| max_upload_size | |
| id | 1909994 |
| size | 67,031 |
Procedural macros that provide structured AI generation capabilities for the rsai crate. This crate enables type-safe tool calling and automatic JSON schema generation for AI interactions.
#[completion_schema] - Automatic JSON schema generation for AI response types#[tool] - Transform Rust functions into AI-callable tools with automatic schema generationtoolset! - Create collections of tools for AI agentsAdd this to your Cargo.toml:
[dependencies]
rsai-macros = "0.1.0-pre"
#[completion_schema]Automatically adds the necessary derives and attributes for types used with the complete::<T>() method.
#[derive(serde::Deserialize, schemars::JsonSchema)]#[schemars(deny_unknown_fields)] for strict validationuse rsai_macros::completion_schema;
#[completion_schema]
struct WeatherResponse {
city: String,
temperature: f64,
conditions: String,
humidity: Option<f64>,
}
// The macro expands to:
#[derive(serde::Deserialize, schemars::JsonSchema)]
#[schemars(deny_unknown_fields)]
struct WeatherResponse {
city: String,
temperature: f64,
conditions: String,
humidity: Option<f64>,
}
#[tool]Transforms Rust functions into AI-callable tools with automatic JSON schema generation.
Option<T> types and marks them as non-requiredLlmError with proper context#[tool]
/// Function description (required)
/// param_name: Parameter description (required for each parameter)
/// optional_param: Description for optional parameters (also required)
fn function_name(param: Type, optional_param: Option<Type>) -> ReturnType {
// implementation
}
Basic Tool:
use rsai_macros::tool;
#[tool]
/// Get current weather for a city
/// city: The city to get weather for
/// unit: Temperature unit (celsius or fahrenheit)
fn get_weather(city: String, unit: Option<String>) -> String {
match unit.as_deref() {
Some("fahrenheit") => format!("Weather for {}: 72ยฐF", city),
_ => format!("Weather for {}: 22ยฐC", city),
}
}
Async Tool:
use rsai_macros::tool;
use async_trait::async_trait;
#[tool]
/// Send an email to a recipient
/// to: Email address of the recipient
/// subject: Email subject line
/// body: Email body content
async fn send_email(to: String, subject: String, body: String) -> Result<String, String> {
// Simulate sending email
Ok(format!("Email sent to {}", to))
}
Complex Types:
use rsai_macros::tool;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct Location {
latitude: f64,
longitude: f64,
}
#[tool]
/// Calculate distance between two locations
/// from: Starting location with coordinates
/// to: Destination location with coordinates
/// unit: Distance unit (km or miles)
fn calculate_distance(from: Location, to: Location, unit: Option<String>) -> f64 {
let distance = ((to.latitude - from.latitude).powi(2) +
(to.longitude - from.longitude).powi(2)).sqrt();
match unit.as_deref() {
Some("miles") => distance * 0.621371,
_ => distance,
}
}
toolset!Creates a collection of tools from multiple #[tool]-annotated functions.
let tools = toolset![function_name1, function_name2, ...];
use rsai_macros::{tool, toolset};
#[tool]
/// Get current weather for a city
/// city: The city to get weather for
fn get_weather(city: String) -> String {
format!("Weather for {}: 22ยฐC", city)
}
#[tool]
/// Calculate distance between two locations
/// from: Starting location
/// to: Destination location
fn calculate_distance(from: String, to: String) -> f64 {
42.5
}
// Create a toolset containing both tools
let tools = toolset![get_weather, calculate_distance];
assert_eq!(tools.tools().len(), 2);
The macros automatically convert Rust types to JSON schema types:
| Rust Type | JSON Schema Type |
|---|---|
String, &str |
string |
i8, i16, i32, i64, u8, u16, u32, u64, f32, f64 |
number |
bool |
boolean |
Vec<T> |
array |
Option<T> |
T (optional) |
struct |
object |
enum |
enum |
The macros provide comprehensive compile-time validation:
#[tool]
/// This will cause a compile error
/// city: The city to get weather for
fn get_weather(city: String, country: String) -> String {
// Error: Missing description for parameter 'country'
}
#[tool]
/// This will cause a compile error
/// city: The city to get weather for
/// temperature: Temperature (not in function signature)
fn get_weather(city: String) -> String {
// Error: Parameter 'temperature' described but not found in function signature
}
The macros provide clear, actionable error messages to help you fix documentation issues quickly.
This crate includes comprehensive test coverage:
# Run all tests
cargo test
# Run specific test modules
cargo test tool_macro_test
cargo test tools_macro_test
# Run UI tests (compilation failure tests)
cargo test --test compile_fail
Your tool functions can return any type that implements Into<LlmError>:
use rsai_macros::tool;
use rsai::LlmError;
#[derive(Debug)]
enum CustomError {
Network(String),
Validation(String),
}
impl From<CustomError> for LlmError {
fn from(err: CustomError) -> Self {
match err {
CustomError::Network(msg) => LlmError::ToolError(msg),
CustomError::Validation(msg) => LlmError::ValidationError(msg),
}
}
}
#[tool]
/// Call external API
/// endpoint: API endpoint to call
async fn call_api(endpoint: String) -> Result<String, CustomError> {
// Your implementation here
Ok("Success".to_string())
}
This crate is part of the rsai project. When contributing:
This crate is licensed under the MIT License. See the LICENSE file for details.