Consume AI model catalog from middlecache#30505
Conversation
Replace locally-committed model JSON files with live data fetched from the workers_ai_model_catalog middlecache pipeline. Changes: - content.config.ts: replace workers-ai-models + catalog-models collections (local dataLoader) with ai-catalog + workers-ai-catalog collections backed by middlecacheLoader - model-resolver.ts: rewrite getResolvedModels/getLegacyModels to read from the new collections; add fetchModelDetail() to fetch per-model detail.json from middlecache at build time - [...name].astro (both): call fetchModelDetail() concurrently in getStaticPaths to get full model data for detail pages - [...schema].json.ts (both): deleted — schema files are now served directly from R2 via the worker proxy at request time - worker/index.ts: add runtime proxy route for schema JSON files matching /ai/models/**/(sync|streaming|batch|schema)-(input|output).json and the workers-ai equivalent; R2 key mirrors URL path exactly - src/schemas/ai-model-catalog.ts: new Zod schemas for the middlecache catalog file format (AiModelCard, AiModelDetail)
card.slug and detail.slug in the middlecache output have @ stripped (they are R2 path keys). The URL-facing slug must preserve @ to match the existing /ai/models/@cf/... URL structure that ModelDetailPage also uses for schemaBasePath construction.
- Add schemaFiles to ResolvedModel type - Populate schemaFiles in detailToResolved from schema_manifest.files (extracts filenames from full R2 paths, no schema content needed) - Split hasSchema (Parameters gate) from hasSchemaFiles (API Schemas gate) - Render API Schemas (Raw) section from schemaFiles list, deriving human-readable labels from filenames (sync-input → Synchronous · Input)
Astro parses <string, string> as JSX inside template expressions. Move label derivation logic to frontmatter as a typed helper function.
In production, schema files are served by the Worker via R2. In local dev the Worker doesn't run, so proxy matching requests to middlecache.
Instead of fetching schema files at build time (which would add ~300 extra HTTP requests), SchemaDisplayLazy fetches the schema client-side when the user scrolls to the Parameters section (IntersectionObserver with 200px margin). - SchemaDisplayLazy.tsx: React component that fetches a schema URL, runs the same @stoplight/json-schema-tree processing as SchemaDisplay.astro, and renders via SchemaTree/SchemaVariantSelector - ModelDetailPage.astro: use SchemaDisplayLazy (client:visible) when schema is not in memory but schemaFiles URLs are available from schema_manifest; keep existing SchemaDisplay path for build-time schema
|
This pull request requires reviews from CODEOWNERS as it changes files that match the following patterns:
|
No longer needed — model data is fetched from middlecache at build time.
|
Preview URL: https://5365f2f2.preview.developers.cloudflare.com |
- fetchAllModelDetails() downloads all-models-detail.json once via downloadToDotTempIfNotPresent (cached for the build session) - Returns a slug→ResolvedModel map; detail pages look up their model with a single O(1) map access - Throws on failure so the build fails loudly instead of silently generating index links that 404 - Both [...name].astro pages now fetch the map once with Promise.all alongside the card collection read
The package uses require() at module level — it's CJS-only and breaks when @stoplight/json-schema-tree is imported client-side. Since none of the AI model schemas use allOf, a no-op stub (return schema unchanged) is safe. The real package still runs in Node for build-time SSG usage.
SchemaDisplayLazy now fetches .rows.json (pre-processed SchemaRowData[]) instead of raw schema + running @stoplight/json-schema-tree client-side. The CJS library runs in Node at pipeline time; the browser just receives plain JSON and renders it directly via SchemaTree. - SchemaDisplayLazy: simplified to fetch RowsPayload and render; no more json-schema-tree dependency in browser bundle - ModelDetailPage: use .rows.json URLs for lazy Parameters rendering - worker/index.ts + middleware: extend regex to also proxy .rows.json - astro.config.ts: remove @stoplight/json-schema-merge-allof alias - src/util/merge-allof-stub.ts: deleted (no longer needed)
|
/bonk please review |
There was a problem hiding this comment.
A few issues to address before merge.
Out-of-scope notes (not blocking):
bin/compare-model-sources.tsreferences the deleted local JSON directories. Since model data now lives in middlecache, this utility is dead code and should be removed or rewritten in a follow-up PR.AGENTS.mdstill references the deletedworkers-ai-modelscontent collection. Update it to reflect the newai-catalogandworkers-ai-catalogcollections.
|
Review complete. No build breakers found ( Issues:
Out-of-scope notes (not blocking):
|
- All schema files now live under /ai/models/{slug}/ for both catalog
and legacy models — schemaBasePath uses r2Slug (@ stripped) for all
- parameters.json replaces multiple .rows.json files: single fetch
contains pre-processed SchemaRowData for all modes
- SchemaDisplayLazy updated to fetch parameters.json and render both
flat (input/output tabs) and multi-mode (primary mode tabs) layouts
- Worker proxy + dev middleware simplified: single regex for
/ai/models/<slug>/(parameters.json|{mode}-{dir}.json) → R2 models/<slug>/
- schema_manifest.{parameters_json, raw_files} shape consumed correctly
- No workers-ai URL changes — page URLs unchanged, just schema fetch paths
SchemaDisplayLazy now replicates ModelDetailPage's production rendering: - Flat models: Input heading + RowsDisplay, Output heading + RowsDisplay - Multi-mode with shared input: Input once + per-mode output collapsibles (Synchronous, Streaming, Batch) matching the production collapsible layout - Multi-mode with differing inputs: per-mode collapsibles with Input/Output Detects shared inputs by comparing JSON serialization of RowsPayload, mirroring the production firstInputJson/allInputsIdentical check.
…meters - Fetch parameters.json at build time in ModelDetailPage.astro frontmatter - SchemaDisplayFromRows.astro renders pre-processed SchemaRowData using SchemaTreeView/SchemaVariantSelector (pure Astro, no React component) - ModelDetailPage uses four clean separate conditional blocks instead of one ternary chain — Starlight Tabs used correctly for flat Input/Output, matching production layout exactly - Delete SchemaDisplayLazy.tsx (React component no longer needed)
Plain <h2 id="..."> elements inside StarlightPage slots don't pass through the rehype pipeline, so they never get the .heading-wrapper anchor link structure. Replace all section-level h2s with AnchorHeading (same pattern used by WranglerCommand, CompatibilityFlags, etc.).
Replace repeated Open/Download Lucide SVGs in ModelDetailPage with a dedicated SchemaFileLinks.astro component.
Replace Date.now() with a stable hash of the schema JSON so sessionStorage expand/collapse state persists across builds.
ModelDetailPage.astro now imports ModelInfo.astro (pure display, no interactivity). ModelInfo.tsx kept for use inside ModelCatalog.tsx (client React context).
Fixes any types, fragment-in-tr HTML bug, and locale-sensitive Intl formatting that could differ between build and client.
…ayout Cases 1 and 4 (build-time schema and pre-processed rows) now share the same MultiModeParams component for the shared-input/differing-input collapsible structure.
…psible layout" This reverts commit f373f62.
/workers-ai/glossary/ → /workers-ai/platform/glossary/
|
/bonk please review |
There was a problem hiding this comment.
A few minor issues to address.
Out-of-scope notes (not blocking):
- Cases 1 and 2 in ModelDetailPage.astro (lines 460–561) are now dead code because always sets and . With the middlecache path, only Cases 3 and 4 (parametersFlat / parametersMulti) ever execute. Consider removing the legacy build-time schema paths in a follow-up PR.
- still references deleted local JSON directories — should be removed or rewritten for middlecache.
There was a problem hiding this comment.
A few minor issues to address.
Out-of-scope notes (not blocking):
- Cases 1 and 2 in ModelDetailPage.astro (lines 460-561) are now dead code because detailToResolved always sets schema to empty objects and apiModes to undefined. With the middlecache path, only Cases 3 and 4 (parametersFlat / parametersMulti) ever execute. Consider removing the legacy build-time schema paths in a follow-up PR.
- bin/compare-model-sources.ts still references deleted local JSON directories -- should be removed or rewritten for middlecache.
|
Review complete. Out-of-scope notes (not blocking):
|
- model-resolver.ts: filter .rows.json from schemaFiles defensively (worker proxy only serves raw .json schema files) - ModelDetailPage.astro: clarify Cases 1 and 2 are legacy/unused paths now that detailToResolved always sets empty schema/apiModes - ModelFeatures.astro: add trailing slash to /workers-ai/function-calling/ - bin/compare-model-sources.ts: delete dead code referencing deleted local JSON directories - AGENTS.md: replace deleted workers-ai-models collection with new ai-catalog and workers-ai-catalog middlecache-backed collections
- bin/fetch-models.ts: downloads models.tar.gz from middlecache and extracts to .tmp/middlecache/v1/workers-ai-model-catalog/models/ (same pattern as bin/fetch-skills.ts) - package.json: wire into prebuild and predev hooks - ModelDetailPage.astro: use downloadToDotTempIfNotPresent for parameters.json — reads from .tmp/ if already extracted by fetch-models.ts (no-op), otherwise fetches from middlecache HTTP
Allows triggering a production rebuild programmatically via the GitHub Actions API without needing to push a commit.
…fetch-models - getDotTmpPath() in model-resolver.ts resolves .tmp/ relative to src/util/ (repo root) — ModelDetailPage.astro was resolving from src/components/models/ giving src/.tmp/ instead of .tmp/ - fetch-models.ts now clears stale catalog files on each run so all-models-detail.json etc. are always re-fetched after a pipeline graduation
- [fetch-models] and [fetch-skills] blue prefix tags via kleur - dim text for skip message, cyan for re-fetch hint - fetch-models: move stale cache cleanup before download so downloadToDotTempIfNotPresent always re-fetches after --force
- ModelCatalog.astro: server-renders all cards as static HTML with data-* attributes; vanilla JS <script> owns filter/sort/URL state - FilterDropdown.tsx + FilterDropdownWrapper.tsx: extracted from old ModelCatalog.tsx; wrapper self-initialises from URL params on mount and communicates via model-catalog-filter CustomEvents - SortSelect.tsx + SortSelectWrapper.tsx: same pattern for sort order - ModelBadges.astro: direct port of ModelBadges.tsx (no interactivity) - ModelInfo.astro: widened Props to accept ModelCardData | ResolvedModel - Deleted ModelCatalog.tsx
|
/bonk please review |
|
Review complete. All previously flagged issues have been addressed ( Issues:
Out-of-scope notes (not blocking):
|
- FilterDropdown: remove CustomEvent dispatch (FilterDropdownWrapper owns it — both were firing on every selection causing applyFilters to run twice) - SortSelect: same fix — remove duplicate dispatch - FilterDropdown: remove unused filterKey prop (only the wrapper needs it) - ModelCatalog.astro syncUrl: only pushState when URL actually changes (previously pushed duplicate history entries on every filter pass, breaking browser back navigation) - Delete ModelFeatures.tsx (superseded by ModelFeatures.astro) - compare-model-sources.ts was already deleted in a prior commit
downloadToDotTempIfNotPresent was fetching from middlecache when the file wasn't found, but individual model parameters.json files aren't served as standalone HTTP endpoints (they only exist in models.tar.gz). In CI this caused every model detail page to get a 404 HTML response and silently render without a Parameters section. parameters.json is always extracted by bin/fetch-models.ts (prebuild); read it directly with readFileSync instead.
Previously ai-catalog.json, workers-ai-catalog.json, and all-models-detail.json were fetched lazily by downloadToDotTempIfNotPresent during the Astro build. Now fetch-models.ts pulls all four files (three JSONs + tarball) in parallel before the build starts, so the entire catalog payload is on disk and nothing depends on HTTP during the build.
…tags - All log/warn/error messages now start with the blue tag - Warnings are yellow, errors are red, success is green - Extracted tag into a const to avoid repetition
import.meta.url in getDotTmpPath() and downloadToDotTempIfNotPresent resolves relative to the *compiled* file location during astro build, which is dist/ — making ../../.tmp resolve to dist/.tmp/ instead of the repo root .tmp/ where fetch-models.ts actually writes files. process.cwd() is always the repo root regardless of where the compiled output lives.
Fetches AI model data from the
workers_ai_model_catalogmiddlecache pipeline instead of committed JSON files.What changed
Data sources
catalog-models+workers-ai-modelscontent collections (committed JSON) withai-catalog+workers-ai-catalogbacked bymiddlecacheLoaderall-models-detail.jsonModel detail pages
parameters.json(pre-processedSchemaRowDataper model, extracted frommodels.tar.gzbybin/fetch-models.ts)sync-input.jsonetc.) served from R2 via worker proxy at request time — no longer static build outputs/ai/models/**schema requests to middlecacheCatalog index pages
ModelCatalogconverted from a React island to Astro — cards are static HTML baked at build time, filter/sort/URL state managed by a vanilla JS script@base-ui/reactModelBadgesconverted from React to AstroInfra
workflow_dispatchadded topublish-production.ymlso middlecache graduations can trigger a docs rebuildbin/fetch-models.tspre-extractsmodels.tar.gzas apredev/prebuildhook;--forcere-fetches and clears stale cached catalog files