use serde_json::{json, Value};
use std::collections::HashMap;
pub fn type_name_to_schema(type_name: &str) -> Value {
match type_name {
"String" | "str" | "&str" => json!({
"type": "string",
"description": "A string value"
}),
"i8" | "i16" | "i32" | "i64" | "isize" | "u8" | "u16" | "u32" | "u64" | "usize" => json!({
"type": "integer",
"description": "An integer value"
}),
"f32" | "f64" => json!({
"type": "number",
"description": "A floating point number"
}),
"bool" => json!({
"type": "boolean",
"description": "A boolean value"
}),
s if s.starts_with("Vec<") || s.starts_with("&[") => {
let inner = if s.starts_with("Vec<") {
s.strip_prefix("Vec<")
.and_then(|s| s.strip_suffix(">"))
.unwrap_or("String")
} else {
s.strip_prefix("&[")
.and_then(|s| s.strip_suffix("]"))
.unwrap_or("String")
};
json!({
"type": "array",
"items": type_name_to_schema(inner),
"description": format!("An array of {}", inner)
})
},
s if s.starts_with("Option<") => {
let inner = s.strip_prefix("Option<")
.and_then(|s| s.strip_suffix(">"))
.unwrap_or("String");
type_name_to_schema(inner)
},
s if s.starts_with("HashMap<") || s.starts_with("BTreeMap<") => {
json!({
"type": "object",
"additionalProperties": true,
"description": "A map of key-value pairs"
})
},
_ => {
json!({
"type": "object",
"description": format!("An object of type {}", type_name)
})
}
}
}
pub fn build_tool_schema(
name: &str,
description: &str,
parameters: &HashMap<String, String>,
required: &[String],
) -> Value {
let mut properties = serde_json::Map::new();
for (param_name, type_name) in parameters {
let schema = type_name_to_schema(type_name);
properties.insert(param_name.clone(), schema);
}
json!({
"name": name,
"description": description,
"parameters": {
"type": "object",
"properties": properties,
"required": required
}
})
}
pub fn extract_doc_comment(_item_name: &str) -> Option<String> {
None
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_string_schema() {
let schema = type_name_to_schema("String");
assert_eq!(schema["type"], "string");
assert!(schema["description"].is_string());
}
#[test]
fn test_integer_schema() {
let schema = type_name_to_schema("i32");
assert_eq!(schema["type"], "integer");
}
#[test]
fn test_float_schema() {
let schema = type_name_to_schema("f64");
assert_eq!(schema["type"], "number");
}
#[test]
fn test_bool_schema() {
let schema = type_name_to_schema("bool");
assert_eq!(schema["type"], "boolean");
}
#[test]
fn test_vec_schema() {
let schema = type_name_to_schema("Vec<String>");
assert_eq!(schema["type"], "array");
assert_eq!(schema["items"]["type"], "string");
}
#[test]
fn test_option_schema() {
let schema = type_name_to_schema("Option<i32>");
assert_eq!(schema["type"], "integer");
}
#[test]
fn test_hashmap_schema() {
let schema = type_name_to_schema("HashMap<String, i32>");
assert_eq!(schema["type"], "object");
assert_eq!(schema["additionalProperties"], true);
}
#[test]
fn test_build_tool_schema() {
let mut params = HashMap::new();
params.insert("name".to_string(), "String".to_string());
params.insert("age".to_string(), "i32".to_string());
params.insert("emails".to_string(), "Vec<String>".to_string());
let required = vec!["name".to_string(), "age".to_string()];
let schema = build_tool_schema(
"create_person",
"Create a new person",
¶ms,
&required,
);
assert_eq!(schema["name"], "create_person");
assert_eq!(schema["description"], "Create a new person");
assert!(schema["parameters"]["properties"].is_object());
assert_eq!(schema["parameters"]["properties"]["name"]["type"], "string");
assert_eq!(schema["parameters"]["properties"]["age"]["type"], "integer");
assert_eq!(schema["parameters"]["properties"]["emails"]["type"], "array");
assert_eq!(schema["parameters"]["required"][0], "name");
assert_eq!(schema["parameters"]["required"][1], "age");
}
}