use crate::value::{DictMap, VmError, VmValue};
const SCHEMA_CONFIG_KEYS: [&str; 3] = ["parameters", "input_schema", "inputSchema"];
pub(super) fn declared_schema<'a>(
config: &'a DictMap,
name: &str,
) -> Result<Option<(&'static str, &'a VmValue)>, VmError> {
let declared: Vec<(&'static str, &VmValue)> = SCHEMA_CONFIG_KEYS
.iter()
.filter_map(|key| {
config
.get(*key)
.filter(|value| !matches!(value, VmValue::Nil))
.map(|value| (*key, value))
})
.collect();
if declared.len() > 1 {
let keys = declared
.iter()
.map(|(key, _)| format!("{key:?}"))
.collect::<Vec<_>>()
.join(" and ");
return Err(VmError::Thrown(VmValue::String(arcstr::ArcStr::from(
format!(
"tool_define: tool {name:?} declares its input schema twice ({keys}); \
use `inputSchema` for a complete JSON Schema or legacy `parameters` \
for a per-parameter map, not both"
),
))));
}
Ok(declared.into_iter().next())
}
pub(super) fn insert_resolved_schema(
entry: &mut DictMap,
declared: Option<(&'static str, &VmValue)>,
) {
match declared {
Some(("parameters", value)) => {
entry.insert(crate::value::intern_key("parameters"), value.clone());
}
Some((_, value)) => {
entry.insert(crate::value::intern_key("inputSchema"), value.clone());
}
None => {
entry.insert(
crate::value::intern_key("parameters"),
VmValue::dict(DictMap::new()),
);
}
}
}