diff --git a/src/utils/router.ts b/src/utils/router.ts index 8bd0e02b..3517cb7f 100644 --- a/src/utils/router.ts +++ b/src/utils/router.ts @@ -179,6 +179,23 @@ const getUseModel = async ( return Router!.default; }; +const setReqModel = (req: any, model: string) => { + // If the model is in format "{provider},default", use the original request model + if (model && model.includes(",")) { + const [provider, modelName] = model.split(","); + if (modelName.toLowerCase() === "default") { + // Extract the original model from request, keep provider but use original model name + const originalModel = req.body.model; + req.log.info(`Using default model placeholder - keeping original model: ${originalModel} with provider: ${provider}`); + req.body.model = `${provider},${originalModel}`; + } else { + req.body.model = model; + } + } else { + req.body.model = model; + } +} + export const router = async (req: any, _res: any, context: any) => { const { config, event } = context; // Parse sessionId from metadata.user_id @@ -221,10 +238,11 @@ export const router = async (req: any, _res: any, context: any) => { if (!model) { model = await getUseModel(req, tokenCount, config, lastMessageUsage); } - req.body.model = model; + setReqModel(req, model); } catch (error: any) { req.log.error(`Error in router middleware: ${error.message}`); - req.body.model = config.Router!.default; + // Fallback to default model in case of error + setReqModel(req, config.Router!.default); } return; }; diff --git a/ui/src/components/Router.tsx b/ui/src/components/Router.tsx index d2deccd0..877d63df 100644 --- a/ui/src/components/Router.tsx +++ b/ui/src/components/Router.tsx @@ -47,21 +47,24 @@ export function Router() { // Handle case where config.Providers might be null or undefined const providers = Array.isArray(config.Providers) ? config.Providers : []; - + + // Create model options with provider grouping and add "default" option for each provider const modelOptions = providers.flatMap((provider) => { // Handle case where individual provider might be null or undefined if (!provider) return []; - + // Handle case where provider.models might be null or undefined const models = Array.isArray(provider.models) ? provider.models : []; - + // Handle case where provider.name might be null or undefined const providerName = provider.name || "Unknown Provider"; - + return models.map((model) => ({ value: `${providerName},${model || "Unknown Model"}`, - label: `${providerName}, ${model || "Unknown Model"}`, - })); + label: `${model || "Unknown Model"}`, + displayLabel: `${providerName}, ${model || "Unknown Model"}`, + group: providerName, + })) }); return ( diff --git a/ui/src/components/ui/combobox.tsx b/ui/src/components/ui/combobox.tsx index d446599d..b4ade1a8 100644 --- a/ui/src/components/ui/combobox.tsx +++ b/ui/src/components/ui/combobox.tsx @@ -20,7 +20,12 @@ import { } from "@/components/ui/popover" interface ComboboxProps { - options: { label: string; value: string }[]; + options: { + label: string; + value: string; + group?: string; + displayLabel?: string; + }[]; value?: string; onChange: (value: string) => void; placeholder?: string; @@ -40,6 +45,31 @@ export function Combobox({ const selectedOption = options.find((option) => option.value === value) + // Check if any options have groups + const hasGroups = React.useMemo(() => { + return options.some((option) => option.group !== undefined); + }, [options]) + + // Group options by their group property if groups exist + const groupedOptions = React.useMemo(() => { + if (!hasGroups) { + // If no groups, return all options in a single unnamed group + return [[undefined, options] as [undefined, typeof options]] + } + + const groups = new Map() + + options.forEach((option) => { + const groupName = option.group || "Other"; + if (!groups.has(groupName)) { + groups.set(groupName, []) + } + groups.get(groupName)?.push(option) + }); + + return Array.from(groups.entries()); + }, [options, hasGroups]) + return ( @@ -49,7 +79,9 @@ export function Combobox({ aria-expanded={open} className="w-full justify-between transition-all-ease hover:scale-[1.02] active:scale-[0.98]" > - {selectedOption ? selectedOption.label : placeholder} + {selectedOption + ? selectedOption.displayLabel || selectedOption.label + : placeholder} @@ -58,30 +90,32 @@ export function Combobox({ {emptyPlaceholder} - - {options.map((option) => ( - { - onChange(currentValue === value ? "" : currentValue) - setOpen(false) - }} - className="transition-all-ease hover:bg-accent hover:text-accent-foreground" - > - - {option.label} - - ))} - + {groupedOptions.map(([groupName, groupOptions]) => ( + + {groupOptions.map((option) => ( + { + onChange(currentValue === value ? "" : currentValue) + setOpen(false) + }} + className="transition-all-ease hover:bg-accent hover:text-accent-foreground" + > + + {option.label} + + ))} + + ))} - ) -} \ No newline at end of file + ); +}