From dfc5b5eec46157c87be4931519d4590d81e94c6c Mon Sep 17 00:00:00 2001 From: Markus Hartung Date: Mon, 24 Aug 2026 12:23:50 -0300 Subject: [PATCH] perf(providers): lazy validate provider schema on demand to reduce startup heap --- src/shared/constants/providers.ts | 33 +++++++++++-------- .../provider-node-reserved-prefix.test.ts | 12 ++++--- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/shared/constants/providers.ts b/src/shared/constants/providers.ts index be4366817f..a9bfee5671 100644 --- a/src/shared/constants/providers.ts +++ b/src/shared/constants/providers.ts @@ -14,6 +14,7 @@ import { AUDIO_ONLY_PROVIDERS } from "./providers/audio"; import { UPSTREAM_PROXY_PROVIDERS } from "./providers/upstream-proxy"; import { CLOUD_AGENT_PROVIDERS } from "./providers/cloud-agent"; import { SYSTEM_PROVIDERS } from "./providers/system"; +import { validateProviders } from "../validation/providerSchema"; export const FREE_PROVIDERS = {}; @@ -309,10 +310,27 @@ const _PROVIDER_SECTIONS = [ SYSTEM_PROVIDERS, ] as const; +let _validated = false; + +function ensureProvidersValidated() { + if (_validated) return; + validateProviders(NOAUTH_PROVIDERS, "NOAUTH_PROVIDERS"); + validateProviders(OAUTH_PROVIDERS, "OAUTH_PROVIDERS"); + validateProviders(APIKEY_PROVIDERS, "APIKEY_PROVIDERS"); + validateProviders(WEB_COOKIE_PROVIDERS, "WEB_COOKIE_PROVIDERS"); + validateProviders(LOCAL_PROVIDERS, "LOCAL_PROVIDERS"); + validateProviders(SEARCH_PROVIDERS, "SEARCH_PROVIDERS"); + validateProviders(AUDIO_ONLY_PROVIDERS, "AUDIO_ONLY_PROVIDERS"); + validateProviders(UPSTREAM_PROXY_PROVIDERS, "UPSTREAM_PROXY_PROVIDERS"); + validateProviders(CLOUD_AGENT_PROVIDERS, "CLOUD_AGENT_PROVIDERS"); + _validated = true; +} + let _aiProviders: Record | null = null; function getOrCreateAiProviders(): Record { if (!_aiProviders) { + ensureProvidersValidated(); _aiProviders = {}; for (const section of _PROVIDER_SECTIONS) { Object.assign(_aiProviders, section); @@ -522,7 +540,8 @@ export const USAGE_SUPPORTED_PROVIDERS = [ "agentrouter", ]; -// ── Zod validation at module load (Phase 7.2) ── +// ── Zod validation, lazily on first AI_PROVIDERS access (perf: skips the walk +// for processes that never touch AI_PROVIDERS, e.g. short-lived CLI commands) ── // Re-export the extracted data catalogs so external importers of providers.ts are unchanged. export { @@ -537,15 +556,3 @@ export { CLOUD_AGENT_PROVIDERS, SYSTEM_PROVIDERS, }; - -import { validateProviders } from "../validation/providerSchema"; - -validateProviders(NOAUTH_PROVIDERS, "NOAUTH_PROVIDERS"); -validateProviders(OAUTH_PROVIDERS, "OAUTH_PROVIDERS"); -validateProviders(APIKEY_PROVIDERS, "APIKEY_PROVIDERS"); -validateProviders(WEB_COOKIE_PROVIDERS, "WEB_COOKIE_PROVIDERS"); -validateProviders(LOCAL_PROVIDERS, "LOCAL_PROVIDERS"); -validateProviders(SEARCH_PROVIDERS, "SEARCH_PROVIDERS"); -validateProviders(AUDIO_ONLY_PROVIDERS, "AUDIO_ONLY_PROVIDERS"); -validateProviders(UPSTREAM_PROXY_PROVIDERS, "UPSTREAM_PROXY_PROVIDERS"); -validateProviders(CLOUD_AGENT_PROVIDERS, "CLOUD_AGENT_PROVIDERS"); diff --git a/tests/unit/provider-node-reserved-prefix.test.ts b/tests/unit/provider-node-reserved-prefix.test.ts index 722c938699..e0c6655974 100644 --- a/tests/unit/provider-node-reserved-prefix.test.ts +++ b/tests/unit/provider-node-reserved-prefix.test.ts @@ -106,11 +106,13 @@ test("shared set excludes manual aliases that never intercept nodes at runtime", assert.equal(RESERVED_PROVIDER_PREFIXES.has("aq"), false); }); -test("shared set size matches full REGISTRY scan (391 unique prefixes)", () => { - // Count measured against upstream/main 65e81158a (was 329 at c68cda7df — new - // providers shift the number; the assertion pins that the set is a full - // REGISTRY walk, not a hand-maintained list). - assert.equal(RESERVED_PREFIX_COUNT, 391); +test("shared set size matches full REGISTRY scan (395 unique prefixes)", () => { + // Count measured against release/v3.8.50 tip after this merge-batch boarded + // #11333 (volcengine-coding-plan + volcengine-agent-plan, +4 ids/aliases) on + // top of the 391 pinned post-upstream-65e81158a (was 329 at c68cda7df) — + // the assertion pins that the set is a full REGISTRY walk, not a + // hand-maintained list. + assert.equal(RESERVED_PREFIX_COUNT, 395); }); test("isReservedProviderPrefix rejects non-string input", () => {