Skip to content

feat(cloudflare-ai-gateway): derive models from live catalog + schema + docs - #4922

Merged
rekram1-node merged 10 commits into
anomalyco:devfrom
superhighfives:feat/cloudflare-aig-reconciler
Aug 25, 2026
Merged

feat(cloudflare-ai-gateway): derive models from live catalog + schema + docs#4922
rekram1-node merged 10 commits into
anomalyco:devfrom
superhighfives:feat/cloudflare-aig-reconciler

Conversation

@superhighfives

@superhighfives superhighfives commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

The cloudflare-ai-gateway model files used to come from a committed catalog snapshot plus a hand-maintained overrides.toml. That snapshot was ~8 months stale and the overrides restated a lot the APIs already know. This reworks the generator to derive everything it can from Cloudflare's own live sources and shrink human curation to the few things those sources genuinely can't express.

Three live sources now drive generation:

  • catalog (ai/catalog/models) - canonical dotted ids, cost (flat/tiered/cache), limits
  • per-model catalog schema - proxied reasoning_options for OpenAI-compat providers (xAI, Alibaba)
  • Workers-AI docs - hosted @cf detail + reasoning knobs

curation.toml replaces overrides.toml and holds only the irreducible: hosted base_model maps, live-tested structured_output (schema acceptance != conformance), reasoning_options for native-format providers the schema doesn't expose, and a skip list.

  • name/description now inherit from base_model instead of restating Cloudflare's casing
  • reasoning_options is gated on the base's reasoning flag (fixes both schema constraints)
  • structured_output for the new hosted models was verified live against the gateway
  • fetches are throttled with retry to avoid raw.githubusercontent rate limits

Net model delta: +24 new, -14 phantom OpenAI ids absent from the live catalog, 52 updated (77 total: 58 proxied + 29 hosted). bun validate passes; live --check matches committed output with zero drift.

Replace the legacy 4-script bash pipeline with a single catalog-aware
reconciler. It sources canonical dotted model ids and pricing from
Cloudflare's ai/catalog/models (proxied) and ai/models/search (hosted @cf/*),
and isolates all human curation in a committed overrides.toml.

- add packages/core/script/generate-cloudflare-ai-gateway.ts (fetch with
  fixture fallback, catalog/manual cost derivation, tiered pricing, --check
  mode; hard-fails on an unmapped Text-Generation catalog id)
- add providers/cloudflare-ai-gateway/overrides.toml (67 model entries +
  33-id skip list) as the sole hand-authored curation layer
- wire cloudflare-ai-gateway:generate; rewrite the provider README
- regenerate all 67 model stubs via the shared formatToml serializer;
  resolved model JSON is unchanged (compare:migrations clean, validate passes)
- remove the legacy scripts/ pipeline and stale data/ JSON

Leading source-citation comments on hand-authored files are dropped by
regeneration for now; modeling them as a structured notes field is a
documented follow-up.
… + docs

Replace overrides.toml with a 3-source reconciler: catalog for cost/limits,
per-model schema and Workers-AI docs for reasoning_options, curation.toml only
for base_model maps, live-tested structured_output, and native-provider
reasoning shapes. Inherit name/description from base_model.
@superhighfives superhighfives changed the title feat(cloudflare-ai-gateway): generate models from catalog + overrides feat(cloudflare-ai-gateway): derive models from live catalog + schema + docs Aug 18, 2026
@superhighfives
superhighfives marked this pull request as ready for review August 19, 2026 01:17
@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [high] [violation] providers/cloudflare-ai-gateway/models/workers-ai/@cf/deepseek-ai/deepseek-v4-pro-0813.toml:9 - Check: Reasoning options baseline for DeepSeek V4 (lab + same-surface peers). Why: Generated effort is low/medium/high, but first-party DeepSeek and providers/cloudflare-workers-ai for the same model use toggle + high/max (lab maps lower levels to high). Publishing L/M/H invents a GPT-style surface and misrepresents this host. Same shape is on deepseek-v4-flash-0731. Action: Derive or curate toggle + ["high","max"] (with a leading toggle wire comment), matching Workers AI / lab; do not accept schema enums that expand past the native set without host-specific proof.
  • [high] [violation] packages/core/script/generate-cloudflare-ai-gateway.ts:3346 - Check: Every toggle needs a leading top-of-file wire comment (AGENTS.md → Reasoning options). Why: deriveReasoningOptions / formatToml emit bare type = "toggle" with no wire path. That drops existing comments and ships new toggle models (hosted DeepSeek/Kimi/Gemma/Nemotron/GLM/Qwen, proxied Gemini/DeepSeek/Moonshot, Claude Sonnet 5) without the required thinking.type / enable_thinking / etc. documentation that sync stripping already makes fragile. Action: Preserve or inject leading toggle/effort wire comments for every toggle model (curation field, post-format header, or non-stripped notes), including regenerated hosted files that previously had them.
  • [high] [violation] packages/core/script/generate-cloudflare-ai-gateway.ts:3491 - Check: Provider-only fields (interleaved) must remain when this API exposes a reasoning side channel. Why: Hosted build never copies interleaved, so the PR removes interleaved / reasoning_content from models that still have it on Workers AI peers (kimi-k2.6, glm-4.7-flash, gemma-4-26b-a4b-it, nemotron-3-120b-a12b). That is a capability regression for the same @cf surface. Action: Preserve existing interleaved (or derive/curate it) for hosted reasoners that return a side-channel field; stop wiping it on regenerate.
  • [high] [possible mistake] providers/cloudflare-ai-gateway/models/alibaba/qwen3.7-plus.toml:4 - Check: Relay reasoning baseline for Alibaba/Qwen (lab + peers), not a fixed GPT effort enum. Why: Proxied Qwen reasoners are authored as effort none/low/medium/high from the catalog schema, while first-party Alibaba is typically toggle + budget_tokens (and Qwen3.8 Max is toggle + effort + budget). Schema acceptance of reasoning_effort is not the same as this gateway’s real control set. Action: Verify AI Gateway’s actual request fields for these models; if native-style, curate lab/peer shapes instead of schema-derived L/M/H; if OpenAI-compat effort is truly the only surface, document that host-specific evidence in curation and drop unsupported levels.
  • [medium] [possible mistake] providers/cloudflare-ai-gateway/models/workers-ai/@cf/openai/gpt-oss-20b.toml:7 - Check: [] means no caller control; do not invent effort from an incomplete schema. Why: Prior gateway/Workers AI entries and comments state native /ai/run has no reasoning control (reasoning_options = []). This PR changes gpt-oss-20b to effort low/medium/high while Workers AI still documents empty controls. Action: Confirm a real, effective control on AI Gateway/docs; if none, keep [] and prevent the docs walker from promoting unverified enums.
  • [medium] [possible mistake] providers/cloudflare-ai-gateway/models/xai/grok-4.6.toml:5 - Check: Effort values must match lab/first-party when the host is a passthrough. Why: First-party xAI Grok 4.6 uses low/medium/high/xhigh; generated gateway entry drops xhigh to L/M/H only. Same risk on other schema-derived Grok rows if the enum is truncated. Action: Align with xAI (include xhigh if the gateway forwards it) or cite gateway-only evidence for the narrower set.
  • [medium] [possible mistake] providers/cloudflare-ai-gateway/models/deepseek/deepseek-v4-pro.toml:4 - Check: DeepSeek V4 relay controls should not drop graded effort without host proof. Why: Curation sets toggle-only (citing merge-gateway), but lab and Cloudflare Workers AI expose toggle + high/max. Toggle-only is only valid if AI Gateway cannot forward effort. Action: Verify the proxied DeepSeek path; if effort is forwarded, curate toggle + ["high","max"] with wire comments; if not, keep toggle-only and document the wire path.
  • [medium] [possible mistake] packages/core/script/generate-cloudflare-ai-gateway.ts:3519 - Check: Host-specific limit.output must not be silently discarded. Why: Hosted generation writes only context_window, so previous host output caps (e.g. gpt-oss 16_384, many @cf equal context/output limits) fall back to lab limit.output via merge—often larger than the Workers AI deployment. Action: Prefer docs/catalog max-output when present; otherwise preserve prior provider limit.output (as cloudflare-workers-ai sync does) instead of dropping it.
  • [low] [possible mistake] providers/cloudflare-ai-gateway/models/anthropic/claude-haiku-4.5.toml:12 - Check: Catalog max_output_tokens vs lab/first-party limits. Why: Generated output = 8_192 while lab/Anthropic Haiku 4.5 is 64_000. If the catalog field is completion default rather than max, the gateway entry understates capacity. Action: Confirm against Cloudflare catalog meaning/docs; if wrong, curate the real max or stop writing output from that field.

…d output limits per lab/peer baselines

The generator was deriving reasoning_options straight from catalog/docs schema enums instead of
matching each host's real native controls, silently dropping interleaved fields and toggle wire
comments on every regen, and writing limit.output from a catalog field that's verified wrong
against lab/first-party for several models (gpt-5.5, claude-haiku-4.5, gpt-oss-20b, and more).

- curation.toml gains interleaved and note (leading wire-path comment) fields; both proxied and
  hosted loops now consult them
- proxied/hosted limit.output no longer derives from an unreliable field — curated only, so it
  correctly inherits from base_model when not host-specific
- restored the hand-verified reasoning_options/interleaved/output/wire-comments that existed
  before this rework for gpt-oss-20b/120b, gemma-4-26b-a4b-it, kimi-k2.6, nemotron-3-120b-a12b,
  glm-4.7-flash, glm-5.2, and backfilled limit.output for every other previously-verified @cf model
- fixed proxied deepseek-v4-pro, qwen3.7-plus, and grok-4.6 to match their lab/first-party
  reasoning controls instead of a generic schema-derived effort enum

Verified live against Cloudflare (bun run cloudflare-ai-gateway:generate --check passes, bun
validate passes).

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

Copy link
Copy Markdown
Contributor Author

Addressed the action items from the bot review in 4672743. Verified everything against providers/*/models, models/* (lab canon), peer cloudflare-workers-ai/merge-gateway entries, and pre-rework git history (commit 734f5bf), then re-ran the generator live against Cloudflare (bun run cloudflare-ai-gateway:generate --check passes, bun validate passes).

  1. deepseek-v4-pro-0813 (hosted) — fixed: curated toggle + ["high","max"] with the wire-path comment, matching the cloudflare-workers-ai peer exactly.
  2. Toggle wire comments — fixed generically: added note (leading # comment lines) and interleaved fields to curation.toml's schema; both the proxied and hosted generator loops now emit them. Restored the pre-rework comments for gpt-oss-20b/120b, gemma-4-26b-a4b-it, kimi-k2.6, nemotron-3-120b-a12b, glm-5.2, and added new ones for the newly-curated proxied DeepSeek/Qwen entries.
  3. interleaved dropped on hosted regen — fixed: restored interleaved for gemma-4-26b-a4b-it, kimi-k2.6, nemotron-3-120b-a12b, and glm-4.7-flash (confirmed these came from curation, not the lab file, which has no interleaved at all — so it's genuinely host-specific and can't be inherited).
  4. qwen3.7-plus effort baseline — fixed: providers/alibaba/models/qwen3.7-plus.toml (first-party) uses toggle + budget_tokens, not graded effort. Curated to match.
  5. gpt-oss-20b [] vs schema-derived effort — fixed: restored the hand-verified reasoning_options = [] (also applied to gpt-oss-120b, same shape, same regression).
  6. grok-4.6 missing xhigh — fixed: added xhigh to match providers/xai/models/grok-4.6.toml.
  7. deepseek-v4-pro (proxied) toggle-only — fixed: the toggle-only precedent was merge-gateway's own live-tested route constraint, not evidence about Cloudflare's gateway. Absent host-specific proof Cloudflare drops the effort field, matched lab/Workers-AI baseline: toggle + ["high","max"].
  8. limit.output dropped on hosted regen — fixed generically: hosted output limit is curation-only now (docs don't expose it, and it's frequently lower than the lab's SaaS cap — e.g. gpt-oss-20b hosted caps at 16,384 vs the lab's 32,768). Backfilled the pre-rework value for every previously-verified hosted model (22 total).
  9. claude-haiku-4.5 output 8,192 vs 64,000 — fixed at the root: the catalog's max_output_tokens field is not a reliable ceiling for proxied models either — cross-checked and also verified wrong for gpt-5 and gpt-5.5 (both understated 4-8x vs lab/first-party). Removed that derivation entirely; proxied limit.output is now curation-only or inherited from base_model, matching how merge-gateway/openrouter handle the same models.

Diff: 63 files, mostly proxied limit.output removals (now correctly inheriting from lab) plus the curation.toml additions/restorations above.

@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [high] [violation] providers/cloudflare-ai-gateway/models/alibaba/qwen3.5-397b-a17b.toml:3 - Check: Relay reasoning_options must match the lab/same-surface baseline, not a generic OpenAI-compat enum. Why: Final files use effort none|low|medium|high for qwen3.5-397b-a17b, qwen3.7-max, and qwen3.8-max. Lab Alibaba is toggle + budget_tokens (and qwen3.8-max adds effort low|medium|xhigh + budget), so callers get the wrong control surface. Action: Curate those three like qwen3.7-plus (wire note + lab-shaped options) and stop accepting schema-derived L/M/H for Alibaba reasoners.
  • [high] [violation] providers/cloudflare-ai-gateway/models/google/gemini-3.5-flash-lite.toml:4 - Check: Google Gemini reasoning controls must match first-party providers/google/. Why: Final gateway files set gemini-3.5-flash-lite and gemini-3.6-flash to toggle-only and gemini-3.7-flash to [], while lab entries use graded effort (minimal|low|medium|high / low|medium|high). Empty/toggle-only misstates caller control. Action: Align curation.toml + generated TOMLs with lab effort sets (or document host-specific Cloudflare proof if intentionally different).
  • [high] [violation] providers/cloudflare-ai-gateway/models/moonshotai/kimi-k3.toml:3 - Check: Moonshot Kimi K3 baseline is toggle + effort. Why: Gateway file is toggle-only; lab providers/moonshotai/models/kimi-k3.toml is toggle + effort low|high|max with a wire comment. Action: Curate toggle + low|high|max and a leading wire-path note.
  • [high] [violation] providers/cloudflare-ai-gateway/models/workers-ai/@cf/deepseek-ai/deepseek-v4-flash-0731.toml:7 - Check: DeepSeek V4 Flash effort baseline is not GPT L/M/H. Why: Final file still has schema-derived effort low|medium|high; lab Flash is toggle + low|high|max (and Pro was correctly fixed to high|max). Action: Curate Flash like the lab/Pro fix (toggle + low|high|max + wire note).
  • [high] [violation] providers/cloudflare-ai-gateway/models/xai/grok-4.20-0309-reasoning.toml:3 - Check: Always-on reasoners must not invent graded effort. Why: Gateway publishes effort low|high while first-party xAI is reasoning_options = [] (no caller control). Action: Set [] (or prove Cloudflare exposes a real effort API on this id).
  • [high] [violation] providers/cloudflare-ai-gateway/models/workers-ai/@cf/zai-org/glm-5.2.toml:5 - Check: GLM reasoning options must match lab/peer baselines. Why: Hosted GLM-5.2 uses toggle + low|medium|high; lab Zhipu is effort high|max only (no toggle). Hosted GLM-4.7-flash uses toggle + L/M/H while lab is toggle-only. Action: Align both with lab shapes (or Cloudflare-docs-backed host deltas), including toggle wire notes where toggle remains.
  • [medium] [violation] providers/cloudflare-ai-gateway/models/anthropic/claude-sonnet-5.toml:4 - Check: Every toggle needs a leading top-of-file wire-path comment. Why: claude-sonnet-5, hosted gemma/kimi/nemotron/glm toggles, and other toggle models ship without # Toggle: … notes (only a subset got note in patch 3). Action: Add curated note lines for every toggle-bearing model the generator emits.
  • [medium] [possible mistake] providers/cloudflare-ai-gateway/models/openai/gpt-5.6-sol.toml:5 - Check: Catalog-derived pricing should not silently diverge from OpenAI/peer USD rates without evidence. Why: Patch 3 changes Sol from 5/30 (+ cache/tiers matching OpenAI) to 2/10 / 0.25 / 3.125 and drops tiers; OpenAI first-party remains 5/30. Action: Confirm Cloudflare catalog really bills Sol at that rate; if not, restore OpenAI-aligned pricing/tiers or cite the Cloudflare price source in curation.
  • [medium] [possible mistake] providers/cloudflare-ai-gateway/models/workers-ai/@cf/qwen/qwen3.8-27b.toml:6 - Check: Hosted Qwen3.8-27B options should not invent L/M/H without host proof. Why: Derived toggle + low|medium|high has no first-party Alibaba provider file for this id; OpenRouter peer is toggle + effort with different values, and lab metadata does not define the control surface. Action: Curate from Cloudflare docs/live wire behavior (or a verified peer), and add a toggle wire note.

…t lab/peer baselines

Second pass on bot review feedback: several proxied and hosted models were still using
schema-derived L/M/H effort instead of matching their real native controls.

- alibaba/qwen3.5-397b-a17b, qwen3.7-max, qwen3.8-max: toggle + budget_tokens (qwen3.8-max
  also gets low|medium|xhigh effort + interleaved), matching first-party Alibaba shapes
- google/gemini-3.5-flash-lite, gemini-3.6-flash, gemini-3.7-flash: restored graded lab effort
  instead of a toggle-only/[] shape copied from merge-gateway without host-specific evidence
- moonshotai/kimi-k3 (proxied), workers-ai/@cf/deepseek-ai/deepseek-v4-flash-0731,
  workers-ai/@cf/qwen/qwen3.8-27b: corrected effort values to match lab/peer instead of a
  generic enum (deepseek-v4-flash-0731 matches its same-@cf-id cloudflare-workers-ai peer,
  which is host-specific evidence trumping the general lab set)
- workers-ai/@cf/moonshotai/kimi-k2.7-code, xai/grok-4.20-0309-reasoning: restored
  reasoning_options = [] (always-on, no caller control) per first-party lab files
- workers-ai/@cf/zai-org/glm-5.2: effort high|max only (no toggle) + interleaved, matching lab;
  glm-4.7-flash kept its existing toggle+effort shape but gained the wire note, since its
  cloudflare-workers-ai peer cites docs-verified evidence for that host-specific delta
- added missing toggle wire-path notes (claude-sonnet-5, gemini-2.5-flash/-lite budget models)

Left providers/cloudflare-ai-gateway/models/openai/gpt-5.6-sol.toml unchanged: its cheaper
non-tiered pricing is live and correct — Cloudflare's catalog carries an active "50% off
through Sept 18" promotional banner for this model, confirmed via direct API query.

bun run cloudflare-ai-gateway:generate --check and bun validate both pass.

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

Copy link
Copy Markdown
Contributor Author

Addressed the second round of action items in c960980. bun run cloudflare-ai-gateway:generate --check and bun validate both pass; test suite shows the same 4 pre-existing unrelated failures as dev (DeepInfra sync test, sdk snapshot build artifact — untouched by this PR).

  1. qwen3.5-397b-a17b / qwen3.7-max / qwen3.8-max — fixed: curated toggle + budget_tokens per providers/alibaba/models/qwen3.7-plus.toml's established shape; qwen3.8-max additionally gets effort [low,medium,xhigh] + budget + interleaved, matching its own first-party file exactly (it has a fuller documented API than the other two).
  2. gemini-3.5-flash-lite / 3.6-flash / 3.7-flash — fixed: restored graded lab effort instead of the toggle-only/[] shape. That shape was copied from merge-gateway, but unlike merge-gateway's DeepSeek entry (which cites a live-tested "selected route" comment), its Gemini entries cite no host-specific evidence — so it wasn't proof of Cloudflare's behavior, just an unverified copy.
  3. kimi-k3 — fixed: toggle + effort [low,high,max] + wire note, matching providers/moonshotai/models/kimi-k3.toml.
  4. deepseek-v4-flash-0731 (hosted) — fixed, but to toggle + ["high","max"] rather than the low|high|max you suggested: the same @cf id's cloudflare-workers-ai entry (identical deployment, not just "a peer") is curated to high|max specifically, which is stronger host-specific evidence than the general DeepSeek lab shape for this exact hosted surface.
  5. grok-4.20-0309-reasoning — fixed: restored reasoning_options = [] per providers/xai/models/grok-4.20-0309-reasoning.toml (always-on, no control).
  6. glm-5.2 / glm-4.7-flash (hosted) — glm-5.2 fixed to effort [high,max] (no toggle) + added interleaved, matching lab. glm-4.7-flash's shape was left as toggle+L/M/H and only gained the wire note — its cloudflare-workers-ai peer file cites Cloudflare's own docs schema (sync-input.json) verifying that exact shape, which is a documented host-specific delta from the lab default, not an unverified guess.
  7. Missing toggle notes — added for claude-sonnet-5 (sourced from the azure-cognitive-services peer's already-verified output_config.effort wire path for this same model) and both gemini-2.5-flash/-flash-lite budget models.
  8. gpt-5.6-sol pricing — left unchanged: queried Cloudflare's catalog API directly and the model carries an active promotional banner ("GPT-5.6 Sol is 50% off through Sept 18"), so $2/$10 flat is genuinely live pricing, not tiers being silently dropped. It'll re-diverge back toward $5/$30 once the promo ends and the catalog updates.
  9. qwen3.8-27b (hosted) — fixed: toggle + effort [low,medium,xhigh] (not L/M/H) + wire note, matching the OpenRouter peer and the qwen3.8-max family's documented low|medium|xhigh convention (no first-party Alibaba file exists for this specific id).

Also proactively fixed one more instance of the same defect I found while verifying #3's neighbor: kimi-k2.7-code (hosted) had the same schema-derived toggle+L/M/H invented over its first-party reasoning_options = [] (always-on) — restored to [].

Cloudflare fronts Anthropic and OpenAI with native passthrough routes (the
Messages and Responses APIs), not the gateway's generic openai-compatible
transform. Emit [provider] npm per model for those two families so consumers
route to the endpoint that serves them best instead of inheriting the provider
default (ai-gateway-provider). Workers AI and the compat-only third parties keep
the default.

Restores the @ai-sdk/anthropic signal the generator rewrite dropped.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [high] [violation] packages/core/script/generate-cloudflare-ai-gateway.ts / providers/cloudflare-ai-gateway/curation.toml - Check: Host-specific capability deltas must stay override-only and must not silently re-inherit lab values the same @cf surface already disproved. Why: The generator only ever sets tool_call/attachment when docs say true, and curation.toml cannot author tool_call, attachment, or modalities. That drops previously verified host disables, so several Workers AI gateway entries now inherit lab capabilities the same @cf peer still marks false. Action: Extend curation + generation to allow explicit tool_call, attachment, and modalities overrides, then restore at least: workers-ai/@cf/meta/llama-3.1-8b-instruct-fp8 tool_call = false; workers-ai/@cf/meta/llama-3.2-11b-vision-instruct tool_call = false; workers-ai/@cf/qwen/qwen2.5-coder-32b-instruct tool_call = false; workers-ai/@cf/qwen/qwq-32b tool_call = false; workers-ai/@cf/meta/llama-3.3-70b-instruct-fp8-fast attachment = false; workers-ai/@cf/mistralai/mistral-small-3.1-24b-instruct attachment = false and text-only [modalities] (match providers/cloudflare-workers-ai peers).
  • [high] [violation] providers/cloudflare-ai-gateway/models/thinkingmachines/inkling.toml:2 - Check: Relay reasoning_options must match lab/first-party controls unless this host has affirmative evidence of no caller control. Why: Final file sets reasoning_options = [], but first-party providers/thinkingmachines/models/thinkingmachines/Inkling.toml exposes toggle + effort low|medium|high|xhigh|max. Empty means “no control,” not “unverified,” and no Cloudflare-specific note justifies narrowing. Action: Align with the lab shape (and leading toggle wire comment), or keep [] only with a leading host-evidence note that Cloudflare’s route truly has no reasoning control.
  • [medium] [possible mistake] providers/cloudflare-ai-gateway/models/thinkingmachines/inkling.toml:10 - Check: Provider limit.output should not inherit an oversized lab ceiling when peers already document a much smaller served cap. Why: Only context = 64_000 is written, so limit.output inherits lab 1_048_576; first-party Thinking Machines serves 65_536. That likely overstates Cloudflare’s ceiling the same way uncurated @cf output did before. Action: Verify Cloudflare’s actual max output for this id and curate limit.output if it is not the lab million-token value.
  • [low] [possible mistake] providers/cloudflare-ai-gateway/models/openai/gpt-5.5.toml - Check: Catalog-derived costs should not drop established cache/tier pricing without host evidence. Why: Final cost is flat input = 5 / output = 30 with no cache_read and no 272k tier, while first-party OpenAI and peers keep cache + tiered rates. If the live catalog omits them, say so; if it includes them, generation is dropping data. Action: Confirm Cloudflare catalog pricing for openai/gpt-5.5 (and similar GPT-5.4/5.5/5.6 family entries) and restore cache/tiers when present, or document the catalog-only flat rate in a leading note.

…imit deltas

Curation could not author tool_call/attachment/modalities, so several Workers AI
@cf entries silently re-inherited lab capabilities the same @cf peer marks false.
Extend the curation schema + hosted generation to carry those host disables, and
restore them for the six affected models (matching cloudflare-workers-ai peers).

Align thinkingmachines/inkling reasoning_options with the lab toggle+effort shape
(with the required wire-path note), and curate its served output ceiling (65_536)
instead of inheriting the lab canon's 1M. Proxied limit now merges catalog context
with curated fields so context stays catalog-derived.

Regenerated live; gpt-5.5's flat catalog pricing (no cache/tier) confirmed as what
Cloudflare's catalog returns, not dropped data.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@superhighfives

Copy link
Copy Markdown
Contributor Author

Addressed the action items in 384873b (regenerated live against Cloudflare; bun validate passes):

  1. [high] Workers AI capability deltas — extended the curation schema + hosted generation to author tool_call / attachment / modalities (docs only ever advertise capabilities as true, so a curated explicit value now overrides). Restored the verified host disables to match the cloudflare-workers-ai peers: tool_call = false on llama-3.1-8b-instruct-fp8, llama-3.2-11b-vision-instruct, qwen2.5-coder-32b-instruct, qwq-32b; attachment = false on llama-3.3-70b-instruct-fp8-fast; attachment = false + text-only [modalities] on mistral-small-3.1-24b-instruct.

  2. [high] thinkingmachines/inkling reasoning — aligned with the lab shape: toggle + effort low|medium|high|xhigh|max, with the required leading wire-path note (thinking.type = adaptive|disabled, output_config.effort).

  3. [medium] inkling limit.output — curated the first-party served ceiling 65_536 instead of inheriting the lab canon 1_048_576. Also made the proxied limit derivation merge catalog context with curated fields (matching the hosted loop), so context stays catalog-derived while output is curated.

  4. [low] gpt-5.5 cost — confirmed via the live regen: Cloudflare's catalog returns only flat input/output for gpt-5.5 (no cache_read, no 272k tier), and cost is derived straight from that catalog pricing — so the flat rate is catalog-accurate, not dropped data. Same for the GPT-5.4/5.5/5.6 family.

@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [high] [violation] providers/cloudflare-ai-gateway/curation.toml (workers-ai/@cf/deepseek-ai/deepseek-r1-distill-qwen-32b) - Check: Host capability disables must match the same @cf Workers AI peer when that peer is the deployment evidence. Why: Patch 6 restored several tool_call = false / attachment = false deltas from cloudflare-workers-ai, but this model still omits them. The peer file sets tool_call = false; the lab base is also tool_call = false for the distill id, while the gateway entry can still pick up a true value if docs advertise function calling (or if inheritance differs). Leaving it uncured reintroduces the exact silent re-inherit bug the last commit claims to fix. Action: Add tool_call = false (and any other peer-verified host disables) for this id in curation.toml and regenerate the model TOML.
  • [high] [possible mistake] providers/cloudflare-ai-gateway/models/workers-ai/@cf/moonshotai/kimi-k2.7-code.toml / curation.toml - Check: Relay reasoning_options = [] only when the host truly has no caller control; do not use [] from uncertainty when lab/same-surface peers expose controls. Why: Curation forces reasoning_options = [] from the first-party Moonshot file, but the same @cf id on cloudflare-workers-ai authors toggle + effort low|medium|high. Empty means “no caller control,” not “prefer lab over an explicit same-host peer.” Action: Align with the Workers AI peer (toggle + effort + wire-path note), or cite host-specific evidence that the AI Gateway @cf route rejects those controls and keep [] only with that proof.
  • [medium] [possible mistake] providers/cloudflare-ai-gateway/models/workers-ai/@cf/zai-org/glm-5.2.toml / curation.toml - Check: Hosted @cf reasoning baseline should prefer same-surface peer evidence over a generic lab shape when they conflict. Why: Final shape is lab effort high|max (no toggle). The same @cf peer on cloudflare-workers-ai is toggle + low|medium|high. That is the same class of host delta the PR accepts for glm-4.7-flash, but rejects here because the peer header only mentions limits. Action: Either match the Workers AI peer controls (with a toggle wire note) or document live/schema proof that this @cf deployment only accepts high|max effort.
  • [medium] [possible mistake] providers/cloudflare-ai-gateway/curation.toml (Alibaba proxied: qwen3.5-397b-a17b, qwen3.7-max, qwen3.7-plus, qwen3.8-max) - Check: Multi-model relay options must be the intersection this host actually exposes, not a full first-party lab paste when the host schema differs. Why: The generator’s own catalog schema path derived OpenAI-compat reasoning_effort enums for these ids; curation replaces that with Alibaba-native enable_thinking + thinking_budget (and hybrid effort on qwen3.8-max). AI Gateway third-party routes are largely OpenAI-compat (provider.toml), so lab DashScope wire paths may not be what Cloudflare fronts. Action: Confirm on the Cloudflare Alibaba/OpenAI-compat route which fields work (enable_thinking / thinking_budget vs reasoning_effort), then keep only the verified host surface (and matching note lines).

The gateway entries don't support tiered pricing, so keep only the base/default-
context rate and drop the higher-context [[cost.tiers]] bands (google gemini-3.x
flash, xai grok-4.5/4.6). The lower band was already folded into the flat rate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [high] [possible mistake] providers/cloudflare-ai-gateway/models/workers-ai/@cf/openai/gpt-oss-120b.toml - Check: Relay reasoning_options must follow the same-surface peer baseline (AGENTS.md → Reasoning options). Why: This PR sets reasoning_options = [] (no caller control), but the same @cf deployment in providers/cloudflare-workers-ai/models/@cf/openai/gpt-oss-120b.toml authors effort = low|medium|high. Empty means affirmative no control, not uncertainty, and contradicts the established same-host peer. Action: Align with the workers-ai peer (low/medium/high) unless you have Cloudflare-AI-Gateway-specific proof that this path drops effort; if so, document that host delta in the leading note and explain why the peer is wrong.
  • [medium] [possible mistake] providers/cloudflare-ai-gateway/models/deepseek/deepseek-v4-pro.toml - Check: Provider-authored interleaved when this host returns reasoning on a side channel. Why: Final file has toggle + high/max but no interleaved, while first-party DeepSeek and OpenRouter peers set interleaved.field = "reasoning_content". Omitting it understates the gateway wire shape for a multi-model relay of DeepSeek V4. Action: Add interleaved = { field = "reasoning_content" } in curation.toml (and regenerate) unless Cloudflare’s DeepSeek route does not emit a separate reasoning field—then note that host delta.
  • [medium] [possible mistake] providers/cloudflare-ai-gateway/models/moonshotai/kimi-k3.toml - Check: Same interleaved baseline as the lab host. Why: Lab providers/moonshotai/models/kimi-k3.toml sets interleaved.field = "reasoning_content" with toggle + low/high/max. The gateway entry matches the effort shape but drops interleaved. Action: Add the interleaved field via curation, or document why this Cloudflare route does not expose it.
  • [medium] [possible mistake] providers/cloudflare-ai-gateway/models/thinkingmachines/inkling.toml - Check: Reasoning controls must match this host’s real API, not an unverified third-party surface. Why: The PR authors Tinker-style thinking.type = adaptive|disabled + output_config.effort = low|medium|high|xhigh|max, but established peers disagree (OpenRouter: effort including none; merge-gateway: []; Neon: different effort set). There is no Cloudflare catalog/docs citation in the PR that the gateway fronts Inkling via Tinker’s Anthropic-compatible path. Action: Cite Cloudflare-specific wire evidence for this model, or rewrite reasoning_options/note to a peer-supported shape for the actual CF route.
  • [medium] [violation] packages/core/script/generate-cloudflare-ai-gateway.ts (proxied limit write) - Check: After base_model, provider files must stay override-only—do not restate identical inherited values (AGENTS.md → Override-only provider files). Why: The generator always writes limit.context from the catalog even when it equals the lab base (e.g. Anthropic Haiku 4.5 200_000), producing redundant [limit] blocks on many regenerated stubs. Action: Only emit limit keys that differ from the resolved base_model (or are host-required deltas such as curated output), then regenerate.
  • [low] [possible mistake] providers/cloudflare-ai-gateway/models/xai/grok-4.5.toml / .../grok-4.6.toml - Check: Catalog-derived cost should not silently drop real context tiers. Why: Patch 7 strips all higher-context [[cost.tiers]] under a global “gateway doesn’t support tiered pricing” claim, while first-party xAI still prices >200k at 2×. If Cloudflare still bills the higher band, flat rates understate cost above 200k. Action: Confirm against Cloudflare’s live catalog/pricing for these ids; restore tiers if present, or keep a top-of-file note that CF publishes only the base band.

Workers AI (@cf/...) is a different pathway from the proxied third-party models -
hosted on Cloudflare, CF-token auth, per-model agreements - and already has its own
provider (cloudflare-workers-ai). Mirroring it here mixed two pathways in one
provider for no benefit, so drop the hosted @cf set and the generator's hosted path
(search API, cloudflare-docs fetch, hostedCost/hostedProp). The provider is now
proxied third-party models only.

Also skip thinkingmachines/inkling: it is BYOK-only on the gateway (not available
via unified billing), so it can't be invoked the way the other proxied models are.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [medium] [violation] providers/cloudflare-ai-gateway/models/deepseek/deepseek-v4-pro.toml:1 - Check: Relay reasoning side-channel / lab+peer baseline for DeepSeek V4. Why: Lab first-party and established relays (providers/deepseek/models/deepseek-v4-pro.toml, OpenRouter, merge-gateway) set interleaved.field = "reasoning_content" for this model; the new gateway entry only authors toggle+effort and omits interleaved, so consumers lose the documented reasoning side channel on a multi-model relay. Action: Add interleaved = { field = "reasoning_content" } in curation.toml for deepseek/deepseek-v4-pro (with regen) unless you have host-specific evidence Cloudflare does not expose it.
  • [medium] [violation] providers/cloudflare-ai-gateway/models/moonshotai/kimi-k3.toml:1 - Check: Relay baseline for Kimi K3 interleaved reasoning. Why: First-party providers/moonshotai/models/kimi-k3.toml sets interleaved.field = "reasoning_content" with the same toggle+effort controls this PR already copied; the gateway file omits interleaved. Action: Author interleaved = { field = "reasoning_content" } via curation and regenerate, or document host-specific evidence that this path has no side channel.
  • [medium] [possible mistake] providers/cloudflare-ai-gateway/models/deepseek/deepseek-v4-pro.toml ([limit].context) - Check: Catalog-derived limit.context vs lab/peer served context. Why: Generated context = 131_072 is ~8× below lab metadata and OpenRouter peers (~1_048_576 / 1_000_000). If the live catalog value is truncated or wrong, this understates the gateway context window. Action: Confirm Cloudflare ai/catalog/models really reports 131072 for this id; if the gateway serves the full window, curate the correct context (and note the source).
  • [medium] [possible mistake] providers/cloudflare-ai-gateway/models/anthropic/claude-sonnet-4.6.toml ([limit].output) - Check: Host limit.output override vs lab. Why: Curation forces output = 128_000 while models/anthropic/claude-sonnet-4-6.toml is 64_000. Output is no longer auto-derived (catalog max_output was rejected as unreliable), so this must be a verified gateway ceiling, not a leftover. Action: Verify the gateway’s real max output for this model; if it matches the lab, drop the curated output override so inheritance applies.
  • [low] [violation] providers/cloudflare-ai-gateway/curation.toml ([models."thinkingmachines/inkling"]) - Check: Curation only for models the generator emits. Why: Commit 8 skips thinkingmachines/inkling (BYOK-only) and deletes the model TOML, but the full curation block (note / reasoning_options / limit) remains and is never applied (skip continues before curation is read). Action: Remove the dead [models."thinkingmachines/inkling"] entry; keep only the skip list entry.

grok-4.6's reasoning_effort was curated as low|medium|high|xhigh from the first-party
xAI API, but the Cloudflare gateway route rejects xhigh (verified live: code 7003,
'expected one of low|medium|high'). Match what the CF route actually accepts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@superhighfives

Copy link
Copy Markdown
Contributor Author

For traceability — the opencode side that makes this catalog usable in the CLI:

Both were validated by exercising every model in this provider (base + each reasoning-effort variant) through opencode against a live Cloudflare gateway. That pass also caught a curation bug fixed here in bbb7276: Cloudflare's grok-4.6 route rejects xhigh (accepts only low|medium|high), though the first-party xAI API allows it.

@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [medium] [violation] providers/cloudflare-ai-gateway/models/deepseek/deepseek-v4-pro.toml / providers/cloudflare-ai-gateway/models/moonshotai/kimi-k3.toml / providers/cloudflare-ai-gateway/curation.toml - Check: Provider-authored interleaved when this host returns reasoning on a side channel (AGENTS.md provider-only fields; lab + same-surface peers). Why: First-party providers/deepseek/models/deepseek-v4-pro.toml and providers/moonshotai/models/kimi-k3.toml both set interleaved.field = "reasoning_content", and OpenRouter’s DeepSeek V4 Pro peer does too. This PR adds those reasoners with toggle/effort (and wires notes) but never authors interleaved, while it does for alibaba/qwen3.8-max. Consumers will miss the reasoning side channel on the gateway. Action: Add interleaved = { field = "reasoning_content" } in curation.toml for deepseek/deepseek-v4-pro and moonshotai/kimi-k3 (and any other proxied reasoner whose lab/peer wire uses it), regenerate, and confirm the gateway actually returns that field.
  • [medium] [violation] packages/core/script/generate-cloudflare-ai-gateway.ts (proxied limit build) - Check: Override-only base_model files — do not restate identical [limit] values (AGENTS.md → Override-only / redundant overrides blocker). Why: The generator always writes limit.context from the catalog. When that matches the lab base (e.g. google/gemini-3.5-flash 1_048_576, xai/grok-4.5/4.6 500_000, many Anthropic 200_000/1_000_000 contexts), committed TOMLs restate an unchanged nested field. That breaks override-only factoring and will keep regenerating noise. Action: Compare catalog context_length to the resolved base_model limit.context and omit it when equal; only emit limit keys that are real host deltas (same for any other auto-derived field that can match base).
  • [medium] [possible mistake] providers/cloudflare-ai-gateway/curation.toml (alibaba/qwen3.5-397b-a17b, qwen3.7-max, qwen3.7-plus, qwen3.8-max) - Check: Relay reasoning_options must match this host’s control surface; do not invent budget_tokens unless the host (or a clear native proxy) exposes a real reasoning budget (AGENTS.md / audit-reasoning-options). Why: The generator comments and README treat Alibaba’s catalog schema as OpenAI-compatible and derive reasoning_effort enums from it, but curation forces lab-native toggle + budget_tokens (enable_thinking / thinking_budget). If the gateway only accepts the OpenAI-compat effort field (as the schema derivation path implies), published options will not match the live wire. Action: Live-test each Alibaba id on the gateway for enable_thinking/thinking_budget vs reasoning_effort; keep lab-shaped options only if those fields work, otherwise author the CF-accepted set (and wire notes) and drop unsupported budget_tokens.
  • [low] [possible mistake] .pr-review/pull-request.json (PR body) / providers/cloudflare-ai-gateway/curation.toml (thinkingmachines/inkling) - Check: PR evidence and curation stay aligned with the final tree. Why: The PR body still describes hosted @cf derivation and a large hosted model delta, but patch 8 drops all Workers AI models and scopes the provider to proxied third parties only. curation.toml still carries a full thinkingmachines/inkling block after that model was moved to skip and its TOML deleted, so the entry is dead weight. Action: Update the PR body to the final proxied-only scope and net deltas, and remove the unused thinkingmachines/inkling curation section (keep the skip entry if still desired).

Gemini's API rejects any request whose message list ends on an assistant turn
(verified live: gemini-3.7-flash returns code 7003, gemini-3.5-flash returns 2002),
which is exactly what opencode's agent loop sends when checking for further tool
calls. Every Gemini model fails under that condition, so skip the whole google/*
set until the client sends Gemini-compatible message sequences. Routing itself is
fine — this is a message-format incompatibility, not a gateway issue.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [high] [possible mistake] providers/cloudflare-ai-gateway/curation.toml / models/alibaba/*.toml - Check: Relay reasoning_options must match this host’s request surface (lab + same-surface peers), not invent another API’s knobs. Why: The generator treats Alibaba as OpenAI-compat schema (reasoning_effort enums), and the PR live-corrected Grok when CF rejected lab-only values—but Alibaba was overridden to first-party toggle + budget_tokens / hybrid effort (enable_thinking, thinking_budget) without equivalent CF-route proof. If the gateway only forwards OpenAI-compat effort, published controls and wire notes will be wrong for qwen3.5-397b-a17b, qwen3.7-max, qwen3.7-plus, and qwen3.8-max. Action: Live-verify which fields CF accepts on the Alibaba path; set reasoning_options (and notes) to that surface. Prefer catalog/schema effort when that is what CF exposes; keep lab toggle/budget only with host evidence.
  • [medium] [possible mistake] providers/cloudflare-ai-gateway/models/xai/grok-4.5.toml / grok-4.6.toml - Check: Catalog pricing should preserve real context tiers as [[cost.tiers]] when the source bills them. Why: Commit drops higher-context bands (e.g. 200k → 2× input/output) and keeps only the lower band, claiming tiers are unsupported. If CF still charges the catalog’s upper band, long-context Grok costs are understated. Action: Confirm CF billing for context >200k; restore tiers when charged, or document host-flat pricing evidence in curation if CF truly never applies the upper band.
  • [medium] [possible mistake] providers/cloudflare-ai-gateway/models/deepseek/deepseek-v4-pro.toml - Check: Provider interleaved when this host returns reasoning on a side channel. Why: First-party DeepSeek and established relays (OpenRouter, Merge Gateway) set interleaved.field = "reasoning_content" for V4 Pro; the CF entry has toggle/effort but no interleaved, so clients may miss reasoning content on this route. Action: Verify CF DeepSeek responses; add interleaved = { field = "reasoning_content" } in curation when the side channel is present, or note why this host differs.
  • [medium] [violation] packages/core/script/generate-cloudflare-ai-gateway.ts (proxied limit emit) - Check: After base_model, provider files must be override-only—do not restate identical [limit] values. Why: The generator always writes catalog limit.context, including when it matches the lab (many Anthropic 200k/1M and xAI entries), which violates override-only and bloats every regen. Action: Omit limit.context (and other limit keys) when equal to the resolved base_model; keep only real host deltas (e.g. claude-sonnet-4.5 1M vs lab 200k, claude-sonnet-4.6 output 128k if verified).

@superhighfives

Copy link
Copy Markdown
Contributor Author

Follow-up (Google Gemini): the google/* models are skipped here for now, but the models and routing are fine — the blocker is a client-side message-format issue worth tracking so they can be reinstated.

Root cause: Gemini rejects any request whose message list ends on an assistant turn. Verified live against the gateway:

  • ends on user → OK
  • ends on assistant → gemini-3.7-flash returns code 7003 (User Input Error), gemini-3.5-flash returns code 2002 (Failed to parse model output)

This affects every Gemini model uniformly (not just the newest), via any route — it is not specific to Cloudflare or the REST endpoint. It surfaced because opencode's agent loop round-trips the model's own reply back as the trailing message when checking for further tool calls; most providers tolerate that, Gemini does not.

To reinstate: once the client normalizes Gemini message sequences (never end a request on an assistant turn — e.g. coalesce/trim trailing assistant turns for Gemini), drop the google/* entries from skip in curation.toml and regenerate. Nothing else here needs to change.

Minimal repro:

POST /accounts/{id}/ai/v1/chat/completions   (cf-aig-gateway-id: <gw>)
{"model":"google/gemini-3.7-flash","messages":[
  {"role":"system","content":"be brief"},
  {"role":"user","content":"hi"},
  {"role":"assistant","content":"OK"}]}
-> {"code":7003,"message":"Model execution failed (User Input Error)"}

@rekram1-node
rekram1-node merged commit e48051c into anomalyco:dev Aug 25, 2026
2 checks passed
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