From 7baf293ccbcb76da0a1cbc981e083a3d34eda19f Mon Sep 17 00:00:00 2001 From: decolua Date: Sun, 21 Jun 2026 16:46:21 +0700 Subject: [PATCH] fix(cloudflare-ai): flatten content-part arrays to string to avoid oneOf 400 (#1926) Workers AI rejects OpenAI content-part array shape; flatten text parts to a plain string per message before sending. Co-authored-by: Cursor --- open-sse/translator/concerns/paramSupport.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/open-sse/translator/concerns/paramSupport.js b/open-sse/translator/concerns/paramSupport.js index 3b8fc9a9..bf344c22 100644 --- a/open-sse/translator/concerns/paramSupport.js +++ b/open-sse/translator/concerns/paramSupport.js @@ -10,6 +10,8 @@ const STRIP_RULES = [ { provider: "github", match: /gpt-5\.4/i, drop: ["temperature"] }, // GitHub Copilot Claude (except opus/sonnet 4.6): thinking + reasoning_effort rejected. #713 { provider: "github", match: (m) => /claude/i.test(m) && !/claude.*(opus|sonnet).*4\.6/i.test(m), drop: ["thinking", "reasoning_effort"] }, + // Cloudflare Workers AI: content must be plain string, rejects OpenAI content-part array (#1926) + { provider: "cloudflare-ai", flattenContent: true }, ]; // Test a rule's match (regex or predicate) against the model id. @@ -26,6 +28,16 @@ export function stripUnsupportedParams(provider, model, body) { for (const key of rule.drop) { if (body[key] !== undefined) delete body[key]; } + // CF Workers AI oneOf root schema only accepts content as plain string (#1926) + if (rule.flattenContent && Array.isArray(body.messages)) { + for (const msg of body.messages) { + if (msg && Array.isArray(msg.content)) { + msg.content = msg.content + .map(b => (b?.type === "text" && typeof b.text === "string") ? b.text : "") + .join(""); + } + } + } } return body; }