mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-19 01:40:15 +01:00
🔧 refactor: Enhance Model & Endpoint Configurations with Global Indicators 🌍 (#6578)
* 🔧 fix: Simplify event handling in Badge component by always preventing default behavior and stopping propagation on toggle
* feat: show Global agents icon in ModelSelector
* feat: show Global agents icon in ModelSelector's search results
* refactor(Header): remove unused import
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* refactor(EndpointModelItem): remove unused import of useGetStartupConfig
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
b9ebdd4aa5
commit
e630c0a00d
13 changed files with 76 additions and 127 deletions
|
|
@ -9,7 +9,6 @@ import ExportAndShareMenu from './ExportAndShareMenu';
|
|||
import { useMediaQuery, useHasAccess } from '~/hooks';
|
||||
import BookmarkMenu from './Menus/BookmarkMenu';
|
||||
import AddMultiConvo from './AddMultiConvo';
|
||||
|
||||
const defaultInterface = getConfigDefaults().interface;
|
||||
|
||||
export default function Header() {
|
||||
|
|
@ -38,7 +37,7 @@ export default function Header() {
|
|||
<div className="hide-scrollbar flex w-full items-center justify-between gap-2 overflow-x-auto">
|
||||
<div className="mx-2 flex items-center gap-2">
|
||||
{!navVisible && <HeaderNewChat />}
|
||||
{<ModelSelector interfaceConfig={interfaceConfig} modelSpecs={modelSpecs} />}
|
||||
{<ModelSelector startupConfig={startupConfig} modelSpecs={modelSpecs} />}
|
||||
{interfaceConfig.presets === true && interfaceConfig.modelSelect && <PresetsMenu />}
|
||||
{hasAccessToBookmarks === true && <BookmarkMenu />}
|
||||
{hasAccessToMultiConvo === true && <AddMultiConvo />}
|
||||
|
|
|
|||
|
|
@ -98,9 +98,9 @@ function ModelSelectorContent() {
|
|||
);
|
||||
}
|
||||
|
||||
export default function ModelSelector({ interfaceConfig, modelSpecs }: ModelSelectorProps) {
|
||||
export default function ModelSelector({ startupConfig, modelSpecs }: ModelSelectorProps) {
|
||||
return (
|
||||
<ModelSelectorProvider modelSpecs={modelSpecs} interfaceConfig={interfaceConfig}>
|
||||
<ModelSelectorProvider modelSpecs={modelSpecs} startupConfig={startupConfig}>
|
||||
<ModelSelectorContent />
|
||||
</ModelSelectorProvider>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -45,13 +45,13 @@ export function useModelSelectorContext() {
|
|||
interface ModelSelectorProviderProps {
|
||||
children: React.ReactNode;
|
||||
modelSpecs: t.TModelSpec[];
|
||||
interfaceConfig: t.TInterfaceConfig;
|
||||
startupConfig: t.TStartupConfig | undefined;
|
||||
}
|
||||
|
||||
export function ModelSelectorProvider({
|
||||
children,
|
||||
modelSpecs,
|
||||
interfaceConfig,
|
||||
startupConfig,
|
||||
}: ModelSelectorProviderProps) {
|
||||
const agentsMap = useAgentsMapContext();
|
||||
const assistantsMap = useAssistantsMapContext();
|
||||
|
|
@ -61,7 +61,7 @@ export function ModelSelectorProvider({
|
|||
agentsMap,
|
||||
assistantsMap,
|
||||
endpointsConfig,
|
||||
interfaceConfig,
|
||||
startupConfig,
|
||||
});
|
||||
const { onSelectEndpoint, onSelectSpec } = useSelectMention({
|
||||
// presets,
|
||||
|
|
|
|||
|
|
@ -89,7 +89,13 @@ export function EndpointItem({ endpoint }: EndpointItemProps) {
|
|||
|
||||
if (endpoint.hasModels) {
|
||||
const filteredModels = searchValue
|
||||
? filterModels(endpoint, endpoint.models || [], searchValue, agentsMap, assistantsMap)
|
||||
? filterModels(
|
||||
endpoint,
|
||||
(endpoint.models || []).map((model) => model.name),
|
||||
searchValue,
|
||||
agentsMap,
|
||||
assistantsMap,
|
||||
)
|
||||
: null;
|
||||
const placeholder =
|
||||
isAgentsEndpoint(endpoint.value) || isAssistantsEndpoint(endpoint.value)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import React from 'react';
|
||||
import { EarthIcon } from 'lucide-react';
|
||||
import { isAgentsEndpoint, isAssistantsEndpoint } from 'librechat-data-provider';
|
||||
import type { Endpoint } from '~/common';
|
||||
import { useModelSelectorContext } from '../ModelSelectorContext';
|
||||
|
|
@ -12,12 +13,16 @@ interface EndpointModelItemProps {
|
|||
|
||||
export function EndpointModelItem({ modelId, endpoint, isSelected }: EndpointModelItemProps) {
|
||||
const { handleSelectModel } = useModelSelectorContext();
|
||||
let isGlobal = false;
|
||||
let modelName = modelId;
|
||||
const avatarUrl = endpoint?.modelIcons?.[modelId ?? ''] || null;
|
||||
|
||||
// Use custom names if available
|
||||
if (endpoint && modelId && isAgentsEndpoint(endpoint.value) && endpoint.agentNames?.[modelId]) {
|
||||
modelName = endpoint.agentNames[modelId];
|
||||
|
||||
const modelInfo = endpoint?.models?.find((m) => m.name === modelId);
|
||||
isGlobal = modelInfo?.isGlobal ?? false;
|
||||
} else if (
|
||||
endpoint &&
|
||||
modelId &&
|
||||
|
|
@ -46,6 +51,7 @@ export function EndpointModelItem({ modelId, endpoint, isSelected }: EndpointMod
|
|||
) : null}
|
||||
<span>{modelName}</span>
|
||||
</div>
|
||||
{isGlobal && <EarthIcon className="ml-auto size-4 text-green-400" />}
|
||||
{isSelected && (
|
||||
<svg
|
||||
width="16"
|
||||
|
|
@ -53,7 +59,7 @@ export function EndpointModelItem({ modelId, endpoint, isSelected }: EndpointMod
|
|||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="ml-auto block"
|
||||
className="block"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
|
|
@ -69,11 +75,11 @@ export function EndpointModelItem({ modelId, endpoint, isSelected }: EndpointMod
|
|||
|
||||
export function renderEndpointModels(
|
||||
endpoint: Endpoint | null,
|
||||
models: string[],
|
||||
models: Array<{ name: string; isGlobal?: boolean }>,
|
||||
selectedModel: string | null,
|
||||
filteredModels?: string[],
|
||||
) {
|
||||
const modelsToRender = filteredModels || models;
|
||||
const modelsToRender = filteredModels || models.map((model) => model.name);
|
||||
|
||||
return modelsToRender.map(
|
||||
(modelId) =>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Fragment } from 'react';
|
||||
import { EarthIcon } from 'lucide-react';
|
||||
import { isAgentsEndpoint, isAssistantsEndpoint } from 'librechat-data-provider';
|
||||
import type { TModelSpec } from 'librechat-data-provider';
|
||||
import type { Endpoint } from '~/common';
|
||||
|
|
@ -20,8 +21,6 @@ export function SearchResults({ results, localize, searchValue }: SearchResultsP
|
|||
handleSelectModel,
|
||||
handleSelectEndpoint,
|
||||
endpointsConfig,
|
||||
agentsMap,
|
||||
assistantsMap,
|
||||
} = useModelSelectorContext();
|
||||
|
||||
const {
|
||||
|
|
@ -102,20 +101,20 @@ export function SearchResults({ results, localize, searchValue }: SearchResultsP
|
|||
const lowerQuery = searchValue.toLowerCase();
|
||||
const filteredModels = endpoint.label.toLowerCase().includes(lowerQuery)
|
||||
? endpoint.models
|
||||
: endpoint.models.filter((modelId) => {
|
||||
let modelName = modelId;
|
||||
: endpoint.models.filter((model) => {
|
||||
let modelName = model.name;
|
||||
if (
|
||||
isAgentsEndpoint(endpoint.value) &&
|
||||
endpoint.agentNames &&
|
||||
endpoint.agentNames[modelId]
|
||||
endpoint.agentNames[model.name]
|
||||
) {
|
||||
modelName = endpoint.agentNames[modelId];
|
||||
modelName = endpoint.agentNames[model.name];
|
||||
} else if (
|
||||
isAssistantsEndpoint(endpoint.value) &&
|
||||
endpoint.assistantNames &&
|
||||
endpoint.assistantNames[modelId]
|
||||
endpoint.assistantNames[model.name]
|
||||
) {
|
||||
modelName = endpoint.assistantNames[modelId];
|
||||
modelName = endpoint.assistantNames[model.name];
|
||||
}
|
||||
return modelName.toLowerCase().includes(lowerQuery);
|
||||
});
|
||||
|
|
@ -134,7 +133,10 @@ export function SearchResults({ results, localize, searchValue }: SearchResultsP
|
|||
)}
|
||||
{endpoint.label}
|
||||
</div>
|
||||
{filteredModels.map((modelId) => {
|
||||
{filteredModels.map((model) => {
|
||||
const modelId = model.name;
|
||||
|
||||
let isGlobal = false;
|
||||
let modelName = modelId;
|
||||
if (
|
||||
isAgentsEndpoint(endpoint.value) &&
|
||||
|
|
@ -142,6 +144,8 @@ export function SearchResults({ results, localize, searchValue }: SearchResultsP
|
|||
endpoint.agentNames[modelId]
|
||||
) {
|
||||
modelName = endpoint.agentNames[modelId];
|
||||
const modelInfo = endpoint?.models?.find((m) => m.name === modelId);
|
||||
isGlobal = modelInfo?.isGlobal ?? false;
|
||||
} else if (
|
||||
isAssistantsEndpoint(endpoint.value) &&
|
||||
endpoint.assistantNames &&
|
||||
|
|
@ -168,6 +172,7 @@ export function SearchResults({ results, localize, searchValue }: SearchResultsP
|
|||
)}
|
||||
<span>{modelName}</span>
|
||||
</div>
|
||||
{isGlobal && <EarthIcon className="ml-auto size-4 text-green-400" />}
|
||||
{selectedEndpoint === endpoint.value && selectedModel === modelId && (
|
||||
<svg
|
||||
width="16"
|
||||
|
|
@ -175,7 +180,7 @@ export function SearchResults({ results, localize, searchValue }: SearchResultsP
|
|||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="ml-auto block"
|
||||
className="block"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
|
|
|
|||
|
|
@ -12,7 +12,12 @@ import SpecIcon from '~/components/Chat/Menus/Endpoints/components/SpecIcon';
|
|||
import { Endpoint, SelectedValues } from '~/common';
|
||||
|
||||
export function filterItems<
|
||||
T extends { label: string; name?: string; value?: string; models?: string[] },
|
||||
T extends {
|
||||
label: string;
|
||||
name?: string;
|
||||
value?: string;
|
||||
models?: Array<{ name: string; isGlobal?: boolean }>;
|
||||
},
|
||||
>(
|
||||
items: T[],
|
||||
searchValue: string,
|
||||
|
|
@ -36,18 +41,18 @@ export function filterItems<
|
|||
|
||||
if (item.models && item.models.length > 0) {
|
||||
return item.models.some((modelId) => {
|
||||
if (modelId.toLowerCase().includes(searchTermLower)) {
|
||||
if (modelId.name.toLowerCase().includes(searchTermLower)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isAgentsEndpoint(item.value) && agentsMap && modelId in agentsMap) {
|
||||
const agentName = agentsMap[modelId]?.name;
|
||||
if (isAgentsEndpoint(item.value) && agentsMap && modelId.name in agentsMap) {
|
||||
const agentName = agentsMap[modelId.name]?.name;
|
||||
return typeof agentName === 'string' && agentName.toLowerCase().includes(searchTermLower);
|
||||
}
|
||||
|
||||
if (isAssistantsEndpoint(item.value) && assistantsMap) {
|
||||
const endpoint = item.value ?? '';
|
||||
const assistant = assistantsMap[endpoint][modelId];
|
||||
const assistant = assistantsMap[endpoint][modelId.name];
|
||||
if (assistant && typeof assistant.name === 'string') {
|
||||
return assistant.name.toLowerCase().includes(searchTermLower);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,9 +44,7 @@ export default function Badge({
|
|||
}
|
||||
|
||||
if (!isEditing && onToggle) {
|
||||
if (typeof window !== 'undefined' && window.innerWidth >= 768) {
|
||||
e.preventDefault();
|
||||
}
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
onToggle();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue