'use client' import { useMemo } from 'react' import { ChipInput, Search } from '@sim/emcn' import Link from 'next/link' import { debounce, useQueryStates } from 'nuqs' import { ChevronArrow } from '@/app/(landing)/components/chevron-arrow' import { ProviderIcon } from '@/app/(landing)/models/components/model-primitives' import { modelsParsers, modelsUrlKeys } from '@/app/(landing)/models/search-params' import { type CatalogModel, type CatalogProvider, formatPrice, formatTokenCount, MODEL_PROVIDERS_WITH_CATALOGS, MODEL_PROVIDERS_WITH_DYNAMIC_CATALOGS, } from '@/app/(landing)/models/utils' /** Debounce window for writing the search term to the URL (filtering is instant). */ const SEARCH_DEBOUNCE_MS = 300 const PROVIDER_OPTIONS = MODEL_PROVIDERS_WITH_CATALOGS.map((provider) => ({ id: provider.id, name: provider.name, count: provider.modelCount, })) export function ModelDirectory() { const [{ q: query, provider }, setParams] = useQueryStates(modelsParsers, modelsUrlKeys) const activeProviderId = provider || null const normalizedQuery = query.trim().toLowerCase() const { filteredProviders, filteredDynamicProviders } = useMemo(() => { const filteredProviders = MODEL_PROVIDERS_WITH_CATALOGS.map((provider) => { const providerMatchesSearch = normalizedQuery.length > 0 && provider.searchText.includes(normalizedQuery) const providerMatchesFilter = !activeProviderId || provider.id === activeProviderId if (!providerMatchesFilter) { return null } const models = normalizedQuery.length === 0 ? provider.models : provider.models.filter( (model) => model.searchText.includes(normalizedQuery) || (providerMatchesSearch && normalizedQuery.length > 0) ) if (!providerMatchesSearch && models.length === 0) { return null } return { ...provider, models: providerMatchesSearch && normalizedQuery.length > 0 ? provider.models : models, } }).filter((provider): provider is CatalogProvider => provider !== null) const filteredDynamicProviders = MODEL_PROVIDERS_WITH_DYNAMIC_CATALOGS.filter((provider) => { const providerMatchesFilter = !activeProviderId || provider.id === activeProviderId if (!providerMatchesFilter) { return false } if (!normalizedQuery) { return true } return provider.searchText.includes(normalizedQuery) }) return { filteredProviders, filteredDynamicProviders, } }, [activeProviderId, normalizedQuery]) const hasResults = filteredProviders.length > 0 || filteredDynamicProviders.length > 0 return (
Try a provider name like OpenAI or Anthropic, or search for capabilities like structured outputs, reasoning, or deep research.
{provider.modelCount} models · {provider.description}
These providers load their model lists dynamically at runtime.
{model.id} · Input {formatPrice(model.pricing.input)}/1M · Output{' '} {formatPrice(model.pricing.output)}/1M {model.contextWindow ? ` · ${formatTokenCount(model.contextWindow)} context` : ''}