Omit Responses API reasoning field when unset

Open 💬 0 comments Opened Jul 6, 2026 by yazandabbas

What issue are you seeing?

When Codex builds a Responses API request without an explicit reasoning effort or reasoning summary, the provider-facing JSON can include:

"reasoning": null

Some OpenAI-compatible Responses API providers reject that payload because reasoning, when present, is expected to be an object rather than null.

The request should omit the reasoning field entirely when no reasoning settings are configured.

What steps can reproduce the bug?

From the current main branch, inspect the provider request structs in codex-rs/codex-api/src/common.rs.

ResponsesApiRequest currently has:

pub reasoning: Option<Reasoning>,

and ResponseCreateWsRequest also has:

pub reasoning: Option<Reasoning>,

Unlike nearby optional fields such as tools, service_tier, prompt_cache_key, text, and client_metadata, these fields are not annotated with:

#[serde(skip_serializing_if = "Option::is_none")]

A minimal serialization check demonstrates the issue:

let request = ResponsesApiRequest {
    model: "gpt-test".to_string(),
    instructions: "Say hi".to_string(),
    input: Vec::new(),
    tools: Some(Vec::new()),
    tool_choice: "auto".to_string(),
    parallel_tool_calls: false,
    reasoning: None,
    store: false,
    stream: true,
    include: Vec::new(),
    service_tier: None,
    prompt_cache_key: None,
    text: None,
    client_metadata: None,
};

let payload = serde_json::to_value(&request).unwrap();
assert!(payload.get("reasoning").is_none());

That assertion currently fails because reasoning is serialized as null.

The same applies to the websocket response.create payload built from ResponseCreateWsRequest.

What is the expected behavior?

When reasoning is None, Codex should omit the reasoning key from provider-facing Responses API payloads.

Expected behavior: the payload has no reasoning field when no reasoning settings are set.

Not:

{
  "reasoning": null
}

Additional information

This looks like a small serialization fix.

Potential change:

#[serde(skip_serializing_if = "Option::is_none")]
pub reasoning: Option<Reasoning>,

on both:

  • ResponsesApiRequest
  • ResponseCreateWsRequest

Suggested regression coverage:

  • a ResponsesApiRequest serialization test that asserts reasoning is absent when unset
  • a websocket response.create serialization test that asserts reasoning is absent when unset

This should preserve existing behavior when reasoning is set, while improving compatibility with OpenAI-compatible Responses API providers that reject null for object fields.

View original on GitHub ↗