From 5f0c1382abcecdfbf72311f12dc6e7bcf1b5d320 Mon Sep 17 00:00:00 2001 From: Diego Rodrigues de Sa e Souza Date: Mon, 22 Jun 2026 08:49:18 -0300 Subject: [PATCH] fix(translator): normalize `developer` role to `system` for OpenAI-format providers `filterToOpenAIFormat` rewrites the OpenAI Responses-style `developer` role to `system` before downstream dispatch so OpenAI-compatible providers that reject the newer role keep working on passthrough routes. Co-authored-by: Tran Hoang Nguyen Inspired-by: https://github.com/decolua/9router/pull/1011 --- open-sse/translator/helpers/openaiHelper.ts | 5 +++ .../openai-developer-role-normalize.test.ts | 38 +++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 tests/unit/openai-developer-role-normalize.test.ts diff --git a/open-sse/translator/helpers/openaiHelper.ts b/open-sse/translator/helpers/openaiHelper.ts index 502d309fe3..375364c725 100644 --- a/open-sse/translator/helpers/openaiHelper.ts +++ b/open-sse/translator/helpers/openaiHelper.ts @@ -35,6 +35,11 @@ export function filterToOpenAIFormat(body) { if (!body.messages || !Array.isArray(body.messages)) return body; body.messages = body.messages.map((msg) => { + // Normalize OpenAI Responses-style `developer` role to `system` — many + // OpenAI-compatible providers reject `developer` (ported from + // decolua/9router#1011). + if (msg.role === "developer") msg = { ...msg, role: "system" }; + // Keep tool messages as-is (OpenAI format) if (msg.role === "tool") return msg; diff --git a/tests/unit/openai-developer-role-normalize.test.ts b/tests/unit/openai-developer-role-normalize.test.ts new file mode 100644 index 0000000000..8d6d5190ee --- /dev/null +++ b/tests/unit/openai-developer-role-normalize.test.ts @@ -0,0 +1,38 @@ +import { test } from "node:test"; +import assert from "node:assert/strict"; + +import { filterToOpenAIFormat } from "../../open-sse/translator/helpers/openaiHelper.ts"; + +// Ported from upstream decolua/9router#1011 — many OpenAI-compatible providers +// reject the `developer` role (introduced by OpenAI Responses API). Normalize to +// `system` so passthrough requests keep working downstream. +test("filterToOpenAIFormat normalizes developer role to system", () => { + const body = { + messages: [ + { role: "developer", content: "You are helpful" }, + { role: "user", content: "Hi" }, + ], + }; + + const out = filterToOpenAIFormat(body); + + assert.equal(out.messages[0].role, "system"); + assert.equal(out.messages[0].content, "You are helpful"); + assert.equal(out.messages[1].role, "user"); +}); + +test("filterToOpenAIFormat normalizes developer role with array content", () => { + const body = { + messages: [ + { + role: "developer", + content: [{ type: "text", text: "Be concise" }], + }, + ], + }; + + const out = filterToOpenAIFormat(body); + + assert.equal(out.messages[0].role, "system"); + assert.deepEqual(out.messages[0].content, [{ type: "text", text: "Be concise" }]); +});