vtcode_core/llm/providers/gemini/
sanitize.rs1use super::*;
2
3pub fn sanitize_function_parameters(parameters: Value) -> Value {
4 sanitize_function_parameters_impl(parameters, false)
5}
6
7fn should_alias_description_property(properties: &Map<String, Value>) -> bool {
8 properties.contains_key("description") && !properties.contains_key("details")
9}
10
11fn sanitize_property_name(name: &str, alias_description: bool) -> &str {
12 if alias_description && name == "description" {
13 "details"
14 } else {
15 name
16 }
17}
18
19fn sanitize_function_parameters_impl(parameters: Value, inside_properties_map: bool) -> Value {
20 match parameters {
21 Value::Object(map) => {
22 const UNSUPPORTED_FIELDS: &[&str] = &[
25 "additionalProperties",
26 "oneOf",
27 "anyOf",
28 "allOf",
29 "exclusiveMaximum",
30 "exclusiveMinimum",
31 "minimum",
32 "maximum",
33 "$schema",
34 "$id",
35 "$ref",
36 "definitions",
37 "patternProperties",
38 "dependencies",
39 "const",
40 "if",
41 "then",
42 "else",
43 "not",
44 "contentMediaType",
45 "contentEncoding",
46 ];
47
48 let alias_description_property =
49 inside_properties_map && should_alias_description_property(&map);
50 let alias_required_description = map
51 .get("properties")
52 .and_then(Value::as_object)
53 .is_some_and(should_alias_description_property);
54
55 let mut sanitized = Map::new();
57 for (key, value) in map {
58 let is_properties_map = key == "properties";
59 if !inside_properties_map
61 && (UNSUPPORTED_FIELDS.contains(&key.as_str()) || key.starts_with("x-"))
62 {
63 continue;
64 }
65 let sanitized_key = if inside_properties_map {
67 sanitize_property_name(&key, alias_description_property).to_string()
68 } else {
69 key
70 };
71 sanitized.insert(
72 sanitized_key,
73 sanitize_function_parameters_impl(value, is_properties_map),
74 );
75 }
76
77 let property_names = sanitized
78 .get("properties")
79 .and_then(Value::as_object)
80 .map(|properties| properties.keys().cloned().collect::<Vec<_>>());
81 let drop_required = sanitized
82 .get_mut("required")
83 .and_then(Value::as_array_mut)
84 .map(|required| {
85 let Some(property_names) = property_names.as_ref() else {
86 return true;
87 };
88
89 for item in required.iter_mut() {
90 if let Some(name) = item.as_str() {
91 let sanitized_name =
92 sanitize_property_name(name, alias_required_description);
93 if sanitized_name != name {
94 *item = Value::String(sanitized_name.to_string());
95 }
96 }
97 }
98 required.retain(|item| {
99 item.as_str()
100 .map(|name| property_names.iter().any(|property| property == name))
101 .unwrap_or(false)
102 });
103 required.is_empty()
104 })
105 .unwrap_or(false);
106 if drop_required {
107 sanitized.remove("required");
108 }
109
110 Value::Object(sanitized)
111 }
112 Value::Array(values) => Value::Array(
113 values
114 .into_iter()
115 .map(|value| sanitize_function_parameters_impl(value, false))
116 .collect(),
117 ),
118 other => other,
119 }
120}