use serde_json::Value;
use std::fmt;
pub trait StrExt {
fn trunc(&self, max_bytes: usize) -> &str;
fn ellipsis(&self, max_bytes: usize) -> Ellipsis<'_>;
fn oneline(&self, max_bytes: usize) -> String;
}
impl StrExt for str {
#[inline]
fn trunc(&self, max_bytes: usize) -> &str {
&self[..self.floor_char_boundary(max_bytes)]
}
#[inline]
fn ellipsis(&self, max_bytes: usize) -> Ellipsis<'_> {
Ellipsis(self, max_bytes)
}
fn oneline(&self, max_bytes: usize) -> String {
let flat: String = self.split_whitespace().collect::<Vec<_>>().join(" ");
flat.trunc(max_bytes).to_string()
}
}
pub struct Ellipsis<'a>(&'a str, usize);
impl fmt::Display for Ellipsis<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = self.0.trunc(self.1);
f.write_str(s)?;
if s.len() < self.0.len() {
f.write_str("…")?;
}
Ok(())
}
}
pub fn parse_tool_args(args_str: &str) -> Value {
serde_json::from_str(args_str).unwrap_or_else(|_| {
match llm_json::repair_json(args_str, &llm_json::RepairOptions::default()) {
Ok(fixed) => serde_json::from_str(&fixed).unwrap_or(Value::Object(Default::default())),
Err(_) => Value::Object(Default::default()),
}
})
}