Spaces:
Runtime error
Runtime error
import { useState, useEffect, memo } from 'react'; | |
import { useRecoilState, useRecoilValue } from 'recoil'; | |
import { Settings2, ChevronDownIcon } from 'lucide-react'; | |
import { | |
SelectDropDown, | |
PluginStoreDialog, | |
MultiSelectDropDown, | |
Button, | |
GPTIcon, | |
} from '~/components'; | |
import EndpointOptionsPopover from '../../Endpoints/EndpointOptionsPopover'; | |
import SaveAsPresetDialog from '../../Endpoints/SaveAsPresetDialog'; | |
import { Settings, AgentSettings } from '../../Endpoints/Plugins/'; | |
import { cn } from '~/utils/'; | |
import store from '~/store'; | |
import { useAuthContext } from '~/hooks/AuthContext'; | |
import { useAvailablePluginsQuery } from '@librechat/data-provider'; | |
function PluginsOptions() { | |
const { data: allPlugins } = useAvailablePluginsQuery(); | |
const [visibile, setVisibility] = useState(true); | |
const [advancedMode, setAdvancedMode] = useState(false); | |
const [availableTools, setAvailableTools] = useState([]); | |
const [showAgentSettings, setShowAgentSettings] = useState(false); | |
const [showSavePresetDialog, setShowSavePresetDialog] = useState(false); | |
const [showPluginStoreDialog, setShowPluginStoreDialog] = useState(false); | |
const [opacityClass, setOpacityClass] = useState('full-opacity'); | |
const [conversation, setConversation] = useRecoilState(store.conversation) || {}; | |
const endpointsConfig = useRecoilValue(store.endpointsConfig); | |
const messagesTree = useRecoilValue(store.messagesTree); | |
const { user } = useAuthContext(); | |
useEffect(() => { | |
if (advancedMode) { | |
return; | |
} else if (messagesTree?.length >= 1) { | |
setOpacityClass('show'); | |
} else { | |
setOpacityClass('full-opacity'); | |
} | |
}, [messagesTree, advancedMode]); | |
useEffect(() => { | |
if (allPlugins && user) { | |
const pluginStore = { name: 'Plugin store', pluginKey: 'pluginStore', isButton: true }; | |
if (!user.plugins || user.plugins.length === 0) { | |
setAvailableTools([pluginStore]); | |
return; | |
} | |
const tools = [...user.plugins] | |
.map((el) => { | |
return allPlugins.find((plugin) => plugin.pluginKey === el); | |
}) | |
.filter((el) => el); | |
setAvailableTools([...tools, pluginStore]); | |
} | |
}, [allPlugins, user]); | |
const triggerAgentSettings = () => setShowAgentSettings((prev) => !prev); | |
const { endpoint, agentOptions } = conversation; | |
if (endpoint !== 'gptPlugins') { | |
return null; | |
} | |
const models = endpointsConfig?.['gptPlugins']?.['availableModels'] || []; | |
const triggerAdvancedMode = () => setAdvancedMode((prev) => !prev); | |
const switchToSimpleMode = () => { | |
setAdvancedMode(false); | |
}; | |
const saveAsPreset = () => { | |
setShowSavePresetDialog(true); | |
}; | |
function checkIfSelected(value) { | |
if (!conversation.tools) { | |
return false; | |
} | |
return conversation.tools.find((el) => el.pluginKey === value) ? true : false; | |
} | |
const setOption = (param) => (newValue) => { | |
let update = {}; | |
update[param] = newValue; | |
setConversation((prevState) => ({ | |
...prevState, | |
...update, | |
})); | |
}; | |
const setAgentOption = (param) => (newValue) => { | |
const editableConvo = JSON.stringify(conversation); | |
const convo = JSON.parse(editableConvo); | |
let { agentOptions } = convo; | |
agentOptions[param] = newValue; | |
setConversation((prevState) => ({ | |
...prevState, | |
agentOptions, | |
})); | |
}; | |
const setTools = (newValue) => { | |
if (newValue === 'pluginStore') { | |
setShowPluginStoreDialog(true); | |
return; | |
} | |
let update = {}; | |
let current = conversation.tools || []; | |
let isSelected = checkIfSelected(newValue); | |
let tool = availableTools[availableTools.findIndex((el) => el.pluginKey === newValue)]; | |
if (isSelected) { | |
update.tools = current.filter((el) => el.pluginKey !== newValue); | |
} else { | |
update.tools = [...current, tool]; | |
} | |
localStorage.setItem('lastSelectedTools', JSON.stringify(update.tools)); | |
setConversation((prevState) => ({ | |
...prevState, | |
...update, | |
})); | |
}; | |
const cardStyle = | |
'transition-colors shadow-md rounded-md min-w-[75px] font-normal bg-white border-black/10 hover:border-black/10 focus:border-black/10 dark:border-black/10 dark:hover:border-black/10 dark:focus:border-black/10 border dark:bg-gray-700 text-black dark:text-white'; | |
return ( | |
<> | |
<div | |
className={ | |
'pluginOptions flex w-full flex-wrap items-center justify-center gap-2 ' + | |
(!advancedMode ? opacityClass : '') | |
} | |
onMouseEnter={() => { | |
if (advancedMode) { | |
return; | |
} | |
setOpacityClass('full-opacity'); | |
}} | |
onMouseLeave={() => { | |
if (advancedMode) { | |
return; | |
} | |
if (!messagesTree || messagesTree.length === 0) { | |
return; | |
} | |
setOpacityClass('show'); | |
}} | |
> | |
<Button | |
type="button" | |
className={cn( | |
cardStyle, | |
'min-w-4 z-40 flex h-[40px] flex-none items-center justify-center px-4 hover:bg-white focus:ring-0 focus:ring-offset-0 dark:hover:bg-gray-700', | |
)} | |
onClick={() => setVisibility((prev) => !prev)} | |
> | |
<ChevronDownIcon | |
className={cn( | |
!visibile ? 'rotate-180 transform' : '', | |
'w-4 text-gray-600 dark:text-white', | |
)} | |
/> | |
</Button> | |
<SelectDropDown | |
value={conversation.model} | |
setValue={setOption('model')} | |
availableValues={models} | |
showAbove={true} | |
className={cn(cardStyle, 'min-w-60 z-40 flex w-60', !visibile && 'hidden')} | |
/> | |
<MultiSelectDropDown | |
value={conversation.tools || []} | |
isSelected={checkIfSelected} | |
setSelected={setTools} | |
availableValues={availableTools} | |
optionValueKey="pluginKey" | |
showAbove={true} | |
className={cn(cardStyle, 'min-w-60 z-50 w-60', !visibile && 'hidden')} | |
/> | |
<Button | |
type="button" | |
className={cn( | |
cardStyle, | |
'min-w-4 z-50 flex h-[40px] flex-none items-center justify-center px-4 hover:bg-slate-50 focus:ring-0 focus:ring-offset-0 dark:hover:bg-gray-600', | |
!visibile && 'hidden', | |
)} | |
onClick={triggerAdvancedMode} | |
> | |
<Settings2 className="w-4 text-gray-600 dark:text-white" /> | |
</Button> | |
</div> | |
<EndpointOptionsPopover | |
content={ | |
<div className="px-4 py-4"> | |
{showAgentSettings ? ( | |
<AgentSettings | |
agent={agentOptions.agent} | |
skipCompletion={agentOptions.skipCompletion} | |
model={agentOptions.model} | |
endpoint={agentOptions.endpoint} | |
temperature={agentOptions.temperature} | |
topP={agentOptions.top_p} | |
freqP={agentOptions.presence_penalty} | |
presP={agentOptions.frequency_penalty} | |
setOption={setAgentOption} | |
tools={conversation.tools} | |
/> | |
) : ( | |
<Settings | |
model={conversation.model} | |
endpoint={endpoint} | |
chatGptLabel={conversation.chatGptLabel} | |
promptPrefix={conversation.promptPrefix} | |
temperature={conversation.temperature} | |
topP={conversation.top_p} | |
freqP={conversation.presence_penalty} | |
presP={conversation.frequency_penalty} | |
setOption={setOption} | |
tools={conversation.tools} | |
/> | |
)} | |
</div> | |
} | |
visible={advancedMode} | |
saveAsPreset={saveAsPreset} | |
switchToSimpleMode={switchToSimpleMode} | |
additionalButton={{ | |
label: `Show ${showAgentSettings ? 'Completion' : 'Agent'} Settings`, | |
handler: triggerAgentSettings, | |
icon: <GPTIcon className="mr-1 mt-[2px] w-[14px]" size={14} />, | |
}} | |
/> | |
<SaveAsPresetDialog | |
open={showSavePresetDialog} | |
onOpenChange={setShowSavePresetDialog} | |
preset={conversation} | |
/> | |
<PluginStoreDialog isOpen={showPluginStoreDialog} setIsOpen={setShowPluginStoreDialog} /> | |
</> | |
); | |
} | |
export default memo(PluginsOptions); | |