perf(providers): lazy validate provider schema on demand to reduce startup heap

This commit is contained in:
Markus Hartung
2026-08-24 12:23:50 -03:00
parent 0a53c8a2ce
commit dfc5b5eec4
2 changed files with 27 additions and 18 deletions

View File

@@ -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<string, any> | null = null;
function getOrCreateAiProviders(): Record<string, any> {
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");

View File

@@ -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", () => {