📛 refactor: Decouple MCP Dialog UI from BadgeRowContext (#8920)

* decouple MCP dialog from BadgeRowContext

* chore: import order and style according to guidelines

---------

Co-authored-by: Dustin Healy <dustinhealy1@gmail.com>
This commit is contained in:
Federico Ruggi 2025-08-18 17:20:45 +02:00 committed by GitHub
parent a6fd32a15a
commit 2a0a8f6beb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 18 additions and 29 deletions

View file

@ -2,27 +2,18 @@ import React, { createContext, useContext, useEffect, useRef } from 'react';
import { useSetRecoilState } from 'recoil'; import { useSetRecoilState } from 'recoil';
import { Tools, Constants, LocalStorageKeys, AgentCapabilities } from 'librechat-data-provider'; import { Tools, Constants, LocalStorageKeys, AgentCapabilities } from 'librechat-data-provider';
import type { TAgentsEndpoint } from 'librechat-data-provider'; import type { TAgentsEndpoint } from 'librechat-data-provider';
import { import { useSearchApiKeyForm, useGetAgentsConfig, useCodeApiKeyForm, useToolToggle } from '~/hooks';
useSearchApiKeyForm,
useGetAgentsConfig,
useCodeApiKeyForm,
useToolToggle,
useMCPSelect,
} from '~/hooks';
import { useGetStartupConfig } from '~/data-provider';
import { ephemeralAgentByConvoId } from '~/store'; import { ephemeralAgentByConvoId } from '~/store';
interface BadgeRowContextType { interface BadgeRowContextType {
conversationId?: string | null; conversationId?: string | null;
agentsConfig?: TAgentsEndpoint | null; agentsConfig?: TAgentsEndpoint | null;
mcpSelect: ReturnType<typeof useMCPSelect>;
webSearch: ReturnType<typeof useToolToggle>; webSearch: ReturnType<typeof useToolToggle>;
artifacts: ReturnType<typeof useToolToggle>; artifacts: ReturnType<typeof useToolToggle>;
fileSearch: ReturnType<typeof useToolToggle>; fileSearch: ReturnType<typeof useToolToggle>;
codeInterpreter: ReturnType<typeof useToolToggle>; codeInterpreter: ReturnType<typeof useToolToggle>;
codeApiKeyForm: ReturnType<typeof useCodeApiKeyForm>; codeApiKeyForm: ReturnType<typeof useCodeApiKeyForm>;
searchApiKeyForm: ReturnType<typeof useSearchApiKeyForm>; searchApiKeyForm: ReturnType<typeof useSearchApiKeyForm>;
startupConfig: ReturnType<typeof useGetStartupConfig>['data'];
} }
const BadgeRowContext = createContext<BadgeRowContextType | undefined>(undefined); const BadgeRowContext = createContext<BadgeRowContextType | undefined>(undefined);
@ -119,12 +110,6 @@ export default function BadgeRowProvider({
} }
}, [key, isSubmitting, setEphemeralAgent]); }, [key, isSubmitting, setEphemeralAgent]);
/** Startup config */
const { data: startupConfig } = useGetStartupConfig();
/** MCPSelect hook */
const mcpSelect = useMCPSelect({ conversationId });
/** CodeInterpreter hooks */ /** CodeInterpreter hooks */
const codeApiKeyForm = useCodeApiKeyForm({}); const codeApiKeyForm = useCodeApiKeyForm({});
const { setIsDialogOpen: setCodeDialogOpen } = codeApiKeyForm; const { setIsDialogOpen: setCodeDialogOpen } = codeApiKeyForm;
@ -172,12 +157,10 @@ export default function BadgeRowProvider({
}); });
const value: BadgeRowContextType = { const value: BadgeRowContextType = {
mcpSelect,
webSearch, webSearch,
artifacts, artifacts,
fileSearch, fileSearch,
agentsConfig, agentsConfig,
startupConfig,
conversationId, conversationId,
codeApiKeyForm, codeApiKeyForm,
codeInterpreter, codeInterpreter,

View file

@ -10,11 +10,12 @@ import {
PermissionTypes, PermissionTypes,
defaultAgentCapabilities, defaultAgentCapabilities,
} from 'librechat-data-provider'; } from 'librechat-data-provider';
import { useLocalize, useHasAccess, useAgentCapabilities } from '~/hooks'; import { useLocalize, useHasAccess, useAgentCapabilities, useMCPSelect } from '~/hooks';
import ArtifactsSubMenu from '~/components/Chat/Input/ArtifactsSubMenu'; import ArtifactsSubMenu from '~/components/Chat/Input/ArtifactsSubMenu';
import MCPSubMenu from '~/components/Chat/Input/MCPSubMenu'; import MCPSubMenu from '~/components/Chat/Input/MCPSubMenu';
import { useBadgeRowContext } from '~/Providers'; import { useBadgeRowContext } from '~/Providers';
import { cn } from '~/utils'; import { cn } from '~/utils';
import { useGetStartupConfig } from '~/data-provider';
interface ToolsDropdownProps { interface ToolsDropdownProps {
disabled?: boolean; disabled?: boolean;
@ -26,15 +27,16 @@ const ToolsDropdown = ({ disabled }: ToolsDropdownProps) => {
const [isPopoverActive, setIsPopoverActive] = useState(false); const [isPopoverActive, setIsPopoverActive] = useState(false);
const { const {
webSearch, webSearch,
mcpSelect,
artifacts, artifacts,
fileSearch, fileSearch,
agentsConfig, agentsConfig,
startupConfig,
codeApiKeyForm, codeApiKeyForm,
codeInterpreter, codeInterpreter,
searchApiKeyForm, searchApiKeyForm,
} = useBadgeRowContext(); } = useBadgeRowContext();
const mcpSelect = useMCPSelect();
const { data: startupConfig } = useGetStartupConfig();
const { codeEnabled, webSearchEnabled, artifactsEnabled, fileSearchEnabled } = const { codeEnabled, webSearchEnabled, artifactsEnabled, fileSearchEnabled } =
useAgentCapabilities(agentsConfig?.capabilities ?? defaultAgentCapabilities); useAgentCapabilities(agentsConfig?.capabilities ?? defaultAgentCapabilities);

View file

@ -10,8 +10,8 @@ import {
import type { TUpdateUserPlugins, TPlugin } from 'librechat-data-provider'; import type { TUpdateUserPlugins, TPlugin } from 'librechat-data-provider';
import type { ConfigFieldDetail } from '~/components/MCP/MCPConfigDialog'; import type { ConfigFieldDetail } from '~/components/MCP/MCPConfigDialog';
import { useMCPConnectionStatusQuery } from '~/data-provider/Tools/queries'; import { useMCPConnectionStatusQuery } from '~/data-provider/Tools/queries';
import { useBadgeRowContext } from '~/Providers'; import { useGetStartupConfig } from '~/data-provider';
import { useLocalize } from '~/hooks'; import { useLocalize, useMCPSelect } from '~/hooks';
interface ServerState { interface ServerState {
isInitializing: boolean; isInitializing: boolean;
@ -24,7 +24,8 @@ interface ServerState {
export function useMCPServerManager() { export function useMCPServerManager() {
const localize = useLocalize(); const localize = useLocalize();
const { showToast } = useToastContext(); const { showToast } = useToastContext();
const { mcpSelect, startupConfig } = useBadgeRowContext(); const mcpSelect = useMCPSelect();
const { data: startupConfig } = useGetStartupConfig();
const { mcpValues, setMCPValues, mcpToolDetails, isPinned, setIsPinned } = mcpSelect; const { mcpValues, setMCPValues, mcpToolDetails, isPinned, setIsPinned } = mcpSelect;
const queryClient = useQueryClient(); const queryClient = useQueryClient();

View file

@ -5,6 +5,7 @@ import type { TPlugin } from 'librechat-data-provider';
import { useAvailableToolsQuery, useGetStartupConfig } from '~/data-provider'; import { useAvailableToolsQuery, useGetStartupConfig } from '~/data-provider';
import useLocalStorage from '~/hooks/useLocalStorageAlt'; import useLocalStorage from '~/hooks/useLocalStorageAlt';
import { ephemeralAgentByConvoId } from '~/store'; import { ephemeralAgentByConvoId } from '~/store';
import { useChatContext } from '~/Providers';
const storageCondition = (value: unknown, rawCurrentValue?: string | null) => { const storageCondition = (value: unknown, rawCurrentValue?: string | null) => {
if (rawCurrentValue) { if (rawCurrentValue) {
@ -20,12 +21,14 @@ const storageCondition = (value: unknown, rawCurrentValue?: string | null) => {
return Array.isArray(value) && value.length > 0; return Array.isArray(value) && value.length > 0;
}; };
interface UseMCPSelectOptions { export function useMCPSelect() {
conversationId?: string | null; const { conversation } = useChatContext();
}
const key = useMemo(
() => conversation?.conversationId ?? Constants.NEW_CONVO,
[conversation?.conversationId],
);
export function useMCPSelect({ conversationId }: UseMCPSelectOptions) {
const key = conversationId ?? Constants.NEW_CONVO;
const hasSetFetched = useRef<string | null>(null); const hasSetFetched = useRef<string | null>(null);
const [ephemeralAgent, setEphemeralAgent] = useRecoilState(ephemeralAgentByConvoId(key)); const [ephemeralAgent, setEphemeralAgent] = useRecoilState(ephemeralAgentByConvoId(key));
const { data: startupConfig } = useGetStartupConfig(); const { data: startupConfig } = useGetStartupConfig();