From faca0398df44570c3832808e8b0cda7b7921a007 Mon Sep 17 00:00:00 2001 From: Vaibhav Shinde Date: Fri, 13 Feb 2026 15:31:15 +0530 Subject: [PATCH 1/6] fix: run workers-ai models without api key also updated the example to use the config properly --- examples/tanstack-ai/worker/index.ts | 5 ++--- packages/tanstack-ai/src/utils/create-fetcher.ts | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/tanstack-ai/worker/index.ts b/examples/tanstack-ai/worker/index.ts index 454ae4efc..39f85bf1f 100644 --- a/examples/tanstack-ai/worker/index.ts +++ b/examples/tanstack-ai/worker/index.ts @@ -155,13 +155,12 @@ function workersAiGatewayConfig(creds: RequestCredentials) { if (creds.useBinding) { return { binding: env.AI.gateway(resolveGatewayId(creds)), - apiKey: env.CLOUDFLARE_API_TOKEN, }; } if (creds.cloudflare) { - return { ...gwRestConfig(creds), apiKey: creds.cloudflare.apiToken }; + return gwRestConfig(creds); } - return { binding: env.AI.gateway(resolveGatewayId(creds)), apiKey: env.CLOUDFLARE_API_TOKEN }; + return { binding: env.AI.gateway(resolveGatewayId(creds)) }; } // --------------------------------------------------------------------------- diff --git a/packages/tanstack-ai/src/utils/create-fetcher.ts b/packages/tanstack-ai/src/utils/create-fetcher.ts index b5fb9baf9..2669a2c48 100644 --- a/packages/tanstack-ai/src/utils/create-fetcher.ts +++ b/packages/tanstack-ai/src/utils/create-fetcher.ts @@ -233,7 +233,7 @@ export function createGatewayFetch( }; if (provider === "workers-ai") { - request.endpoint = query.model as string; + request.endpoint = `run/${query.model}`; delete query.model; delete query.instructions; } From 2d200b9eef2e6ceb6d6cc37377347f3cca68092e Mon Sep 17 00:00:00 2001 From: Vaibhav Shinde Date: Fri, 13 Feb 2026 15:43:30 +0530 Subject: [PATCH 2/6] fix tests --- packages/tanstack-ai/test/gateway-fetch.test.ts | 2 +- packages/tanstack-ai/test/gateway-urls.test.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/tanstack-ai/test/gateway-fetch.test.ts b/packages/tanstack-ai/test/gateway-fetch.test.ts index 95b87cabd..c1835427e 100644 --- a/packages/tanstack-ai/test/gateway-fetch.test.ts +++ b/packages/tanstack-ai/test/gateway-fetch.test.ts @@ -333,7 +333,7 @@ describe("createGatewayFetch", () => { const request = mockBinding.run.mock.calls[0]![0]; expect(request.provider).toBe("workers-ai"); - expect(request.endpoint).toBe("@cf/meta/llama-3.3-70b-instruct-fp8-fast"); + expect(request.endpoint).toBe("run/@cf/meta/llama-3.3-70b-instruct-fp8-fast"); expect(request.query.model).toBeUndefined(); expect(request.query.messages).toEqual([{ role: "user", content: "Hello" }]); }); diff --git a/packages/tanstack-ai/test/gateway-urls.test.ts b/packages/tanstack-ai/test/gateway-urls.test.ts index 4bea05623..ebaa1595f 100644 --- a/packages/tanstack-ai/test/gateway-urls.test.ts +++ b/packages/tanstack-ai/test/gateway-urls.test.ts @@ -61,7 +61,7 @@ describe("Workers AI gateway URL verification", () => { const body = JSON.parse((init as any).body as string); expect(body.provider).toBe("workers-ai"); // createGatewayFetch moves model from query to endpoint for workers-ai - expect(body.endpoint).toBe("@cf/stabilityai/stable-diffusion-xl-base-1.0"); + expect(body.endpoint).toBe("run/@cf/stabilityai/stable-diffusion-xl-base-1.0"); expect(body.query.prompt).toBe("test prompt"); }); @@ -89,7 +89,7 @@ describe("Workers AI gateway URL verification", () => { const body = JSON.parse((init as any).body as string); expect(body.provider).toBe("workers-ai"); - expect(body.endpoint).toBe("@cf/openai/whisper"); + expect(body.endpoint).toBe("run/@cf/openai/whisper"); }); it("TTS adapter sends model name in body and hits gateway URL", async () => { @@ -107,7 +107,7 @@ describe("Workers AI gateway URL verification", () => { const body = JSON.parse((init as any).body as string); expect(body.provider).toBe("workers-ai"); - expect(body.endpoint).toBe("@cf/deepgram/aura-1"); + expect(body.endpoint).toBe("run/@cf/deepgram/aura-1"); expect(body.query.text).toBe("Hello world"); }); @@ -137,7 +137,7 @@ describe("Workers AI gateway URL verification", () => { const body = JSON.parse((init as any).body as string); expect(body.provider).toBe("workers-ai"); - expect(body.endpoint).toBe("@cf/facebook/bart-large-cnn"); + expect(body.endpoint).toBe("run/@cf/facebook/bart-large-cnn"); expect(body.query.input_text).toBe("A long article..."); }); From 40e53c851cd0c1cc80d0c44b1146ef564da782bc Mon Sep 17 00:00:00 2001 From: Vaibhav Shinde Date: Tue, 17 Feb 2026 11:46:06 +0530 Subject: [PATCH 3/6] add changeset --- .changeset/plenty-cooks-hide.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/plenty-cooks-hide.md diff --git a/.changeset/plenty-cooks-hide.md b/.changeset/plenty-cooks-hide.md new file mode 100644 index 000000000..8438a8445 --- /dev/null +++ b/.changeset/plenty-cooks-hide.md @@ -0,0 +1,5 @@ +--- +"@cloudflare/tanstack-ai": patch +--- + +Workers AI adapter for Tanstack AI doesn't require API Key From b769133c7a3e07e9036bddd542d333d350437e69 Mon Sep 17 00:00:00 2001 From: Vaibhav Shinde Date: Mon, 23 Feb 2026 13:36:24 +0530 Subject: [PATCH 4/6] fix: prepend `run/` only after checking if it doesn't start with it --- packages/tanstack-ai/src/utils/create-fetcher.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/tanstack-ai/src/utils/create-fetcher.ts b/packages/tanstack-ai/src/utils/create-fetcher.ts index 2669a2c48..db53178c8 100644 --- a/packages/tanstack-ai/src/utils/create-fetcher.ts +++ b/packages/tanstack-ai/src/utils/create-fetcher.ts @@ -233,7 +233,9 @@ export function createGatewayFetch( }; if (provider === "workers-ai") { - request.endpoint = `run/${query.model}`; + if (!request.endpoint.startsWith("run/")) { + request.endpoint = `run/${query.model}`; + } delete query.model; delete query.instructions; } From 65cfb79140b48ded24227599a15a8c68cc3e01b0 Mon Sep 17 00:00:00 2001 From: Vaibhav Shinde Date: Mon, 23 Feb 2026 14:01:53 +0530 Subject: [PATCH 5/6] add tests for checking if run/ is prepended --- .../tanstack-ai/test/gateway-fetch.test.ts | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/packages/tanstack-ai/test/gateway-fetch.test.ts b/packages/tanstack-ai/test/gateway-fetch.test.ts index c1835427e..32d789200 100644 --- a/packages/tanstack-ai/test/gateway-fetch.test.ts +++ b/packages/tanstack-ai/test/gateway-fetch.test.ts @@ -358,6 +358,44 @@ describe("createGatewayFetch", () => { expect(request.query.instructions).toBeUndefined(); expect(request.query.messages).toEqual([]); }); + + it("should preserve endpoint when it already starts with run/", async () => { + const config: AiGatewayAdapterConfig = { + binding: mockBinding, + apiKey: "test-key", + }; + const fetcher = createGatewayFetch("workers-ai", config); + + await fetcher("https://gateway.ai.cloudflare.com/v1/run/@cf/meta/llama-3.3-70b-instruct-fp8-fast", { + method: "POST", + body: JSON.stringify({ + model: "run/@cf/meta/llama-3.3-70b-instruct-fp8-fast", + messages: [{ role: "user", content: "Hello" }], + }), + }); + + const request = mockBinding.run.mock.calls[0]![0]; + expect(request.endpoint).toBe("run/@cf/meta/llama-3.3-70b-instruct-fp8-fast"); + }); + + it("should prepend run/ when endpoint does not start with run/", async () => { + const config: AiGatewayAdapterConfig = { + binding: mockBinding, + apiKey: "test-key", + }; + const fetcher = createGatewayFetch("workers-ai", config); + + await fetcher("https://api.openai.com/v1/chat/completions", { + method: "POST", + body: JSON.stringify({ + model: "@cf/meta/llama-3.3-70b-instruct-fp8-fast", + messages: [{ role: "user", content: "Hello" }], + }), + }); + + const request = mockBinding.run.mock.calls[0]![0]; + expect(request.endpoint).toBe("run/@cf/meta/llama-3.3-70b-instruct-fp8-fast"); + }); }); describe("endpoint extraction", () => { From e25d21581c2684e8fde4016a12bc94b9c720c7f9 Mon Sep 17 00:00:00 2001 From: Sunil Pai Date: Wed, 18 Mar 2026 21:08:51 +0000 Subject: [PATCH 6/6] Fix workers-ai endpoint handling and tests Update changelog to note adding `run/` prefix to workers-ai gateway endpoint and making API key optional for gateway bindings. Adjust test: rename to clarify it should not double-prefix `run/`, ensure model is sent without the `run/` prefix, and assert that `request.query.model` is undefined. --- .changeset/plenty-cooks-hide.md | 2 +- .../tanstack-ai/test/gateway-fetch.test.ts | 20 ++++++----- .../workers-ai-provider/test/utils.test.ts | 36 +++++++++++++++---- 3 files changed, 43 insertions(+), 15 deletions(-) diff --git a/.changeset/plenty-cooks-hide.md b/.changeset/plenty-cooks-hide.md index 8438a8445..908478e72 100644 --- a/.changeset/plenty-cooks-hide.md +++ b/.changeset/plenty-cooks-hide.md @@ -2,4 +2,4 @@ "@cloudflare/tanstack-ai": patch --- -Workers AI adapter for Tanstack AI doesn't require API Key +fix: add `run/` prefix to workers-ai gateway endpoint and make API key optional for gateway bindings diff --git a/packages/tanstack-ai/test/gateway-fetch.test.ts b/packages/tanstack-ai/test/gateway-fetch.test.ts index 32d789200..96cebaff0 100644 --- a/packages/tanstack-ai/test/gateway-fetch.test.ts +++ b/packages/tanstack-ai/test/gateway-fetch.test.ts @@ -359,23 +359,27 @@ describe("createGatewayFetch", () => { expect(request.query.messages).toEqual([]); }); - it("should preserve endpoint when it already starts with run/", async () => { + it("should not double-prefix run/ when URL path already contains it", async () => { const config: AiGatewayAdapterConfig = { binding: mockBinding, apiKey: "test-key", }; const fetcher = createGatewayFetch("workers-ai", config); - await fetcher("https://gateway.ai.cloudflare.com/v1/run/@cf/meta/llama-3.3-70b-instruct-fp8-fast", { - method: "POST", - body: JSON.stringify({ - model: "run/@cf/meta/llama-3.3-70b-instruct-fp8-fast", - messages: [{ role: "user", content: "Hello" }], - }), - }); + await fetcher( + "https://gateway.ai.cloudflare.com/v1/run/@cf/meta/llama-3.3-70b-instruct-fp8-fast", + { + method: "POST", + body: JSON.stringify({ + model: "@cf/meta/llama-3.3-70b-instruct-fp8-fast", + messages: [{ role: "user", content: "Hello" }], + }), + }, + ); const request = mockBinding.run.mock.calls[0]![0]; expect(request.endpoint).toBe("run/@cf/meta/llama-3.3-70b-instruct-fp8-fast"); + expect(request.query.model).toBeUndefined(); }); it("should prepend run/ when endpoint does not start with run/", async () => { diff --git a/packages/workers-ai-provider/test/utils.test.ts b/packages/workers-ai-provider/test/utils.test.ts index 40b9932ab..efa5f5727 100644 --- a/packages/workers-ai-provider/test/utils.test.ts +++ b/packages/workers-ai-provider/test/utils.test.ts @@ -454,7 +454,11 @@ describe("createRun", () => { vi.mocked(globalThis.fetch).mockResolvedValue(mockResponse as unknown as Response); const run = createRun({ accountId: "test-account", apiKey: "test-key" }); - await run("@cf/meta/llama-3.1-8b-instruct" as any, { prompt: "Hi" }, { gateway: { id: "my-gateway" } }); + await run( + "@cf/meta/llama-3.1-8b-instruct" as any, + { prompt: "Hi" }, + { gateway: { id: "my-gateway" } }, + ); expect(globalThis.fetch).toHaveBeenCalledWith( "https://gateway.ai.cloudflare.com/v1/test-account/my-gateway/workers-ai/run/@cf/meta/llama-3.1-8b-instruct", @@ -494,7 +498,11 @@ describe("createRun", () => { vi.mocked(globalThis.fetch).mockResolvedValue(mockResponse as unknown as Response); const run = createRun({ accountId: "test-account", apiKey: "test-key" }); - await run("run/@cf/meta/llama-3.1-8b-instruct" as any, { prompt: "Hi" }, { gateway: { id: "my-gateway" } }); + await run( + "run/@cf/meta/llama-3.1-8b-instruct" as any, + { prompt: "Hi" }, + { gateway: { id: "my-gateway" } }, + ); expect(globalThis.fetch).toHaveBeenCalledWith( "https://gateway.ai.cloudflare.com/v1/test-account/my-gateway/workers-ai/run/@cf/meta/llama-3.1-8b-instruct", @@ -511,7 +519,11 @@ describe("createRun", () => { vi.mocked(globalThis.fetch).mockResolvedValue(mockResponse as unknown as Response); const run = createRun({ accountId: "test-account", apiKey: "test-key" }); - await run("@cf/meta/llama-3.1-8b-instruct" as any, { prompt: "Hi" }, { gateway: { id: "my-gateway", skipCache: true } }); + await run( + "@cf/meta/llama-3.1-8b-instruct" as any, + { prompt: "Hi" }, + { gateway: { id: "my-gateway", skipCache: true } }, + ); expect(globalThis.fetch).toHaveBeenCalledWith( expect.any(String), @@ -532,7 +544,11 @@ describe("createRun", () => { vi.mocked(globalThis.fetch).mockResolvedValue(mockResponse as unknown as Response); const run = createRun({ accountId: "test-account", apiKey: "test-key" }); - await run("@cf/meta/llama-3.1-8b-instruct" as any, { prompt: "Hi" }, { gateway: { id: "my-gateway", cacheTtl: 3600 } }); + await run( + "@cf/meta/llama-3.1-8b-instruct" as any, + { prompt: "Hi" }, + { gateway: { id: "my-gateway", cacheTtl: 3600 } }, + ); expect(globalThis.fetch).toHaveBeenCalledWith( expect.any(String), @@ -553,7 +569,11 @@ describe("createRun", () => { vi.mocked(globalThis.fetch).mockResolvedValue(mockResponse as unknown as Response); const run = createRun({ accountId: "test-account", apiKey: "test-key" }); - await run("@cf/meta/llama-3.1-8b-instruct" as any, { prompt: "Hi" }, { gateway: { id: "my-gateway", cacheKey: "my-custom-key" } }); + await run( + "@cf/meta/llama-3.1-8b-instruct" as any, + { prompt: "Hi" }, + { gateway: { id: "my-gateway", cacheKey: "my-custom-key" } }, + ); expect(globalThis.fetch).toHaveBeenCalledWith( expect.any(String), @@ -574,7 +594,11 @@ describe("createRun", () => { vi.mocked(globalThis.fetch).mockResolvedValue(mockResponse as unknown as Response); const run = createRun({ accountId: "test-account", apiKey: "test-key" }); - await run("@cf/meta/llama-3.1-8b-instruct" as any, { prompt: "Hi" }, { gateway: { id: "my-gateway", metadata: { user: "test", session: 123 } } }); + await run( + "@cf/meta/llama-3.1-8b-instruct" as any, + { prompt: "Hi" }, + { gateway: { id: "my-gateway", metadata: { user: "test", session: 123 } } }, + ); expect(globalThis.fetch).toHaveBeenCalledWith( expect.any(String),