feat(ai): add Cloudflare Workers AI as a provider (#3851)
* feat(ai): add Cloudflare Workers AI as a provider
Cloudflare Workers AI hosts open-weight LLMs (Kimi K2.6, GPT-OSS,
GLM-4.7, Llama 4, Gemma 4, Nemotron 3) on Cloudflare's GPU network with
an OpenAI-compatible endpoint. Reuses the openai-completions API
protocol; the per-account URL contains a {CLOUDFLARE_ACCOUNT_ID}
placeholder resolved at request time by a small helper.
Pi automatically sets x-session-affinity for prefix caching:
https://developers.cloudflare.com/workers-ai/features/prompt-caching/
Auth: CLOUDFLARE_API_KEY (matches pi's *_API_KEY convention) +
CLOUDFLARE_ACCOUNT_ID. The User-Agent identifies traffic as
'pi-coding-agent' in Cloudflare analytics.
Verified end-to-end against a real Cloudflare account: 17 e2e tests
pass across stream/empty/tokens/unicode/tool-call-without-result/
total-tokens against @cf/moonshotai/kimi-k2.6.
Cloudflare AI Gateway is a separate, larger change (it requires routing
through provider-specific subpaths with the matching API protocol per
upstream) and will land in a follow-up PR.
* refactor(ai): move Cloudflare User-Agent and session-affinity flag to per-model metadata
Instead of conditionally setting them in openai-completions.ts based on
provider detection, declare them as model-level fields in the catalog
(headers + compat). This is consistent with how the github-copilot and
kimi-coding entries already declare their static headers.
packages/ai/scripts/generate-models.ts: emit headers and compat fields
on each cloudflare-workers-ai entry (CLOUDFLARE_STATIC_HEADERS).
packages/ai/src/providers/openai-completions.ts: drop the
isCloudflareProvider conditional that injected User-Agent and the
isCloudflareWorkersAI override of sendSessionAffinityHeaders.
packages/ai/src/models.generated.ts: re-spliced 8 cloudflare-workers-ai
entries with headers + compat.
Behavior is unchanged - verified via fetch interceptor that User-Agent
and x-session-affinity / session_id / x-client-request-id are still sent
on outbound requests. 5/5 e2e tests pass.
This commit is contained in:
@@ -114,6 +114,7 @@ For each built-in provider, pi maintains a list of tool-capable models, updated
|
||||
- Mistral
|
||||
- Groq
|
||||
- Cerebras
|
||||
- Cloudflare Workers AI
|
||||
- xAI
|
||||
- OpenRouter
|
||||
- Vercel AI Gateway
|
||||
|
||||
@@ -61,6 +61,7 @@ pi
|
||||
| Mistral | `MISTRAL_API_KEY` | `mistral` |
|
||||
| Groq | `GROQ_API_KEY` | `groq` |
|
||||
| Cerebras | `CEREBRAS_API_KEY` | `cerebras` |
|
||||
| Cloudflare Workers AI | `CLOUDFLARE_API_KEY` (+ `CLOUDFLARE_ACCOUNT_ID`) | `cloudflare-workers-ai` |
|
||||
| xAI | `XAI_API_KEY` | `xai` |
|
||||
| OpenRouter | `OPENROUTER_API_KEY` | `openrouter` |
|
||||
| Vercel AI Gateway | `AI_GATEWAY_API_KEY` | `vercel-ai-gateway` |
|
||||
@@ -172,6 +173,18 @@ export AWS_BEDROCK_SKIP_AUTH=1
|
||||
export AWS_BEDROCK_FORCE_HTTP1=1
|
||||
```
|
||||
|
||||
### Cloudflare Workers AI
|
||||
|
||||
`CLOUDFLARE_API_KEY` can be set via `/login`. `CLOUDFLARE_ACCOUNT_ID` must be set as an environment variable.
|
||||
|
||||
```bash
|
||||
export CLOUDFLARE_API_KEY=... # or use /login
|
||||
export CLOUDFLARE_ACCOUNT_ID=...
|
||||
pi --provider cloudflare-workers-ai --model "@cf/moonshotai/kimi-k2.6"
|
||||
```
|
||||
|
||||
Pi automatically sets `x-session-affinity` for [prefix caching](https://developers.cloudflare.com/workers-ai/features/prompt-caching/) discounts.
|
||||
|
||||
### Google Vertex AI
|
||||
|
||||
Uses Application Default Credentials:
|
||||
|
||||
@@ -316,6 +316,8 @@ ${chalk.bold("Environment Variables:")}
|
||||
MINIMAX_API_KEY - MiniMax API key
|
||||
OPENCODE_API_KEY - OpenCode Zen/OpenCode Go API key
|
||||
KIMI_API_KEY - Kimi For Coding API key
|
||||
CLOUDFLARE_API_KEY - Cloudflare API token (Workers AI)
|
||||
CLOUDFLARE_ACCOUNT_ID - Cloudflare account id (required for Workers AI)
|
||||
AWS_PROFILE - AWS profile for Amazon Bedrock
|
||||
AWS_ACCESS_KEY_ID - AWS access key for Amazon Bedrock
|
||||
AWS_SECRET_ACCESS_KEY - AWS secret key for Amazon Bedrock
|
||||
|
||||
@@ -37,6 +37,7 @@ export const defaultModelPerProvider: Record<KnownProvider, string> = {
|
||||
opencode: "kimi-k2.6",
|
||||
"opencode-go": "kimi-k2.6",
|
||||
"kimi-coding": "kimi-for-coding",
|
||||
"cloudflare-workers-ai": "@cf/moonshotai/kimi-k2.6",
|
||||
};
|
||||
|
||||
export interface ScopedModel {
|
||||
|
||||
@@ -182,6 +182,7 @@ const API_KEY_LOGIN_PROVIDERS: Record<string, string> = {
|
||||
[BEDROCK_PROVIDER_ID]: "Amazon Bedrock",
|
||||
"azure-openai-responses": "Azure OpenAI Responses",
|
||||
cerebras: "Cerebras",
|
||||
"cloudflare-workers-ai": "Cloudflare Workers AI",
|
||||
deepseek: "DeepSeek",
|
||||
fireworks: "Fireworks",
|
||||
google: "Google Gemini",
|
||||
|
||||
Reference in New Issue
Block a user