"use client"; import { useAtomValue } from "jotai"; import { AlertCircle, Bot, ChevronRight, Globe, User, X } from "lucide-react"; import { AnimatePresence, motion } from "motion/react"; import { useCallback, useEffect, useState } from "react"; import { toast } from "sonner"; import { createNewLLMConfigMutationAtom, updateLLMPreferencesMutationAtom, updateNewLLMConfigMutationAtom, } from "@/atoms/new-llm-config/new-llm-config-mutation.atoms"; import { LLMConfigForm, type LLMConfigFormData } from "@/components/shared/llm-config-form"; import { Alert, AlertDescription } from "@/components/ui/alert"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import type { GlobalNewLLMConfig, NewLLMConfigPublic, } from "@/contracts/types/new-llm-config.types"; import { cn } from "@/lib/utils"; interface ModelConfigSidebarProps { open: boolean; onOpenChange: (open: boolean) => void; config: NewLLMConfigPublic | GlobalNewLLMConfig | null; isGlobal: boolean; searchSpaceId: number; mode: "create" | "edit" | "view"; } export function ModelConfigSidebar({ open, onOpenChange, config, isGlobal, searchSpaceId, mode, }: ModelConfigSidebarProps) { const [isSubmitting, setIsSubmitting] = useState(false); // Mutations - use mutateAsync from the atom value const { mutateAsync: createConfig } = useAtomValue(createNewLLMConfigMutationAtom); const { mutateAsync: updateConfig } = useAtomValue(updateNewLLMConfigMutationAtom); const { mutateAsync: updatePreferences } = useAtomValue(updateLLMPreferencesMutationAtom); // Handle escape key useEffect(() => { const handleEscape = (e: KeyboardEvent) => { if (e.key === "Escape" && open) { onOpenChange(false); } }; window.addEventListener("keydown", handleEscape); return () => window.removeEventListener("keydown", handleEscape); }, [open, onOpenChange]); // Get title based on mode const getTitle = () => { if (mode === "create") return "Add New Configuration"; if (isGlobal) return "View Global Configuration"; return "Edit Configuration"; }; // Handle form submit const handleSubmit = useCallback( async (data: LLMConfigFormData) => { setIsSubmitting(true); try { if (mode === "create") { // Create new config const result = await createConfig({ ...data, search_space_id: searchSpaceId, }); // Assign the new config to the agent role if (result?.id) { await updatePreferences({ search_space_id: searchSpaceId, data: { agent_llm_id: result.id, }, }); } toast.success("Configuration created and assigned!"); onOpenChange(false); } else if (!isGlobal && config) { // Update existing user config await updateConfig({ id: config.id, data: { name: data.name, description: data.description, provider: data.provider, custom_provider: data.custom_provider, model_name: data.model_name, api_key: data.api_key, api_base: data.api_base, litellm_params: data.litellm_params, system_instructions: data.system_instructions, use_default_system_instructions: data.use_default_system_instructions, citations_enabled: data.citations_enabled, }, }); toast.success("Configuration updated!"); onOpenChange(false); } } catch (error) { console.error("Failed to save configuration:", error); toast.error("Failed to save configuration"); } finally { setIsSubmitting(false); } }, [ mode, isGlobal, config, searchSpaceId, createConfig, updateConfig, updatePreferences, onOpenChange, ] ); // Handle "Use this model" for global configs const handleUseGlobalConfig = useCallback(async () => { if (!config || !isGlobal) return; setIsSubmitting(true); try { await updatePreferences({ search_space_id: searchSpaceId, data: { agent_llm_id: config.id, }, }); toast.success(`Now using ${config.name}`); onOpenChange(false); } catch (error) { console.error("Failed to set model:", error); toast.error("Failed to set model"); } finally { setIsSubmitting(false); } }, [config, isGlobal, searchSpaceId, updatePreferences, onOpenChange]); return ( {open && ( <> {/* Backdrop */} onOpenChange(false)} /> {/* Sidebar Panel */} {/* Header */}

{getTitle()}

{isGlobal ? ( Global ) : mode !== "create" ? ( Custom ) : null} {config && ( {config.model_name} )}
{/* Content - use overflow-y-auto instead of ScrollArea for better compatibility */}
{/* Global config notice */} {isGlobal && mode !== "create" && ( Global configurations are read-only. To customize settings, create a new configuration based on this template. )} {/* Form */} {mode === "create" ? ( onOpenChange(false)} isSubmitting={isSubmitting} mode="create" submitLabel="Create & Use" /> ) : isGlobal && config ? ( // Read-only view for global configs
{/* Config Details */}

{config.name}

{config.description && (

{config.description}

)}

{config.provider}

{config.model_name}

{config.citations_enabled ? "Enabled" : "Disabled"}
{config.system_instructions && ( <>

{config.system_instructions}

)}
{/* Action Buttons */}
) : config ? ( // Edit form for user configs onOpenChange(false)} isSubmitting={isSubmitting} mode="edit" submitLabel="Save Changes" /> ) : null}
)} ); }