import { useMemo } from 'react'; import { VisuallyHidden } from '@ariakit/react'; import { Spinner, TooltipAnchor } from '@librechat/client'; import { CheckCircle2, MousePointerClick, SettingsIcon } from 'lucide-react'; import { EModelEndpoint, isAgentsEndpoint, isAssistantsEndpoint } from 'librechat-data-provider'; import type { TModelSpec } from 'librechat-data-provider'; import type { Endpoint } from '~/common'; import { CustomMenu as Menu, CustomMenuItem as MenuItem } from '../CustomMenu'; import { useModelSelectorContext } from '../ModelSelectorContext'; import { renderEndpointModels } from './EndpointModelItem'; import { ModelSpecItem } from './ModelSpecItem'; import { filterModels } from '../utils'; import { useLocalize } from '~/hooks'; import { cn } from '~/utils'; interface EndpointItemProps { endpoint: Endpoint; endpointIndex: number; } const SettingsButton = ({ endpoint, className, handleOpenKeyDialog, }: { endpoint: Endpoint; className?: string; handleOpenKeyDialog: (endpoint: EModelEndpoint, e: React.MouseEvent) => void; }) => { const localize = useLocalize(); const text = localize('com_endpoint_config_key'); const handleClick = (e: React.MouseEvent) => { if (!endpoint.value) { return; } e.stopPropagation(); handleOpenKeyDialog(endpoint.value as EModelEndpoint, e); }; const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); e.stopPropagation(); if (endpoint.value) { handleOpenKeyDialog(endpoint.value as EModelEndpoint, e as unknown as React.MouseEvent); } } }; return ( ); }; export function EndpointItem({ endpoint, endpointIndex }: EndpointItemProps) { const localize = useLocalize(); const { agentsMap, assistantsMap, modelSpecs, selectedValues, handleOpenKeyDialog, handleSelectEndpoint, endpointSearchValues, setEndpointSearchValue, endpointRequiresUserKey, } = useModelSelectorContext(); const { model: selectedModel, endpoint: selectedEndpoint, modelSpec: selectedSpec, } = selectedValues; // Filter modelSpecs for this endpoint (by group matching endpoint value) const endpointSpecs = useMemo(() => { if (!modelSpecs || !modelSpecs.length) { return []; } return modelSpecs.filter((spec: TModelSpec) => spec.group === endpoint.value); }, [modelSpecs, endpoint.value]); const searchValue = endpointSearchValues[endpoint.value] || ''; const isUserProvided = useMemo( () => endpointRequiresUserKey(endpoint.value), [endpointRequiresUserKey, endpoint.value], ); const isAssistantsNotLoaded = isAssistantsEndpoint(endpoint.value) && endpoint.models === undefined; const renderIconLabel = () => (
{endpoint.icon && ( )} {endpoint.label}
); const isEndpointSelected = selectedEndpoint === endpoint.value; if (endpoint.hasModels) { const filteredModels = searchValue ? filterModels( endpoint, (endpoint.models || []).map((model) => model.name), searchValue, agentsMap, assistantsMap, ) : null; const placeholder = isAgentsEndpoint(endpoint.value) || isAssistantsEndpoint(endpoint.value) ? localize('com_endpoint_search_var', { 0: endpoint.label }) : localize('com_endpoint_search_endpoint_models', { 0: endpoint.label }); return ( setEndpointSearchValue(endpoint.value, value)} combobox={} comboboxLabel={placeholder} onClick={() => handleSelectEndpoint(endpoint)} label={
{renderIconLabel()}
{isUserProvided && ( )} {isEndpointSelected && ( <>
} > {isAssistantsEndpoint(endpoint.value) && endpoint.models === undefined ? (
) : ( <> {/* Render modelSpecs for this endpoint */} {endpointSpecs.map((spec: TModelSpec) => ( ))} {/* Render endpoint models */} {filteredModels ? renderEndpointModels( endpoint, endpoint.models || [], selectedModel, filteredModels, endpointIndex, ) : endpoint.models && renderEndpointModels( endpoint, endpoint.models, selectedModel, undefined, endpointIndex, )} )}
); } else { return ( handleSelectEndpoint(endpoint)} aria-selected={isEndpointSelected || undefined} className="group flex w-full cursor-pointer items-center justify-between gap-1.5 py-2 text-sm" > {renderIconLabel()}
{endpointRequiresUserKey(endpoint.value) && ( )} {isAssistantsNotLoaded && (
); } } export function renderEndpoints(mappedEndpoints: Endpoint[]) { return mappedEndpoints.map((endpoint, index) => ( )); }