fix(codex): adapt the Responses body to the ChatGPT/Codex backend contract
Root cause of 400 {"detail":"System messages are not allowed"} at
chatgpt.com/backend-api/codex/responses (both platforms): the codex
adaptation covered only IDENTITY HEADERS (originator/OpenAI-Beta/UA/
chatgpt-account-id) — the BODY still carried the system prompt as
role:system input items, which the codex backend rejects outright. Its
system channel is the top-level field, and stateless
(store:false) reasoning replay requires
include:["reasoning.encrypted_content"] — both per the same reference
the headers were ported from (official Codex CLI + Pi's
api/openai-codex-responses.ts).
New adapt_body_for_codex_backend (kigi-sampling-types): hoists every
system input item into (order preserved, appended to any
existing instructions; string and parts content shapes) and requests
encrypted reasoning. Idempotent. Applied at both Responses send paths,
openai_codex-GATED — the API-key path stays byte-identical
(pinned by a control wire test).
Tests: adapter unit tests (hoist+include, no-system no-op, idempotence)
plus two mock-server wire tests (codex body has no system role,
instructions + include present; plain Responses body unchanged).
Verified: sampling-types + sampler + chat-state + shell 6076 tests
green, clippy clean.
This commit is contained in:
@@ -1183,6 +1183,9 @@ impl SamplingClient {
|
||||
// old raw_output machinery.
|
||||
kigi_sampling_types::patch_reasoning_text_types(&mut request_body);
|
||||
kigi_sampling_types::patch_reasoning_effort(&mut request_body, request.reasoning_effort);
|
||||
if self.defaults.openai_codex {
|
||||
kigi_sampling_types::adapt_body_for_codex_backend(&mut request_body);
|
||||
}
|
||||
let http_request = self.post(self.endpoint("responses")).json(&request_body);
|
||||
|
||||
let response = http_request.send().await.map_err(|e| {
|
||||
@@ -1321,6 +1324,9 @@ impl SamplingClient {
|
||||
}
|
||||
kigi_sampling_types::patch_reasoning_text_types(&mut request_body);
|
||||
kigi_sampling_types::patch_reasoning_effort(&mut request_body, request.reasoning_effort);
|
||||
if self.defaults.openai_codex {
|
||||
kigi_sampling_types::adapt_body_for_codex_backend(&mut request_body);
|
||||
}
|
||||
// Fresh per attempt so signals never leak across retries; `None`
|
||||
// (check disabled) sends no header and does no peek work per event.
|
||||
let doom_loop = self
|
||||
|
||||
Reference in New Issue
Block a user