AI
env.AI lets your app call OpenAI and Anthropic chat models, plus a set of built-in models. By default calls are proxied through Cloudrizz and billed to your plan's AI credits — no API keys to manage. Set your own provider key on the app and calls go direct, billed by the provider.
Chat completions
env.AI.openai and env.AI.anthropic work out of the box. The native env.AI.run model runner is an attachable resource — ask your assistant to enable it (it runs manage_resource with action: attach) and it appears on your next deploy.The provider request body is passed straight through, so you use each provider's native shape — including the model field:
// api/ask.js
export default {
async fetch(request, env, ctx) {
const { question } = await request.json();
// OpenAI
const openai = await env.AI.openai.chat({
model: "gpt-5",
messages: [{ role: "user", content: question }],
});
// Anthropic
const claude = await env.AI.anthropic.chat({
model: "claude-sonnet-4-6",
max_tokens: 1024,
messages: [{ role: "user", content: question }],
});
return Response.json({ openai, claude });
},
};env.AI.openai.chat(params)— OpenAI Chat Completions request body; returns the OpenAI response.env.AI.anthropic.chat(params)— Anthropic Messages request body; returns the Anthropic response.env.AI.openai.stream(params)·env.AI.anthropic.stream(params)— the streaming counterparts. Resolve to aResponsewhose body is the provider's token-by-token SSE stream (see below).env.AI.run(model, input)— the platform's native model runner, for the models it hosts.
gpt-5, gpt-5-mini, gpt-5-nano) and Anthropic (claude-opus-4-8, claude-sonnet-4-6, claude-haiku-4-5) models, plus text-embedding-3-small. With your own key (set OPENAI_API_KEY or ANTHROPIC_API_KEY) the call goes straight to the provider, so you can pass any model their API accepts.Streaming (for chat UIs)
For a live “typing” chat, use .stream(...). It resolves to a Response whose body is the provider's Server-Sent-Events stream — pipe it straight to the browser and render tokens as they arrive. Credits are still metered: Cloudrizz reads the usage from the stream and debits when it finishes, so streaming costs the same as a buffered call.
// api/chat.js — stream Claude's reply straight to the browser
export default {
async fetch(request, env, ctx) {
const { messages } = await request.json();
const ai = await env.AI.anthropic.stream({
model: "claude-sonnet-4-6",
max_tokens: 1024,
messages,
});
// ai.body is the SSE stream — hand it to the client as-is.
return new Response(ai.body, {
headers: { "content-type": "text/event-stream; charset=utf-8" },
});
},
};On the client, read it with EventSource (or fetch + a stream reader) and append each delta. OpenAI is identical via env.AI.openai.stream(...). With your own key the stream goes direct to the provider (unbilled); otherwise it streams through Cloudrizz's metered proxy.
Error) rather than mid-stream.Answer from your own data (RAG)
To make the model answer from your app's content — docs, notes, a knowledge base — pair it with env.SEARCH. Retrieve the most relevant passages by meaning, put them in the prompt, then stream the answer. That's Retrieval-Augmented Generation, and it's only a few lines:
const { matches } = await env.SEARCH.query(question, { topK: 6 });
const context = matches.map((m) => m.text).join("\n---\n");
const ai = await env.AI.anthropic.stream({
model: "claude-sonnet-4-6",
max_tokens: 1024,
messages: [{ role: "user", content: `Context:\n${context}\n\nQuestion: ${question}` }],
});
return new Response(ai.body, { headers: { "content-type": "text/event-stream" } });Managed credits vs your own key
Managed (default): with no provider key set, calls are proxied through Cloudrizz and charged against your plan's monthly AI credits. Nothing to configure.
Bring your own key: set OPENAI_API_KEY or ANTHROPIC_API_KEY as an app environment variable (via manage_app_env, action: set) and that provider's calls go directly to the vendor on your own account — Cloudrizz doesn't bill them.
Errors & credits
A failed call throws an Error with status and code fields mirroring the provider's error. When you're on managed credits and the balance is relevant, the error also carries a balance field so you can surface “out of credits” cleanly. Free-tier apps have no managed credits — bring your own key, or see Limits & quotas.