'use client' import { useMemo, useState } from 'react' import Image from 'next/image' import { useRouter } from 'next/navigation' import { IconCheck as Check, IconChevronDown as ChevronDown } from '@tabler/icons-react' import { MODEL_SELECTION_COOKIE, serializeModelSelectionCookie } from '@/lib/config/model-selection-cookie' import { ModelSelectorData } from '@/lib/types/model-selector' import { Model } from '@/lib/types/models' import { cn } from '@/lib/utils' import { setCookie } from '@/lib/utils/cookies' import { Button } from './ui/button' import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from './ui/command' import { Popover, PopoverContent, PopoverTrigger } from './ui/popover' function modelKey(model: Model): string { return `${model.providerId}:${model.id}` } const PROVIDER_LOGO_BY_ID: Record = { openai: '/providers/logos/openai.svg', anthropic: '/providers/logos/anthropic.svg', google: '/providers/logos/google.svg', gateway: '/providers/logos/gateway.svg', 'openai-compatible': '/providers/logos/openai-compatible.svg', ollama: '/providers/logos/ollama.svg' } function ProviderLogo({ providerId }: { providerId: string }) { const logoSrc = PROVIDER_LOGO_BY_ID[providerId] if (!logoSrc) { return } return ( {`${providerId} ) } interface ModelSelectorClientProps { data: ModelSelectorData } export function ModelSelectorClient({ data }: ModelSelectorClientProps) { const router = useRouter() const [open, setOpen] = useState(false) const [selectedModelKey, setSelectedModelKey] = useState( data.selectedModelKey ) const providerEntries = useMemo( () => Object.entries(data.modelsByProvider).sort(([providerA], [providerB]) => providerA.localeCompare(providerB) ), [data.modelsByProvider] ) const selectableModels = useMemo( () => providerEntries.flatMap(([, models]) => models), [providerEntries] ) const selectableByKey = useMemo( () => Object.fromEntries( selectableModels.map(model => [modelKey(model), model]) ) as Record, [selectableModels] ) const selectedModel = selectableByKey[selectedModelKey] if (!data.enabled) { return null } if (!data.hasAvailableModels) { return ( ) } if (!selectedModel) { return null } return ( No model found. {providerEntries.map(([provider, models]) => ( {models.map(model => { const value = modelKey(model) const isSelected = selectedModelKey === value return ( { const nextModel = selectableByKey[value] if (!nextModel) { return } setSelectedModelKey(value) setCookie( MODEL_SELECTION_COOKIE, serializeModelSelectionCookie({ providerId: nextModel.providerId, modelId: nextModel.id }) ) setOpen(false) router.refresh() }} className="cursor-pointer" > {model.name} ) })} ))} ) }