"use client"; import { AlertCircle, Bot, Check, ChevronsUpDown, Plus, Trash2 } from "lucide-react"; import { motion } from "motion/react"; import { useTranslations } from "next-intl"; import { useState } from "react"; import { toast } from "sonner"; import { Alert, AlertDescription } from "@/components/ui/alert"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, } from "@/components/ui/command"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { LANGUAGES } from "@/contracts/enums/languages"; import { getModelsByProvider, LLM_MODELS } from "@/contracts/enums/llm-models"; import { LLM_PROVIDERS } from "@/contracts/enums/llm-providers"; import { type CreateLLMConfig, useLLMConfigs } from "@/hooks/use-llm-configs"; import { cn } from "@/lib/utils"; import InferenceParamsEditor from "../inference-params-editor"; interface AddProviderStepProps { searchSpaceId: number; onConfigCreated?: () => void; onConfigDeleted?: () => void; } export function AddProviderStep({ searchSpaceId, onConfigCreated, onConfigDeleted, }: AddProviderStepProps) { const t = useTranslations("onboard"); const { llmConfigs, createLLMConfig, deleteLLMConfig } = useLLMConfigs(searchSpaceId); const [isAddingNew, setIsAddingNew] = useState(false); const [formData, setFormData] = useState({ name: "", provider: "", custom_provider: "", model_name: "", api_key: "", api_base: "", language: "English", litellm_params: {}, search_space_id: searchSpaceId, }); const [isSubmitting, setIsSubmitting] = useState(false); const [modelComboboxOpen, setModelComboboxOpen] = useState(false); const handleInputChange = (field: keyof CreateLLMConfig, value: string) => { setFormData((prev) => ({ ...prev, [field]: value })); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!formData.name || !formData.provider || !formData.model_name || !formData.api_key) { toast.error("Please fill in all required fields"); return; } setIsSubmitting(true); const result = await createLLMConfig(formData); setIsSubmitting(false); if (result) { setFormData({ name: "", provider: "", custom_provider: "", model_name: "", api_key: "", api_base: "", language: "English", litellm_params: {}, search_space_id: searchSpaceId, }); setIsAddingNew(false); // Notify parent component that a config was created onConfigCreated?.(); } }; const selectedProvider = LLM_PROVIDERS.find((p) => p.value === formData.provider); const availableModels = formData.provider ? getModelsByProvider(formData.provider) : []; const handleParamsChange = (newParams: Record) => { setFormData((prev) => ({ ...prev, litellm_params: newParams })); }; // Reset model when provider changes const handleProviderChange = (value: string) => { handleInputChange("provider", value); setFormData((prev) => ({ ...prev, model_name: "" })); }; return (
{/* Info Alert */} {t("add_provider_instruction")} {/* Existing Configurations */} {llmConfigs.length > 0 && (

{t("your_llm_configs")}

{llmConfigs.map((config) => (

{config.name}

{config.provider}

{t("model")}: {config.model_name} {config.language && ` • ${t("language")}: ${config.language}`} {config.api_base && ` • ${t("base")}: ${config.api_base}`}

))}
)} {/* Add New Provider */} {!isAddingNew ? (

{t("add_provider_title")}

{t("add_provider_subtitle")}

) : ( {t("add_new_llm_provider")} {t("configure_new_provider")}
handleInputChange("name", e.target.value)} required />
{/* language */}
{formData.provider === "CUSTOM" && (
handleInputChange("custom_provider", e.target.value)} required />
)}
handleInputChange("model_name", value)} />
{formData.model_name ? `Using custom model: "${formData.model_name}"` : "Type your model name above"}
{availableModels.length > 0 && ( {availableModels .filter( (model) => !formData.model_name || model.value .toLowerCase() .includes(formData.model_name.toLowerCase()) || model.label .toLowerCase() .includes(formData.model_name.toLowerCase()) ) .map((model) => ( { handleInputChange("model_name", currentValue); setModelComboboxOpen(false); }} className="flex flex-col items-start py-3" >
{model.label}
{model.contextWindow && (
Context: {model.contextWindow}
)}
))}
)}

{availableModels.length > 0 ? `Type freely or select from ${availableModels.length} model suggestions` : selectedProvider?.example ? `${t("examples")}: ${selectedProvider.example}` : "Type your model name freely"}

handleInputChange("api_key", e.target.value)} required />
handleInputChange("api_base", e.target.value)} />
{/* Optional Inference Parameters */}
)}
); }