feat: implement useToolToggle hook for managing tool toggle state, refactor CodeInterpreter and WebSearch components to utilize new hook

This commit is contained in:
Danny Avila 2025-06-21 22:41:46 -04:00
parent ef7e517c06
commit 1d532a864d
No known key found for this signature in database
GPG key ID: BF31EEB2C5CA0956
4 changed files with 118 additions and 136 deletions

View file

@ -0,0 +1,97 @@
import { useRef, useEffect, useCallback, useMemo } from 'react';
import { useRecoilState } from 'recoil';
import debounce from 'lodash/debounce';
import { Constants, LocalStorageKeys } from 'librechat-data-provider';
import useLocalStorage from '~/hooks/useLocalStorageAlt';
import { ephemeralAgentByConvoId } from '~/store';
const storageCondition = (value: unknown, rawCurrentValue?: string | null) => {
if (rawCurrentValue) {
try {
const currentValue = rawCurrentValue?.trim() ?? '';
if (currentValue === 'true' && value === false) {
return true;
}
} catch (e) {
console.error(e);
}
}
return value !== undefined && value !== null && value !== '' && value !== false;
};
interface UseToolToggleOptions {
conversationId?: string | null;
toolKey: string;
localStorageKey: LocalStorageKeys;
isAuthenticated?: boolean;
setIsDialogOpen?: (open: boolean) => void;
}
export function useToolToggle({
conversationId,
toolKey,
localStorageKey,
isAuthenticated,
setIsDialogOpen,
}: UseToolToggleOptions) {
const key = conversationId ?? Constants.NEW_CONVO;
const [ephemeralAgent, setEphemeralAgent] = useRecoilState(ephemeralAgentByConvoId(key));
const isToolEnabled = useMemo(() => {
return ephemeralAgent?.[toolKey] ?? false;
}, [ephemeralAgent, toolKey]);
/** Track previous value to prevent infinite loops */
const prevIsToolEnabled = useRef(isToolEnabled);
const setValue = useCallback(
(isChecked: boolean) => {
setEphemeralAgent((prev) => ({
...prev,
[toolKey]: isChecked,
}));
},
[setEphemeralAgent, toolKey],
);
const [toggleState, setToggleState] = useLocalStorage<boolean>(
`${localStorageKey}${key}`,
isToolEnabled,
setValue,
storageCondition,
);
const handleChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>, isChecked: boolean) => {
if (isAuthenticated !== undefined && !isAuthenticated && setIsDialogOpen) {
setIsDialogOpen(true);
e.preventDefault();
return;
}
setToggleState(isChecked);
},
[setToggleState, setIsDialogOpen, isAuthenticated],
);
const debouncedChange = useMemo(
() => debounce(handleChange, 50, { leading: true }),
[handleChange],
);
useEffect(() => {
if (prevIsToolEnabled.current !== isToolEnabled) {
setToggleState(isToolEnabled);
}
prevIsToolEnabled.current = isToolEnabled;
}, [isToolEnabled, setToggleState]);
return {
toggleState,
handleChange,
isToolEnabled,
setToggleState,
ephemeralAgent,
debouncedChange,
setEphemeralAgent,
};
}