Expand description
§open_ai_rust_fn_call_extension
Ergonomic procedural macros for building OpenAI function-calling tools in Rust.
The companion crate to open_ai_rust.
§What this crate gives you
Three macros, one purpose: describe Rust types and functions as structured OpenAI tool schemas with zero boilerplate.
| Macro | Apply to | What it emits |
|---|---|---|
#[derive(FunctionCall)] | structs / unit enums | FunctionCallable impl (schema_type, fn_schema) |
#[function_call] | free functions | a const FN_NAME: FunctionCallRaw<'static> schema next to the function |
#[tool] | free functions | the schema const plus a JSON-dispatch async wrapper, optionally auto-registered into a global tool registry |
§Quick start
Add both crates to your Cargo.toml:
[dependencies]
open_ai_rust = "1"
open_ai_rust_fn_call_extension = "0.3"
serde_json = "1"
# Optional: auto-register #[tool] functions into a global registry.
# [dependencies.open_ai_rust]
# version = "1"
# features = ["tool_registry"]
# [dependencies.open_ai_rust_fn_call_extension]
# version = "0.3"
# features = ["tool_registry"]Describe a tool function and a tool argument struct:
use open_ai_rust::{FunctionCallable, FunctionType};
use open_ai_rust_fn_call_extension::{tool, FunctionCall};
/// A point in 2D space.
#[derive(FunctionCall, serde::Deserialize, serde::Serialize)]
struct Point {
/// X coordinate.
x: f64,
/// Y coordinate.
y: f64,
/// Optional label (omittable in the JSON schema's `required` array).
label: Option<String>,
}
/// Compute the Euclidean distance between two points.
#[tool("Compute Euclidean distance between two points")]
async fn distance(a: Point, b: Point) -> f64 {
((a.x - b.x).powi(2) + (a.y - b.y).powi(2)).sqrt()
}After expansion you have:
Point::schema_type()returning a JSON-schemaFunctionType::Objectwith three parameters (labelmarkedrequired: false).Point::fn_schema()returning a fullFunctionCallschema.const DISTANCE: FunctionCallRaw<'static>describing the function.fn distance_dispatch(args: serde_json::Value) -> Pin<Box<dyn Future<...>>>, ready to be wired into a tool-call loop.
With the tool_registry feature enabled, distance is also registered into
open_ai_rust::tool_registry::TOOLS at link time, so you can simply call
open_ai_rust::tool_registry::invoke_tool with the tool name and arguments.
§Feature flags
| Feature | Default | Effect |
|---|---|---|
tool_registry | off | Auto-register #[tool] functions into the global TOOLS linkme slice. Requires open_ai_rust/tool_registry. |
§Description sources
Wherever a description string is accepted, the macros resolve it in this priority order:
-
Functions, structs, fields, enums:
- Explicit macro argument:
#[function_call("...")]/#[tool("...")]on a fn, or#[function_call(description = "...")]on a derive field. - Outer doc-comment:
/// ...directly above the item. - Omitted (
None).
- Explicit macro argument:
-
Function parameters (for
#[function_call]/#[tool]):#[function_call_description = "..."]attached to the parameter. This is the only mechanism — stable Rust rejects#[doc = "..."](and therefore///) on function parameters.
§Compatibility
- MSRV: 1.65 (uses
let ... elsesyntax). - Requires
syn 2.x— already on board, no further setup needed. - Pairs with
open_ai_rust≥ 1.1.
§Status
Pre-1.0 of this crate; emitted-code shape may change in minor releases.
See CHANGELOG.md.
Attribute Macros§
- function_
call - Emit a
const FN_NAME: FunctionCallRaw<'static>schema next to a free function. The original function body is preserved unchanged. - tool
- Superset of
#[function_call]: emits the schema const and a JSON-dispatch wrapper that deserialises arguments, invokes the underlying function, and serialises its return value back to JSON.
Derive Macros§
- Function
Call - Derive
FunctionCallablefor a struct or unit-variant enum, generating all the methods needed to describe the type as a JSON schema in an OpenAI tool definition.