Skip to content

Pi AI

Last updated View as MarkdownAgent setup

To use Workers AI with Pi AI ↗︎, use createAI from agents/models/pi-ai. It returns Pi AI Model objects, so Workers AI models work with Pi AI's stream and complete, with Pi Durable ↗︎, and with the Pi harness. This page covers Workers AI models. For AI Gateway catalog models, fallback, gateway options, and the full reference, refer to Pi AI.

Setup

Install the Agents SDK and Pi AI. createAI needs @earendil-works/pi-ai@~1.3.0:

npm i agents @earendil-works/pi-ai

Add the AI binding to your Wrangler configuration:

{
	"ai": {
		"binding": "AI",
	},
}
[ai]
binding = "AI"

Generate text

Name a Workers AI model by its @cf/ id. The provider carries Pi AI's entry points, so nothing is registered globally:

import { createAI } from "agents/models/pi-ai";

export default {
	async fetch(request, env) {
		const ai = createAI({ binding: env.AI });

		const reply = await ai.complete(ai("@cf/zai-org/glm-4.7-flash"), {
			messages: [
				{ role: "user", content: "What is Cloudflare?", timestamp: Date.now() },
			],
		});

		// `content` holds text, thinking, and tool call parts.
		const text = reply.content
			.filter((part) => part.type === "text")
			.map((part) => part.text)
			.join("");

		return Response.json({ text });
	},
};
import { createAI } from "agents/models/pi-ai";

export default {
	async fetch(request: Request, env: Env) {
		const ai = createAI({ binding: env.AI });

		const reply = await ai.complete(ai("@cf/zai-org/glm-4.7-flash"), {
			messages: [
				{ role: "user", content: "What is Cloudflare?", timestamp: Date.now() },
			],
		});

		// `content` holds text, thinking, and tool call parts.
		const text = reply.content
			.filter((part) => part.type === "text")
			.map((part) => part.text)
			.join("");

		return Response.json({ text });
	},
};

Stream text

ai.stream() returns Pi AI's event stream. ai.streamSimple() and ai.completeSimple() take Pi AI's simple options, such as a reasoning level and maxTokens:

const model = ai("@cf/zai-org/glm-4.7-flash");
const context = {
	messages: [{ role: "user", content: "Hi", timestamp: Date.now() }],
};

for await (const event of ai.stream(model, context)) {
	// text_delta, thinking_delta, toolcall_*, done, error
}

A compatibility layer turns each Workers AI model's response into the shape Pi AI's parsers read, so tool calls and reasoning work the same across model families.

Set model details

A Workers AI id that Pi AI does not list resolves with a 128,000 token context window, 8,192 output tokens, and zero cost. Pass the real values when you know them:

const model = ai("@cf/zai-org/glm-4.7-flash", {
	contextWindow: 131_072,
	maxTokens: 16_384,
});

Generate images

const images = ai.images("@cf/black-forest-labs/flux-1-schnell", { steps: 8 });
const result = await ai.generateImages(images, {
	input: [{ type: "text", text: "A red bicycle" }],
});

Use AI Gateway

Every request goes through AI Gateway. Set the gateway with id, which defaults to default:

const ai = createAI({ binding: env.AI, id: "my-gateway" });

To call from outside a Worker, pass accountId and apiToken instead of binding. For gateway options, catalog models, and fallback, refer to Pi AI.

Was this helpful?