lean_ctx/proxy/
verbosity.rs1use serde_json::{Map, Value};
24
25pub const STEER: &str =
28 "Be concise: answer directly and do not restate the question or surrounding context.";
29
30fn string_suffix() -> String {
32 format!("\n\n{STEER}")
33}
34
35fn already_steered(text: &str) -> bool {
38 text.trim_end().ends_with(STEER)
39}
40
41fn steer_text_block() -> Value {
43 let mut m = Map::new();
44 m.insert("type".to_string(), Value::String("text".to_string()));
45 m.insert("text".to_string(), Value::String(STEER.to_string()));
46 Value::Object(m)
47}
48
49fn steer_gemini_part() -> Value {
51 let mut m = Map::new();
52 m.insert("text".to_string(), Value::String(STEER.to_string()));
53 Value::Object(m)
54}
55
56fn append_to_content(content: &mut Value, block: impl FnOnce() -> Value) -> bool {
60 match content {
61 Value::String(s) => {
62 if already_steered(s) {
63 return false;
64 }
65 s.push_str(&string_suffix());
66 true
67 }
68 Value::Array(parts) => {
69 let last_text = parts
71 .iter()
72 .rev()
73 .find_map(|p| p.get("text").and_then(Value::as_str));
74 if last_text.is_some_and(already_steered) {
75 return false;
76 }
77 parts.push(block());
78 true
79 }
80 _ => false,
81 }
82}
83
84fn last_role_index(messages: &[Value], role: &str) -> Option<usize> {
86 messages
87 .iter()
88 .rposition(|m| m.get("role").and_then(Value::as_str) == Some(role))
89}
90
91pub fn apply_anthropic(doc: &mut Value) -> bool {
94 let Some(messages) = doc.get_mut("messages").and_then(Value::as_array_mut) else {
95 return false;
96 };
97 let Some(idx) = last_role_index(messages, "user") else {
98 return false;
99 };
100 let Some(content) = messages[idx].get_mut("content") else {
101 return false;
102 };
103 let changed = append_to_content(content, steer_text_block);
104 if changed {
105 record();
106 }
107 changed
108}
109
110pub fn apply_openai_chat(doc: &mut Value) -> bool {
114 let Some(messages) = doc.get_mut("messages").and_then(Value::as_array_mut) else {
115 return false;
116 };
117 let Some(idx) = last_role_index(messages, "user") else {
118 return false;
119 };
120 let Some(content) = messages[idx].get_mut("content") else {
121 return false;
122 };
123 let changed = append_to_content(content, steer_text_block);
124 if changed {
125 record();
126 }
127 changed
128}
129
130pub fn apply_openai_responses(doc: &mut Value) -> bool {
133 let changed = match doc.get_mut("input") {
134 Some(Value::String(s)) => {
135 if already_steered(s) {
136 false
137 } else {
138 s.push_str(&string_suffix());
139 true
140 }
141 }
142 Some(Value::Array(items)) => {
143 let Some(idx) = last_role_index(items, "user") else {
144 return false;
145 };
146 match items[idx].get_mut("content") {
147 Some(content) => append_to_content(content, steer_text_block),
148 None => false,
149 }
150 }
151 _ => false,
152 };
153 if changed {
154 record();
155 }
156 changed
157}
158
159pub fn apply_google(doc: &mut Value) -> bool {
162 let Some(contents) = doc.get_mut("contents").and_then(Value::as_array_mut) else {
163 return false;
164 };
165 let Some(idx) = last_role_index(contents, "user") else {
166 return false;
167 };
168 let Some(parts) = contents[idx].get_mut("parts").and_then(Value::as_array_mut) else {
169 return false;
170 };
171 let last_text = parts
172 .iter()
173 .rev()
174 .find_map(|p| p.get("text").and_then(Value::as_str));
175 if last_text.is_some_and(already_steered) {
176 return false;
177 }
178 parts.push(steer_gemini_part());
179 record();
180 true
181}
182
183use std::sync::atomic::{AtomicU64, Ordering};
184
185static STEERED: AtomicU64 = AtomicU64::new(0);
187
188fn record() {
189 STEERED.fetch_add(1, Ordering::Relaxed);
190}
191
192#[must_use]
194pub fn steered_count() -> u64 {
195 STEERED.load(Ordering::Relaxed)
196}
197
198#[cfg(test)]
199mod tests {
200 use super::*;
201 use serde_json::json;
202
203 #[test]
204 fn anthropic_appends_block_to_last_user() {
205 let mut doc = json!({
206 "messages": [
207 {"role": "user", "content": "first"},
208 {"role": "assistant", "content": "ok"},
209 {"role": "user", "content": [{"type": "text", "text": "second"}]}
210 ]
211 });
212 assert!(apply_anthropic(&mut doc));
213 let last = &doc["messages"][2]["content"];
214 let arr = last.as_array().unwrap();
215 assert_eq!(arr.len(), 2, "new steer block appended");
216 assert_eq!(arr[1]["text"], STEER);
217 assert_eq!(doc["messages"][0]["content"], "first");
219 }
220
221 #[test]
222 fn anthropic_string_content_concatenates() {
223 let mut doc = json!({"messages": [{"role": "user", "content": "hello"}]});
224 assert!(apply_anthropic(&mut doc));
225 let s = doc["messages"][0]["content"].as_str().unwrap();
226 assert!(s.starts_with("hello"));
227 assert!(s.ends_with(STEER));
228 }
229
230 #[test]
231 fn never_modifies_cache_control_blocks() {
232 let mut doc = json!({
233 "messages": [{
234 "role": "user",
235 "content": [
236 {"type": "text", "text": "cached", "cache_control": {"type": "ephemeral"}}
237 ]
238 }]
239 });
240 assert!(apply_anthropic(&mut doc));
241 let arr = doc["messages"][0]["content"].as_array().unwrap();
242 assert_eq!(arr.len(), 2);
245 assert!(arr[0].get("cache_control").is_some());
246 assert_eq!(arr[0]["text"], "cached");
247 assert_eq!(arr[1]["text"], STEER);
248 assert!(arr[1].get("cache_control").is_none());
249 }
250
251 #[test]
252 fn idempotent_no_double_append() {
253 let mut doc = json!({"messages": [{"role": "user", "content": "hi"}]});
254 assert!(apply_anthropic(&mut doc));
255 let once = doc.clone();
256 assert!(!apply_anthropic(&mut doc), "second pass is a no-op");
257 assert_eq!(doc, once, "byte-identical after a redundant pass");
258 }
259
260 #[test]
261 fn deterministic_constant_suffix() {
262 let mk = || json!({"messages": [{"role": "user", "content": "ask"}]});
263 let mut a = mk();
264 let mut b = mk();
265 apply_anthropic(&mut a);
266 apply_anthropic(&mut b);
267 assert_eq!(a, b, "constant steer ⇒ byte-identical rewrite");
268 }
269
270 #[test]
271 fn openai_chat_appends_to_last_user() {
272 let mut doc = json!({
273 "messages": [
274 {"role": "system", "content": "sys"},
275 {"role": "user", "content": "q"}
276 ]
277 });
278 assert!(apply_openai_chat(&mut doc));
279 let s = doc["messages"][1]["content"].as_str().unwrap();
280 assert!(s.ends_with(STEER));
281 assert_eq!(doc["messages"][0]["content"], "sys", "system untouched");
282 }
283
284 #[test]
285 fn responses_string_and_array_input() {
286 let mut s = json!({"input": "plain"});
287 assert!(apply_openai_responses(&mut s));
288 assert!(s["input"].as_str().unwrap().ends_with(STEER));
289
290 let mut a =
291 json!({"input": [{"role": "user", "content": [{"type": "text", "text": "q"}]}]});
292 assert!(apply_openai_responses(&mut a));
293 let parts = a["input"][0]["content"].as_array().unwrap();
294 assert_eq!(parts.last().unwrap()["text"], STEER);
295 }
296
297 #[test]
298 fn google_appends_part_to_last_user() {
299 let mut doc = json!({
300 "contents": [
301 {"role": "user", "parts": [{"text": "q1"}]},
302 {"role": "model", "parts": [{"text": "a1"}]},
303 {"role": "user", "parts": [{"text": "q2"}]}
304 ]
305 });
306 assert!(apply_google(&mut doc));
307 let parts = doc["contents"][2]["parts"].as_array().unwrap();
308 assert_eq!(parts.len(), 2);
309 assert_eq!(parts[1]["text"], STEER);
310 }
311
312 #[test]
313 fn no_user_turn_is_noop() {
314 let mut doc = json!({"messages": [{"role": "assistant", "content": "x"}]});
315 assert!(!apply_anthropic(&mut doc));
316 }
317}