🔄 refactor(EditPresetDialog): Update Model on Endpoint Change (#2936)

* refactor(EditPresetDialog): dynamically update current editable preset model on endpoint change

* feat: Add null check for models in EditPresetDialog

* chore(AlertDialogPortal): typing

* fix(EditPresetDialog): prevent Unknown endpoint edge case for custom endpoints
This commit is contained in:
Danny Avila 2024-05-31 11:43:14 -04:00 committed by GitHub
parent 248dfb8b5b
commit f9a0166352
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 98 additions and 13 deletions

View file

@ -196,6 +196,7 @@ export type TEditPresetProps = {
title?: string; title?: string;
}; };
export type TSetOptions = (options: Record<string, unknown>) => void;
export type TSetOptionsPayload = { export type TSetOptionsPayload = {
setOption: TSetOption; setOption: TSetOption;
setExample: TSetExample; setExample: TSetExample;
@ -205,6 +206,7 @@ export type TSetOptionsPayload = {
// getConversation: () => TConversation | TPreset | null; // getConversation: () => TConversation | TPreset | null;
checkPluginSelection: (value: string) => boolean; checkPluginSelection: (value: string) => boolean;
setTools: (newValue: string, remove?: boolean) => void; setTools: (newValue: string, remove?: boolean) => void;
setOptions?: TSetOptions;
}; };
export type TPresetItemProps = { export type TPresetItemProps = {

View file

@ -1,10 +1,20 @@
import { useRecoilState } from 'recoil'; import { useRecoilState } from 'recoil';
import { useCallback, useEffect } from 'react';
import { useQueryClient } from '@tanstack/react-query';
import { QueryKeys } from 'librechat-data-provider';
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query'; import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
import { cn, defaultTextProps, removeFocusOutlines, mapEndpoints } from '~/utils'; import type { TModelsConfig, TEndpointsConfig } from 'librechat-data-provider';
import { Input, Label, Dropdown, Dialog, DialogClose, DialogButton } from '~/components/'; import {
cn,
defaultTextProps,
removeFocusOutlines,
mapEndpoints,
getConvoSwitchLogic,
} from '~/utils';
import { Input, Label, Dropdown, Dialog, DialogClose, DialogButton } from '~/components';
import { useSetIndexOptions, useLocalize, useDebouncedInput } from '~/hooks';
import PopoverButtons from '~/components/Chat/Input/PopoverButtons'; import PopoverButtons from '~/components/Chat/Input/PopoverButtons';
import DialogTemplate from '~/components/ui/DialogTemplate'; import DialogTemplate from '~/components/ui/DialogTemplate';
import { useSetIndexOptions, useLocalize, useDebouncedInput } from '~/hooks';
import { EndpointSettings } from '~/components/Endpoints'; import { EndpointSettings } from '~/components/Endpoints';
import { useChatContext } from '~/Providers'; import { useChatContext } from '~/Providers';
import store from '~/store'; import store from '~/store';
@ -17,8 +27,9 @@ const EditPresetDialog = ({
submitPreset: () => void; submitPreset: () => void;
}) => { }) => {
const localize = useLocalize(); const localize = useLocalize();
const queryClient = useQueryClient();
const { preset, setPreset } = useChatContext(); const { preset, setPreset } = useChatContext();
const { setOption } = useSetIndexOptions(preset); const { setOption, setOptions, setAgentOption } = useSetIndexOptions(preset);
const [onTitleChange, title] = useDebouncedInput({ const [onTitleChange, title] = useDebouncedInput({
setOption, setOption,
optionKey: 'title', optionKey: 'title',
@ -30,6 +41,67 @@ const EditPresetDialog = ({
select: mapEndpoints, select: mapEndpoints,
}); });
useEffect(() => {
if (!preset) {
return;
}
if (!preset.endpoint) {
return;
}
const modelsConfig = queryClient.getQueryData<TModelsConfig>([QueryKeys.models]);
if (!modelsConfig) {
return;
}
const models = modelsConfig[preset.endpoint];
if (!models) {
return;
}
if (!models.length) {
return;
}
if (preset.model === models[0]) {
return;
}
if (!models.includes(preset.model ?? '')) {
console.log('setting model', models[0]);
setOption('model')(models[0]);
}
if (preset.agentOptions?.model === models[0]) {
return;
}
if (preset.agentOptions?.model && !models.includes(preset.agentOptions.model)) {
console.log('setting agent model', models[0]);
setAgentOption('model')(models[0]);
}
}, [preset, queryClient, setOption, setAgentOption]);
const switchEndpoint = useCallback(
(newEndpoint: string) => {
if (!setOptions) {
return console.warn('setOptions is not defined');
}
const { newEndpointType } = getConvoSwitchLogic({
newEndpoint,
modularChat: true,
conversation: null,
endpointsConfig: queryClient.getQueryData<TEndpointsConfig>([QueryKeys.endpoints]) ?? {},
});
setOptions({
endpoint: newEndpoint,
endpointType: newEndpointType,
});
},
[queryClient, setOptions],
);
const { endpoint, endpointType, model } = preset || {}; const { endpoint, endpointType, model } = preset || {};
if (!endpoint) { if (!endpoint) {
return null; return null;
@ -76,7 +148,7 @@ const EditPresetDialog = ({
</Label> </Label>
<Dropdown <Dropdown
value={endpoint || ''} value={endpoint || ''}
onChange={(value) => setOption('endpoint')(value)} onChange={switchEndpoint}
options={availableEndpoints} options={availableEndpoints}
/> />
</div> </div>

View file

@ -7,12 +7,10 @@ const AlertDialog = AlertDialogPrimitive.Root;
const AlertDialogTrigger = AlertDialogPrimitive.Trigger; const AlertDialogTrigger = AlertDialogPrimitive.Trigger;
const AlertDialogPortal = ({ type AlertPortalProps = AlertDialogPrimitive.AlertDialogPortalProps & { className?: string };
className = '',
children, const AlertDialogPortal = ({ className = '', children, ...props }: AlertPortalProps) => (
...props <AlertDialogPrimitive.Portal className={cn(className)} {...(props as AlertPortalProps)}>
}: AlertDialogPrimitive.AlertDialogPortalProps) => (
<AlertDialogPrimitive.Portal className={cn(className)} {...props}>
<div className="fixed inset-0 z-50 flex items-end justify-center sm:items-center"> <div className="fixed inset-0 z-50 flex items-end justify-center sm:items-center">
{children} {children}
</div> </div>

View file

@ -1,6 +1,6 @@
import { useRecoilValue, useSetRecoilState } from 'recoil'; import { useRecoilValue, useSetRecoilState } from 'recoil';
import type { TPreset, TPlugin } from 'librechat-data-provider'; import type { TPreset, TPlugin } from 'librechat-data-provider';
import type { TSetOptionsPayload, TSetExample, TSetOption } from '~/common'; import type { TSetOptionsPayload, TSetExample, TSetOption, TSetOptions } from '~/common';
import { useChatContext } from '~/Providers/ChatContext'; import { useChatContext } from '~/Providers/ChatContext';
import { cleanupPreset } from '~/utils'; import { cleanupPreset } from '~/utils';
import store from '~/store'; import store from '~/store';
@ -17,6 +17,18 @@ const usePresetIndexOptions: TUsePresetOptions = (_preset) => {
} }
const getConversation: () => TPreset | null = () => preset; const getConversation: () => TPreset | null = () => preset;
const setOptions: TSetOptions = (options) => {
const update = { ...options };
setPreset((prevState) =>
cleanupPreset({
preset: {
...prevState,
...update,
},
}),
);
};
const setOption: TSetOption = (param) => (newValue) => { const setOption: TSetOption = (param) => (newValue) => {
const update = {}; const update = {};
update[param] = newValue; update[param] = newValue;
@ -155,6 +167,7 @@ const usePresetIndexOptions: TUsePresetOptions = (_preset) => {
setOption, setOption,
setExample, setExample,
addExample, addExample,
setOptions,
removeExample, removeExample,
getConversation, getConversation,
checkPluginSelection, checkPluginSelection,

View file

@ -157,13 +157,13 @@ const useSetIndexOptions: TUseSetOptions = (preset = false) => {
}; };
return { return {
setTools,
setOption, setOption,
setExample, setExample,
addExample, addExample,
removeExample, removeExample,
setAgentOption, setAgentOption,
checkPluginSelection, checkPluginSelection,
setTools,
}; };
}; };