1use serde::Deserialize;
2use serde::de::{self, Deserializer, MapAccess, SeqAccess, Visitor};
3use std::convert::Infallible;
4use std::fmt;
5use std::marker::PhantomData;
6use std::str::FromStr;
7
8#[allow(clippy::trivially_copy_pass_by_ref)]
11pub(crate) fn is_false(value: &bool) -> bool {
12 !value
13}
14
15pub fn canonical(value: serde_json::Value) -> serde_json::Value {
18 match value {
19 serde_json::Value::Object(map) => {
20 let mut entries: Vec<_> = map.into_iter().collect();
21 entries.sort_by(|(left, _), (right, _)| left.cmp(right));
22 let entries = entries
23 .into_iter()
24 .map(|(key, value)| (key, canonical(value)));
25 serde_json::Value::Object(entries.collect())
26 }
27 serde_json::Value::Array(items) => {
28 serde_json::Value::Array(items.into_iter().map(canonical).collect())
29 }
30 other => other,
31 }
32}
33
34pub fn to_canonical_string(value: &serde_json::Value) -> String {
36 canonical(value.clone()).to_string()
37}
38
39pub fn remove_preserving_order(
43 map: &mut serde_json::Map<String, serde_json::Value>,
44 key: &str,
45) -> Option<serde_json::Value> {
46 let mut removed = None;
47 map.retain(|candidate, value| {
48 if candidate == key {
49 removed = Some(value.take());
50 false
51 } else {
52 true
53 }
54 });
55 removed
56}
57
58pub fn merge(a: serde_json::Value, b: serde_json::Value) -> serde_json::Value {
59 match (a, b) {
60 (serde_json::Value::Object(mut a_map), serde_json::Value::Object(b_map)) => {
61 b_map.into_iter().for_each(|(key, value)| {
62 a_map.insert(key, value);
63 });
64 serde_json::Value::Object(a_map)
65 }
66 (a, _) => a,
67 }
68}
69
70pub(crate) fn merge_params(
74 existing: Option<serde_json::Value>,
75 params: Option<serde_json::Value>,
76) -> Option<serde_json::Value> {
77 Some(match (existing, params?) {
78 (Some(existing), params) => merge(existing, params),
79 (None, params) => params,
80 })
81}
82
83#[cfg_attr(not(any(feature = "image", feature = "audio")), allow(dead_code))]
85pub fn merge_inplace(a: &mut serde_json::Value, b: serde_json::Value) {
86 if let (serde_json::Value::Object(a_map), serde_json::Value::Object(b_map)) = (a, b) {
87 b_map.into_iter().for_each(|(key, value)| {
88 a_map.insert(key, value);
89 });
90 }
91}
92
93pub fn value_to_json_string(value: &serde_json::Value) -> String {
98 match value {
99 serde_json::Value::String(s) => s.clone(),
100 other => other.to_string(),
101 }
102}
103
104pub fn parse_tool_arguments(arguments: &str) -> serde_json::Result<serde_json::Value> {
107 if arguments.trim().is_empty() {
108 return Ok(serde_json::Value::Object(serde_json::Map::new()));
109 }
110
111 serde_json::from_str(arguments)
112}
113
114pub fn is_whole_object(arguments: &str) -> bool {
118 let end = arguments.trim_end();
119 (end.is_empty() || end.ends_with('}'))
120 && matches!(
121 parse_tool_arguments(arguments),
122 Ok(serde_json::Value::Object(_))
123 )
124}
125
126pub fn parse_partial_object(text: &str) -> Option<serde_json::Map<String, serde_json::Value>> {
130 const MAX_ATTEMPTS: usize = 256;
133 let mut stack = Vec::new();
134 let mut in_string = false;
135 let mut escaped = false;
136 let mut cuts: Vec<(usize, Vec<u8>, bool)> = Vec::new();
138 let bytes = text.as_bytes();
139 for (at, byte) in bytes.iter().enumerate() {
140 if in_string {
141 match (escaped, *byte) {
142 (true, _) => escaped = false,
143 (false, b'\\') => escaped = true,
144 (false, b'"') => {
145 in_string = false;
146 cuts.push((at + 1, stack.clone(), false));
147 }
148 (false, _) => {}
149 }
150 continue;
151 }
152 match byte {
153 b'"' => in_string = true,
154 b'{' | b'[' => {
155 stack.push(*byte);
156 cuts.push((at + 1, stack.clone(), false));
157 }
158 b'}' | b']' => {
159 stack.pop();
160 cuts.push((at + 1, stack.clone(), false));
161 }
162 b if b.is_ascii_alphanumeric() || *b == b'.' || *b == b'-' || *b == b'+' => {
163 let next = bytes.get(at + 1).copied();
164 if !next.is_some_and(|n| {
165 n.is_ascii_alphanumeric() || n == b'.' || n == b'-' || n == b'+'
166 }) {
167 cuts.push((at + 1, stack.clone(), false));
168 }
169 }
170 _ => {}
171 }
172 }
173 if in_string {
174 let at = text.len() - usize::from(escaped);
175 cuts.push((at, stack.clone(), true));
176 }
177 cuts.iter()
178 .rev()
179 .take(MAX_ATTEMPTS)
180 .find_map(|(at, open, quote)| {
181 let mut candidate = text.get(..*at)?.to_owned();
182 if *quote {
183 candidate.push('"');
184 }
185 for container in open.iter().rev() {
186 candidate.push(if *container == b'{' { '}' } else { ']' });
187 }
188 match serde_json::from_str(&candidate) {
189 Ok(serde_json::Value::Object(object)) => Some(object),
190 _ => None,
191 }
192 })
193}
194
195pub fn parse_partial_arguments(text: &str) -> serde_json::Map<String, serde_json::Value> {
213 if text.trim().is_empty() {
214 return serde_json::Map::new();
215 }
216 let repaired = repair_json(text);
217 let complete = serde_json::from_str(text)
218 .ok()
219 .or_else(|| serde_json::from_str(&repaired).ok());
220 if let Some(value) = complete {
221 return match value {
222 serde_json::Value::Object(object) => object,
223 _ => serde_json::Map::new(),
224 };
225 }
226 let cut = without_partial_escape(&repaired);
227 parse_partial_object(cut)
228 .or_else(|| parse_partial_object(text))
229 .unwrap_or_default()
230}
231
232fn repair_json(text: &str) -> String {
236 let mut repaired = String::with_capacity(text.len());
237 let mut in_string = false;
238 let mut chars = text.chars().peekable();
239 while let Some(c) = chars.next() {
240 if !in_string {
241 in_string = c == '"';
242 repaired.push(c);
243 continue;
244 }
245 match c {
246 '"' => {
247 in_string = false;
248 repaired.push(c);
249 }
250 '\\' => match chars.peek() {
251 Some('"' | '\\' | '/' | 'b' | 'f' | 'n' | 'r' | 't' | 'u') => {
252 repaired.push(c);
253 if let Some(next) = chars.next() {
254 repaired.push(next);
255 }
256 }
257 None => repaired.push(c),
259 Some(_) => repaired.push_str("\\\\"),
260 },
261 '\n' => repaired.push_str("\\n"),
262 '\r' => repaired.push_str("\\r"),
263 '\t' => repaired.push_str("\\t"),
264 c if c.is_control() => {
265 use std::fmt::Write as _;
266 let _ = write!(repaired, "\\u{:04x}", u32::from(c));
268 }
269 c => repaired.push(c),
270 }
271 }
272 repaired
273}
274
275fn without_partial_escape(text: &str) -> &str {
278 let bytes = text.as_bytes();
279 let tail = bytes.len().saturating_sub(5);
280 let Some(at) = (tail..bytes.len())
281 .rev()
282 .find(|at| bytes.get(*at..*at + 2) == Some(b"\\u"))
283 else {
284 return text;
285 };
286 let digits = bytes.get(at + 2..).unwrap_or_default();
287 let escaping = bytes
289 .get(..at)
290 .unwrap_or_default()
291 .iter()
292 .rev()
293 .take_while(|byte| **byte == b'\\')
294 .count();
295 if digits.len() < 4 && digits.iter().all(u8::is_ascii_hexdigit) && escaping % 2 == 0 {
296 text.get(..at).unwrap_or(text)
297 } else {
298 text
299 }
300}
301
302pub fn string_or_vec<'de, T, D>(deserializer: D) -> Result<Vec<T>, D::Error>
305where
306 T: Deserialize<'de> + FromStr<Err = Infallible>,
307 D: Deserializer<'de>,
308{
309 struct StringOrVec<T>(PhantomData<fn() -> T>);
310
311 impl<'de, T> Visitor<'de> for StringOrVec<T>
312 where
313 T: Deserialize<'de> + FromStr<Err = Infallible>,
314 {
315 type Value = Vec<T>;
316
317 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
318 formatter.write_str("a string, sequence, or null")
319 }
320
321 fn visit_str<E>(self, value: &str) -> Result<Vec<T>, E>
322 where
323 E: de::Error,
324 {
325 let item = FromStr::from_str(value).map_err(de::Error::custom)?;
326 Ok(vec![item])
327 }
328
329 fn visit_seq<A>(self, seq: A) -> Result<Vec<T>, A::Error>
330 where
331 A: SeqAccess<'de>,
332 {
333 Deserialize::deserialize(de::value::SeqAccessDeserializer::new(seq))
334 }
335
336 fn visit_map<M>(self, map: M) -> Result<Vec<T>, M::Error>
337 where
338 M: MapAccess<'de>,
339 {
340 let item = Deserialize::deserialize(de::value::MapAccessDeserializer::new(map))?;
341 Ok(vec![item])
342 }
343
344 fn visit_none<E>(self) -> Result<Vec<T>, E>
345 where
346 E: de::Error,
347 {
348 Ok(vec![])
349 }
350
351 fn visit_unit<E>(self) -> Result<Vec<T>, E>
352 where
353 E: de::Error,
354 {
355 Ok(vec![])
356 }
357 }
358
359 deserializer.deserialize_any(StringOrVec(PhantomData))
360}
361
362pub fn null_or_default<'de, T, D>(deserializer: D) -> Result<T, D::Error>
367where
368 T: Deserialize<'de> + Default,
369 D: Deserializer<'de>,
370{
371 Ok(Option::<T>::deserialize(deserializer)?.unwrap_or_default())
372}
373
374#[cfg(test)]
375mod tests;
376
377pub trait Lenient {
392 fn str(&self, key: &str) -> Option<&str>;
394 fn u64(&self, key: &str) -> Option<u64>;
396 fn i64(&self, key: &str) -> Option<i64>;
398 fn f64(&self, key: &str) -> Option<f64>;
400 fn bool(&self, key: &str) -> Option<bool>;
402 fn obj(&self, key: &str) -> Option<&serde_json::Map<String, serde_json::Value>>;
404 fn arr(&self, key: &str) -> &[serde_json::Value];
406 fn at(&self, pointer: &str) -> Option<&serde_json::Value>;
408 fn as_u64_lenient(&self) -> Option<u64>;
410}
411
412impl Lenient for serde_json::Value {
413 fn str(&self, key: &str) -> Option<&str> {
414 self.get(key)?.as_str()
415 }
416
417 fn u64(&self, key: &str) -> Option<u64> {
418 self.get(key)?.as_u64_lenient()
419 }
420
421 fn i64(&self, key: &str) -> Option<i64> {
422 match self.get(key)? {
423 serde_json::Value::Number(number) => number.as_i64(),
424 serde_json::Value::String(text) => text.trim().parse().ok(),
425 _ => None,
426 }
427 }
428
429 fn f64(&self, key: &str) -> Option<f64> {
430 match self.get(key)? {
431 serde_json::Value::Number(number) => number.as_f64(),
432 serde_json::Value::String(text) => text.trim().parse().ok(),
433 _ => None,
434 }
435 }
436
437 fn bool(&self, key: &str) -> Option<bool> {
438 self.get(key)?.as_bool()
439 }
440
441 fn obj(&self, key: &str) -> Option<&serde_json::Map<String, serde_json::Value>> {
442 self.get(key)?.as_object()
443 }
444
445 fn arr(&self, key: &str) -> &[serde_json::Value] {
446 self.get(key)
447 .and_then(serde_json::Value::as_array)
448 .map_or(&[], Vec::as_slice)
449 }
450
451 fn at(&self, pointer: &str) -> Option<&serde_json::Value> {
452 self.pointer(pointer).filter(|value| !value.is_null())
453 }
454
455 fn as_u64_lenient(&self) -> Option<u64> {
456 match self {
457 serde_json::Value::Number(number) => number.as_u64().or_else(|| {
458 number
459 .as_f64()
460 .filter(|float| *float >= 0.0 && float.fract() == 0.0)
461 .map(|float| float as u64)
462 }),
463 serde_json::Value::String(text) => text.trim().parse().ok(),
464 _ => None,
465 }
466 }
467}