import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { getErrorMessage, useForcePricingSyncMutation, useGetCoreConfigQuery, useUpdateCoreConfigMutation } from "@/lib/store"; import { DefaultCoreConfig } from "@/lib/types/config"; import { RbacOperation, RbacResource, useRbac } from "@enterprise/lib"; import { useEffect, useMemo } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; interface ModelSettingsFormData { pricing_datasheet_url: string; pricing_sync_interval_hours: number; routing_chain_max_depth: number; } export default function ModelSettingsView() { const hasSettingsUpdateAccess = useRbac(RbacResource.Settings, RbacOperation.Update); const { data: bifrostConfig } = useGetCoreConfigQuery({ fromDB: true }); const frameworkConfig = bifrostConfig?.framework_config; const clientConfig = bifrostConfig?.client_config; const [updateCoreConfig, { isLoading }] = useUpdateCoreConfigMutation(); const [forcePricingSync, { isLoading: isForceSyncing }] = useForcePricingSyncMutation(); const { register, handleSubmit, formState: { errors, isDirty }, reset, watch, } = useForm({ defaultValues: { pricing_datasheet_url: "", pricing_sync_interval_hours: 24, routing_chain_max_depth: DefaultCoreConfig.routing_chain_max_depth, }, }); const formValues = watch(); useEffect(() => { if (!bifrostConfig || isDirty) return; reset({ pricing_datasheet_url: frameworkConfig?.pricing_url || "", pricing_sync_interval_hours: Math.round((frameworkConfig?.pricing_sync_interval ?? 0) / 3600) || 24, routing_chain_max_depth: clientConfig?.routing_chain_max_depth ?? DefaultCoreConfig.routing_chain_max_depth, }); }, [frameworkConfig?.pricing_url, frameworkConfig?.pricing_sync_interval, clientConfig?.routing_chain_max_depth, isDirty, reset]); const hasChanges = useMemo(() => { if (!bifrostConfig || !isDirty) return false; const serverUrl = frameworkConfig?.pricing_url || ""; const serverInterval = Math.round((frameworkConfig?.pricing_sync_interval ?? 0) / 3600); const serverDepth = clientConfig?.routing_chain_max_depth ?? DefaultCoreConfig.routing_chain_max_depth; return ( formValues.pricing_datasheet_url !== serverUrl || formValues.pricing_sync_interval_hours !== serverInterval || formValues.routing_chain_max_depth !== serverDepth ); }, [bifrostConfig, frameworkConfig, clientConfig, formValues, isDirty]); const onSubmit = async (data: ModelSettingsFormData) => { try { await updateCoreConfig({ ...bifrostConfig!, framework_config: { ...frameworkConfig, id: bifrostConfig?.framework_config.id || 0, pricing_url: data.pricing_datasheet_url, pricing_sync_interval: data.pricing_sync_interval_hours * 3600, }, client_config: { ...clientConfig!, routing_chain_max_depth: data.routing_chain_max_depth, }, }).unwrap(); toast.success("Model settings updated successfully."); reset(data); } catch (error) { toast.error(getErrorMessage(error)); } }; const handleForceSync = async () => { try { await forcePricingSync().unwrap(); toast.success("Pricing sync triggered successfully."); } catch (error) { toast.error(getErrorMessage(error)); } }; return (

Model Settings

Configure pricing and routing behaviour.

{/* Pricing Datasheet URL */}

URL to a custom pricing datasheet. Leave empty to use default pricing.

{ if (!value) return true; return value.startsWith("http://") || value.startsWith("https://") || "URL must start with http:// or https://"; }, }, })} className={errors.pricing_datasheet_url ? "border-destructive" : ""} /> {errors.pricing_datasheet_url &&

{errors.pricing_datasheet_url.message}

}
{/* Pricing Sync Interval */}

How often to sync pricing data from the datasheet URL.

{errors.pricing_sync_interval_hours &&

{errors.pricing_sync_interval_hours.message}

}
{/* Routing Chain Max Depth */}

Maximum number of chained routing rule evaluations per request. Prevents infinite loops from circular rule definitions.

{errors.routing_chain_max_depth &&

{errors.routing_chain_max_depth.message}

}
); }