From e97a7027932ae97ebc206032b4b0e3397bd026df Mon Sep 17 00:00:00 2001 From: mikemikimike <13286568797@163.com> Date: Sun, 23 Aug 2026 00:29:53 +0800 Subject: [PATCH 1/2] fix(workers-ai-provider): route gpt-5.6 through responses --- .changeset/fix-gpt-56-responses.md | 5 ++++ packages/workers-ai-provider/src/openai.ts | 10 ++++--- .../workers-ai-provider/test/openai.test.ts | 26 +++++++++++++++++++ 3 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 .changeset/fix-gpt-56-responses.md create mode 100644 packages/workers-ai-provider/test/openai.test.ts diff --git a/.changeset/fix-gpt-56-responses.md b/.changeset/fix-gpt-56-responses.md new file mode 100644 index 0000000000..bc55888035 --- /dev/null +++ b/.changeset/fix-gpt-56-responses.md @@ -0,0 +1,5 @@ +--- +"workers-ai-provider": patch +--- + +Route OpenAI gpt-5.6 models through the Responses API. diff --git a/packages/workers-ai-provider/src/openai.ts b/packages/workers-ai-provider/src/openai.ts index 7312f64e68..14e326d99b 100644 --- a/packages/workers-ai-provider/src/openai.ts +++ b/packages/workers-ai-provider/src/openai.ts @@ -11,9 +11,9 @@ import type { ProviderPlugin } from "./gateway-delegate"; * * Requires `@ai-sdk/openai` (an optional peer dependency — install it yourself). * - * Uses `.chat()` (Chat Completions) deliberately: the bare `openai()` call - * (AI SDK v6+) defaults to the Responses API, which the AI Gateway run catalog - * does not serve. + * Uses `.chat()` (Chat Completions) for the catalog's chat-completions models. + * The gpt-5.6 class only accepts the Responses API, so those models use + * `.responses()` instead. */ export const openai: ProviderPlugin = { wireFormat: "openai", @@ -22,5 +22,7 @@ export const openai: ProviderPlugin = { // and the delegate strips the Authorization header on the gateway path. // baseURL (set by the registry for non-OpenAI openai-wire providers) makes // the generated URL host-strip to the right gateway-native endpoint. - createOpenAI({ apiKey: "unused", fetch, ...(baseURL ? { baseURL } : {}) }).chat(modelId), + createOpenAI({ apiKey: "unused", fetch, ...(baseURL ? { baseURL } : {}) })[ + /^gpt-5\.6(?:-|$)/.test(modelId) ? "responses" : "chat" + ](modelId), }; diff --git a/packages/workers-ai-provider/test/openai.test.ts b/packages/workers-ai-provider/test/openai.test.ts new file mode 100644 index 0000000000..35d180443e --- /dev/null +++ b/packages/workers-ai-provider/test/openai.test.ts @@ -0,0 +1,26 @@ +import { describe, expect, it, vi } from "vitest"; +import { openai } from "../src/openai"; + +async function requestedUrl(modelId: string) { + const fetch = vi.fn(async (input: RequestInfo | URL) => { + throw new Error(String(input)); + }); + + const model = openai.create({ + modelId, + fetch: fetch as typeof globalThis.fetch, + }); + + await expect(model.doGenerate({ prompt: [] } as never)).rejects.toThrow(); + return String(fetch.mock.calls[0]?.[0]); +} + +describe("openai provider plugin", () => { + it("uses the Responses API for gpt-5.6 models", async () => { + expect(await requestedUrl("gpt-5.6-luna")).toContain("/responses"); + }); + + it("keeps Chat Completions for ordinary OpenAI models", async () => { + expect(await requestedUrl("gpt-5.4-mini")).toContain("/chat/completions"); + }); +}); From 570dc20583cfc9ab979b409c0b31af98a9a7127e Mon Sep 17 00:00:00 2001 From: mikemikimike <13286568797@163.com> Date: Sun, 23 Aug 2026 00:37:11 +0800 Subject: [PATCH 2/2] test(workers-ai-provider): cover gpt-5.6 routing boundaries --- .../workers-ai-provider/test/openai.test.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/workers-ai-provider/test/openai.test.ts b/packages/workers-ai-provider/test/openai.test.ts index 35d180443e..9ee9c48367 100644 --- a/packages/workers-ai-provider/test/openai.test.ts +++ b/packages/workers-ai-provider/test/openai.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it, vi } from "vitest"; import { openai } from "../src/openai"; -async function requestedUrl(modelId: string) { +async function requestedUrl(modelId: string, baseURL?: string) { const fetch = vi.fn(async (input: RequestInfo | URL) => { throw new Error(String(input)); }); @@ -9,6 +9,7 @@ async function requestedUrl(modelId: string) { const model = openai.create({ modelId, fetch: fetch as typeof globalThis.fetch, + ...(baseURL ? { baseURL } : {}), }); await expect(model.doGenerate({ prompt: [] } as never)).rejects.toThrow(); @@ -17,10 +18,20 @@ async function requestedUrl(modelId: string) { describe("openai provider plugin", () => { it("uses the Responses API for gpt-5.6 models", async () => { - expect(await requestedUrl("gpt-5.6-luna")).toContain("/responses"); + for (const modelId of ["gpt-5.6", "gpt-5.6-luna", "gpt-5.6-mini"]) { + expect(await requestedUrl(modelId)).toContain("/responses"); + } }); it("keeps Chat Completions for ordinary OpenAI models", async () => { - expect(await requestedUrl("gpt-5.4-mini")).toContain("/chat/completions"); + for (const modelId of ["gpt-5.4-mini", "gpt-5.5"]) { + expect(await requestedUrl(modelId)).toContain("/chat/completions"); + } + }); + + it("preserves the Responses endpoint when a Gateway base URL is configured", async () => { + expect(await requestedUrl("gpt-5.6-luna", "https://gateway.example/v1")).toBe( + "https://gateway.example/v1/responses", + ); }); });