pub trait RustTool: Send + Sync {
type Params: DeserializeOwned + JsonSchema + Send;
const NAME: &'static str;
const DESCRIPTION: &'static str;
// Required method
fn call(
&self,
params: Self::Params,
ctx: &ToolContext,
) -> impl Future<Output = Result<ToolOutput, ToolError>> + Send;
// Provided method
fn description(&self) -> Cow<'static, str> { ... }
}Expand description
A custom tool implemented entirely in Rust with strongly-typed parameters.
Define your parameters as a struct deriving serde::Deserialize and
JsonSchema, then implement this trait to provide the tool’s logic.
The JSON Schema sent to the model is derived automatically from the
params struct — doc comments on fields become parameter descriptions.
Tools are async: for I/O-bound work (HTTP, filesystem, subprocess) the
runtime stays unblocked. Sync tools just don’t .await anything — the
compiler optimizes the state machine to an immediate return.
§Example
use llm_tool::{JsonSchema, RustTool, ToolContext, ToolError, ToolOutput};
use serde::Deserialize;
#[derive(Deserialize, JsonSchema)]
struct FlashParams {
/// Target device identifier.
device_id: String,
/// Path to the firmware image.
image_path: String,
}
struct FlashDevice;
impl RustTool for FlashDevice {
type Params = FlashParams;
const NAME: &'static str = "flash_device";
const DESCRIPTION: &'static str = "Flashes firmware to a connected device.";
async fn call(
&self,
params: Self::Params,
_ctx: &ToolContext,
) -> Result<ToolOutput, ToolError> {
Ok(format!("Flashed {} to {}", params.image_path, params.device_id).into())
}
}Required Associated Constants§
Sourceconst DESCRIPTION: &'static str
const DESCRIPTION: &'static str
Human-readable description shown to the model.
Required Associated Types§
Sourcetype Params: DeserializeOwned + JsonSchema + Send
type Params: DeserializeOwned + JsonSchema + Send
The strongly-typed parameters struct.
Derive serde::Deserialize and JsonSchema on your params struct.
JsonSchema auto-generates the parameter schema sent to the model;
Deserialize parses the model’s JSON arguments into your struct.
Required Methods§
Sourcefn call(
&self,
params: Self::Params,
ctx: &ToolContext,
) -> impl Future<Output = Result<ToolOutput, ToolError>> + Send
fn call( &self, params: Self::Params, ctx: &ToolContext, ) -> impl Future<Output = Result<ToolOutput, ToolError>> + Send
Execute the tool with typed parameters and an execution context.
Async to support I/O-bound tools (HTTP, filesystem, subprocess). Sync tools just compute and return — the async wrapper is zero-cost.
The ctx parameter provides access to conversation metadata and a
shared key-value state store. Tools that don’t need context can simply
ignore it with _ctx.
§Errors
Returns Err(ToolError) if the tool execution fails.
Provided Methods§
Sourcefn description(&self) -> Cow<'static, str>
fn description(&self) -> Cow<'static, str>
Return the tool description used in ToolDefinition.
The default returns Self::DESCRIPTION (the static string from a
doc comment or template body). When using
#[llm_tool(template = "...", context = ...)], the generated
implementation overrides this to render the template with runtime
variables on each call. Templates are parsed once via LazyLock.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".