diff --git a/.changeset/fair-moonshotai.md b/.changeset/fair-moonshotai.md new file mode 100644 index 0000000000..67c0917aaf --- /dev/null +++ b/.changeset/fair-moonshotai.md @@ -0,0 +1,5 @@ +--- +"workers-ai-provider": patch +--- + +Support Moonshot AI unified billing catalog slugs such as `moonshotai/kimi-k3`. diff --git a/packages/gateway-core/src/gateway-providers.ts b/packages/gateway-core/src/gateway-providers.ts index ac692df4fa..0b268db6a2 100644 --- a/packages/gateway-core/src/gateway-providers.ts +++ b/packages/gateway-core/src/gateway-providers.ts @@ -240,6 +240,17 @@ export const GATEWAY_PROVIDERS: GatewayProviderInfo[] = [ billing: "unified", authHeaders: ["authorization"], }, + { + // Moonshot AI / Kimi is served by the unified billing run catalog using + // the OpenAI-compatible response format. It has no native gateway path. + resolverKey: "moonshotai", + gatewayProviderId: "moonshotai", + wireFormat: "openai", + runCatalog: true, + gatewayPath: false, + billing: "unified", + authHeaders: ["authorization"], + }, { resolverKey: "google-vertex", gatewayProviderId: "google-vertex-ai", diff --git a/packages/gateway-core/test/gateway-providers.test.ts b/packages/gateway-core/test/gateway-providers.test.ts index c5ff7cf0d8..ecbc739ff5 100644 --- a/packages/gateway-core/test/gateway-providers.test.ts +++ b/packages/gateway-core/test/gateway-providers.test.ts @@ -22,6 +22,16 @@ describe("findProviderBySlug", () => { expect(findProviderBySlug("azure")?.resolverKey).toBe("azure-openai"); }); + it("resolves the Moonshot AI unified catalog slug", () => { + expect(findProviderBySlug("moonshotai")).toMatchObject({ + gatewayProviderId: "moonshotai", + wireFormat: "openai", + runCatalog: true, + gatewayPath: false, + billing: "unified", + }); + }); + it("maps google ⇒ google-ai-studio gateway id, anthropic native run wire", () => { expect(findProviderBySlug("google")?.gatewayProviderId).toBe("google-ai-studio"); const anthropic = findProviderBySlug("anthropic"); diff --git a/packages/workers-ai-provider/test/gateway-delegate.test.ts b/packages/workers-ai-provider/test/gateway-delegate.test.ts index 038cf11a33..09c1496eed 100644 --- a/packages/workers-ai-provider/test/gateway-delegate.test.ts +++ b/packages/workers-ai-provider/test/gateway-delegate.test.ts @@ -342,7 +342,7 @@ describe("createGatewayDelegate", () => { ); }); - it("builds alibaba + minimax on the run path with the openai plugin", () => { + it("builds unified run-only providers with the openai plugin", () => { const { binding } = makeBinding(); const wai = createGatewayDelegate({ binding, @@ -353,6 +353,7 @@ describe("createGatewayDelegate", () => { // so a single openai plugin is enough. expect(wai("alibaba/qwen3-max").modelId).toBe("qwen3-max"); expect(wai("minimax/m3").modelId).toBe("m3"); + expect(wai("moonshotai/kimi-k3").modelId).toBe("kimi-k3"); }); it("rejects gateway-path use of a run-only provider with a clear error", () => { @@ -362,10 +363,13 @@ describe("createGatewayDelegate", () => { gateway: "default", providers: [capturePlugin("openai").plugin], }); - // alibaba/minimax have no gateway path — caching, server fallback, and + // run-only providers have no gateway path — caching, server fallback, and // transport:"gateway" must fail fast at build time, not upstream. expect(() => wai("alibaba/qwen3-max", { transport: "gateway" })).toThrow(/no gateway path/); expect(() => wai("alibaba/qwen3-max", { cacheTtl: 60 })).toThrow(/no gateway path/); + expect(() => wai("moonshotai/kimi-k3", { transport: "gateway" })).toThrow( + /no gateway path/, + ); expect(() => wai("minimax/m3", { fallback: { mode: "server", models: ["minimax/m2.7"] } }), ).toThrow(/no gateway path/); diff --git a/packages/workers-ai-provider/test/gateway-providers.test.ts b/packages/workers-ai-provider/test/gateway-providers.test.ts index 07ac2646e0..af5dafd24d 100644 --- a/packages/workers-ai-provider/test/gateway-providers.test.ts +++ b/packages/workers-ai-provider/test/gateway-providers.test.ts @@ -205,7 +205,7 @@ describe("gateway provider registry", () => { .map((p) => p.resolverKey) .sort(); // The headline directory set (openai/anthropic/google/xai/groq), the - // run-only unified chat providers alibaba + minimax, and deepseek — the one + // run-only unified chat providers alibaba + minimax + moonshotai, and deepseek — the one // OpenAI-wire long-tail provider actually on the unified `env.AI.run` catalog // (#596). The rest of the long tail (mistral/perplexity/cerebras/openrouter/ // fireworks) is BYOK gateway-path only, verified by the e2e run-path probe. @@ -216,13 +216,14 @@ describe("gateway provider registry", () => { "google", "groq", "minimax", + "moonshotai", "openai", "xai", ]); }); - it("adds alibaba + minimax as run-only openai-wire chat providers", () => { - for (const slug of ["alibaba", "minimax"]) { + it("adds run-only openai-wire chat providers", () => { + for (const slug of ["alibaba", "minimax", "moonshotai"]) { const info = findProviderBySlug(slug); expect(info, slug).toMatchObject({ runCatalog: true,