import type { CatalogEntry } from "@/lib/ai/registry/catalog"; import type { ModelCapabilities, ModelPricing, ModelStatus } from "@/lib/ai/core/types"; import data from "./catalog-data.json"; /** * OpenAI catalog — generated from docs/provider-research/openai.models.json * (official models/pricing pages + real probes, audited 2026-09-08). * `GET /v1/models` exposes no capability/context/pricing metadata, so this file is * the source of truth for everything except existence and `shutdown_date`. * * Verified rules encoded here: * - sampling params (temperature/top_p/penalties) are accepted only on non-reasoning * models, or on reasoning models when `reasoning.effort === "none"` ("conditional"); * - `seed` and `stop` do not exist in the Responses API; * - effort levels are per model (`reasoningEfforts`). */ interface Row { id: string; displayName: string; family: string; contextTokens: number | null; maxOutputTokens: number | null; capabilities: ModelCapabilities; sampling: "yes" | "no" | "conditional"; verbosity: boolean; reasoningEfforts: string[] | null; defaultReasoningEffort: string | null; pricing: { inputPerMillion: number | null; cachedInputPerMillion: number | null; outputPerMillion: number | null }; status: ModelStatus; apis: string[] | null; shutdownDate: string | null; } function weight(id: string): number { if (id.startsWith("gpt-6")) return 100; if (id.startsWith("gpt-5.6-sol")) return 96; if (id.startsWith("gpt-5.6-terra")) return 94; if (id.startsWith("gpt-5.6-luna")) return 92; if (id === "gpt-5.6") return 91; if (id.startsWith("gpt-5.5-pro")) return 86; if (id.startsWith("gpt-5.5")) return 88; if (id.startsWith("gpt-5.4-pro")) return 80; if (id.startsWith("gpt-5.4-mini")) return 82; if (id.startsWith("gpt-5.4-nano")) return 81; if (id.startsWith("gpt-5.4")) return 84; if (id.startsWith("gpt-5.3")) return 70; if (id.startsWith("gpt-5.2")) return 68; if (id.startsWith("gpt-5.1")) return 66; if (id.startsWith("gpt-5")) return 60; if (id === "chat-latest") return 58; if (id.startsWith("gpt-4.1")) return 50; if (id.startsWith("o3") || id.startsWith("o4")) return 45; if (id.startsWith("gpt-4o")) return 40; return 10; } export const OPENAI_CATALOG = new Map( (data as Row[]).map((r) => { const isSnapshot = /-\d{4}-\d{2}-\d{2}$|-\d{4}$/.test(r.id); const pricing: ModelPricing | null = r.pricing.inputPerMillion != null || r.pricing.outputPerMillion != null ? { inputPerMillion: r.pricing.inputPerMillion ?? undefined, cachedInputPerMillion: r.pricing.cachedInputPerMillion ?? undefined, outputPerMillion: r.pricing.outputPerMillion ?? undefined, source: "openai-pricing-page", asOf: "2026-09-08" } : null; const entry: CatalogEntry = { displayName: r.displayName, family: r.family, capabilities: r.capabilities, limits: { contextTokens: r.contextTokens ?? undefined, maxOutputTokens: r.maxOutputTokens ?? undefined }, parameters: { temperature: r.sampling !== "no", topP: r.sampling !== "no", frequencyPenalty: r.sampling !== "no", presencePenalty: r.sampling !== "no", maxTokens: true, stop: false, seed: false, topK: false, verbosity: r.verbosity, reasoningEffort: Boolean(r.reasoningEfforts?.length), reasoningEffortLevels: r.reasoningEfforts ?? undefined, temperatureRange: { min: 0, max: 2 }, }, pricing, status: r.status, sortWeight: weight(r.id) - (isSnapshot ? 5 : 0), metadata: { samplingMode: r.sampling, defaultReasoningEffort: r.defaultReasoningEffort, apis: r.apis ?? ["responses"], responsesSupported: (r.apis ?? ["responses"]).includes("responses"), shutdownDate: r.shutdownDate, snapshot: isSnapshot, }, }; return [r.id, entry]; }), ); /** Ids returned by /v1/models that are not chat models (audio, image, embeddings…). */ export const OPENAI_NON_CHAT = /babbage|davinci|instruct|transcribe|tts|whisper|audio|realtime|image|sora|embedding|moderation|search-preview|search-api|deep-research|computer-use/i; /** Listed by /v1/models but return 404 (verified 2026-09-08). */ export const OPENAI_DEAD_IDS = new Set(["gpt-5-chat-latest", "gpt-5.1-chat-latest", "gpt-5.2-chat-latest", "gpt-5.3-chat-latest", "gpt-5-codex", "gpt-5.1-codex", "gpt-5.1-codex-max", "gpt-5.1-codex-mini", "gpt-5.2-codex", "o3-deep-research", "o4-mini-deep-research"]);