diff --git a/open-sse/translator/request/openai-responses.js b/open-sse/translator/request/openai-responses.js index 98c516cd..23603a71 100644 --- a/open-sse/translator/request/openai-responses.js +++ b/open-sse/translator/request/openai-responses.js @@ -221,13 +221,14 @@ export function openaiToOpenAIResponsesRequest(model, body, stream, credentials) const messages = body.messages || []; for (const msg of messages) { - if (msg.role === ROLE.SYSTEM) { - // Use first system message as instructions + if (msg.role === ROLE.SYSTEM || msg.role === ROLE.DEVELOPER) { + // Use the first instruction-bearing message as instructions. + // OpenAI recommends role="developer" for GPT-5/Codex as the system-level prompt. if (!hasSystemMessage) { result.instructions = typeof msg.content === "string" ? msg.content : ""; hasSystemMessage = true; } - continue; // Skip system messages in input + continue; // Skip instruction messages in input } // Convert user/assistant messages to input items diff --git a/tests/translator/bugs-codexCli-responses.test.js b/tests/translator/bugs-codexCli-responses.test.js index 6f947833..c3401341 100644 --- a/tests/translator/bugs-codexCli-responses.test.js +++ b/tests/translator/bugs-codexCli-responses.test.js @@ -46,6 +46,20 @@ describe("Codex CLI Responses → OpenAI", () => { }); describe("OpenAI → Codex Responses (reverse)", () => { + it("maps developer messages to Responses API instructions", () => { + const out = O2R({ + messages: [ + { role: "developer", content: "Follow the project rules." }, + { role: "user", content: "Hello" }, + ], + }); + + expect(out.instructions).toBe("Follow the project rules."); + expect(out.input).toEqual([ + { type: "message", role: "user", content: [{ type: "input_text", text: "Hello" }] }, + ]); + }); + // openai-responses.js:13 — clampCallId NOT applied on Responses→Chat; but here Chat→Responses must clamp it("call_id longer than 64 chars is clamped", () => { const longId = "call_" + "x".repeat(80);