refactor(x): models.dev — single startup writer, cache-only consumers

Previously catalog readers (listOnboardingModels, getChatModelIds)
fetched models.dev inline on a 24h TTL, while the reasoning-capability
paths read the cache only — so a signed-in install could run forever
with no cache and the effort chip never appeared, and catalog calls
could stall on a slow third-party fetch.

Now main calls startModelsDevRefresh() once at boot: refresh if the
cache is missing or older than 24h, then every 24h while running, with
a 10s fetch timeout, errors logged and swallowed (existing cache stays
in use). Every consumer reads the on-disk cache only. Catalog-shaped
readers (models:list, gateway annotation) await the warm-up's first
attempt so a fresh install's first list sees the fetched data; the
turn-start capability gate never waits. A missing cache is an empty
catalog, not an error — chat is unaffected either way.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Ramnique Singh 2026-07-10 10:38:33 +05:30
parent 885d4bc5cf
commit 3b447d07b9
2 changed files with 87 additions and 26 deletions

View file

@ -64,6 +64,7 @@ import {
setMainWindowForDeepLinks,
} from "./deeplink.js";
import { disconnectGoogleIfScopesStale } from "./oauth-handler.js";
import { startModelsDevRefresh } from "@x/core/dist/models/models-dev.js";
// Captured as early as possible so it reflects actual process start. Used to
// gate grace-eligible notifications (e.g. the burst of background-task
@ -381,6 +382,12 @@ app.whenReady().then(async () => {
// Initialize all config files before UI can access them
await initConfigs();
// Warm the models.dev catalog cache (single writer; refreshed every 24h
// while the app runs). Every consumer — catalog listings, the reasoning
// capability gate — reads the on-disk cache only. Best-effort: failures
// leave any existing cache in use and never block boot.
startModelsDevRefresh();
// PostHog identify() is idempotent — call it on every startup so existing
// signed-in installs (and every cold start of v0.3.4+) get re-identified.
// Otherwise main-process events stay anonymous until the user re-signs-in.