From 8c3b2b7d02fafaee4dac24141e3e3fa198bfe4e8 Mon Sep 17 00:00:00 2001 From: diegosouzapw Date: Tue, 28 Apr 2026 13:36:57 -0300 Subject: [PATCH] fix: preserve previous_response_id and conversation_id fields on empty input array (#1729) --- open-sse/executors/codex.ts | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/open-sse/executors/codex.ts b/open-sse/executors/codex.ts index 720930e4d1..f3b795103f 100644 --- a/open-sse/executors/codex.ts +++ b/open-sse/executors/codex.ts @@ -362,12 +362,16 @@ function convertSystemToDeveloperRole(body: Record): void { * 4. Always deletes previous_response_id (endpoint doesn't persist responses) */ function stripStoredItemReferences(body: Record): void { - // Always strip previous_response_id — the /codex/responses endpoint does not - // persist responses, so any reference to a previous response would cause a 404. - // The official Codex CLI sets previous_response_id to None for HTTP transport. - // Ref: codex-rs codex-api/src/common.rs:187 — previous_response_id: None - // Ref: CLIProxyAPI codex_executor.go:115 — sjson.DeleteBytes(body, "previous_response_id") - delete body.previous_response_id; + const hasInput = Array.isArray(body.input) && body.input.length > 0; + + // Always strip previous_response_id IF we have input. + // The /codex/responses endpoint does not persist responses, so any reference + // to a previous response would cause a 404. However, if input is missing (e.g. Cursor + // trying to continue generation), stripping it leaves the payload empty causing a 400 Schema error. + // We leave it intact so Codex returns 404, which correctly triggers Cursor's fallback to resend history. + if (hasInput) { + delete body.previous_response_id; + } if (!Array.isArray(body.input)) return; @@ -1144,9 +1148,13 @@ export class CodexExecutor extends BaseExecutor { // Delete session_id and conversation_id from the body. // These are often injected by OmniRoute's fallback logic for store=true, - // but the upstream Codex API strictly rejects them as unsupported parameters. + // but the upstream Codex API strictly rejects them as unsupported parameters + // UNLESS the request lacks input entirely (where they are required to avoid a 400 Schema Error). delete body.session_id; - delete body.conversation_id; + const hasInput = Array.isArray(body.input) && body.input.length > 0; + if (hasInput) { + delete body.conversation_id; + } if (nativeCodexPassthrough) { return body;