TypeScript 97.4%
SQL 1%
JavaScript 0.9%
CSS 0.6%
1import type { CatalogEntry } from "@/lib/ai/registry/catalog";2import type { ModelCapabilities, ModelPricing, ModelStatus } from "@/lib/ai/core/types";3import data from "./catalog-data.json";45/**6 * Gemini catalog — generated from docs/provider-research/gemini.models.json (official docs +7 * real probes, audited 2026-09-08) joined with the live `models.list` limits.8 *9 * Verified rules (Gemini Developer API):10 * - temperature 0–2, topP, topK, seed, stopSequences accepted (sampling deprecated on 3.6+ but still accepted);11 * - frequency/presence penalties → 400 "Penalty is not enabled for this model" on every model;12 * - thinking is configured per family (`thinkingProfile`): `thinkingLevel` OR `thinkingBudget`, never both;13 * 3.8/3.7 Flash cannot disable thinking and reject MINIMAL; 3.5 Flash disables with budget 0;14 * Flash-Lite models are off by default (omit the config for "none"); Gemma rejects any thinkingConfig;15 * - thought signatures MUST be replayed on function-call parts for 3.x (400 otherwise);16 * - responseJsonSchema for structured output; googleSearch grounding; 2.5-generation → 404 for new users.17 */18export interface ThinkingProfile {19 mode: "level" | "budget" | "none";20 levels?: string[];21 /** How to express "no reasoning": a thinkingLevel value, "budget0", "omit", or null when impossible. */22 none?: string | null;23}2425interface Row {26 id: string;27 displayName: string;28 family: string | null;29 contextTokens: number | null;30 maxOutputTokens: number | null;31 thinking: boolean;32 status: ModelStatus;33 capabilities: ModelCapabilities;34 pricing: { inputPerMillion: number | null; cachedInputPerMillion: number | null; outputPerMillion: number | null } | null;35 pricingNote: string | null;36 thinkingProfile: ThinkingProfile;37 chat: boolean;38 notes: string;39}4041function weight(id: string): number {42 if (id.startsWith("gemini-3.8-flash")) return 100;43 if (id.startsWith("gemini-3.1-pro")) return 96;44 if (id.startsWith("gemini-3.7-flash")) return 92;45 if (id.startsWith("gemini-3.6-flash")) return 90;46 if (id.startsWith("gemini-3.5-flash-lite")) return 84;47 if (id.startsWith("gemini-3.5-flash")) return 88;48 if (id.startsWith("gemini-3.1-flash-lite")) return 80;49 if (id.startsWith("gemini-3-flash")) return 76;50 if (id.endsWith("-latest")) return 60;51 if (id.startsWith("gemma")) return 40;52 return 10;53}5455export const GEMINI_CATALOG = new Map<string, CatalogEntry>(56 (data as Row[]).map((r) => {57 const tp = r.thinkingProfile;58 const reasoning = r.thinking && tp.mode !== "none";59 const effortLevels = tp.mode === "level" && tp.levels ? [...(tp.none ? ["none"] : []), ...tp.levels] : tp.mode === "budget" ? ["none", "low", "medium", "high"] : undefined;60 const pricing: ModelPricing | null = r.pricing && r.pricing.inputPerMillion !== null ? { inputPerMillion: r.pricing.inputPerMillion, cachedInputPerMillion: r.pricing.cachedInputPerMillion ?? undefined, outputPerMillion: r.pricing.outputPerMillion ?? undefined, source: "gemini-pricing-page", asOf: "2026-09-08" } : null;61 if (pricing && /^gemini-3\.1-pro|^gemini-pro-latest|^gemini-2\.5-pro/.test(r.id)) pricing.longContext = { thresholdTokens: 200_000, inputPerMillion: (pricing.inputPerMillion ?? 0) * 2, outputPerMillion: (pricing.outputPerMillion ?? 0) * 1.5, cachedInputPerMillion: pricing.cachedInputPerMillion ? pricing.cachedInputPerMillion * 2 : undefined };62 const entry: CatalogEntry = {63 displayName: r.displayName,64 family: r.family ?? "Gemini",65 capabilities: { ...r.capabilities, reasoning },66 limits: { contextTokens: r.contextTokens ?? undefined, maxOutputTokens: r.maxOutputTokens ?? undefined },67 parameters: {68 temperature: true,69 topP: true,70 topK: true,71 seed: true,72 stop: true,73 maxTokens: true,74 frequencyPenalty: false,75 presencePenalty: false,76 reasoningEffort: Boolean(effortLevels?.length),77 reasoningEffortLevels: effortLevels,78 thinkingBudget: reasoning && tp.mode === "budget",79 thinkingBudgetRange: reasoning && tp.mode === "budget" ? { min: 128, max: 32_768 } : undefined,80 temperatureRange: { min: 0, max: 2 },81 },82 pricing,83 status: r.status,84 sortWeight: weight(r.id),85 metadata: { thinkingProfile: tp, pricingNote: r.pricingNote, codeExecution: !r.id.startsWith("gemma"), notes: r.notes, chat: r.chat },86 };87 return [r.id, entry];88 }),89);9091export const GEMINI_NON_CHAT = /tts|image|banana|lyria|veo|embedding|aqa|transcribe|robotics|computer-use|antigravity|deep-research|native-audio|live|imagen|omni/i;92