import { useState, useMemo } from 'react'; import { useQueryClient } from '@tanstack/react-query'; import { useForm, FormProvider, Controller, useWatch } from 'react-hook-form'; import { useGetModelsQuery } from 'librechat-data-provider/react-query'; import { Tools, QueryKeys, Capabilities, actionDelimiter, ImageVisionTool, defaultAssistantFormValues, } from 'librechat-data-provider'; import type { FunctionTool, TConfig, TPlugin } from 'librechat-data-provider'; import type { AssistantForm, AssistantPanelProps } from '~/common'; import { useCreateAssistantMutation, useUpdateAssistantMutation } from '~/data-provider'; import { cn, cardStyle, defaultTextProps, removeFocusOutlines } from '~/utils'; import { useAssistantsMapContext, useToastContext } from '~/Providers'; import { useSelectAssistant, useLocalize } from '~/hooks'; import { ToolSelectDialog } from '~/components/Tools'; import CapabilitiesForm from './CapabilitiesForm'; import { SelectDropDown } from '~/components/ui'; import AssistantAvatar from './AssistantAvatar'; import AssistantSelect from './AssistantSelect'; import AssistantAction from './AssistantAction'; import ContextButton from './ContextButton'; import AssistantTool from './AssistantTool'; import { Spinner } from '~/components/svg'; import Knowledge from './Knowledge'; import { Panel } from '~/common'; const labelClass = 'mb-2 text-token-text-primary block font-medium'; const inputClass = cn( defaultTextProps, 'flex w-full px-3 py-2 dark:border-gray-800 dark:bg-gray-800', removeFocusOutlines, ); export default function AssistantPanel({ // index = 0, setAction, endpoint, actions = [], setActivePanel, assistant_id: current_assistant_id, setCurrentAssistantId, assistantsConfig, version, }: AssistantPanelProps & { assistantsConfig?: TConfig | null }) { const queryClient = useQueryClient(); const modelsQuery = useGetModelsQuery(); const assistantMap = useAssistantsMapContext(); const allTools = queryClient.getQueryData([QueryKeys.tools]) ?? []; const { onSelect: onSelectAssistant } = useSelectAssistant(endpoint); const { showToast } = useToastContext(); const localize = useLocalize(); const methods = useForm({ defaultValues: defaultAssistantFormValues, }); const [showToolDialog, setShowToolDialog] = useState(false); const { control, handleSubmit, reset } = methods; const assistant = useWatch({ control, name: 'assistant' }); const functions = useWatch({ control, name: 'functions' }); const assistant_id = useWatch({ control, name: 'id' }); const activeModel = useMemo(() => { return assistantMap?.[endpoint]?.[assistant_id]?.model; }, [assistantMap, endpoint, assistant_id]); const toolsEnabled = useMemo( () => assistantsConfig?.capabilities?.includes(Capabilities.tools), [assistantsConfig], ); const actionsEnabled = useMemo( () => assistantsConfig?.capabilities?.includes(Capabilities.actions), [assistantsConfig], ); const retrievalEnabled = useMemo( () => assistantsConfig?.capabilities?.includes(Capabilities.retrieval), [assistantsConfig], ); const codeEnabled = useMemo( () => assistantsConfig?.capabilities?.includes(Capabilities.code_interpreter), [assistantsConfig], ); /* Mutations */ const update = useUpdateAssistantMutation({ onSuccess: (data) => { showToast({ message: `${localize('com_assistants_update_success')} ${ data.name ?? localize('com_ui_assistant') }`, }); }, onError: (err) => { const error = err as Error; showToast({ message: `${localize('com_assistants_update_error')}${ error?.message ? ` ${localize('com_ui_error')}: ${error?.message}` : '' }`, status: 'error', }); }, }); const create = useCreateAssistantMutation({ onSuccess: (data) => { setCurrentAssistantId(data.id); showToast({ message: `${localize('com_assistants_create_success')} ${ data.name ?? localize('com_ui_assistant') }`, }); }, onError: (err) => { const error = err as Error; showToast({ message: `${localize('com_assistants_create_error')}${ error?.message ? ` ${localize('com_ui_error')}: ${error?.message}` : '' }`, status: 'error', }); }, }); const files = useMemo(() => { if (typeof assistant === 'string') { return []; } return assistant.files; }, [assistant]); const onSubmit = (data: AssistantForm) => { const tools: Array = [...functions].map((functionName) => { if (!functionName.includes(actionDelimiter)) { return functionName; } else { const assistant = assistantMap?.[endpoint]?.[assistant_id]; const tool = assistant?.tools?.find((tool) => tool.function?.name === functionName); if (assistant && tool) { return tool; } } return functionName; }); console.log(data); if (data.code_interpreter) { tools.push({ type: Tools.code_interpreter }); } if (data.retrieval) { tools.push({ type: version == 2 ? Tools.file_search : Tools.retrieval }); } if (data.image_vision) { tools.push(ImageVisionTool); } const { name, description, instructions, model, // file_ids, // TODO: add file handling here } = data; if (assistant_id) { update.mutate({ assistant_id, data: { name, description, instructions, model, tools, endpoint, }, }); return; } create.mutate({ name, description, instructions, model, tools, endpoint, version, }); }; return (
( )} /> {/* Select Button */} {assistant_id && ( )}
{/* Avatar & Name */}
( )} /> (

{field.value ?? ''}

)} />
{/* Description */}
( )} />
{/* Instructions */}
(