Skip to content

Commit 0af7e4a

Browse files
fix: omit reasoning summary when ReasoningSummary::None (openai#7845)
``` { "error": { "message": "Invalid value: 'none'. Supported values are: 'concise', 'detailed', and 'auto'.", "type": "invalid_request_error", "param": "reasoning.summary", "code": "invalid_value" } } ```
1 parent 8c4c6a1 commit 0af7e4a

File tree

2 files changed

+81
-1
lines changed

2 files changed

+81
-1
lines changed

codex-rs/core/src/client.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,11 @@ impl ModelClient {
206206
let reasoning = if model_family.supports_reasoning_summaries {
207207
Some(Reasoning {
208208
effort: self.effort.or(model_family.default_reasoning_effort),
209-
summary: Some(self.summary),
209+
summary: if self.summary == ReasoningSummaryConfig::None {
210+
None
211+
} else {
212+
Some(self.summary)
213+
},
210214
})
211215
} else {
212216
None

codex-rs/core/tests/suite/client.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use codex_core::protocol::Op;
2222
use codex_core::protocol::SessionSource;
2323
use codex_otel::otel_event_manager::OtelEventManager;
2424
use codex_protocol::ConversationId;
25+
use codex_protocol::config_types::ReasoningSummary;
2526
use codex_protocol::config_types::Verbosity;
2627
use codex_protocol::models::ReasoningItemContent;
2728
use codex_protocol::models::ReasoningItemReasoningSummary;
@@ -823,6 +824,81 @@ async fn includes_default_reasoning_effort_in_request_when_defined_by_model_fami
823824
Ok(())
824825
}
825826

827+
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
828+
async fn configured_reasoning_summary_is_sent() -> anyhow::Result<()> {
829+
skip_if_no_network!(Ok(()));
830+
let server = MockServer::start().await;
831+
832+
let resp_mock = mount_sse_once(&server, sse_completed("resp1")).await;
833+
let TestCodex { codex, .. } = test_codex()
834+
.with_config(|config| {
835+
config.model_reasoning_summary = ReasoningSummary::Concise;
836+
})
837+
.build(&server)
838+
.await?;
839+
840+
codex
841+
.submit(Op::UserInput {
842+
items: vec![UserInput::Text {
843+
text: "hello".into(),
844+
}],
845+
})
846+
.await
847+
.unwrap();
848+
849+
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TaskComplete(_))).await;
850+
851+
let request = resp_mock.single_request();
852+
let request_body = request.body_json();
853+
854+
pretty_assertions::assert_eq!(
855+
request_body
856+
.get("reasoning")
857+
.and_then(|reasoning| reasoning.get("summary"))
858+
.and_then(|value| value.as_str()),
859+
Some("concise")
860+
);
861+
862+
Ok(())
863+
}
864+
865+
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
866+
async fn reasoning_summary_is_omitted_when_disabled() -> anyhow::Result<()> {
867+
skip_if_no_network!(Ok(()));
868+
let server = MockServer::start().await;
869+
870+
let resp_mock = mount_sse_once(&server, sse_completed("resp1")).await;
871+
let TestCodex { codex, .. } = test_codex()
872+
.with_config(|config| {
873+
config.model_reasoning_summary = ReasoningSummary::None;
874+
})
875+
.build(&server)
876+
.await?;
877+
878+
codex
879+
.submit(Op::UserInput {
880+
items: vec![UserInput::Text {
881+
text: "hello".into(),
882+
}],
883+
})
884+
.await
885+
.unwrap();
886+
887+
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TaskComplete(_))).await;
888+
889+
let request = resp_mock.single_request();
890+
let request_body = request.body_json();
891+
892+
pretty_assertions::assert_eq!(
893+
request_body
894+
.get("reasoning")
895+
.and_then(|reasoning| reasoning.get("summary")),
896+
None
897+
);
898+
899+
Ok(())
900+
}
901+
826902
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
827903
async fn includes_default_verbosity_in_request() -> anyhow::Result<()> {
828904
skip_if_no_network!(Ok(()));

0 commit comments

Comments
 (0)