There are two ways to reach Workers AI. Inside a Worker, use the AI binding through the AI SDK provider. From anywhere else, use the OpenAI-compatible REST endpoint.
In a Worker, with the AI SDK
npm i ai workers-ai-provider @gistui/catalogyarn add ai workers-ai-provider @gistui/catalogpnpm add ai workers-ai-provider @gistui/catalogbun add ai workers-ai-provider @gistui/catalog{
"ai": { "binding": "AI" }
}import { prompt } from "@gistui/catalog";
import { streamText } from "ai";
import { createWorkersAI } from "workers-ai-provider";
export default {
async fetch(req: Request, env: Env): Promise<Response> {
const { messages } = await req.json<{ messages: { role: "user" | "assistant"; content: string }[] }>();
const workersai = createWorkersAI({ binding: env.AI });
const result = streamText({
model: workersai("@cf/openai/gpt-oss-120b"),
system: prompt().text,
messages,
});
return result.toTextStreamResponse();
},
};@gistui/catalog, @gistui/core and @gistui/server have no Node-only dependencies, so they run in the Workers runtime as they are.
From anywhere, with the OpenAI-compatible endpoint
import { prompt } from "@gistui/catalog";
import { textDeltas, toReadable } from "@gistui/server";
const res = await fetch(`https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/ai/v1/chat/completions`, {
method: "POST",
headers: { Authorization: `Bearer ${CLOUDFLARE_API_TOKEN}`, "Content-Type": "application/json" },
body: JSON.stringify({
model: "@cf/openai/gpt-oss-120b",
stream: true,
messages: [{ role: "system", content: prompt().text }, ...messages],
}),
});
if (!res.ok) return new Response(await res.text(), { status: res.status });
return new Response(toReadable(textDeltas(res, "openai")));Render it
The browser side is the same as everywhere else: <GistUI library={ui} stream={res.body} />. See Frameworks.