use super::{CodexResponsesMode, SubscriptionProvider};
fn input_item_text(item: &serde_json::Value) -> Option<String> {
match item.get("content") {
Some(serde_json::Value::String(s)) => Some(s.clone()),
Some(serde_json::Value::Array(parts)) => {
let text: String = parts
.iter()
.filter_map(|p| p.get("text").and_then(serde_json::Value::as_str))
.collect::<Vec<_>>()
.join("");
(!text.is_empty()).then_some(text)
}
_ => None,
}
}
pub(super) fn normalize_subscription_request(
provider: SubscriptionProvider,
body: &mut serde_json::Value,
responses_mode: CodexResponsesMode,
) {
crate::openai::reconcile_subscription_parameters(provider, body);
if provider == SubscriptionProvider::Codex {
normalize_codex_responses_body(body, responses_mode);
}
}
pub(super) fn normalize_codex_responses_body(
body: &mut serde_json::Value,
mode: CodexResponsesMode,
) {
let Some(obj) = body.as_object_mut() else {
return;
};
obj.entry("reasoning").or_insert_with(
|| serde_json::json!({"effort": crate::clients::DEFAULT_OPENAI_REASONING_EFFORT}),
);
obj.insert("stream".to_string(), serde_json::Value::Bool(true));
obj.insert("store".to_string(), serde_json::Value::Bool(false));
obj.remove("max_output_tokens");
if mode == CodexResponsesMode::Lite {
return;
}
if let Some(input) = obj.get("input") {
let normalized = crate::responses::normalize_input_items(input);
obj.insert("input".to_string(), normalized);
}
let mut hoisted: Vec<String> = Vec::new();
if let Some(serde_json::Value::Array(items)) = obj.get_mut("input") {
items.retain(
|item| match item.get("role").and_then(serde_json::Value::as_str) {
Some("system" | "developer") => {
if let Some(text) = input_item_text(item) {
hoisted.push(text);
}
false
}
_ => true,
},
);
}
let mut parts: Vec<String> = Vec::new();
if let Some(existing) = obj.get("instructions").and_then(serde_json::Value::as_str)
&& !existing.trim().is_empty()
{
parts.push(existing.to_string());
}
parts.extend(hoisted);
let instructions = if parts.is_empty() {
"You are a helpful assistant.".to_string()
} else {
parts.join("\n\n")
};
obj.insert(
"instructions".to_string(),
serde_json::Value::String(instructions),
);
}