mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-18 09:20:15 +01:00
🔧 refactor: Consolidate Logging, Model Selection & Actions Optimizations, Minor Fixes (#6553)
* 🔧 feat: Enhance logging configuration for production and debug environments * 🔒 feat: Implement encryption and decryption functions for sensitive values in ActionService with URL encoding/decoding * refactor: optimize action service for agent tools * refactor: optimize action processing for Assistants API * fix: handle case where agent is not found in loadAgent function * refactor: improve error handling in API calls by throwing new Error with logAxiosError output * chore: bump @librechat/agents to 2.3.95, fixes "Invalid tool call structure: No preceding AIMessage with tool_call_ids" * refactor: enhance error logging in logAxiosError function to include response status * refactor: remove unused useModelSelection hook from Endpoint * refactor: add support for assistants in useSelectorEffects hook * refactor: replace string easing with imported easings in Landing component * chore: remove duplicate translation * refactor: update model selection logic and improve localization for UI elements * refactor: replace endpoint value checks with helper functions for agents and assistants * refactor: optimize display value logic and utilize useMemo for performance improvements * refactor: clean up imports and optimize display/icon value logic in endpoint components, fix spec selection * refactor: enhance error logging in axios utility to include stack traces for better debugging * refactor: update logging configuration to use DEBUG_LOGGING and streamline log level handling * refactor: adjust className for export menu button to improve layout consistency and remove unused title prop from ShareButton * refactor: update import path for logAxiosError utility to improve module organization and clarity * refactor: implement debounced search value setter in ModelSelectorContext for improved performance
This commit is contained in:
parent
801b602e27
commit
299cabd6ed
26 changed files with 970 additions and 1135 deletions
|
|
@ -79,7 +79,7 @@ export default function ExportAndShareMenu({
|
|||
<Ariakit.MenuButton
|
||||
id="export-menu-button"
|
||||
aria-label="Export options"
|
||||
className="inline-flex size-10 items-center justify-center rounded-lg border border-border-light bg-transparent text-text-primary transition-all ease-in-out hover:bg-surface-tertiary disabled:pointer-events-none disabled:opacity-50 radix-state-open:bg-surface-tertiary"
|
||||
className="inline-flex size-10 flex-shrink-0 items-center justify-center rounded-lg border border-border-light bg-transparent text-text-primary transition-all ease-in-out hover:bg-surface-tertiary disabled:pointer-events-none disabled:opacity-50 radix-state-open:bg-surface-tertiary"
|
||||
>
|
||||
<Upload
|
||||
className="icon-md text-text-secondary"
|
||||
|
|
@ -103,7 +103,6 @@ export default function ExportAndShareMenu({
|
|||
<ShareButton
|
||||
triggerRef={shareButtonRef}
|
||||
conversationId={conversation.conversationId ?? ''}
|
||||
title={conversation.title ?? ''}
|
||||
open={showShareDialog}
|
||||
onOpenChange={setShowShareDialog}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useMemo, useCallback, useState, useEffect } from 'react';
|
||||
import { easings } from '@react-spring/web';
|
||||
import { useMemo, useCallback } from 'react';
|
||||
import { EModelEndpoint } from 'librechat-data-provider';
|
||||
import type * as t from 'librechat-data-provider';
|
||||
import { useChatContext, useAgentsMapContext, useAssistantsMapContext } from '~/Providers';
|
||||
import { useGetEndpointsQuery, useGetStartupConfig } from '~/data-provider';
|
||||
import { BirthdayIcon, TooltipAnchor, SplitText } from '~/components';
|
||||
|
|
@ -117,7 +117,7 @@ export default function Landing({ centerFormOnLanding }: { centerFormOnLanding:
|
|||
textAlign="center"
|
||||
animationFrom={{ opacity: 0, transform: 'translate3d(0,50px,0)' }}
|
||||
animationTo={{ opacity: 1, transform: 'translate3d(0,0,0)' }}
|
||||
easing="easeOutCubic"
|
||||
easing={easings.easeOutCubic}
|
||||
threshold={0}
|
||||
rootMargin="0px"
|
||||
/>
|
||||
|
|
@ -131,7 +131,7 @@ export default function Landing({ centerFormOnLanding }: { centerFormOnLanding:
|
|||
textAlign="center"
|
||||
animationFrom={{ opacity: 0, transform: 'translate3d(0,50px,0)' }}
|
||||
animationTo={{ opacity: 1, transform: 'translate3d(0,0,0)' }}
|
||||
easing="easeOutCubic"
|
||||
easing={easings.easeOutCubic}
|
||||
threshold={0}
|
||||
rootMargin="0px"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import type { ModelSelectorProps } from '~/common';
|
||||
import { ModelSelectorProvider, useModelSelectorContext } from './ModelSelectorContext';
|
||||
import { renderModelSpecs, renderEndpoints, renderSearchResults } from './components';
|
||||
import { getSelectedIcon, getDisplayValue } from './utils';
|
||||
import { CustomMenu as Menu } from './CustomMenu';
|
||||
import DialogManager from './DialogManager';
|
||||
import { getSelectedIcon } from './utils';
|
||||
import { useLocalize } from '~/hooks';
|
||||
|
||||
function ModelSelectorContent() {
|
||||
|
|
@ -22,7 +22,6 @@ function ModelSelectorContent() {
|
|||
|
||||
// Functions
|
||||
setSearchValue,
|
||||
getDisplayValue,
|
||||
setSelectedValues,
|
||||
// Dialog
|
||||
keyDialogOpen,
|
||||
|
|
@ -30,18 +29,31 @@ function ModelSelectorContent() {
|
|||
keyDialogEndpoint,
|
||||
} = useModelSelectorContext();
|
||||
|
||||
const selectedIcon = getSelectedIcon({
|
||||
mappedEndpoints: mappedEndpoints ?? [],
|
||||
selectedValues,
|
||||
modelSpecs,
|
||||
endpointsConfig,
|
||||
});
|
||||
const selectedDisplayValue = getDisplayValue();
|
||||
const selectedIcon = useMemo(
|
||||
() =>
|
||||
getSelectedIcon({
|
||||
mappedEndpoints: mappedEndpoints ?? [],
|
||||
selectedValues,
|
||||
modelSpecs,
|
||||
endpointsConfig,
|
||||
}),
|
||||
[mappedEndpoints, selectedValues, modelSpecs, endpointsConfig],
|
||||
);
|
||||
const selectedDisplayValue = useMemo(
|
||||
() =>
|
||||
getDisplayValue({
|
||||
localize,
|
||||
modelSpecs,
|
||||
selectedValues,
|
||||
mappedEndpoints,
|
||||
}),
|
||||
[localize, modelSpecs, selectedValues, mappedEndpoints],
|
||||
);
|
||||
|
||||
const trigger = (
|
||||
<button
|
||||
className="my-1 flex h-10 w-full max-w-[70vw] items-center justify-center gap-2 rounded-xl border border-border-light bg-surface-secondary px-3 py-2 text-sm text-text-primary hover:bg-surface-tertiary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white"
|
||||
aria-label={localize('com_endpoint_select_model')}
|
||||
aria-label={localize('com_ui_select_model')}
|
||||
>
|
||||
{selectedIcon && React.isValidElement(selectedIcon) && (
|
||||
<div className="flex flex-shrink-0 items-center justify-center overflow-hidden">
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import React, { startTransition, createContext, useContext, useState, useMemo } from 'react';
|
||||
import { EModelEndpoint, isAgentsEndpoint, isAssistantsEndpoint } from 'librechat-data-provider';
|
||||
import debounce from 'lodash/debounce';
|
||||
import React, { createContext, useContext, useState, useMemo } from 'react';
|
||||
import { isAgentsEndpoint, isAssistantsEndpoint } from 'librechat-data-provider';
|
||||
import type * as t from 'librechat-data-provider';
|
||||
import type { Endpoint, SelectedValues } from '~/common';
|
||||
import { useAgentsMapContext, useAssistantsMapContext, useChatContext } from '~/Providers';
|
||||
import { useEndpoints, useSelectorEffects, useKeyDialog, useLocalize } from '~/hooks';
|
||||
import { useEndpoints, useSelectorEffects, useKeyDialog } from '~/hooks';
|
||||
import useSelectMention from '~/hooks/Input/useSelectMention';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import { filterItems } from './utils';
|
||||
|
|
@ -22,7 +23,6 @@ type ModelSelectorContextType = {
|
|||
endpointsConfig: t.TEndpointsConfig;
|
||||
|
||||
// Functions
|
||||
getDisplayValue: () => string;
|
||||
endpointRequiresUserKey: (endpoint: string) => boolean;
|
||||
setSelectedValues: React.Dispatch<React.SetStateAction<SelectedValues>>;
|
||||
setSearchValue: (value: string) => void;
|
||||
|
|
@ -53,7 +53,6 @@ export function ModelSelectorProvider({
|
|||
modelSpecs,
|
||||
interfaceConfig,
|
||||
}: ModelSelectorProviderProps) {
|
||||
const localize = useLocalize();
|
||||
const agentsMap = useAgentsMapContext();
|
||||
const assistantsMap = useAssistantsMapContext();
|
||||
const { data: endpointsConfig } = useGetEndpointsQuery();
|
||||
|
|
@ -101,10 +100,13 @@ export function ModelSelectorProvider({
|
|||
}, [searchValue, modelSpecs, mappedEndpoints, agentsMap, assistantsMap]);
|
||||
|
||||
// Functions
|
||||
const setSearchValue = (value: string) => {
|
||||
startTransition(() => setSearchValueState(value));
|
||||
};
|
||||
|
||||
const setDebouncedSearchValue = useMemo(
|
||||
() =>
|
||||
debounce((value: string) => {
|
||||
setSearchValueState(value);
|
||||
}, 200),
|
||||
[],
|
||||
);
|
||||
const setEndpointSearchValue = (endpoint: string, value: string) => {
|
||||
setEndpointSearchValues((prev) => ({
|
||||
...prev,
|
||||
|
|
@ -113,10 +115,16 @@ export function ModelSelectorProvider({
|
|||
};
|
||||
|
||||
const handleSelectSpec = (spec: t.TModelSpec) => {
|
||||
let model = spec.preset.model ?? null;
|
||||
onSelectSpec?.(spec);
|
||||
if (isAgentsEndpoint(spec.preset.endpoint)) {
|
||||
model = spec.preset.agent_id ?? '';
|
||||
} else if (isAssistantsEndpoint(spec.preset.endpoint)) {
|
||||
model = spec.preset.assistant_id ?? '';
|
||||
}
|
||||
setSelectedValues({
|
||||
endpoint: spec.preset.endpoint,
|
||||
model: spec.preset.model ?? null,
|
||||
model,
|
||||
modelSpec: spec.name,
|
||||
});
|
||||
};
|
||||
|
|
@ -154,46 +162,6 @@ export function ModelSelectorProvider({
|
|||
});
|
||||
};
|
||||
|
||||
const getDisplayValue = () => {
|
||||
if (selectedValues.modelSpec) {
|
||||
const spec = modelSpecs.find((s) => s.name === selectedValues.modelSpec);
|
||||
return spec?.label || localize('com_endpoint_select_model');
|
||||
}
|
||||
|
||||
if (selectedValues.model && selectedValues.endpoint) {
|
||||
const endpoint = mappedEndpoints.find((e) => e.value === selectedValues.endpoint);
|
||||
if (!endpoint) {
|
||||
return localize('com_endpoint_select_model');
|
||||
}
|
||||
|
||||
if (
|
||||
endpoint.value === EModelEndpoint.agents &&
|
||||
endpoint.agentNames &&
|
||||
endpoint.agentNames[selectedValues.model]
|
||||
) {
|
||||
return endpoint.agentNames[selectedValues.model];
|
||||
}
|
||||
|
||||
if (
|
||||
(endpoint.value === EModelEndpoint.assistants ||
|
||||
endpoint.value === EModelEndpoint.azureAssistants) &&
|
||||
endpoint.assistantNames &&
|
||||
endpoint.assistantNames[selectedValues.model]
|
||||
) {
|
||||
return endpoint.assistantNames[selectedValues.model];
|
||||
}
|
||||
|
||||
return selectedValues.model;
|
||||
}
|
||||
|
||||
if (selectedValues.endpoint) {
|
||||
const endpoint = mappedEndpoints.find((e) => e.value === selectedValues.endpoint);
|
||||
return endpoint?.label || localize('com_endpoint_select_model');
|
||||
}
|
||||
|
||||
return localize('com_endpoint_select_model');
|
||||
};
|
||||
|
||||
const value = {
|
||||
// State
|
||||
searchValue,
|
||||
|
|
@ -208,14 +176,13 @@ export function ModelSelectorProvider({
|
|||
endpointsConfig,
|
||||
|
||||
// Functions
|
||||
setSearchValue,
|
||||
getDisplayValue,
|
||||
handleSelectSpec,
|
||||
handleSelectModel,
|
||||
setSelectedValues,
|
||||
handleSelectEndpoint,
|
||||
setEndpointSearchValue,
|
||||
endpointRequiresUserKey,
|
||||
setSearchValue: setDebouncedSearchValue,
|
||||
// Dialog
|
||||
...keyProps,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -116,17 +116,15 @@ export function EndpointItem({ endpoint }: EndpointItemProps) {
|
|||
</div>
|
||||
}
|
||||
>
|
||||
{(endpoint.value === EModelEndpoint.assistants ||
|
||||
endpoint.value === EModelEndpoint.azureAssistants) &&
|
||||
endpoint.models === undefined ? (
|
||||
<div className="flex items-center justify-center p-2">
|
||||
<Spinner />
|
||||
</div>
|
||||
) : filteredModels ? (
|
||||
renderEndpointModels(endpoint, endpoint.models || [], selectedModel, filteredModels)
|
||||
) : (
|
||||
endpoint.models && renderEndpointModels(endpoint, endpoint.models, selectedModel)
|
||||
)}
|
||||
{isAssistantsEndpoint(endpoint.value) && endpoint.models === undefined ? (
|
||||
<div className="flex items-center justify-center p-2">
|
||||
<Spinner />
|
||||
</div>
|
||||
) : filteredModels ? (
|
||||
renderEndpointModels(endpoint, endpoint.models || [], selectedModel, filteredModels)
|
||||
) : (
|
||||
endpoint.models && renderEndpointModels(endpoint, endpoint.models, selectedModel)
|
||||
)}
|
||||
</Menu>
|
||||
);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { EModelEndpoint } from 'librechat-data-provider';
|
||||
import { isAgentsEndpoint, isAssistantsEndpoint } from 'librechat-data-provider';
|
||||
import type { Endpoint } from '~/common';
|
||||
import { useModelSelectorContext } from '../ModelSelectorContext';
|
||||
import { CustomMenuItem as MenuItem } from '../CustomMenu';
|
||||
|
|
@ -16,18 +16,12 @@ export function EndpointModelItem({ modelId, endpoint, isSelected }: EndpointMod
|
|||
const avatarUrl = endpoint?.modelIcons?.[modelId ?? ''] || null;
|
||||
|
||||
// Use custom names if available
|
||||
if (
|
||||
endpoint &&
|
||||
modelId &&
|
||||
endpoint.value === EModelEndpoint.agents &&
|
||||
endpoint.agentNames?.[modelId]
|
||||
) {
|
||||
if (endpoint && modelId && isAgentsEndpoint(endpoint.value) && endpoint.agentNames?.[modelId]) {
|
||||
modelName = endpoint.agentNames[modelId];
|
||||
} else if (
|
||||
endpoint &&
|
||||
modelId &&
|
||||
(endpoint.value === EModelEndpoint.assistants ||
|
||||
endpoint.value === EModelEndpoint.azureAssistants) &&
|
||||
isAssistantsEndpoint(endpoint.value) &&
|
||||
endpoint.assistantNames?.[modelId]
|
||||
) {
|
||||
modelName = endpoint.assistantNames[modelId];
|
||||
|
|
@ -44,9 +38,7 @@ export function EndpointModelItem({ modelId, endpoint, isSelected }: EndpointMod
|
|||
<div className="flex h-5 w-5 items-center justify-center overflow-hidden rounded-full">
|
||||
<img src={avatarUrl} alt={modelName ?? ''} className="h-full w-full object-cover" />
|
||||
</div>
|
||||
) : (endpoint.value === EModelEndpoint.agents ||
|
||||
endpoint.value === EModelEndpoint.assistants ||
|
||||
endpoint.value === EModelEndpoint.azureAssistants) &&
|
||||
) : (isAgentsEndpoint(endpoint.value) || isAssistantsEndpoint(endpoint.value)) &&
|
||||
endpoint.icon ? (
|
||||
<div className="flex h-5 w-5 items-center justify-center overflow-hidden rounded-full">
|
||||
{endpoint.icon}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { Fragment } from 'react';
|
||||
import { EModelEndpoint } from 'librechat-data-provider';
|
||||
import { isAgentsEndpoint, isAssistantsEndpoint } from 'librechat-data-provider';
|
||||
import type { TModelSpec } from 'librechat-data-provider';
|
||||
import type { Endpoint } from '~/common';
|
||||
import { useModelSelectorContext } from '../ModelSelectorContext';
|
||||
|
|
@ -105,14 +105,13 @@ export function SearchResults({ results, localize, searchValue }: SearchResultsP
|
|||
: endpoint.models.filter((modelId) => {
|
||||
let modelName = modelId;
|
||||
if (
|
||||
endpoint.value === EModelEndpoint.agents &&
|
||||
isAgentsEndpoint(endpoint.value) &&
|
||||
endpoint.agentNames &&
|
||||
endpoint.agentNames[modelId]
|
||||
) {
|
||||
modelName = endpoint.agentNames[modelId];
|
||||
} else if (
|
||||
(endpoint.value === EModelEndpoint.assistants ||
|
||||
endpoint.value === EModelEndpoint.azureAssistants) &&
|
||||
isAssistantsEndpoint(endpoint.value) &&
|
||||
endpoint.assistantNames &&
|
||||
endpoint.assistantNames[modelId]
|
||||
) {
|
||||
|
|
@ -138,14 +137,13 @@ export function SearchResults({ results, localize, searchValue }: SearchResultsP
|
|||
{filteredModels.map((modelId) => {
|
||||
let modelName = modelId;
|
||||
if (
|
||||
endpoint.value === EModelEndpoint.agents &&
|
||||
isAgentsEndpoint(endpoint.value) &&
|
||||
endpoint.agentNames &&
|
||||
endpoint.agentNames[modelId]
|
||||
) {
|
||||
modelName = endpoint.agentNames[modelId];
|
||||
} else if (
|
||||
(endpoint.value === EModelEndpoint.assistants ||
|
||||
endpoint.value === EModelEndpoint.azureAssistants) &&
|
||||
isAssistantsEndpoint(endpoint.value) &&
|
||||
endpoint.assistantNames &&
|
||||
endpoint.assistantNames[modelId]
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
import React from 'react';
|
||||
import { Bot } from 'lucide-react';
|
||||
import { EModelEndpoint } from 'librechat-data-provider';
|
||||
import { isAgentsEndpoint, isAssistantsEndpoint } from 'librechat-data-provider';
|
||||
import type {
|
||||
TModelSpec,
|
||||
TAgentsMap,
|
||||
TAssistantsMap,
|
||||
TEndpointsConfig,
|
||||
TModelSpec,
|
||||
} from 'librechat-data-provider';
|
||||
import type { useLocalize } from '~/hooks';
|
||||
import SpecIcon from '~/components/Chat/Menus/Endpoints/components/SpecIcon';
|
||||
import { Endpoint, SelectedValues } from '~/common';
|
||||
|
||||
|
|
@ -39,17 +40,13 @@ export function filterItems<
|
|||
return true;
|
||||
}
|
||||
|
||||
if (item.value === EModelEndpoint.agents && agentsMap && modelId in agentsMap) {
|
||||
if (isAgentsEndpoint(item.value) && agentsMap && modelId in agentsMap) {
|
||||
const agentName = agentsMap[modelId]?.name;
|
||||
return typeof agentName === 'string' && agentName.toLowerCase().includes(searchTermLower);
|
||||
}
|
||||
|
||||
if (
|
||||
(item.value === EModelEndpoint.assistants ||
|
||||
item.value === EModelEndpoint.azureAssistants) &&
|
||||
assistantsMap
|
||||
) {
|
||||
const endpoint = item.value;
|
||||
if (isAssistantsEndpoint(item.value) && assistantsMap) {
|
||||
const endpoint = item.value ?? '';
|
||||
const assistant = assistantsMap[endpoint][modelId];
|
||||
if (assistant && typeof assistant.name === 'string') {
|
||||
return assistant.name.toLowerCase().includes(searchTermLower);
|
||||
|
|
@ -80,11 +77,10 @@ export function filterModels(
|
|||
return models.filter((modelId) => {
|
||||
let modelName = modelId;
|
||||
|
||||
if (endpoint.value === EModelEndpoint.agents && agentsMap && agentsMap[modelId]) {
|
||||
if (isAgentsEndpoint(endpoint.value) && agentsMap && agentsMap[modelId]) {
|
||||
modelName = agentsMap[modelId].name || modelId;
|
||||
} else if (
|
||||
(endpoint.value === EModelEndpoint.assistants ||
|
||||
endpoint.value === EModelEndpoint.azureAssistants) &&
|
||||
isAssistantsEndpoint(endpoint.value) &&
|
||||
assistantsMap &&
|
||||
assistantsMap[endpoint.value]
|
||||
) {
|
||||
|
|
@ -160,3 +156,52 @@ export function getSelectedIcon({
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
export const getDisplayValue = ({
|
||||
localize,
|
||||
mappedEndpoints,
|
||||
selectedValues,
|
||||
modelSpecs,
|
||||
}: {
|
||||
localize: ReturnType<typeof useLocalize>;
|
||||
selectedValues: SelectedValues;
|
||||
mappedEndpoints: Endpoint[];
|
||||
modelSpecs: TModelSpec[];
|
||||
}) => {
|
||||
if (selectedValues.modelSpec) {
|
||||
const spec = modelSpecs.find((s) => s.name === selectedValues.modelSpec);
|
||||
return spec?.label || spec?.name || localize('com_ui_select_model');
|
||||
}
|
||||
|
||||
if (selectedValues.model && selectedValues.endpoint) {
|
||||
const endpoint = mappedEndpoints.find((e) => e.value === selectedValues.endpoint);
|
||||
if (!endpoint) {
|
||||
return localize('com_ui_select_model');
|
||||
}
|
||||
|
||||
if (
|
||||
isAgentsEndpoint(endpoint.value) &&
|
||||
endpoint.agentNames &&
|
||||
endpoint.agentNames[selectedValues.model]
|
||||
) {
|
||||
return endpoint.agentNames[selectedValues.model];
|
||||
}
|
||||
|
||||
if (
|
||||
isAssistantsEndpoint(endpoint.value) &&
|
||||
endpoint.assistantNames &&
|
||||
endpoint.assistantNames[selectedValues.model]
|
||||
) {
|
||||
return endpoint.assistantNames[selectedValues.model];
|
||||
}
|
||||
|
||||
return selectedValues.model;
|
||||
}
|
||||
|
||||
if (selectedValues.endpoint) {
|
||||
const endpoint = mappedEndpoints.find((e) => e.value === selectedValues.endpoint);
|
||||
return endpoint?.label || localize('com_ui_select_model');
|
||||
}
|
||||
|
||||
return localize('com_ui_select_model');
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue