Skip to main content

agentic_core/tool/
function.rs

1use serde_json::Value;
2
3use crate::types::io::FunctionTool;
4use crate::types::tools::FunctionToolParam;
5
6use super::handler::{ToolError, ToolHandler};
7use super::registry::ToolType;
8
9impl From<&FunctionToolParam> for FunctionTool {
10    fn from(p: &FunctionToolParam) -> Self {
11        Self {
12            type_: "function".to_owned(),
13            name: p.name.as_str().to_owned(),
14            description: p.description.clone(),
15            parameters: p.parameters.clone(),
16            strict: p.strict,
17        }
18    }
19}
20
21/// Handler for `type: "function"` tools.
22///
23/// Function tools are client-owned: the gateway normalises them for vLLM but
24/// never executes them. `FunctionHandler` intentionally implements only
25/// [`ToolHandler`], not [`super::handler::GatewayExecutor`] — the type system
26/// makes it impossible to call `execute()` on a client-owned tool.
27#[derive(Debug)]
28pub struct FunctionHandler;
29
30impl ToolHandler for FunctionHandler {
31    fn tool_type(&self) -> ToolType {
32        ToolType::Function
33    }
34
35    fn validate(&self, param: &Value) -> Result<(), ToolError> {
36        match param.get("name").and_then(Value::as_str) {
37            Some(name) if !name.is_empty() => Ok(()),
38            _ => Err(ToolError::Config("function tool must have a non-empty name".into())),
39        }
40    }
41
42    fn normalize(&self, param: &Value) -> Vec<FunctionTool> {
43        // Deserialize into the typed struct so From<&FunctionToolParam> is the single
44        // conversion path. name is NonEmptyToolName so serde rejects empty names;
45        // any remaining deserialize error means validate() was not called first.
46        match serde_json::from_value::<FunctionToolParam>(param.clone()) {
47            Ok(p) => vec![FunctionTool::from(&p)],
48            Err(e) => {
49                tracing::warn!("normalize() called with invalid param: {e} — validate() must be called first");
50                vec![]
51            }
52        }
53    }
54}