Skip to content

Commit becd326

Browse files
made model names reader friendly
1 parent c249efa commit becd326

9 files changed

Lines changed: 92 additions & 35 deletions

File tree

client/src/components/Chat/Input/Mention.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { useAssistantsMapContext } from '~/Providers';
88
import useMentions from '~/hooks/Input/useMentions';
99
import { useLocalize, useCombobox, TranslationKeys } from '~/hooks';
1010
import { removeCharIfLast } from '~/utils';
11+
import { formatModelDisplayName } from '~/utils/modelNames';
1112
import MentionItem from './MentionItem';
1213

1314
const ROW_HEIGHT = 40;
@@ -90,7 +91,7 @@ export default function Mention({
9091
} else if (mention.type === 'endpoint') {
9192
const models = (modelsConfig?.[mention.value || ''] ?? []).map((model) => ({
9293
value: mention.value,
93-
label: model,
94+
label: formatModelDisplayName(model),
9495
type: 'model',
9596
}));
9697

client/src/components/Chat/Menus/Endpoints/components/EndpointItem.tsx

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -113,27 +113,36 @@ export function EndpointItem({ endpoint }: EndpointItemProps) {
113113
isAgentsEndpoint(endpoint.value) || isAssistantsEndpoint(endpoint.value)
114114
? localize('com_endpoint_search_var', { 0: endpoint.label })
115115
: localize('com_endpoint_search_endpoint_models', { 0: endpoint.label });
116+
117+
// Only show search bar if there are 5 or more models
118+
const modelCount = endpoint.models?.length || 0;
119+
const showSearchBar = modelCount >= 5;
120+
121+
const menuProps = {
122+
id: `endpoint-${endpoint.value}-menu`,
123+
key: `endpoint-${endpoint.value}-item`,
124+
className: "transition-opacity duration-200 ease-in-out",
125+
defaultOpen: endpoint.value === selectedEndpoint,
126+
label: (
127+
<div
128+
onClick={() => handleSelectEndpoint(endpoint)}
129+
className="group flex w-full flex-shrink cursor-pointer items-center justify-between rounded-xl px-1 py-1 text-sm"
130+
>
131+
{renderIconLabel()}
132+
{isUserProvided && (
133+
<SettingsButton endpoint={endpoint} handleOpenKeyDialog={handleOpenKeyDialog} />
134+
)}
135+
</div>
136+
),
137+
...(showSearchBar && {
138+
searchValue,
139+
onSearch: (value) => setEndpointSearchValue(endpoint.value, value),
140+
combobox: <input placeholder={placeholder} />
141+
})
142+
};
143+
116144
return (
117-
<Menu
118-
id={`endpoint-${endpoint.value}-menu`}
119-
key={`endpoint-${endpoint.value}-item`}
120-
className="transition-opacity duration-200 ease-in-out"
121-
defaultOpen={endpoint.value === selectedEndpoint}
122-
searchValue={searchValue}
123-
onSearch={(value) => setEndpointSearchValue(endpoint.value, value)}
124-
combobox={<input placeholder={placeholder} />}
125-
label={
126-
<div
127-
onClick={() => handleSelectEndpoint(endpoint)}
128-
className="group flex w-full flex-shrink cursor-pointer items-center justify-between rounded-xl px-1 py-1 text-sm"
129-
>
130-
{renderIconLabel()}
131-
{isUserProvided && (
132-
<SettingsButton endpoint={endpoint} handleOpenKeyDialog={handleOpenKeyDialog} />
133-
)}
134-
</div>
135-
}
136-
>
145+
<Menu {...menuProps}>
137146
{isAssistantsEndpoint(endpoint.value) && endpoint.models === undefined ? (
138147
<div className="flex items-center justify-center p-2">
139148
<Spinner />

client/src/components/Chat/Menus/Endpoints/components/EndpointModelItem.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { isAgentsEndpoint, isAssistantsEndpoint } from 'librechat-data-provider'
44
import type { Endpoint } from '~/common';
55
import { useModelSelectorContext } from '../ModelSelectorContext';
66
import { CustomMenuItem as MenuItem } from '../CustomMenu';
7+
import { formatModelDisplayName } from '~/utils/modelNames';
78

89
interface EndpointModelItemProps {
910
modelId: string | null;
@@ -30,6 +31,9 @@ export function EndpointModelItem({ modelId, endpoint, isSelected }: EndpointMod
3031
endpoint.assistantNames?.[modelId]
3132
) {
3233
modelName = endpoint.assistantNames[modelId];
34+
} else if (modelName) {
35+
// For regular models, format the display name
36+
modelName = formatModelDisplayName(modelName);
3337
}
3438

3539
return (

client/src/components/Chat/Menus/Endpoints/utils.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import type {
1010
import type { useLocalize } from '~/hooks';
1111
import SpecIcon from '~/components/Chat/Menus/Endpoints/components/SpecIcon';
1212
import { Endpoint, SelectedValues } from '~/common';
13+
import { formatModelDisplayName } from '~/utils/modelNames';
1314

1415
export function filterItems<
1516
T extends {
@@ -92,6 +93,9 @@ export function filterModels(
9293
const assistant = assistantsMap[endpoint.value][modelId];
9394
modelName =
9495
typeof assistant.name === 'string' && assistant.name ? (assistant.name as string) : modelId;
96+
} else {
97+
// For regular models, use the formatted display name for search
98+
modelName = formatModelDisplayName(modelId);
9599
}
96100

97101
return modelName.toLowerCase().includes(searchTermLower);
@@ -200,7 +204,7 @@ export const getDisplayValue = ({
200204
return endpoint.assistantNames[selectedValues.model];
201205
}
202206

203-
return selectedValues.model;
207+
return formatModelDisplayName(selectedValues.model);
204208
}
205209

206210
if (selectedValues.endpoint) {

client/src/components/SidePanel/Agents/ModelPanel.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { componentMapping } from '~/components/SidePanel/Parameters/components';
1313
import ControlCombobox from '~/components/ui/ControlCombobox';
1414
import { useGetEndpointsQuery } from '~/data-provider';
1515
import { getEndpointField, cn } from '~/utils';
16+
import { formatModelDisplayName } from '~/utils/modelNames';
1617
import { useLocalize } from '~/hooks';
1718
import { Panel } from '~/common';
1819
import keyBy from 'lodash/keyBy';
@@ -180,6 +181,7 @@ export default function ModelPanel({
180181
<>
181182
<ControlCombobox
182183
selectedValue={field.value || ''}
184+
displayValue={field.value ? formatModelDisplayName(field.value) : ''}
183185
selectPlaceholder={
184186
provider
185187
? localize('com_ui_select_model')
@@ -188,14 +190,15 @@ export default function ModelPanel({
188190
searchPlaceholder={localize('com_ui_select_model')}
189191
setValue={field.onChange}
190192
items={models.map((model) => ({
191-
label: model,
193+
label: formatModelDisplayName(model),
192194
value: model,
193195
}))}
194196
disabled={!provider}
195197
className={cn('disabled:opacity-50', error ? 'border-2 border-red-500' : '')}
196198
ariaLabel={localize('com_ui_model')}
197199
isCollapsed={false}
198200
showCarat={true}
201+
hideSearchWhenFewItems={true}
199202
/>
200203
{provider && error && (
201204
<span className="text-sm text-red-500 transition duration-300 ease-in-out">

client/src/components/ui/ControlCombobox.tsx

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ interface ControlComboboxProps {
2323
disabled?: boolean;
2424
iconSide?: 'left' | 'right';
2525
selectId?: string;
26+
hideSearchWhenFewItems?: boolean;
2627
}
2728

2829
const ROW_HEIGHT = 36;
@@ -44,10 +45,14 @@ function ControlCombobox({
4445
iconClassName,
4546
iconSide = 'left',
4647
selectId,
48+
hideSearchWhenFewItems = false,
4749
}: ControlComboboxProps) {
4850
const [searchValue, setSearchValue] = useState('');
4951
const buttonRef = useRef<HTMLButtonElement>(null);
5052
const [buttonWidth, setButtonWidth] = useState<number | null>(null);
53+
54+
// Determine if search should be shown
55+
const showSearch = !hideSearchWhenFewItems || items.length >= 5;
5156

5257
const getItem = (option: OptionWithIcon) => ({
5358
id: `item-${option.value}`,
@@ -160,17 +165,19 @@ function ControlCombobox({
160165
)}
161166
style={{ width: dropdownWidth }}
162167
>
163-
<div className="py-1.5">
164-
<div className="relative">
165-
<Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-primary" />
166-
<Ariakit.Combobox
167-
store={combobox}
168-
autoSelect
169-
placeholder={searchPlaceholder}
170-
className="w-full rounded-md bg-surface-secondary py-2 pl-9 pr-3 text-sm text-text-primary focus:outline-none"
171-
/>
168+
{showSearch && (
169+
<div className="py-1.5">
170+
<div className="relative">
171+
<Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-primary" />
172+
<Ariakit.Combobox
173+
store={combobox}
174+
autoSelect
175+
placeholder={searchPlaceholder}
176+
className="w-full rounded-md bg-surface-secondary py-2 pl-9 pr-3 text-sm text-text-primary focus:outline-none"
177+
/>
178+
</div>
172179
</div>
173-
</div>
180+
)}
174181
<div className="max-h-[300px] overflow-auto">
175182
<Ariakit.ComboboxList store={combobox}>
176183
<SelectRenderer store={select} items={matches} itemSize={ROW_HEIGHT} overscan={5}>

client/src/hooks/Input/useMentions.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import useAssistantListMap from '~/hooks/Assistants/useAssistantListMap';
2121
import { mapEndpoints, getPresetTitle } from '~/utils';
2222
import { EndpointIcon } from '~/components/Endpoints';
2323
import useHasAccess from '~/hooks/Roles/useHasAccess';
24+
import { formatModelDisplayName } from '~/utils/modelNames';
2425

2526
const defaultInterface = getConfigDefaults().interface;
2627

@@ -144,7 +145,7 @@ export default function useMentions({
144145

145146
const models = (modelsConfig?.[endpoint] ?? []).map((model) => ({
146147
value: endpoint,
147-
label: model,
148+
label: formatModelDisplayName(model),
148149
type: 'model' as const,
149150
icon: EndpointIcon({
150151
conversation: { endpoint, model },

client/src/locales/en/translation.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@
255255
"com_endpoint_save_as_preset": "Save As Preset",
256256
"com_endpoint_search": "Search endpoint by name",
257257
"com_endpoint_search_endpoint_models": "Search {{0}} models...",
258-
"com_endpoint_search_models": "Search models...",
258+
"com_endpoint_search_models": "Search...",
259259
"com_endpoint_search_var": "Search {{0}}...",
260260
"com_endpoint_set_custom_name": "Set a custom name, in case you can find this preset",
261261
"com_endpoint_skip_hover": "Enable skipping the completion step, which reviews the final answer and generated steps",

client/src/utils/modelNames.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* Formats model names for display by removing unnecessary suffixes and dates
3+
* while preserving the original model name for API calls
4+
*/
5+
6+
/**
7+
* Cleans up model names for display purposes
8+
* @param modelName - The original model name
9+
* @returns A cleaned up display name
10+
*/
11+
export function formatModelDisplayName(modelName: string): string {
12+
if (!modelName) return modelName;
13+
14+
// For Google models: remove everything from '-preview' onwards
15+
if (modelName.includes('-preview')) {
16+
return modelName.split('-preview')[0];
17+
}
18+
19+
// For Anthropic models: remove date patterns (YYYYMMDD or YYYY-MM-DD)
20+
// Matches patterns like -20250514, -2025-02-19, -20241022
21+
const datePattern = /-(?:\d{4}-\d{2}-\d{2}|\d{8})$/;
22+
if (datePattern.test(modelName)) {
23+
return modelName.replace(datePattern, '');
24+
}
25+
26+
// Return original name if no patterns match
27+
return modelName;
28+
}

0 commit comments

Comments
 (0)