diff --git a/client/src/Providers/BadgeRowContext.tsx b/client/src/Providers/BadgeRowContext.tsx new file mode 100644 index 0000000000..d26c490cbd --- /dev/null +++ b/client/src/Providers/BadgeRowContext.tsx @@ -0,0 +1,28 @@ +import React, { createContext, useContext } from 'react'; + +interface BadgeRowContextType { + conversationId?: string | null; +} + +const BadgeRowContext = createContext(undefined); + +export function useBadgeRowContext() { + const context = useContext(BadgeRowContext); + if (context === undefined) { + throw new Error('useBadgeRowContext must be used within a BadgeRowProvider'); + } + return context; +} + +interface BadgeRowProviderProps { + children: React.ReactNode; + conversationId?: string | null; +} + +export default function BadgeRowProvider({ children, conversationId }: BadgeRowProviderProps) { + const value: BadgeRowContextType = { + conversationId, + }; + + return {children}; +} diff --git a/client/src/Providers/index.ts b/client/src/Providers/index.ts index 41c9cdceb3..8809532b49 100644 --- a/client/src/Providers/index.ts +++ b/client/src/Providers/index.ts @@ -22,3 +22,5 @@ export * from './CodeBlockContext'; export * from './ToolCallsMapContext'; export * from './SetConvoContext'; export * from './SearchContext'; +export * from './BadgeRowContext'; +export { default as BadgeRowProvider } from './BadgeRowContext'; diff --git a/client/src/components/Chat/Input/BadgeRow.tsx b/client/src/components/Chat/Input/BadgeRow.tsx index 57646b218a..95b2e8e0cc 100644 --- a/client/src/components/Chat/Input/BadgeRow.tsx +++ b/client/src/components/Chat/Input/BadgeRow.tsx @@ -11,10 +11,11 @@ import React, { import { useRecoilValue, useRecoilCallback } from 'recoil'; import type { LucideIcon } from 'lucide-react'; import CodeInterpreter from './CodeInterpreter'; +import { BadgeRowProvider } from '~/Providers'; +import ToolsDropdown from './ToolsDropdown'; import type { BadgeItem } from '~/common'; import { useChatBadges } from '~/hooks'; import { Badge } from '~/components/ui'; -import ToolsDropdown from './ToolsDropdown'; import MCPSelect from './MCPSelect'; import WebSearch from './WebSearch'; import store from '~/store'; @@ -314,79 +315,81 @@ function BadgeRow({ }, [dragState.draggedBadge, handleMouseMove, handleMouseUp]); return ( -
- - {tempBadges.map((badge, index) => ( - - {dragState.draggedBadge && dragState.insertIndex === index && ghostBadge && ( -
- -
- )} - -
- ))} - {dragState.draggedBadge && dragState.insertIndex === tempBadges.length && ghostBadge && ( -
- -
- )} - {showEphemeralBadges === true && ( - <> - - - - - )} - {ghostBadge && ( -
- -
- )} -
+ +
+ + {tempBadges.map((badge, index) => ( + + {dragState.draggedBadge && dragState.insertIndex === index && ghostBadge && ( +
+ +
+ )} + +
+ ))} + {dragState.draggedBadge && dragState.insertIndex === tempBadges.length && ghostBadge && ( +
+ +
+ )} + {showEphemeralBadges === true && ( + <> + + + + + )} + {ghostBadge && ( +
+ +
+ )} +
+
); } diff --git a/client/src/components/Chat/Input/CodeInterpreter.tsx b/client/src/components/Chat/Input/CodeInterpreter.tsx index 03407ff068..e6220c690b 100644 --- a/client/src/components/Chat/Input/CodeInterpreter.tsx +++ b/client/src/components/Chat/Input/CodeInterpreter.tsx @@ -11,10 +11,12 @@ import ApiKeyDialog from '~/components/SidePanel/Agents/Code/ApiKeyDialog'; import { useLocalize, useHasAccess, useCodeApiKeyForm, useToolToggle } from '~/hooks'; import CheckboxButton from '~/components/ui/CheckboxButton'; import { useVerifyAgentToolAuth } from '~/data-provider'; +import { useBadgeRowContext } from '~/Providers'; -function CodeInterpreter({ conversationId }: { conversationId?: string | null }) { +function CodeInterpreter() { const triggerRef = useRef(null); const localize = useLocalize(); + const { conversationId } = useBadgeRowContext(); const canRunCode = useHasAccess({ permissionType: PermissionTypes.RUN_CODE, diff --git a/client/src/components/Chat/Input/MCPSelect.tsx b/client/src/components/Chat/Input/MCPSelect.tsx index ebe56c8024..667ba73866 100644 --- a/client/src/components/Chat/Input/MCPSelect.tsx +++ b/client/src/components/Chat/Input/MCPSelect.tsx @@ -5,11 +5,11 @@ import { useUpdateUserPluginsMutation } from 'librechat-data-provider/react-quer import { Constants, EModelEndpoint, LocalStorageKeys } from 'librechat-data-provider'; import type { TPlugin, TPluginAuthConfig, TUpdateUserPlugins } from 'librechat-data-provider'; import MCPConfigDialog, { type ConfigFieldDetail } from '~/components/ui/MCPConfigDialog'; +import { useToastContext, useBadgeRowContext } from '~/Providers'; import { useAvailableToolsQuery } from '~/data-provider'; import useLocalStorage from '~/hooks/useLocalStorageAlt'; import MultiSelect from '~/components/ui/MultiSelect'; import { ephemeralAgentByConvoId } from '~/store'; -import { useToastContext } from '~/Providers'; import MCPIcon from '~/components/ui/MCPIcon'; import { useLocalize } from '~/hooks'; @@ -40,9 +40,10 @@ const storageCondition = (value: unknown, rawCurrentValue?: string | null) => { return Array.isArray(value) && value.length > 0; }; -function MCPSelect({ conversationId }: { conversationId?: string | null }) { +function MCPSelect() { const localize = useLocalize(); const { showToast } = useToastContext(); + const { conversationId } = useBadgeRowContext(); const key = conversationId ?? Constants.NEW_CONVO; const hasSetFetched = useRef(null); const [isConfigModalOpen, setIsConfigModalOpen] = useState(false); diff --git a/client/src/components/Chat/Input/ToolsDropdown.tsx b/client/src/components/Chat/Input/ToolsDropdown.tsx index 19d94789ce..242cff24fe 100644 --- a/client/src/components/Chat/Input/ToolsDropdown.tsx +++ b/client/src/components/Chat/Input/ToolsDropdown.tsx @@ -2,16 +2,17 @@ import React, { useState, useMemo } from 'react'; import * as Ariakit from '@ariakit/react'; import { Settings2, Search, ImageIcon, Globe, PenTool } from 'lucide-react'; import { TooltipAnchor, DropdownPopup } from '~/components'; +import { useBadgeRowContext } from '~/Providers'; import { useLocalize } from '~/hooks'; import { cn } from '~/utils'; interface ToolsDropdownProps { - conversationId?: string | null; disabled?: boolean; } -const ToolsDropdown = ({ disabled, conversationId }: ToolsDropdownProps) => { +const ToolsDropdown = ({ disabled }: ToolsDropdownProps) => { const localize = useLocalize(); + const { conversationId } = useBadgeRowContext(); const isDisabled = disabled ?? false; const [isPopoverActive, setIsPopoverActive] = useState(false); diff --git a/client/src/components/Chat/Input/WebSearch.tsx b/client/src/components/Chat/Input/WebSearch.tsx index 3fe0faa8f3..138923fa0e 100644 --- a/client/src/components/Chat/Input/WebSearch.tsx +++ b/client/src/components/Chat/Input/WebSearch.tsx @@ -5,10 +5,12 @@ import { useLocalize, useHasAccess, useSearchApiKeyForm, useToolToggle } from '~ import ApiKeyDialog from '~/components/SidePanel/Agents/Search/ApiKeyDialog'; import CheckboxButton from '~/components/ui/CheckboxButton'; import { useVerifyAgentToolAuth } from '~/data-provider'; +import { useBadgeRowContext } from '~/Providers'; -function WebSearch({ conversationId }: { conversationId?: string | null }) { +function WebSearch() { const triggerRef = useRef(null); const localize = useLocalize(); + const { conversationId } = useBadgeRowContext(); const canUseWebSearch = useHasAccess({ permissionType: PermissionTypes.WEB_SEARCH,