Crates.io | ftl-sdk-macros |
lib.rs | ftl-sdk-macros |
version | 0.14.0 |
created_at | 2025-07-13 21:53:18.197493+00 |
updated_at | 2025-08-25 06:23:06.745861+00 |
description | Procedural macros for the FTL SDK |
homepage | |
repository | https://github.com/fastertools/ftl |
max_upload_size | |
id | 1750852 |
size | 17,571 |
Procedural macros for reducing boilerplate in FTL tool components written in Rust.
This crate provides the tools!
macro for defining multiple tool handler functions with minimal boilerplate. The macro:
JsonSchema
derive)The tools!
macro simplifies creating tool handlers:
use ftl_sdk::{tools, text, ToolResponse};
use serde::Deserialize;
use schemars::JsonSchema;
#[derive(Deserialize, JsonSchema)]
struct EchoRequest {
message: String,
}
#[derive(Deserialize, JsonSchema)]
struct ReverseRequest {
text: String,
}
tools! {
/// Echoes back the input message
fn echo(req: EchoRequest) -> ToolResponse {
text!("Echo: {}", req.message)
}
/// Reverses the input text
fn reverse(req: ReverseRequest) -> ToolResponse {
let reversed: String = req.text.chars().rev().collect();
text!("{}", reversed)
}
}
Here's a more complete example showing how the macro works with multiple tools:
use ftl_sdk::{tools, text, error};
use serde::Deserialize;
use schemars::JsonSchema;
#[derive(Deserialize, JsonSchema)]
struct CalculatorRequest {
a: f64,
b: f64,
}
#[derive(Deserialize, JsonSchema)]
struct ConvertRequest {
value: f64,
from_unit: String,
to_unit: String,
}
tools! {
/// Add two numbers
fn add(req: CalculatorRequest) -> ToolResponse {
text!("{} + {} = {}", req.a, req.b, req.a + req.b)
}
/// Subtract two numbers
fn subtract(req: CalculatorRequest) -> ToolResponse {
text!("{} - {} = {}", req.a, req.b, req.a - req.b)
}
/// Divide two numbers
fn divide(req: CalculatorRequest) -> ToolResponse {
if req.b == 0.0 {
return error!("Cannot divide by zero");
}
text!("{} / {} = {}", req.a, req.b, req.a / req.b)
}
/// Convert between units
fn convert(req: ConvertRequest) -> ToolResponse {
// Conversion logic here
text!("Converted {} {} to {}", req.value, req.from_unit, req.to_unit)
}
}
// The macro generates the HTTP handler with routing automatically!
The tools!
macro generates:
handle_tool_component
async function that returns metadata for all tools on GET/add
, /subtract
) for POST requestsJust like with the TypeScript SDK, tools should NOT validate inputs themselves. The FTL gateway handles all input validation against your tool's JSON Schema before invoking your handler. This means:
The SDK provides convenient macros for creating responses:
tools! {
fn demo_responses(input: DemoInput) -> ToolResponse {
// Simple text response
text!("Hello, {}!", input.name)
// Error response
error!("Something went wrong: {}", reason)
// Structured response with data
let data = json!({ "result": 42, "status": "complete" });
structured!(data, "Calculation finished")
}
}
The tools!
macro fully supports async functions:
tools! {
/// Async tool example
async fn fetch_data(req: FetchRequest) -> ToolResponse {
// Async operations work seamlessly
let result = some_async_operation().await?;
text!("Fetched: {}", result)
}
}
Apache-2.0
See RELEASE_ORDER.md for release instructions.
This package now uses selective CI - only relevant tests run for each package.