use std::collections::HashMap;
use serde_json::Value;
use crate::types::io::FunctionTool;
use crate::types::tools::FunctionToolParam;
use crate::utils::common::serialize_to_value_or_custom_default;
use super::handler::{ToolError, ToolHandler};
use super::registry::{ToolEntry, ToolType};
impl From<&FunctionToolParam> for FunctionTool {
fn from(p: &FunctionToolParam) -> Self {
Self {
type_: "function".to_owned(),
name: p.name.as_str().to_owned(),
description: p.description.clone(),
parameters: p.parameters.clone(),
strict: p.strict,
}
}
}
#[derive(Debug)]
pub struct FunctionHandler;
impl ToolHandler for FunctionHandler {
fn tool_type(&self) -> ToolType {
ToolType::Function
}
fn validate(&self, param: &Value) -> Result<(), ToolError> {
match param.get("name").and_then(Value::as_str) {
Some(name) if !name.is_empty() => Ok(()),
_ => Err(ToolError::Config("function tool must have a non-empty name".into())),
}
}
fn normalize(&self, param: &Value) -> Vec<FunctionTool> {
match serde_json::from_value::<FunctionToolParam>(param.clone()) {
Ok(p) => vec![FunctionTool::from(&p)],
Err(e) => {
tracing::warn!("normalize() called with invalid param: {e} — validate() must be called first");
vec![]
}
}
}
}
pub(crate) fn insert_function_entry(entries: &mut HashMap<String, ToolEntry>, p: &FunctionToolParam) {
serialize_to_value_or_custom_default(
p,
"function tool config serialization failed",
|config| {
if entries
.insert(
p.name.as_str().to_owned(),
ToolEntry {
tool_type: ToolType::Function,
config,
server_label: None,
handler: None,
},
)
.is_some()
{
tracing::warn!(name = %p.name, "duplicate tool name — previous definition overwritten");
}
},
(),
);
}