Skip to content

feat(opencode): native OpenAI and Anthropic passthroughs for Cloudflare AI Gateway - #42634

Open
rekram1-node wants to merge 4 commits into
devfrom
gateway-native-routing
Open

feat(opencode): native OpenAI and Anthropic passthroughs for Cloudflare AI Gateway#42634
rekram1-node wants to merge 4 commits into
devfrom
gateway-native-routing

Conversation

@rekram1-node

Copy link
Copy Markdown
Collaborator

Summary

Cloudflare AI Gateway models currently all ride the unified OpenAI-compatible `/compat` endpoint. That breaks new OpenAI models (gpt-5.5+/pro reject `tools` + `reasoning_effort` on chat completions and require the Responses API) and squeezes Claude through an OpenAI-shaped body (no native thinking blocks, no `cache_control`, reasoning efforts silently dropped or mistranslated).

This PR routes gateway models through the provider-native passthroughs that `ai-gateway-provider` 3.2 ships:

  • `openai/*` → native OpenAI passthrough on the Responses API
  • `anthropic/*` → native Anthropic passthrough on the Messages API
  • everything else → unified `/compat`, unchanged

The passthrough wrappers inject a `CF_TEMP_TOKEN` sentinel the gateway strips before dispatch, so upstream billing stays on the gateway (Unified Billing / stored BYOK) and the Cloudflare token never reaches a third-party provider.

Changes

  • `provider.ts` loader: prefix routing in `getModel`; keeps the Workers AI token scoping (the Cloudflare token is only forwarded upstream for `workers-ai/` and `@cf/` models — includes fix(provider): scope AI Gateway token to first-party Workers AI models #33597, co-authored)
  • `provider.ts` `cloudflareGatewayNpm`: resolves the native npm (`@ai-sdk/openai` / `@ai-sdk/anthropic`) before variants are computed, so reasoning variants produce payloads the native SDKs understand — Claude effort variants become `thinking` + `output_config.effort` (previously silently dropped), OpenAI variants gain `reasoningSummary` + encrypted reasoning includes for stateless multi-turn
  • `plugin/cloudflare.ts`: removed the `chat.params` maxOutputTokens workaround — it existed because compat couldn't rename `max_tokens` for OpenAI reasoning models; the Responses API accepts `max_output_tokens`, so the hack now just uncapped output
  • Tests: e2e suite asserts the envelope per route (provider + endpoint + wire payload), reasoning-effort fidelity on all three routes, and the token-scoping invariants (`authorization`/`x-api-key` stripped on passthroughs, secret never in the body, Workers AI still receives the token)

Live verification

Tested against a real gateway with Unified Billing: OpenAI models with tools + reasoning efforts (the previously failing case), Claude models, and `workers-ai/@cf/moonshotai/kimi-k2.6` (compat regression). Also live-verified the gateway's boundaries, which shaped this scope: under Unified Billing the legacy endpoint serves exactly `openai/`, `anthropic/`, and `workers-ai/` — Google/xAI fail spend-limit resolution (catalog slug ≠ route prefix) and DeepSeek gets no managed credentials. The models.dev catalog was aligned accordingly (models.dev#4674, #4676, #4693, #4715). Other providers arrive with the REST (`/ai/v1`) transport in V2.

Supersedes #33597 — its token-scoping fix is included here with commit authorship preserved and co-author credit.

keefetang and others added 4 commits June 24, 2026 11:52
#32052 fixed #32051 (Workers AI 401s) by passing apiKey to createUnified,
but applied it to every model — so the Cloudflare API token was sent as the
upstream Authorization header for third-party providers (OpenAI, Anthropic),
causing them to 401 with "Invalid API Key".

Scope token forwarding to be model-aware: attach the Cloudflare token only
for first-party Workers AI models, whose upstream is Cloudflare itself. The
Unified API addresses Workers AI both as "workers-ai/..." and as bare
"@cf/..." ids, so match both; "@cf/" is Cloudflare's reserved namespace, so
this never matches a third-party model. Other providers receive no upstream
Authorization and fall back to the gateway's stored/BYOK keys. Applied in
both the v1 provider (provider.ts) and v2 plugin
(core/.../cloudflare-ai-gateway.ts) paths.

Tests assert both directions, including that third-party sub-requests carry
no upstream authorization header.

Reapplies and extends the approach from #33407.
…ls through native passthroughs

Co-authored-by: Keefe Tang <keefe@pentagram.me>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants