import { useEffect, useState } from 'react' import { DropDrawer, DropDrawerContent, DropDrawerItem, DropDrawerSub, DropDrawerLabel, DropDrawerSubContent, DropDrawerSeparator, DropDrawerSubTrigger, DropDrawerTrigger, DropDrawerGroup, } from '@/components/ui/dropdrawer' import { Switch } from '@/components/ui/switch' import { useThreads } from '@/hooks/useThreads' import { useToolAvailable } from '@/hooks/useToolAvailable' import React from 'react' import { useAppState } from '@/hooks/useAppState' import { useTranslation } from '@/i18n/react-i18next-compat' import { cn } from '@/lib/utils' interface DropdownToolsAvailableProps { children: (isOpen: boolean, toolsCount: number) => React.ReactNode initialMessage?: boolean onOpenChange?: (isOpen: boolean) => void } export default function DropdownToolsAvailable({ children, initialMessage = false, onOpenChange, }: DropdownToolsAvailableProps) { const tools = useAppState((state) => state.tools) const [isOpen, setIsOpen] = useState(false) const { t } = useTranslation() const handleOpenChange = (open: boolean) => { setIsOpen(open) onOpenChange?.(open) } const { getCurrentThread } = useThreads() const { isToolDisabled, setToolDisabledForThread, setDefaultDisabledTools, initializeThreadTools, getDisabledToolsForThread, getDefaultDisabledTools, } = useToolAvailable() const currentThread = getCurrentThread() // Separate effect for thread initialization - only when we have tools and a new thread useEffect(() => { if (tools.length > 0 && currentThread?.id) { initializeThreadTools(currentThread.id, tools) } }, [currentThread?.id, tools, initializeThreadTools]) const handleToolToggle = (toolName: string, checked: boolean) => { if (initialMessage) { // Update default tools for new threads/index page const currentDefaults = getDefaultDisabledTools() if (checked) { setDefaultDisabledTools( currentDefaults.filter((name) => name !== toolName) ) } else { setDefaultDisabledTools([...currentDefaults, toolName]) } } else if (currentThread?.id) { // Update tools for specific thread setToolDisabledForThread(currentThread.id, toolName, checked) } } const isToolChecked = (toolName: string): boolean => { if (initialMessage) { // Use default tools for index page return !getDefaultDisabledTools().includes(toolName) } else if (currentThread?.id) { // Use thread-specific tools return !isToolDisabled(currentThread.id, toolName) } return false } const handleDisableAllServerTools = ( serverName: string, disable: boolean ) => { const allToolsByServer = getToolsByServer() const serverTools = allToolsByServer[serverName] || [] serverTools.forEach((tool) => { handleToolToggle(tool.name, !disable) }) } const areAllServerToolsDisabled = (serverName: string): boolean => { const allToolsByServer = getToolsByServer() const serverTools = allToolsByServer[serverName] || [] return serverTools.every((tool) => !isToolChecked(tool.name)) } const getEnabledToolsCount = (): number => { const disabledTools = initialMessage ? getDefaultDisabledTools() : currentThread?.id ? getDisabledToolsForThread(currentThread.id) : [] return tools.filter((tool) => !disabledTools.includes(tool.name)).length } const getToolsByServer = () => { const toolsByServer = tools.reduce( (acc, tool) => { if (!acc[tool.server]) { acc[tool.server] = [] } acc[tool.server].push(tool) return acc }, {} as Record ) return toolsByServer } const renderTrigger = () => children(isOpen, getEnabledToolsCount()) if (tools.length === 0) { return ( {renderTrigger()} {t('common:noToolsAvailable')} ) } const toolsByServer = getToolsByServer() return ( {renderTrigger()} e.stopPropagation()} > Available Tools
{Object.entries(toolsByServer).map(([serverName, serverTools]) => (
{serverName} { serverTools.filter((tool) => isToolChecked(tool.name)) .length }
{serverTools.length > 1 && (
Disable All Tools
5 ? 'mr-3 md:mr-1.5' : 'mr-2 md:mr-0' )} > handleDisableAllServerTools(serverName, !checked) } />
)}
{serverTools.map((tool) => { const isChecked = isToolChecked(tool.name) return ( { handleToolToggle(tool.name, !isChecked) e.preventDefault() }} onSelect={(e) => { handleToolToggle(tool.name, !isChecked) e.preventDefault() }} key={tool.name} className="mt-1 first:mt-0 py-1.5" icon={ { console.log('checked', checked) handleToolToggle(tool.name, checked) }} onClick={(e) => { e.stopPropagation() }} /> } >
{tool.name}
{tool.description && (

{tool.description}

)}
) })}
))}
) }