pub trait ToolValidator: Send + Sync {
// Required method
fn validate(&self, args: &Value) -> Result<(), AgentRuntimeError>;
}Expand description
Declarative argument validator for a ToolSpec.
Implement this trait to enforce custom argument constraints (type ranges, string patterns, etc.) before the handler is invoked.
Validators run after required_fields checks and before the handler.
The first failing validator short-circuits execution.
§Basic Example
use llm_agent_runtime::agent::ToolValidator;
use llm_agent_runtime::AgentRuntimeError;
use serde_json::Value;
struct NonEmptyQuery;
impl ToolValidator for NonEmptyQuery {
fn validate(&self, args: &Value) -> Result<(), AgentRuntimeError> {
let q = args.get("q").and_then(|v| v.as_str()).unwrap_or("");
if q.is_empty() {
return Err(AgentRuntimeError::AgentLoop(
"tool 'search': q must not be empty".into(),
));
}
Ok(())
}
}§Advanced Example — Parameterised validator
use llm_agent_runtime::agent::{ToolSpec, ToolValidator};
use llm_agent_runtime::AgentRuntimeError;
use serde_json::Value;
/// Validates that a named integer field is within [min, max].
struct RangeValidator { field: &'static str, min: i64, max: i64 }
impl ToolValidator for RangeValidator {
fn validate(&self, args: &Value) -> Result<(), AgentRuntimeError> {
let n = args
.get(self.field)
.and_then(|v| v.as_i64())
.ok_or_else(|| {
AgentRuntimeError::AgentLoop(format!(
"field '{}' must be an integer", self.field
))
})?;
if n < self.min || n > self.max {
return Err(AgentRuntimeError::AgentLoop(format!(
"field '{}' = {n} is outside [{}, {}]",
self.field, self.min, self.max,
)));
}
Ok(())
}
}
// Attach to a tool spec:
let spec = ToolSpec::new("roll_dice", "Roll n dice", |args| {
serde_json::json!({ "result": args })
})
.with_validators(vec![
Box::new(RangeValidator { field: "n", min: 1, max: 100 }),
]);