useLLMSelect: show starred models only

This commit is contained in:
Enrico Ros
2025-11-19 12:01:09 -08:00
parent 4cba819edd
commit 8a2c4aa356
2 changed files with 67 additions and 11 deletions
+39 -7
View File
@@ -1,7 +1,7 @@
import * as React from 'react';
import type { SxProps } from '@mui/joy/styles/types';
import { Box, Chip, ColorPaletteProp, FormControl, IconButton, ListDivider, ListItemDecorator, Option, optionClasses, Select, SelectSlotsAndSlotProps, SvgIconProps, VariantProp } from '@mui/joy';
import { Box, Chip, ColorPaletteProp, FormControl, IconButton, ListDivider, ListItem, ListItemButton, ListItemDecorator, Option, Select, SelectSlotsAndSlotProps, SvgIconProps, VariantProp, optionClasses } from '@mui/joy';
import ArrowForwardRoundedIcon from '@mui/icons-material/ArrowForwardRounded';
import AutoModeIcon from '@mui/icons-material/AutoMode';
import BuildCircleIcon from '@mui/icons-material/BuildCircle';
@@ -13,10 +13,11 @@ import { llmsGetVendorIcon, LLMVendorIcon } from '~/modules/llms/components/LLMV
import type { DModelDomainId } from '~/common/stores/llms/model.domains.types';
import { DLLM, DLLMId, getLLMPricing, LLM_IF_OAI_Reasoning, LLM_IF_Outputs_Audio, LLM_IF_Outputs_Image, LLM_IF_Tools_WebSearch } from '~/common/stores/llms/llms.types';
import { PhGearSixIcon } from '~/common/components/icons/phosphor/PhGearSixIcon';
import { StarredNoXL2 } from '~/common/components/StarIcons';
import { StarIconUnstyled, StarredNoXL2 } from '~/common/components/StarIcons';
import { TooltipOutlined } from '~/common/components/TooltipOutlined';
import { getChatLLMId, llmsStoreActions } from '~/common/stores/llms/store-llms';
import { optimaActions, optimaOpenModels } from '~/common/layout/optima/useOptima';
import { useUIPreferencesStore } from '~/common/stores/store-ui';
import { useVisibleLLMs } from '~/common/stores/llms/llms.hooks';
import { FormLabelStart } from './FormLabelStart';
@@ -58,6 +59,16 @@ const _styles = {
backgroundColor: 'background.popup',
boxShadow: 'xs',
},
listFooter: {
// '--ListItem-minHeight': '2.25rem',
borderTop: '1px solid',
borderTopColor: 'divider',
// pb: 0,
position: 'sticky',
bottom: 0,
backgroundColor: 'background.surface',
zIndex: 1,
},
listVendor: {
// see OptimaBarDropdown's _styles.separator
fontSize: 'sm',
@@ -130,6 +141,7 @@ interface LLMSelectOptions {
isHorizontal?: boolean;
autoRefreshDomain?: DModelDomainId;
appendConfigureModels?: boolean; // appends a bottom option to open the Models panel
showStarFilter?: boolean; // show a button to filter starred models only
}
/**
@@ -145,14 +157,18 @@ export function useLLMSelect(
options: LLMSelectOptions,
): [DLLM | null, React.JSX.Element | null, React.FunctionComponent<SvgIconProps> | undefined] {
// options
const { label, larger = false, disabled = false, placeholder = LLM_TEXT_PLACEHOLDER, isHorizontal = false, autoRefreshDomain, appendConfigureModels = false, showStarFilter = false } = options;
// state
const [controlledOpen, setControlledOpen] = React.useState(false);
// external state
const _filteredLLMs = useVisibleLLMs(llmId);
const starredOnly = useUIPreferencesStore(state => showStarFilter && state.showModelsStarredOnly);
// const modelsStarredOnTop = useUIPreferencesStore(state => state.modelsStarredOnTop); // unsupported, this creates some issues with groups I believe
const { llms: _filteredLLMs, hasStarred } = useVisibleLLMs(llmId, starredOnly, false);
// derived state
const { label, larger = false, disabled = false, placeholder = LLM_TEXT_PLACEHOLDER, isHorizontal = false, autoRefreshDomain, appendConfigureModels = false } = options;
const noIcons = false; //smaller;
const llm = !llmId ? null : _filteredLLMs.find(llm => llm.id === llmId) ?? null;
const isReasoning = !LLM_SELECT_SHOW_REASONING_ICON ? false : llm?.interfaces?.includes(LLM_IF_OAI_Reasoning) ?? false;
@@ -209,7 +225,7 @@ export function useLLMSelect(
>
{!noIcons && (
<ListItemDecorator>
{llm.userStarred ? <StarredNoXL2 /> : vendor?.id ? <LLMVendorIcon vendorId={vendor.id} /> : null}
{(llm.userStarred && !starredOnly) ? <StarredNoXL2 /> : vendor?.id ? <LLMVendorIcon vendorId={vendor.id} /> : null}
</ListItemDecorator>
)}
{/*<Tooltip title={llm.description}>*/}
@@ -244,7 +260,7 @@ export function useLLMSelect(
return acc;
}, [] as React.JSX.Element[]);
}, [_filteredLLMs, llmId, noIcons, optimizeToSingleVisibleId]);
}, [_filteredLLMs, llmId, noIcons, optimizeToSingleVisibleId, starredOnly]);
const onSelectChange = React.useCallback((_event: unknown, value: DLLMId | null) => {
@@ -297,10 +313,26 @@ export function useLLMSelect(
</Option>
)}
{/* Star Filter Toggle - shown at the top of the list only if visible */}
{showStarFilter && hasStarred && !optimizeToSingleVisibleId && (
<ListItem key='star-filter-toggle' sx={_styles.listFooter}>
<ListItemButton
variant={starredOnly ? 'soft' : 'plain'}
onClick={useUIPreferencesStore.getState().toggleShowModelsStarredOnly}
// sx={{ backgroundColor: 'background.surface', position: 'sticky', top: 0, zIndex: 1 }}
>
<ListItemDecorator>
<StarIconUnstyled isStarred={starredOnly} />
</ListItemDecorator>
{starredOnly ? 'Showing: Starred' : 'Showing: All'}
</ListItemButton>
</ListItem>
)}
</Select>
{/*</Box>*/}
</FormControl>
), [appendConfigureModels, autoRefreshDomain, controlledOpen, disabled, hasNoModels, isHorizontal, isReasoning, label, larger, llmId, onSelectChange, optimizeToSingleVisibleId, options.color, options.sx, options.variant, optionsArray, placeholder, showNoOptions]);
), [appendConfigureModels, autoRefreshDomain, controlledOpen, disabled, hasNoModels, hasStarred, isHorizontal, isReasoning, label, larger, llmId, onSelectChange, optimizeToSingleVisibleId, options.color, options.sx, options.variant, optionsArray, placeholder, showNoOptions, showStarFilter, starredOnly]);
// Memo the vendor icon for the chat LLM
const chatLLMVendorIconFC = React.useMemo(() => {
+28 -4
View File
@@ -15,16 +15,40 @@ export function useLLMs(llmIds: ReadonlyArray<DLLMId>): ReadonlyArray<DLLM | und
}));
}
function _sortStarredFirstComparator(a: { userStarred?: boolean }, b: { userStarred?: boolean }) {
if (a.userStarred && !b.userStarred) return -1;
if (!a.userStarred && b.userStarred) return 1;
return 0;
}
export function useLLMsByService(serviceId: false | DModelsServiceId): DLLM[] {
return useModelsStore(useShallow(
state => !serviceId ? state.llms : state.llms.filter(llm => llm.sId === serviceId),
));
}
export function useVisibleLLMs(includeLlmId: undefined | DLLMId | null): ReadonlyArray<DLLM> {
return useModelsStore(useShallow(
({ llms }) => llms.filter(llm => isLLMVisible(llm) || (includeLlmId && llm.id === includeLlmId)),
));
export function useVisibleLLMs(includeLlmId: undefined | DLLMId | null, starredOnly: boolean, starredFirst: boolean): { llms: ReadonlyArray<DLLM>; hasStarred: boolean } {
// for performance, we don't include this in the memo selector, as they'll change in tandem anyway
let hasStarred = false;
const llms = useModelsStore(useShallow(({ llms }) => {
// filter by visibility and starred status
const filtered = llms.filter((llm) => {
// finds out if any starred LLM exists
if (llm.userStarred) hasStarred = true;
// always include the specified LLM ID if provided
if (includeLlmId && llm.id === includeLlmId) return true;
// visibility filter
return isLLMVisible(llm) && (!starredOnly || llm.userStarred);
});
// sort starred first if requested
return !starredFirst ? filtered : filtered.sort(_sortStarredFirstComparator);
}));
return { llms, hasStarred };
}
export function useHasLLMs(): boolean {