diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dbf17187..1529f6cca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,15 @@ matching `## [X.Y.Z]` section (plus install instructions). Do not maintain parallel copies under `docs/` or `scripts/notes/`. At cut time: rename `## [Unreleased]` to `## [X.Y.Z] - YYYY-MM-DD`, then run the release script. +## [Unreleased] + +### Fixed + +- **Codex Responses no longer sends `reasoning.summary: "auto"`.** ChatGPT + Codex rejects that value for gpt-5.6-terra / gpt-5.3-codex family models + (HTTP 400 at turn 0). The adapter now sends `{ effort }` only, matching + Codex CLI catalog `default_reasoning_summary=none` (CL-6893). + ## [0.2.103] - 2026-08-23 ### TUI diff --git a/src/provider/codex-responses-adapter.ts b/src/provider/codex-responses-adapter.ts index fe17667e3..0327f8fe3 100644 --- a/src/provider/codex-responses-adapter.ts +++ b/src/provider/codex-responses-adapter.ts @@ -321,9 +321,12 @@ function buildRequest( } // reasoning_effort rides in providerOptions (same place the OpenAI-compatible // path reads it); map it onto the Responses `reasoning.effort` field. + // ChatGPT Codex rejects summary:"auto" for gpt-5.6-terra / gpt-5.3-codex + // family (HTTP 400; supported: concise | detailed | none). Codex CLI catalog + // default_reasoning_summary is none — send effort only (CL-6893). const effort = options.providerOptions?.["reasoning_effort"]; if (typeof effort === "string" && effort !== "none") { - body["reasoning"] = { effort, summary: "auto" }; + body["reasoning"] = { effort }; } if (sessionId !== undefined) body["prompt_cache_key"] = sessionId; diff --git a/tests/unit/codex-responses-adapter.test.ts b/tests/unit/codex-responses-adapter.test.ts index 4acfce362..2c642619d 100644 --- a/tests/unit/codex-responses-adapter.test.ts +++ b/tests/unit/codex-responses-adapter.test.ts @@ -132,9 +132,26 @@ describe("codex-responses buildRequest", () => { const body = JSON.parse( adapter().buildRequest([userTurn("x")], "gpt-5-codex", options).body, ) as Record; - expect(body["reasoning"]).toEqual({ effort: "high", summary: "auto" }); + expect(body["reasoning"]).toEqual({ effort: "high" }); }); + // CL-6893: ChatGPT Codex rejects reasoning.summary "auto" for the gpt-5.6-terra / + // gpt-5.3-codex family (HTTP 400). Codex CLI catalog default is none — omit summary + // (effort only) so Terra/Luna request bodies never send summary:"auto". + test.each(["gpt-5.6-terra", "gpt-5.6-luna"] as const)( + "omits reasoning.summary auto for %s (CL-6893)", + (model) => { + const options: InferenceOptions = { + providerOptions: { ...baseOptions.providerOptions, reasoning_effort: "high" }, + }; + const body = JSON.parse( + adapter().buildRequest([userTurn("x")], model, options).body, + ) as Record; + expect(body["reasoning"]).toEqual({ effort: "high" }); + expect(body["reasoning"]).not.toHaveProperty("summary"); + }, + ); + test("roundtrips encrypted reasoning signature from prior assistant turn into Responses reasoning item", () => { // Prior turn's assistant content included a thinking block with signature. // buildRequest must emit the "reasoning" item (with encrypted_content) before