systemprompt_models/wire/
inspect.rs1use serde_json::Value;
29
30#[derive(Debug, Clone, PartialEq, Eq)]
31pub struct SurfaceLeaf {
32 pub path: String,
33 pub value: String,
34}
35
36#[derive(Debug, Clone, Default, PartialEq, Eq)]
40pub struct ForwardedSurface {
41 leaves: Vec<SurfaceLeaf>,
42 truncated: bool,
43}
44
45impl ForwardedSurface {
46 #[must_use]
47 pub fn leaves(&self) -> &[SurfaceLeaf] {
48 &self.leaves
49 }
50
51 #[must_use]
52 pub const fn truncated(&self) -> bool {
53 self.truncated
54 }
55
56 #[must_use]
57 pub const fn is_empty(&self) -> bool {
58 self.leaves.is_empty()
59 }
60
61 #[must_use]
62 pub const fn len(&self) -> usize {
63 self.leaves.len()
64 }
65
66 #[must_use]
67 pub fn joined(&self) -> String {
68 let mut out = String::new();
69 for leaf in &self.leaves {
70 if !out.is_empty() {
71 out.push('\n');
72 }
73 out.push_str(&leaf.value);
74 }
75 out
76 }
77}
78
79#[derive(Debug, Clone, Copy)]
82pub struct SurfaceBudget {
83 pub depth: usize,
84 pub leaves: usize,
85 pub total_bytes: usize,
86 pub leaf_bytes: usize,
87}
88
89impl Default for SurfaceBudget {
90 fn default() -> Self {
91 Self {
92 depth: 64,
93 leaves: 50_000,
94 total_bytes: 2 * 1024 * 1024,
95 leaf_bytes: 64 * 1024,
96 }
97 }
98}
99
100#[must_use]
101pub fn string_leaves(body: &[u8], budget: SurfaceBudget) -> ForwardedSurface {
102 let Ok(root) = serde_json::from_slice::<Value>(body) else {
103 return ForwardedSurface::default();
104 };
105 let mut surface = ForwardedSurface::default();
106 let mut total: usize = 0;
107 walk(&mut surface, &mut total, &root, budget);
108 surface
109}
110
111#[must_use]
112pub fn sse_string_leaves(frames: &[u8], budget: SurfaceBudget) -> ForwardedSurface {
113 let mut surface = ForwardedSurface::default();
114 let mut total: usize = 0;
115 let mut rest = frames;
116 while !rest.is_empty() {
117 let (frame, next) = rest.split_at(super::sse::frame_end(rest).unwrap_or(rest.len()));
118 if let Some(payload) = data_payload(frame)
119 && let Ok(root) = serde_json::from_slice::<Value>(&payload)
120 && !walk(&mut surface, &mut total, &root, budget)
121 {
122 return surface;
123 }
124 rest = next;
125 }
126 surface
127}
128
129fn data_payload(frame: &[u8]) -> Option<Vec<u8>> {
130 let mut out: Vec<u8> = Vec::new();
131 let mut found = false;
132 for line in frame.split(|b| *b == b'\n') {
133 let line = line.strip_suffix(b"\r").unwrap_or(line);
134 let Some(value) = line.strip_prefix(b"data:") else {
135 continue;
136 };
137 found = true;
138 out.extend_from_slice(value.strip_prefix(b" ").unwrap_or(value));
139 }
140 found.then_some(out)
141}
142
143fn walk(
144 surface: &mut ForwardedSurface,
145 total: &mut usize,
146 root: &Value,
147 budget: SurfaceBudget,
148) -> bool {
149 let mut stack: Vec<(&Value, String, usize)> = vec![(root, String::from("$"), 0)];
150
151 while let Some((value, path, depth)) = stack.pop() {
152 if depth > budget.depth {
153 surface.truncated = true;
154 continue;
155 }
156 match value {
157 Value::String(s) => {
158 if !push_leaf(surface, total, &budget, &path, s) {
159 return false;
160 }
161 },
162 Value::Array(items) => {
163 for (index, item) in items.iter().enumerate().rev() {
164 stack.push((item, format!("{path}[{index}]"), depth + 1));
165 }
166 },
167 Value::Object(map) => {
168 for (key, item) in map.iter().rev() {
169 if !push_leaf(surface, total, &budget, &format!("{path}.{key}.$key"), key) {
170 return false;
171 }
172 stack.push((item, format!("{path}.{key}"), depth + 1));
173 }
174 },
175 Value::Null | Value::Bool(_) | Value::Number(_) => {},
176 }
177 }
178 true
179}
180
181fn push_leaf(
182 surface: &mut ForwardedSurface,
183 total: &mut usize,
184 budget: &SurfaceBudget,
185 path: &str,
186 value: &str,
187) -> bool {
188 if value.is_empty() {
189 return true;
190 }
191 if surface.leaves.len() >= budget.leaves || *total >= budget.total_bytes {
192 surface.truncated = true;
193 return false;
194 }
195 let (value, clipped) = clip(value, budget.leaf_bytes);
196 if clipped {
197 surface.truncated = true;
198 }
199 *total += value.len();
200 surface.leaves.push(SurfaceLeaf {
201 path: path.to_owned(),
202 value,
203 });
204 true
205}
206
207fn clip(value: &str, limit: usize) -> (String, bool) {
208 if value.len() <= limit {
209 return (value.to_owned(), false);
210 }
211 let half = limit / 2;
212 let head_end = crate::text::floor_char_boundary(value, half);
213 let tail_start = ceil_boundary(value, value.len() - half);
214 let mut out = String::with_capacity(limit + 1);
215 out.push_str(&value[..head_end]);
216 out.push('\n');
217 out.push_str(&value[tail_start..]);
218 (out, true)
219}
220
221const fn ceil_boundary(s: &str, mut index: usize) -> usize {
222 while index < s.len() && !s.is_char_boundary(index) {
223 index += 1;
224 }
225 index
226}