import { useState, useEffect } from "react"; import { Button } from "@/src/components/ui/button"; import { Input } from "@/src/components/ui/input"; import { Select, SelectContent, SelectItem, SelectSeparator, SelectTrigger, SelectValue, } from "@/src/components/ui/select"; import { Slider } from "@/src/components/ui/slider"; import { Switch } from "@/src/components/ui/switch"; import { CreateLLMApiKeyDialog } from "@/src/features/public-api/components/CreateLLMApiKeyDialog"; import useProjectIdFromURL from "@/src/hooks/useProjectIdFromURL"; import { cn } from "@/src/utils/tailwind"; import { type JSONObject, JSONObjectSchema, LLMAdapter, type supportedModels, type UIModelParams, } from "@langfuse/shared"; import { InfoIcon, Settings2 } from "lucide-react"; import { Popover, PopoverContent, PopoverTrigger, } from "@/src/components/ui/popover"; import { Tooltip, TooltipContent, TooltipTrigger, } from "@/src/components/ui/tooltip"; import { LLMApiKeyComponent } from "./LLMApiKeyComponent"; import { FormDescription } from "@/src/components/ui/form"; import { CodeMirrorEditor } from "../editor"; export type ModelParamsContext = { modelParams: UIModelParams; availableProviders: string[]; availableModels: string[]; providerModelCombinations: string[]; updateModelParamValue: ( key: Key, value: UIModelParams[Key]["value"], ) => void; setModelParamEnabled?: (key: keyof UIModelParams, enabled: boolean) => void; formDisabled?: boolean; modelParamsDescription?: string; customHeader?: React.ReactNode; layout?: "compact" | "vertical"; isEmbedded?: boolean; }; export const ModelParameters: React.FC = ({ modelParams, availableProviders, availableModels, providerModelCombinations, updateModelParamValue, setModelParamEnabled, formDisabled = false, modelParamsDescription, customHeader, layout = "vertical", isEmbedded = false, }) => { const projectId = useProjectIdFromURL(); const [modelSettingsOpen, setModelSettingsOpen] = useState(false); const [modelSettingsUsed, setModelSettingsUsed] = useState(false); const [createLlmApiKeyDialogOpen, setCreateLlmApiKeyDialogOpen] = useState(false); useEffect(() => { const hasEnabledModelSetting = Object.keys(modelParams).some( (key) => !["adapter", "provider", "model"].includes(key) && modelParams[key as keyof typeof modelParams].enabled, ); if (hasEnabledModelSetting) { setModelSettingsUsed(true); } else { setModelSettingsUsed(false); } }, [setModelSettingsUsed, modelParams]); if (!projectId) return null; if (availableProviders.length === 0) { return (
{customHeader ? ( customHeader ) : (

Model

)}

No LLM API key set in project.

); } // Settings button component for reuse const SettingsButton = (

Model Advanced Settings

Configure advanced parameters for your model.

{modelParams.adapter.value === LLMAdapter.VertexAI && modelParams.maxReasoningTokens && ( )}
); // Compact layout - single horizontal row following standard codebase patterns if (layout === "compact") { // Create combined options in "Provider: model" format // We create combinations of all available providers with all available models // Current combined value in "Provider: model" format const currentCombinedValue = `${modelParams.provider.value}: ${modelParams.model.value}`; const handleCombinedSelection = (combinedValue: string) => { // Parse the combined value back into provider and model const colonIndex = combinedValue.indexOf(": "); if (colonIndex !== -1) { const provider = combinedValue.substring(0, colonIndex); const model = combinedValue.substring(colonIndex + 2); updateModelParamValue("provider", provider); updateModelParamValue("model", model); } }; return (
{modelParamsDescription ? ( {modelParamsDescription} ) : undefined}
{SettingsButton}
{modelParams.model.value?.startsWith("o1-") ? (

For {modelParams.model.value}, the system message and the temperature, max_tokens and top_p setting are not supported while it is in beta.{" "} More info ↗

) : null}
); } // Vertical layout (default) - existing behavior return (
{!isEmbedded ? (
{customHeader ? customHeader :

Model

} {SettingsButton}
) : (
{SettingsButton}
)}
); }; type ModelParamsSelectProps = { title: string; modelParamsKey: keyof UIModelParams; value: string; options: string[]; updateModelParam: ModelParamsContext["updateModelParamValue"]; disabled?: boolean; modelParamsDescription?: string; layout?: "vertical" | "compact"; }; const ModelParamsSelect = ({ title, modelParamsKey, value, options, updateModelParam, disabled, modelParamsDescription, layout = "vertical", }: ModelParamsSelectProps) => { const [createLlmApiKeyDialogOpen, setCreateLlmApiKeyDialogOpen] = useState(false); // Compact layout - simplified, space-efficient (no individual labels) if (layout === "compact") { return (
{modelParamsDescription ? ( {modelParamsDescription} ) : undefined}
); } // Vertical layout (default) - existing behavior return (

{title}

{modelParamsDescription ? ( {modelParamsDescription} ) : undefined}
); }; type ModelParamsSliderProps = { title: string; modelParamsKey: keyof UIModelParams; value: number; tooltip: string; min: number; max: number; step: number; updateModelParam: ModelParamsContext["updateModelParamValue"]; enabled?: boolean; formDisabled?: boolean; setModelParamEnabled?: ModelParamsContext["setModelParamEnabled"]; }; const ModelParamsSlider = ({ title, modelParamsKey, value, tooltip, min, max, step, updateModelParam, setModelParamEnabled, enabled, formDisabled, }: ModelParamsSliderProps) => { return (

{title}

{ updateModelParam( modelParamsKey, Math.max(Math.min(parseFloat(event.target.value), max), min), ); }} /> {setModelParamEnabled ? ( { setModelParamEnabled(modelParamsKey, checked); }} /> ) : null}
{ if (value[0] !== undefined) updateModelParam(modelParamsKey, value[0]); }} value={[value]} />
); }; type ProviderOptionsInputProps = { value: JSONObject | undefined; updateModelParam: ModelParamsContext["updateModelParamValue"]; setModelParamEnabled: ModelParamsContext["setModelParamEnabled"]; enabled: boolean; formDisabled: boolean; }; const ProviderOptionsInput = ({ value, updateModelParam, setModelParamEnabled, enabled, formDisabled, }: ProviderOptionsInputProps) => { const [inputValue, setInputValue] = useState( value ? JSON.stringify(value, null, 2) : "{}", ); const [error, setError] = useState(null); return (
Additional options Additional options to pass to the invocation. Please check your provider's API reference for supported values.
{setModelParamEnabled ? ( { setModelParamEnabled("providerOptions", checked); }} /> ) : null}
{enabled && (
{ setInputValue(value); try { const parsed = JSONObjectSchema.parse(JSON.parse(value)); updateModelParam("providerOptions", parsed); setError(null); } catch { setError("Invalid JSON Object"); } }} editable={enabled && !formDisabled} mode="json" minHeight="none" lineNumbers={false} /> {error && (

{error}

)}
)}
); };