use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum Tool {
Function { function: FunctionTool },
}
impl Tool {
pub fn new_from_mcp(name: String, tool: &objectiveai_sdk::mcp::tool::Tool) -> Self {
let mut map = IndexMap::new();
map.insert(
"type".to_string(),
serde_json::Value::String("object".to_string()),
);
if let Some(props) = &tool.input_schema.properties {
map.insert(
"properties".to_string(),
serde_json::Value::Object(
props.iter().map(|(k, v)| (k.clone(), v.clone())).collect(),
),
);
}
if let Some(req) = &tool.input_schema.required {
map.insert(
"required".to_string(),
serde_json::Value::Array(
req.iter()
.map(|s| serde_json::Value::String(s.clone()))
.collect(),
),
);
}
for (k, v) in &tool.input_schema.extra {
map.insert(k.clone(), v.clone());
}
Self::Function {
function: FunctionTool {
name,
description: tool.description.clone(),
parameters: Some(map),
strict: None,
},
}
}
pub fn new_from_response_format(
name: String,
description: String,
schema: IndexMap<String, serde_json::Value>,
) -> Self {
Self::Function {
function: FunctionTool {
name,
description: Some(description),
parameters: Some(schema),
strict: None,
},
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct FunctionTool {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parameters: Option<IndexMap<String, serde_json::Value>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub strict: Option<bool>,
}