feat(ai): add Cloudflare Workers AI as a provider#3851
Conversation
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.
|
This PR was auto-closed. Only contributors approved with Maintainers review auto-closed issues daily. Issues that do not meet the quality bar in CONTRIBUTING.md will not be reopened or receive a reply. If a maintainer replies See CONTRIBUTING.md. |
| return new OpenAI({ | ||
| apiKey, | ||
| baseURL: model.baseUrl, | ||
| baseURL: isCloudflareProvider(model.provider) ? resolveCloudflareBaseUrl(model) : model.baseUrl, |
There was a problem hiding this comment.
i don't love this, open to suggestions
There was a problem hiding this comment.
we could do a baseURL: resolveBaseUrl(model), general function, not cloudflare-specific. in case more providers want to be onboarded too
There was a problem hiding this comment.
i think it's fine. the only reason we need resolveCloudflareBaseUrl here is due to the substitution. openai-completions.ts has become a mess already anways due to all provider specific "fixes". one more will not hurt much.
… 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.
badlogic
left a comment
There was a problem hiding this comment.
Looks good to me overall. resolveCloudflareBaseUrl is quite unfortunate. i'll think about this for a bit, fail to come up with a better solution, then merge.
Cheers!
| } as const; | ||
|
|
||
| const CLOUDFLARE_STATIC_HEADERS = { | ||
| "User-Agent": "pi-coding-agent", |
There was a problem hiding this comment.
sneaky :) will have to honor telemetry setting.
There was a problem hiding this comment.
hehe. let me know if i have to change anything to honor it!
| return new OpenAI({ | ||
| apiKey, | ||
| baseURL: model.baseUrl, | ||
| baseURL: isCloudflareProvider(model.provider) ? resolveCloudflareBaseUrl(model) : model.baseUrl, |
There was a problem hiding this comment.
i think it's fine. the only reason we need resolveCloudflareBaseUrl here is due to the substitution. openai-completions.ts has become a mess already anways due to all provider specific "fixes". one more will not hurt much.
| // Cerebras | ||
| { provider: "cerebras", model: "zai-glm-4.7", label: "cerebras-zai-glm-4.7" }, | ||
| // Cloudflare Workers AI | ||
| { provider: "cloudflare-workers-ai", model: "@cf/moonshotai/kimi-k2.6", label: "cloudflare-kimi-k2.6" }, |
Adapts to badlogic#3851's follow-up fix ("honor telemetry for Cloudflare attribution headers", fbb5eed) which moved the 'User-Agent: pi-coding-agent' header out of per-model catalog metadata and into a centralized telemetry-honoring helper (coding-agent/src/core/sdk.ts:getAttributionHeaders). - packages/coding-agent/src/core/sdk.ts: extend the cloudflare branch of getAttributionHeaders to also match cloudflare-ai-gateway and gateway.ai.cloudflare.com. - packages/ai/scripts/generate-models.ts and src/models.generated.ts: drop 'headers' from the 35 cloudflare-ai-gateway entries (constant CLOUDFLARE_STATIC_HEADERS no longer exists). Per-route compat.sendSessionAffinityHeaders is unchanged. End-to-end behavior unchanged: 9/9 tests still pass across all three upstream families (Workers AI, Anthropic, OpenAI Responses).
* 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.
* 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.
* feat(ai): add Cloudflare AI Gateway as a provider
Routes through Cloudflare's Unified API (`/compat`) for Workers AI and
Anthropic models, and through the provider-specific `/openai` subpath
for OpenAI models so reasoning models (gpt-5.x, o-series) can hit
`/v1/responses` natively. Once `/compat` adds Responses-API support,
the OpenAI subpath can be folded back in.
Catalog layout:
workers-ai/@cf/... -> openai-completions, gateway/.../compat
anthropic/... -> openai-completions, gateway/.../compat
<native-id> -> openai-responses, gateway/.../openai
(gpt-5.1, claude-... no, sorry: gpt-5.x and o-series only;
prefix stripped because the OpenAI SDK posts native ids)
Touches:
packages/ai/src/types.ts add cloudflare-ai-gateway to KnownProvider
packages/ai/src/env-api-keys.ts map to CLOUDFLARE_API_KEY
packages/ai/src/providers/cloudflare.ts add CLOUDFLARE_AI_GATEWAY_COMPAT_BASE_URL
and CLOUDFLARE_AI_GATEWAY_OPENAI_BASE_URL
packages/ai/src/providers/openai-responses.ts one-line dispatch through resolveCloudflareBaseUrl
(matches what openai-completions.ts already does)
packages/ai/scripts/generate-models.ts branch openai/* vs workers-ai/anthropic/*
packages/ai/src/models.generated.ts spliced 34 entries
packages/ai/test/stream.test.ts 3 e2e blocks (one per upstream)
packages/coding-agent/* defaultModelPerProvider, login, env docs,
README, providers.md
Verified end-to-end against a real Cloudflare account with unified
billing: 9/9 e2e tests pass across all three upstreams (Workers AI
Kimi K2.6, OpenAI gpt-5.1 reasoning, Anthropic claude-sonnet-4-5).
* refactor(ai): move AI Gateway User-Agent and per-route session-affinity flag to catalog
Mirrors the same per-model metadata refactor done for Workers AI in the
parent branch. All cloudflare-ai-gateway entries get the User-Agent
header. Only workers-ai/* gateway entries set
`compat.sendSessionAffinityHeaders: true` because the gateway
forwards that header to the underlying Workers AI runtime; anthropic/*
upstream and openai/* (openai-responses) don't use it.
packages/ai/scripts/generate-models.ts: emit headers (always) and
per-upstream compat (workers-ai only) on each cloudflare-ai-gateway
entry.
packages/ai/src/models.generated.ts: re-spliced 35 entries with
headers + conditional compat.
Behavior unchanged - 9/9 e2e tests pass across all three upstream
families.
* fix(ai): align AI Gateway with telemetry-aware UA helper
Adapts to #3851's follow-up fix ("honor telemetry for
Cloudflare attribution headers", fbb5eed) which moved the
'User-Agent: pi-coding-agent' header out of per-model catalog metadata
and into a centralized telemetry-honoring helper
(coding-agent/src/core/sdk.ts:getAttributionHeaders).
- packages/coding-agent/src/core/sdk.ts: extend the cloudflare branch of
getAttributionHeaders to also match cloudflare-ai-gateway and
gateway.ai.cloudflare.com.
- packages/ai/scripts/generate-models.ts and src/models.generated.ts:
drop 'headers' from the 35 cloudflare-ai-gateway entries (constant
CLOUDFLARE_STATIC_HEADERS no longer exists). Per-route
compat.sendSessionAffinityHeaders is unchanged.
End-to-end behavior unchanged: 9/9 tests still pass across all three
upstream families (Workers AI, Anthropic, OpenAI Responses).
---------
Co-authored-by: Mario Zechner <badlogicgames@gmail.com>
* feat(ai): add Cloudflare AI Gateway as a provider
Routes through Cloudflare's Unified API (`/compat`) for Workers AI and
Anthropic models, and through the provider-specific `/openai` subpath
for OpenAI models so reasoning models (gpt-5.x, o-series) can hit
`/v1/responses` natively. Once `/compat` adds Responses-API support,
the OpenAI subpath can be folded back in.
Catalog layout:
workers-ai/@cf/... -> openai-completions, gateway/.../compat
anthropic/... -> openai-completions, gateway/.../compat
<native-id> -> openai-responses, gateway/.../openai
(gpt-5.1, claude-... no, sorry: gpt-5.x and o-series only;
prefix stripped because the OpenAI SDK posts native ids)
Touches:
packages/ai/src/types.ts add cloudflare-ai-gateway to KnownProvider
packages/ai/src/env-api-keys.ts map to CLOUDFLARE_API_KEY
packages/ai/src/providers/cloudflare.ts add CLOUDFLARE_AI_GATEWAY_COMPAT_BASE_URL
and CLOUDFLARE_AI_GATEWAY_OPENAI_BASE_URL
packages/ai/src/providers/openai-responses.ts one-line dispatch through resolveCloudflareBaseUrl
(matches what openai-completions.ts already does)
packages/ai/scripts/generate-models.ts branch openai/* vs workers-ai/anthropic/*
packages/ai/src/models.generated.ts spliced 34 entries
packages/ai/test/stream.test.ts 3 e2e blocks (one per upstream)
packages/coding-agent/* defaultModelPerProvider, login, env docs,
README, providers.md
Verified end-to-end against a real Cloudflare account with unified
billing: 9/9 e2e tests pass across all three upstreams (Workers AI
Kimi K2.6, OpenAI gpt-5.1 reasoning, Anthropic claude-sonnet-4-5).
* refactor(ai): move AI Gateway User-Agent and per-route session-affinity flag to catalog
Mirrors the same per-model metadata refactor done for Workers AI in the
parent branch. All cloudflare-ai-gateway entries get the User-Agent
header. Only workers-ai/* gateway entries set
`compat.sendSessionAffinityHeaders: true` because the gateway
forwards that header to the underlying Workers AI runtime; anthropic/*
upstream and openai/* (openai-responses) don't use it.
packages/ai/scripts/generate-models.ts: emit headers (always) and
per-upstream compat (workers-ai only) on each cloudflare-ai-gateway
entry.
packages/ai/src/models.generated.ts: re-spliced 35 entries with
headers + conditional compat.
Behavior unchanged - 9/9 e2e tests pass across all three upstream
families.
* fix(ai): align AI Gateway with telemetry-aware UA helper
Adapts to earendil-works#3851's follow-up fix ("honor telemetry for
Cloudflare attribution headers", fbb5eed) which moved the
'User-Agent: pi-coding-agent' header out of per-model catalog metadata
and into a centralized telemetry-honoring helper
(coding-agent/src/core/sdk.ts:getAttributionHeaders).
- packages/coding-agent/src/core/sdk.ts: extend the cloudflare branch of
getAttributionHeaders to also match cloudflare-ai-gateway and
gateway.ai.cloudflare.com.
- packages/ai/scripts/generate-models.ts and src/models.generated.ts:
drop 'headers' from the 35 cloudflare-ai-gateway entries (constant
CLOUDFLARE_STATIC_HEADERS no longer exists). Per-route
compat.sendSessionAffinityHeaders is unchanged.
End-to-end behavior unchanged: 9/9 tests still pass across all three
upstream families (Workers AI, Anthropic, OpenAI Responses).
---------
Co-authored-by: Mario Zechner <badlogicgames@gmail.com>
commit 324aa1d Author: Mario Zechner <badlogicgames@gmail.com> Date: Mon May 4 00:52:56 2026 +0200 fix(coding-agent): render compact read calls directly Render compact read classifications in the call row and leave the collapsed result row empty. The previous implementation used shared renderer state to let renderResult hide renderCall, which leaked an internal ReadRenderState type through the tool definition and coupled two render phases unnecessarily. The call renderer has all context needed to choose the compact presentation itself. commit 2342001 Author: Mario Zechner <badlogicgames@gmail.com> Date: Mon May 4 00:45:56 2026 +0200 fix(coding-agent): decouple codex session cleanup commit 5fa277b Author: Armin Ronacher <armin.ronacher@active-4.com> Date: Sun May 3 23:25:56 2026 +0200 fix(coding-agent): close codex websocket sessions Fixes earendil-works#4103 commit 370fdae Author: Armin Ronacher <armin.ronacher@active-4.com> Date: Sun May 3 22:51:42 2026 +0200 fix(ai): fall back from codex websocket to sse (earendil-works#4133) commit a646639 Author: Mario Zechner <badlogicgames@gmail.com> Date: Sun May 3 22:14:52 2026 +0200 chore: label bigrefactor issue closures commit 21026cb Author: Mario Zechner <badlogicgames@gmail.com> Date: Sun May 3 22:04:05 2026 +0200 chore: update temporary issue gate message commit 693888a Author: Jake Jia <87770044+Phoen1xCode@users.noreply.github.com> Date: Sun May 3 18:57:11 2026 +0800 feat(ai): switch xiaomi default to api billing, add per-region token plan providers (earendil-works#4112) Built-in `xiaomi` provider now targets the API billing endpoint (https://api.xiaomimimo.com/anthropic) — a single stable URL for keys issued at platform.xiaomimimo.com. The Token Plan endpoints are exposed as three sibling providers, each with its own env var: - xiaomi-token-plan-cn: XIAOMI_TOKEN_PLAN_CN_API_KEY - xiaomi-token-plan-ams: XIAOMI_TOKEN_PLAN_AMS_API_KEY - xiaomi-token-plan-sgp: XIAOMI_TOKEN_PLAN_SGP_API_KEY BREAKING CHANGE: users who previously set XIAOMI_API_KEY against the Token Plan AMS endpoint must move to xiaomi-token-plan-ams and set XIAOMI_TOKEN_PLAN_AMS_API_KEY. This also resolves the 401 reported by on earendil-works#4005, where a platform.xiaomimimo.com key fails against the Token Plan endpoint. closes earendil-works#4082 commit 7c5ef0b Author: myu003 <yzhg1983@163.com> Date: Sun May 3 18:55:23 2026 +0800 test(ai,coding-agent): stabilize env-sensitive test cases (earendil-works#4119) commit c8edb25 Author: Jakub Synowiec <jsynowiec@users.noreply.github.com> Date: Sun May 3 00:41:55 2026 +0200 fix(ai): fix mismatch between models.dev and OpenCode Go (Qwen3.5/3.6, MiniMax M2.7) (earendil-works#4110) commit b9efafc Author: Armin Ronacher <armin.ronacher@active-4.com> Date: Sun May 3 00:04:27 2026 +0200 fix(ci): repair failing test expectations commit cd5bfd0 Author: Armin Ronacher <armin.ronacher@active-4.com> Date: Sat May 2 23:46:37 2026 +0200 fix(ci): install sandbox runtime for root typecheck commit 588639f Author: Armin Ronacher <armin.ronacher@active-4.com> Date: Sat May 2 20:36:07 2026 +0200 feat(read): compact resource read rendering commit 7268e9a Author: Mario Zechner <badlogicgames@gmail.com> Date: Sat May 2 14:58:41 2026 +0200 Add [Unreleased] section for next cycle commit 036bde0 Author: Mario Zechner <badlogicgames@gmail.com> Date: Sat May 2 14:57:51 2026 +0200 Release v0.72.1 commit 97352ac Author: Mario Zechner <badlogicgames@gmail.com> Date: Sat May 2 14:56:52 2026 +0200 chore(ai): update generated models commit b8bb241 Author: Mario Zechner <badlogicgames@gmail.com> Date: Sat May 2 14:14:22 2026 +0200 fix(ai): honor codex transport option closes earendil-works#4083 commit e4163fe Author: Mario Zechner <badlogicgames@gmail.com> Date: Sat May 2 01:55:50 2026 +0200 Add [Unreleased] section for next cycle commit 196226b Author: Mario Zechner <badlogicgames@gmail.com> Date: Sat May 2 01:54:59 2026 +0200 Release v0.72.0 commit 2d33616 Author: Mario Zechner <badlogicgames@gmail.com> Date: Sat May 2 01:54:04 2026 +0200 docs: audit changelog entries for v0.71.1..HEAD commit c0e0469 Author: Mario Zechner <badlogicgames@gmail.com> Date: Sat May 2 01:36:34 2026 +0200 fix(ai): use Xiaomi Token Plan Anthropic endpoint closes earendil-works#3912 commit 80f06d3 Author: Mario Zechner <badlogicgames@gmail.com> Date: Sat May 2 01:20:01 2026 +0200 feat: add model thinking level metadata closes earendil-works#3208 commit 73b7b2c Author: Mario Zechner <badlogicgames@gmail.com> Date: Sat May 2 00:49:22 2026 +0200 feat(agent): add post-turn stop callback commit a446226 Author: Jake Jia <87770044+Phoen1xCode@users.noreply.github.com> Date: Sat May 2 06:46:05 2026 +0800 feat(ai): add Xiaomi MiMo provider (earendil-works#4005) * fix(ai): include minimax-cn in cross-provider-handoff matrix * feat(ai): add Xiaomi MiMo provider Adds Xiaomi MiMo as an openai-completions-compatible provider. - packages/ai: register provider in types/KnownProvider, env-api-keys (XIAOMI_API_KEY), generate-models, models.generated.ts, overflow util, README, CHANGELOG - packages/ai/test: extend stream, tokens, abort, empty, context-overflow, overflow, image-tool-result, tool-call-without-result, total-tokens, unicode-surrogate, cross-provider-handoff matrices with Xiaomi - packages/coding-agent: default model (mimo-v2.5-pro), display name (Xiaomi MiMo), CLI env var docs, README, docs/providers.md closes earendil-works#3912 --------- Co-authored-by: Mario Zechner <badlogicgames@gmail.com> commit ddb8ed0 Author: Mario Zechner <badlogicgames@gmail.com> Date: Fri May 1 22:18:49 2026 +0200 fix(coding-agent): honor registered model base urls closes earendil-works#4063 commit f5b6e4f Author: Mario Zechner <badlogicgames@gmail.com> Date: Fri May 1 19:07:59 2026 +0200 fix(ai): handle OpenRouter DeepSeek V4 reasoning Closes earendil-works#4055 Closes earendil-works#4047 commit ad3f7d7 Author: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Date: Fri May 1 20:18:53 2026 +0000 chore: approve contributor pandada8 commit c3282e4 Author: Armin Ronacher <armin.ronacher@active-4.com> Date: Fri May 1 18:52:54 2026 +0200 refactor(coding-agent): inline npm command parsing commit ade08de Author: Armin Ronacher <armin.ronacher@active-4.com> Date: Thu Apr 30 19:10:06 2026 +0200 fix(coding-agent): repair self-update detection Fixes earendil-works#3942 Fixes earendil-works#3980 Fixes earendil-works#3922 commit def47ec Author: Mario Zechner <badlogicgames@gmail.com> Date: Fri May 1 13:12:41 2026 +0200 Add [Unreleased] section for next cycle commit 80a4390 Author: Mario Zechner <badlogicgames@gmail.com> Date: Fri May 1 13:11:52 2026 +0200 Release v0.71.1 commit 4745a95 Author: Mario Zechner <badlogicgames@gmail.com> Date: Fri May 1 13:07:40 2026 +0200 feat(ai): add cached codex websocket transport commit 8040dd6 Author: Mario Zechner <badlogicgames@gmail.com> Date: Fri May 1 01:32:13 2026 +0200 docs(coding-agent): update subscription provider notes commit 3d44094 Author: Mario Zechner <badlogicgames@gmail.com> Date: Fri May 1 01:03:49 2026 +0200 Add [Unreleased] section for next cycle commit f4efeb2 Author: Mario Zechner <badlogicgames@gmail.com> Date: Fri May 1 01:03:02 2026 +0200 Release v0.71.0 commit 8db0d28 Author: Mario Zechner <badlogicgames@gmail.com> Date: Fri May 1 01:01:54 2026 +0200 chore(coding-agent): remove Qwen CLI extension example commit 879e46a Author: Mario Zechner <badlogicgames@gmail.com> Date: Fri May 1 00:58:33 2026 +0200 docs(coding-agent): add Cloudflare gateway feature changelog Closes earendil-works#3856 commit a45577b Author: Mario Zechner <badlogicgames@gmail.com> Date: Fri May 1 00:56:05 2026 +0200 fix(ai): finalize cloudflare gateway provider support commit 24fb6b8 Author: MC <mchen@cloudflare.com> Date: Thu Apr 30 22:29:37 2026 +0100 feat(ai): add Cloudflare AI Gateway as a provider (earendil-works#3856) * feat(ai): add Cloudflare AI Gateway as a provider Routes through Cloudflare's Unified API (`/compat`) for Workers AI and Anthropic models, and through the provider-specific `/openai` subpath for OpenAI models so reasoning models (gpt-5.x, o-series) can hit `/v1/responses` natively. Once `/compat` adds Responses-API support, the OpenAI subpath can be folded back in. Catalog layout: workers-ai/@cf/... -> openai-completions, gateway/.../compat anthropic/... -> openai-completions, gateway/.../compat <native-id> -> openai-responses, gateway/.../openai (gpt-5.1, claude-... no, sorry: gpt-5.x and o-series only; prefix stripped because the OpenAI SDK posts native ids) Touches: packages/ai/src/types.ts add cloudflare-ai-gateway to KnownProvider packages/ai/src/env-api-keys.ts map to CLOUDFLARE_API_KEY packages/ai/src/providers/cloudflare.ts add CLOUDFLARE_AI_GATEWAY_COMPAT_BASE_URL and CLOUDFLARE_AI_GATEWAY_OPENAI_BASE_URL packages/ai/src/providers/openai-responses.ts one-line dispatch through resolveCloudflareBaseUrl (matches what openai-completions.ts already does) packages/ai/scripts/generate-models.ts branch openai/* vs workers-ai/anthropic/* packages/ai/src/models.generated.ts spliced 34 entries packages/ai/test/stream.test.ts 3 e2e blocks (one per upstream) packages/coding-agent/* defaultModelPerProvider, login, env docs, README, providers.md Verified end-to-end against a real Cloudflare account with unified billing: 9/9 e2e tests pass across all three upstreams (Workers AI Kimi K2.6, OpenAI gpt-5.1 reasoning, Anthropic claude-sonnet-4-5). * refactor(ai): move AI Gateway User-Agent and per-route session-affinity flag to catalog Mirrors the same per-model metadata refactor done for Workers AI in the parent branch. All cloudflare-ai-gateway entries get the User-Agent header. Only workers-ai/* gateway entries set `compat.sendSessionAffinityHeaders: true` because the gateway forwards that header to the underlying Workers AI runtime; anthropic/* upstream and openai/* (openai-responses) don't use it. packages/ai/scripts/generate-models.ts: emit headers (always) and per-upstream compat (workers-ai only) on each cloudflare-ai-gateway entry. packages/ai/src/models.generated.ts: re-spliced 35 entries with headers + conditional compat. Behavior unchanged - 9/9 e2e tests pass across all three upstream families. * fix(ai): align AI Gateway with telemetry-aware UA helper Adapts to earendil-works#3851's follow-up fix ("honor telemetry for Cloudflare attribution headers", fbb5eed) which moved the 'User-Agent: pi-coding-agent' header out of per-model catalog metadata and into a centralized telemetry-honoring helper (coding-agent/src/core/sdk.ts:getAttributionHeaders). - packages/coding-agent/src/core/sdk.ts: extend the cloudflare branch of getAttributionHeaders to also match cloudflare-ai-gateway and gateway.ai.cloudflare.com. - packages/ai/scripts/generate-models.ts and src/models.generated.ts: drop 'headers' from the 35 cloudflare-ai-gateway entries (constant CLOUDFLARE_STATIC_HEADERS no longer exists). Per-route compat.sendSessionAffinityHeaders is unchanged. End-to-end behavior unchanged: 9/9 tests still pass across all three upstream families (Workers AI, Anthropic, OpenAI Responses). --------- Co-authored-by: Mario Zechner <badlogicgames@gmail.com> commit c9ddca1 Author: Mario Zechner <badlogicgames@gmail.com> Date: Thu Apr 30 23:29:12 2026 +0200 docs: note removed Google provider support as breaking commit bd429f7 Author: Mario Zechner <badlogicgames@gmail.com> Date: Thu Apr 30 23:17:32 2026 +0200 test(coding-agent): update stale expectations commit 23fce57 Author: Mario Zechner <badlogicgames@gmail.com> Date: Thu Apr 30 23:10:08 2026 +0200 fix(ci): install sandbox extension dependency commit 0b8452c Author: Mario Zechner <badlogicgames@gmail.com> Date: Thu Apr 30 23:08:51 2026 +0200 fix(coding-agent): fix WSL clipboard image paste closes earendil-works#2469 commit 0452735 Author: Mario Zechner <badlogicgames@gmail.com> Date: Thu Apr 30 23:02:40 2026 +0200 docs: audit unreleased changelogs commit 0ed0d43 Author: Mario Zechner <badlogicgames@gmail.com> Date: Thu Apr 30 23:00:56 2026 +0200 remove mom and pods packages People should check out pi-chat (earendil-works/pi-chat on GitHub), or use an older commit for mom and fork. commit 3ffc2b4 Author: Mario Zechner <badlogicgames@gmail.com> Date: Thu Apr 30 22:50:40 2026 +0200 fix(coding-agent): avoid duplicate blocked edit output closes earendil-works#3830 commit 95ae590 Author: Mario Zechner <badlogicgames@gmail.com> Date: Thu Apr 30 22:49:31 2026 +0200 fix(coding-agent): refresh thinking border from extensions closes earendil-works#3888 commit f7df474 Author: Mario Zechner <badlogicgames@gmail.com> Date: Thu Apr 30 21:59:21 2026 +0200 fix google vertex unsigned tool call replay closes earendil-works#4032 commit 9600a0c Author: Mario Zechner <badlogicgames@gmail.com> Date: Thu Apr 30 21:47:51 2026 +0200 chore: add session usage stats script commit 8191d59 Author: Mario Zechner <badlogicgames@gmail.com> Date: Thu Apr 30 21:37:53 2026 +0200 feat(coding-agent): support session dir env closes earendil-works#4027 commit 8632e1b Author: Mario Zechner <badlogicgames@gmail.com> Date: Thu Apr 30 21:32:53 2026 +0200 fix(coding-agent): update agent package readme link closes earendil-works#4023 commit 3d43d2e Author: Mario Zechner <badlogicgames@gmail.com> Date: Thu Apr 30 21:31:43 2026 +0200 fix(coding-agent): stop tool argument injection closes earendil-works#4018 commit fe66edd Author: Mario Zechner <badlogicgames@gmail.com> Date: Thu Apr 30 21:24:17 2026 +0200 remove gemini cli and antigravity support commit 40c6eab Author: Mario Zechner <badlogicgames@gmail.com> Date: Thu Apr 30 21:19:09 2026 +0200 feat(coding-agent): allow message_end replacements closes earendil-works#3982 commit 24dec9f Author: pica <cumt.xiaochi@gmail.com> Date: Fri May 1 02:59:02 2026 +0800 fix(coding-agent): remove detached: true on Windows to fix pwsh.exe stdio (earendil-works#4013) On Windows, spawn(..., { detached: true }) prevents pwsh.exe (PowerShell) from producing any stdout/stderr through pipe streams. This is because detached creates a new process group which breaks pwsh's console host communication. bash.exe and other cygwin/msys2 shells are unaffected by detached: true, but they don't need it either -- on Windows, killProcessTree() already uses taskkill /F /T /PID which kills the process tree by PID regardless of whether the process was spawned detached. The detached flag only matters on Unix, where kill(-pid, SIGKILL) requires a process group that is only created via detached: true. Fixes earendil-works#4012 commit 7dc1bed Author: Armin Ronacher <armin.ronacher@active-4.com> Date: Thu Apr 30 16:12:03 2026 +0200 feat(ai): add Moonshot AI provider model support
closes #3850
Adds
cloudflare-workers-aitoKnownProvider. OpenAI-compatible endpoint athttps://api.cloudflare.com/client/v4/accounts/{account}/ai/v1, reusing the existingopenai-completionsAPI protocol. The per-account URL contains a{CLOUDFLARE_ACCOUNT_ID}placeholder resolved at request time.Auth:
CLOUDFLARE_API_KEY(matches pi's*_API_KEYconvention) +CLOUDFLARE_ACCOUNT_ID.Summary
Verification
Verified end-to-end against my Cloudflare account: 17 e2e tests pass against
@cf/moonshotai/kimi-k2.6across stream/empty/tokens/unicode/tool-call-without-result/total-tokens.Note on
models.generated.tsI added only the new
"cloudflare-workers-ai"block. The rest is byte-identical tomain— I deliberately did not runnpm run generate-modelsbecause livemodels.devdata has drifted (zai removed several glm models that current tests reference) and a full regenerate would break unrelated testsA separate
cloudflare-ai-gatewayPR will follow this one: #3852