1use serde_json::Value;
2use std::fmt;
3
4pub trait StrExt {
6 fn trunc(&self, max_bytes: usize) -> &str;
8
9 fn ellipsis(&self, max_bytes: usize) -> Ellipsis<'_>;
11
12 fn oneline(&self, max_bytes: usize) -> String;
14}
15
16impl StrExt for str {
17 #[inline]
18 fn trunc(&self, max_bytes: usize) -> &str {
19 &self[..self.floor_char_boundary(max_bytes)]
20 }
21
22 #[inline]
23 fn ellipsis(&self, max_bytes: usize) -> Ellipsis<'_> {
24 Ellipsis(self, max_bytes)
25 }
26
27 fn oneline(&self, max_bytes: usize) -> String {
28 let flat: String = self.split_whitespace().collect::<Vec<_>>().join(" ");
29 flat.trunc(max_bytes).to_string()
30 }
31}
32
33pub struct Ellipsis<'a>(&'a str, usize);
35
36impl fmt::Display for Ellipsis<'_> {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 let s = self.0.trunc(self.1);
39 f.write_str(s)?;
40 if s.len() < self.0.len() {
41 f.write_str("…")?;
42 }
43 Ok(())
44 }
45}
46
47pub fn parse_tool_args(args_str: &str) -> Value {
50 serde_json::from_str(args_str).unwrap_or_else(|_| {
51 match llm_json::repair_json(args_str, &llm_json::RepairOptions::default()) {
52 Ok(fixed) => serde_json::from_str(&fixed).unwrap_or(Value::Object(Default::default())),
53 Err(_) => Value::Object(Default::default()),
54 }
55 })
56}