Skip to main content

llm_tool

Attribute Macro llm_tool 

Source
#[llm_tool]
Expand description

Re-export the #[llm_tool] proc macro for defining tools from plain functions.

§Usage

use llm_tool::{RustTool, ToolContext, ToolRegistry, llm_tool};

/// Adds two numbers together (with a twist).
#[llm_tool]
fn wonky_add(
    /// First number.
    a: i64,
    /// Second number.
    b: i64,
) -> Result<String, String> {
    Ok(format!("{}", a + b + 1))
}

let mut registry = ToolRegistry::new();
registry.register(WonkyAdd);
assert_eq!(registry.definitions().len(), 1);

Transforms a function into a RustTool implementation.

The macro generates:

  • A {FnName}Params struct deriving Deserialize and JsonSchema
  • A {FnName} unit struct (PascalCase) implementing RustTool

The tool name is the function name (snake_case). The tool description comes from one of the sources below. Parameter names and types come from the function signature. Doc comments on parameters become schema descriptions.

§Description sources (in priority order)

SyntaxCostFeature
#[llm_tool] + doc commentZero (static &str)
#[llm_tool(description = "inline text")]Zero (static &str)
#[llm_tool(template = "tools/x.tmpl.md")]Zero (compiled)prompt-templates
#[llm_tool(template = "...", params(k = "v"))]Zero (compiled)prompt-templates
#[llm_tool(template = "...", context = fn)]Runtime Cow::Ownedprompt-templates

§Inline description

Override or replace the doc comment with an inline string:

#[llm_tool(description = "Get the current weather for a city.")]
fn get_weather(/* … */) -> Result<String, ToolError> { /* … */ }

§Template descriptions (feature: prompt-templates)

Load the description from a .tmpl.md file:

#[llm_tool(template = "tools/weather.tmpl.md")]
fn get_weather(/* … */) -> Result<String, ToolError> { /* … */ }

For templates with variables, provide compile-time key-value pairs:

#[llm_tool(template = "tools/weather.tmpl.md", params(api = "v3", env = "prod"))]
fn get_weather(/* … */) -> Result<String, ToolError> { /* … */ }

The macro reads the template, validates all declared variables are provided, renders the description, and embeds the result as a static string — zero runtime cost.

For runtime context (e.g. values from config), provide a context function:

#[llm_tool(template = "tools/weather.tmpl.md", context = build_ctx)]
fn get_weather(/* … */) -> Result<String, ToolError> { /* … */ }

The context function signature is fn(&ToolStruct) -> Context. Templates are parsed once at startup via LazyLock.

§Typed parameters

Parameters may use &str — the generated params struct stores an owned String and the macro auto-borrows it before passing to your function body.

§Return types

The return type can be Result<T, E> or just T (infallible):

  • T: String (wrapped as-is), ToolOutput (passed through), any T: Serialize (auto-serialized to JSON), or any T: Into<ToolOutput>
  • E: any E: Into<ToolError> — built-in for String, ToolError, std::io::Error, serde_json::Error