switchyard_llm_client/
responses_reasoning.rs1use serde::Deserialize;
7use serde_json::Value;
8
9#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq)]
11#[serde(rename_all = "snake_case")]
12pub enum ResponsesReasoningPolicy {
13 #[default]
17 PreserveEncrypted,
18 Drop,
23}
24
25impl ResponsesReasoningPolicy {
26 pub(crate) fn normalize(self, body: &mut Value) {
28 let has_stored_reasoning = body.get("store").and_then(Value::as_bool) != Some(false);
29 let Some(Value::Array(input)) = body.get_mut("input") else {
30 return;
31 };
32 input.retain_mut(|item| self.normalize_item(item, has_stored_reasoning));
33 }
34
35 fn normalize_item(self, item: &mut Value, has_stored_reasoning: bool) -> bool {
37 let Some(object) = item.as_object_mut() else {
38 return true;
39 };
40 if object.get("type").and_then(Value::as_str) != Some("reasoning") {
41 return true;
42 }
43
44 let encrypted_content = object.get("encrypted_content").and_then(Value::as_str);
45 if encrypted_content.is_some_and(switchyard_translation::is_anthropic_thinking_envelope) {
46 return false;
47 }
48 let has_encrypted_content = encrypted_content.is_some_and(|content| !content.is_empty());
49 let has_stored_id = object
50 .get("id")
51 .and_then(Value::as_str)
52 .is_some_and(|id| !id.is_empty());
53 if self == Self::PreserveEncrypted
54 && (has_encrypted_content || (has_stored_reasoning && has_stored_id))
55 {
56 object.insert("content".to_string(), Value::Array(Vec::new()));
57 true
58 } else {
59 false
60 }
61 }
62}