1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
use serde_json::Value;
/// Filter model-facing text without changing protocol tags, tool names, or
/// opaque media bytes that happen to contain the same characters as an input.
pub(super) fn filter_text_fields(value: &mut Value) {
if !crate::session_inputs::has_private_filter() {
return;
}
visit(value, false);
}
fn visit(value: &mut Value, text: bool) {
match value {
Value::String(value) if text => *value = crate::session_inputs::redact(value),
Value::Array(values) => values.iter_mut().for_each(|value| visit(value, text)),
Value::Object(values) => {
let tool_input = values.get("type").and_then(Value::as_str) == Some("tool_use");
for (name, value) in values {
if matches!(
name.as_str(),
"arguments"
| "args"
| "enum"
| "const"
| "default"
| "examples"
| "pattern"
| "stop"
| "stop_sequences"
) || (tool_input && name == "input")
{
filter_data(value);
} else {
visit(
value,
matches!(
name.as_str(),
"text"
| "content"
| "system"
| "instructions"
| "prompt"
| "input"
| "output"
| "reasoning_content"
| "thinking"
| "summary"
| "description"
| "title"
| "$comment"
),
);
}
}
}
_ => {}
}
}
fn filter_data(value: &mut Value) {
match value {
Value::String(value) => *value = crate::session_inputs::redact(value),
Value::Array(values) => values.iter_mut().for_each(filter_data),
Value::Object(values) => values.values_mut().for_each(filter_data),
_ => {}
}
}