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,
148 budget: SurfaceBudget,
149) -> bool {
150 let mut stack: Vec<(&Value, String, usize)> = vec![(root, String::from("$"), 0)];
151
152 while let Some((value, path, depth)) = stack.pop() {
153 if depth > budget.depth {
154 surface.truncated = true;
155 continue;
156 }
157 match value {
158 Value::String(s) => {
159 if !push_leaf(surface, total, &budget, &path, s) {
160 return false;
161 }
162 },
163 Value::Array(items) => {
164 for (index, item) in items.iter().enumerate().rev() {
165 stack.push((item, format!("{path}[{index}]"), depth + 1));
166 }
167 },
168 Value::Object(map) => {
169 for (key, item) in map.iter().rev() {
170 if !push_leaf(surface, total, &budget, &format!("{path}.{key}.$key"), key) {
171 return false;
172 }
173 stack.push((item, format!("{path}.{key}"), depth + 1));
174 }
175 },
176 Value::Null | Value::Bool(_) | Value::Number(_) => {},
177 }
178 }
179 true
180}
181
182fn push_leaf(
183 surface: &mut ForwardedSurface,
184 total: &mut usize,
185 budget: &SurfaceBudget,
186 path: &str,
187 value: &str,
188) -> bool {
189 if value.is_empty() {
190 return true;
191 }
192 if surface.leaves.len() >= budget.leaves || *total >= budget.total_bytes {
193 surface.truncated = true;
194 return false;
195 }
196 let (value, clipped) = clip(value, budget.leaf_bytes);
197 if clipped {
198 surface.truncated = true;
199 }
200 *total += value.len();
201 surface.leaves.push(SurfaceLeaf {
202 path: path.to_owned(),
203 value,
204 });
205 true
206}
207
208fn clip(value: &str, limit: usize) -> (String, bool) {
209 if value.len() <= limit {
210 return (value.to_owned(), false);
211 }
212 let half = limit / 2;
213 let head_end = crate::text::floor_char_boundary(value, half);
214 let tail_start = ceil_boundary(value, value.len() - half);
215 let mut out = String::with_capacity(limit + 1);
216 out.push_str(&value[..head_end]);
217 out.push('\n');
218 out.push_str(&value[tail_start..]);
219 (out, true)
220}
221
222const fn ceil_boundary(s: &str, mut index: usize) -> usize {
223 while index < s.len() && !s.is_char_boundary(index) {
224 index += 1;
225 }
226 index
227}