diff --git a/api/server/routes/assistants/assistants.js b/api/server/routes/assistants/assistants.js index d9c58e6600..70c685a97a 100644 --- a/api/server/routes/assistants/assistants.js +++ b/api/server/routes/assistants/assistants.js @@ -149,7 +149,7 @@ router.delete('/:id', async (req, res) => { */ router.get('/', async (req, res) => { try { - const { limit, order, after, before } = req.query; + const { limit = 100, order = 'desc', after, before } = req.query; const query = { limit, order, after, before }; const azureConfig = req.app.locals[EModelEndpoint.azureOpenAI]; diff --git a/api/server/routes/assistants/chat.js b/api/server/routes/assistants/chat.js index b77a93220f..47580cc686 100644 --- a/api/server/routes/assistants/chat.js +++ b/api/server/routes/assistants/chat.js @@ -154,6 +154,12 @@ router.post('/', validateModel, buildEndpointOption, setHeaders, async (req, res : '' }`; return sendResponse(res, messageData, errorMessage); + } else if (error?.message?.includes('string too long')) { + return sendResponse( + res, + messageData, + 'Message too long. The Assistants API has a limit of 32,768 characters per message. Please shorten it and try again.', + ); } else if (error?.message?.includes(ViolationTypes.TOKEN_BALANCE)) { return sendResponse(res, messageData, error.message); } else { diff --git a/client/src/components/Endpoints/Settings/Assistants.tsx b/client/src/components/Endpoints/Settings/Assistants.tsx index 469a5a916f..8fe4ed9504 100644 --- a/client/src/components/Endpoints/Settings/Assistants.tsx +++ b/client/src/components/Endpoints/Settings/Assistants.tsx @@ -1,6 +1,7 @@ import { useState, useMemo, useEffect } from 'react'; import TextareaAutosize from 'react-textarea-autosize'; -import { TPreset, defaultOrderQuery } from 'librechat-data-provider'; +import { defaultOrderQuery } from 'librechat-data-provider'; +import type { TPreset } from 'librechat-data-provider'; import type { TModelSelectProps, Option } from '~/common'; import { Label, HoverCard, SelectDropDown, HoverCardTrigger } from '~/components/ui'; import { cn, defaultTextProps, removeFocusOutlines, mapAssistants } from '~/utils'; diff --git a/client/src/components/SidePanel/Builder/AssistantSelect.tsx b/client/src/components/SidePanel/Builder/AssistantSelect.tsx index 6ae3a9aa06..07b88cb060 100644 --- a/client/src/components/SidePanel/Builder/AssistantSelect.tsx +++ b/client/src/components/SidePanel/Builder/AssistantSelect.tsx @@ -169,6 +169,8 @@ export default function AssistantSelect({ showLabel={false} emptyTitle={true} containerClassName="flex-grow" + searchClassName="dark:from-gray-850" + searchPlaceholder={localize('com_assistants_search_name')} optionsClass="hover:bg-gray-20/50 dark:border-gray-700" optionsListClass="rounded-lg shadow-lg dark:bg-gray-850 dark:border-gray-700 dark:last:border" currentValueClass={cn( diff --git a/client/src/components/ui/MultiSearch.tsx b/client/src/components/ui/MultiSearch.tsx index ce7bd4fa0a..c3b3c563b2 100644 --- a/client/src/components/ui/MultiSearch.tsx +++ b/client/src/components/ui/MultiSearch.tsx @@ -9,10 +9,12 @@ export default function MultiSearch({ value, onChange, placeholder, + className = '', }: { value: string | null; onChange: (filter: string) => void; placeholder?: string; + className?: string; }) { const localize = useLocalize(); const onChangeHandler: React.ChangeEventHandler = useCallback( @@ -21,7 +23,12 @@ export default function MultiSearch({ ); return ( -
+
( - availableOptions: OptionsType, - placeholder?: string, - getTextKeyOverride?: (node: OptionsType[0]) => string, -): [OptionsType, React.ReactNode] { +export function useMultiSearch({ + availableOptions, + placeholder, + getTextKeyOverride, + className, + disabled = false, +}: { + availableOptions: OptionsType; + placeholder?: string; + getTextKeyOverride?: (node: OptionsType[0]) => string; + className?: string; + disabled?: boolean; +}): [OptionsType, React.ReactNode] { const [filterValue, setFilterValue] = useState(null); // We conditionally show the search when there's more than 10 elements in the menu - const shouldShowSearch = availableOptions.length > 10; + const shouldShowSearch = availableOptions.length > 10 && !disabled; // Define the helper function used to enable search // If this is invalidly described, we will assume developer error - tf. avoid rendering @@ -103,7 +120,12 @@ export function useMultiSearch( const onSearchChange = useCallback((nextFilterValue) => setFilterValue(nextFilterValue), []); const searchRender = shouldShowSearch ? ( - + ) : null; return [filteredOptions, searchRender]; diff --git a/client/src/components/ui/MultiSelectDropDown.tsx b/client/src/components/ui/MultiSelectDropDown.tsx index 13065ed4d4..7fb2856525 100644 --- a/client/src/components/ui/MultiSelectDropDown.tsx +++ b/client/src/components/ui/MultiSelectDropDown.tsx @@ -48,11 +48,12 @@ function MultiSelectDropDown({ // input will appear near the top of the menu, allowing correct filtering of different model menu items. This will // reset once the component is unmounted (as per a normal search) - const [filteredValues, searchRender] = useMultiSearch( - availableValues, - searchPlaceholder, - (option) => (option.name || '').toUpperCase(), - ); + const [filteredValues, searchRender] = useMultiSearch({ + availableOptions: availableValues, + placeholder: searchPlaceholder, + getTextKeyOverride: (option) => (option.name || '').toUpperCase(), + }); + const hasSearchRender = Boolean(searchRender); const options = hasSearchRender ? filteredValues : availableValues; @@ -65,6 +66,7 @@ function MultiSelectDropDown({
{/* the function typing is correct but there's still an issue here */} + {/* @ts-ignore */} {() => ( <> diff --git a/client/src/components/ui/MultiSelectPop.tsx b/client/src/components/ui/MultiSelectPop.tsx index 729d93fef4..72f52a8c40 100644 --- a/client/src/components/ui/MultiSelectPop.tsx +++ b/client/src/components/ui/MultiSelectPop.tsx @@ -39,11 +39,11 @@ function MultiSelectPop({ const excludeIds = ['select-plugin', 'plugins-label', 'selected-plugins']; // Detemine if we should to convert this component into a searchable select - const [filteredValues, searchRender] = useMultiSearch( - availableValues, - searchPlaceholder, - (option) => (option.name || '').toUpperCase(), - ); + const [filteredValues, searchRender] = useMultiSearch({ + availableOptions: availableValues, + placeholder: searchPlaceholder, + getTextKeyOverride: (option) => (option.name || '').toUpperCase(), + }); const hasSearchRender = Boolean(searchRender); const options = hasSearchRender ? filteredValues : availableValues; diff --git a/client/src/components/ui/SelectDropDown.tsx b/client/src/components/ui/SelectDropDown.tsx index 033e7ac35a..53f6df2bbb 100644 --- a/client/src/components/ui/SelectDropDown.tsx +++ b/client/src/components/ui/SelectDropDown.tsx @@ -24,6 +24,8 @@ type SelectDropDownProps = { optionsClass?: string; subContainerClassName?: string; className?: string; + searchClassName?: string; + searchPlaceholder?: string; }; function SelectDropDown({ @@ -43,6 +45,8 @@ function SelectDropDown({ subContainerClassName, className, renderOption, + searchClassName, + searchPlaceholder, }: SelectDropDownProps) { const localize = useLocalize(); const transitionProps = { className: 'top-full mt-3' }; @@ -61,7 +65,12 @@ function SelectDropDown({ // Detemine if we should to convert this component into a searchable select. If we have enough elements, a search // input will appear near the top of the menu, allowing correct filtering of different model menu items. This will // reset once the component is unmounted (as per a normal search) - const [filteredValues, searchRender] = useMultiSearch(availableValues); + const [filteredValues, searchRender] = useMultiSearch({ + availableOptions: availableValues, + placeholder: searchPlaceholder, + getTextKeyOverride: (option) => ((option as Option)?.label || '').toUpperCase(), + className: searchClassName, + }); const hasSearchRender = Boolean(searchRender); const options = hasSearchRender ? filteredValues : availableValues; diff --git a/client/src/components/ui/SelectDropDownPop.tsx b/client/src/components/ui/SelectDropDownPop.tsx index 9278faff8e..cb12c96526 100644 --- a/client/src/components/ui/SelectDropDownPop.tsx +++ b/client/src/components/ui/SelectDropDownPop.tsx @@ -46,7 +46,9 @@ function SelectDropDownPop({ // Detemine if we should to convert this component into a searchable select. If we have enough elements, a search // input will appear near the top of the menu, allowing correct filtering of different model menu items. This will // reset once the component is unmounted (as per a normal search) - const [filteredValues, searchRender] = useMultiSearch(availableValues); + const [filteredValues, searchRender] = useMultiSearch({ + availableOptions: availableValues, + }); const hasSearchRender = Boolean(searchRender); const options = hasSearchRender ? filteredValues : availableValues; diff --git a/client/src/localization/languages/Eng.tsx b/client/src/localization/languages/Eng.tsx index 743d115ade..6e7832116f 100644 --- a/client/src/localization/languages/Eng.tsx +++ b/client/src/localization/languages/Eng.tsx @@ -21,6 +21,7 @@ export default { com_assistants_code_interpreter_files: 'The following files are only available for Code Interpreter:', com_assistants_retrieval: 'Retrieval', + com_assistants_search_name: 'Search assistants by name', com_assistants_tools: 'Tools', com_assistants_actions: 'Actions', com_assistants_add_tools: 'Add Tools', diff --git a/packages/data-provider/src/config.ts b/packages/data-provider/src/config.ts index 393f2bb0eb..4ebff8f633 100644 --- a/packages/data-provider/src/config.ts +++ b/packages/data-provider/src/config.ts @@ -531,9 +531,11 @@ export enum Constants { } export const defaultOrderQuery: { - order: 'asc'; + order: 'desc'; + limit: 100; } = { - order: 'asc', + order: 'desc', + limit: 100, }; export enum AssistantStreamEvents {