Skip to content

fix(provider): send Anthropic's dashed native slug through the AI Gateway - #44281

Open
superhighfives wants to merge 1 commit into
anomalyco:devfrom
superhighfives:gateway-anthropic-slug
Open

fix(provider): send Anthropic's dashed native slug through the AI Gateway#44281
superhighfives wants to merge 1 commit into
anomalyco:devfrom
superhighfives:gateway-anthropic-slug

Conversation

@superhighfives

Copy link
Copy Markdown

Issue for this PR

Closes #44280

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Every Anthropic model under cloudflare-ai-gateway fails with Error: model: claude-haiku-4.5, so none of them are usable.

The plugin already routes anthropic/* models through Anthropic's native Messages passthrough (createAnthropic), which forwards the sliced model id to Anthropic's API unchanged. models.dev lists Cloudflare's canonical dotted ids (anthropic/claude-haiku-4.5), but Anthropic's Messages API expects dashed native slugs (claude-haiku-4-5) — so it 404s.

The fix translates dots to dashes when slicing the anthropic/ prefix. OpenAI is unaffected because its native slugs already use dots (gpt-4.1), which is why only Anthropic was broken.

Worth noting: Cloudflare's own catalog-aware REST endpoints (/ai/v1/messages, /ai/run) accept the dotted id and do this exact dot→dash translation internally before calling Anthropic. The native passthrough route this plugin uses forwards the slug raw, so the plugin has to do the same translation. The dotted id in models.dev is correct — it's Cloudflare's canonical id (see https://developers.cloudflare.com/ai/models/anthropic/claude-haiku-4.5/), so this is fixed on the opencode side, not in the catalog. (Context: surfaced while testing anomalyco/models.dev#4922.)

How did you verify your code works?

  • Built the single binary and ran against a live Cloudflare AI Gateway: anthropic/claude-haiku-4.5 went from Error: model: claude-haiku-4.5 to a normal completion; openai/* and workers-ai/@cf/* still work.
  • Added a regression test in cf-ai-gateway-e2e.test.ts asserting a dotted Anthropic id reaches the Anthropic Messages wire as a dashed slug; confirmed it fails without the fix and passes with it.
  • bun test test/provider/ in packages/opencode passes (one unrelated pre-existing flake in header-timeout.test.ts, which also fails on dev). tsgo --noEmit clean.

Screenshots / recordings

N/A (not a UI change).

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

…eway

The Cloudflare AI Gateway plugin routes anthropic/* models through the native
Anthropic Messages passthrough (createAnthropic), which forwards the model id
to Anthropic's API unchanged. models.dev lists Cloudflare's canonical dotted
ids (anthropic/claude-haiku-4.5), but Anthropic's Messages API expects dashed
native slugs (claude-haiku-4-5), so every Anthropic model 404s with
"model: claude-haiku-4.5".

Translate dots to dashes when slicing the anthropic/ prefix. OpenAI is
unaffected because its native slugs already use dots (gpt-4.1). Cloudflare's
own catalog-aware REST endpoints (/ai/v1/messages, /ai/run) do this same
translation internally; the native passthrough route opencode uses does not,
so the plugin has to.

Verified end-to-end against a live gateway: anthropic/claude-haiku-4.5 goes
from "Error: model: claude-haiku-4.5" to a normal completion, with OpenAI and
Workers AI models unaffected.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Enough1122

Copy link
Copy Markdown

AI code review — automated review for reference, author can ignore or act on any point.

Correct diagnosis and a tidy fix: models.dev lists Anthropic ids dotted (claude-haiku-4.5) while the Messages passthrough forwards them verbatim, so every anthropic/* model under the gateway was doomed to a 404. The new e2e assertion pins both the endpoint (v1/messages) and the translated upstream slug (claude-haiku-4-5) — exactly the regression guard this needs.

Two suggestions:

  1. Extract the shared translation. The .replaceAll(".", "-") logic now exists verbatim in two places: the production loader (packages/opencode/src/provider/provider.ts, ~line 850) and the test harness's gatewayModel (cf-ai-gateway-e2e.test.ts, ~line 168). Mirrored helpers like this drift silently — if the rule ever changes (say, only version-position dots), the tests will keep validating the old behavior. Exporting something like anthropicNativeSlug(id) from the provider module and using it in both spots keeps the test honest.

  2. Document why replaceAll is safe. It works today because no native Anthropic slug contains a dot, so blanket replacement can't corrupt a legitimate id. The code comment explains the dotted→dashed direction well; half a sentence noting the inverse invariant ("no native slug contains '.', so global replacement is lossless here") would preempt someone generalizing this pattern to prefixes where dots are meaningful — e.g., the workers-ai/@cf/moonshotai/kimi-k2.6 family, where dotted ids are apparently accepted as-is on the unified route.

Minor: worth a quick sanity pass over the other first-party branches in custom() to confirm none of them have the same catalog-vs-native mismatch — this one only surfaced because Anthropic is strict about unknown model names.

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.

cloudflare-ai-gateway: Anthropic models 404 (dotted id not translated to Anthropic's dashed slug)

2 participants