# pi-cloudflare-workers-ai

A standalone **pi** extension for [Cloudflare Workers AI](https://developers.cloudflare.com/workers-ai/).

It wires Cloudflare's free-tier models into pi as a single `cloudflare-workers-ai`
provider:

| Capability | Transport | Status |
|---|---|---|
| Chat / reasoning (text) | OpenAI-compatible `…/ai/v1/chat/completions` | ✅ delegated to pi's openai-completions core |
| Image generation (FLUX.1 Schnell) | `…/ai/run/@cf/black-forest-labs/flux-1-schnell` | ✅ verified shape |
| Text-to-speech (Deepgram Aura 2) | `…/ai/run/@cf/deepgram/aura-2-*` | ✅ verified shape |
| Speech-to-text (Whisper / Deepgram Nova-3) | `…/ai/run/@cf/openai/whisper`, `…/ai/run/@cf/deepgram/nova-3` | ✅ verified transports |

> Split out of `pi-cn-free-model-providers` into its own package, modeled on the
> clean structure of `pi-nvidia`.

## Setup

```bash
export CLOUDFLARE_API_KEY=...        # API token from dash.cloudflare.com
export CLOUDFLARE_ACCOUNT_ID=...     # Account ID from the dashboard URL
```

Install like any pi extension:

```bash
npm install pi-cloudflare-workers-ai
```

Then restart pi so the `cloudflare-workers-ai` provider is loaded. The account id
is injected into the request URL at request time (it cannot live in a static base
URL), so both env vars are required before any call — pi will show a clear error
otherwise.

## Two API surfaces

Cloudflare exposes two surfaces, both handled here:

- **OpenAI-compatible chat** — `POST /accounts/{account_id}/ai/v1/chat/completions`.
  The extension delegates these to pi-ai's built-in `openai-completions` core
  (same compat path pi uses for OpenAI-compatible servers), so streaming, tool
  calls, and thinking all work.
- **"Run a model" microservices** — `POST /accounts/{account_id}/ai/run/{model_id}`
  for image / TTS / ASR. These are not chat completions, so they have dedicated
  native streamers.

Auth is `CLOUDFLARE_API_KEY` as a Bearer token; `CLOUDFLARE_ACCOUNT_ID` goes in the
URL path.

## Free-tier models

The curated list is the verified **free** set (10,000 neurons/day, UTC reset). The
five paid frontier models (deepseek-v4-flash/pro, glm-5.2, kimi-k2.6/k2.7-code)
require billing and are intentionally **not** registered.

| Model | Type | Reasoning | Context | Max Out |
| --- | --- | :---: | :---: | ---: |
| `@cf/openai/gpt-oss-120b` | chat | ✓ | 128K | 64K |
| `@cf/openai/gpt-oss-20b` | chat | ✓ | 128K | 64K |
| `@cf/meta/llama-3.3-70b-instruct-fp8-fast` | chat | ✓ | 24K | 8K |
| `@cf/qwen/qwen3-30b-a3b-fp8` | chat | ✓ | 32K | 8K |
| `@cf/qwen/qwen2.5-coder-32b-instruct` | chat | ✓ | 32K | 8K |
| `@cf/google/gemma-4-26b-a4b-it` | chat | ✓ | 128K | 64K |
| `@cf/zai-org/glm-4.7-flash` | chat | ✓ | 128K | 64K |
| `@cf/deepseek-ai/deepseek-r1-distill-qwen-32b` | chat | ✓ | 80K | 64K |
| `@cf/black-forest-labs/flux-1-schnell` | image | — | — | — |
| `@cf/deepgram/aura-2-en` | tts | — | — | — |
| `@cf/deepgram/aura-2-es` | tts | — | — | — |
| `@cf/openai/whisper` | asr | — | — | — |
| `@cf/deepgram/nova-3` | asr | — | — | — |

## Commands

### `/cloudflare-models [chat|image|tts|asr]`

Per-model capability table; the optional filter narrows to one type.

```
/cloudflare-models
/cloudflare-models image
```

### `/cloudflare-usage`

Opens the Cloudflare dashboard in your browser. There is deliberately no data
table — **Cloudflare exposes no usage/quota API**; Workers AI usage (neurons/day)
is visible only in the dashboard UI.

## Notes

- Generated images are saved under `.pi/generated-images/` and reported as a
  clickable link (OSC 8 hyperlink); TTS audio under `.pi/generated-audio/`;
  transcripts under `.pi/generated-transcripts/`.
- The model id contains `/` and `.`, which are unsafe in filenames, so they are
  sanitized when writing generated media.
- If you also use `pi-cn-free-model-providers`, it registers its own `cloudflare`
  provider (chat + native media). Load one or the other to avoid an id clash.
