fix: tools call available dropdown (#5222)

This commit is contained in:
Faisal Amir 2025-06-09 20:58:09 +07:00 committed by GitHub
parent 919b6671a1
commit c41a6c3899
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 66 additions and 50 deletions

View File

@ -64,6 +64,8 @@ const ChatInput = ({
const { selectedModel } = useModelProvider() const { selectedModel } = useModelProvider()
const { sendMessage } = useChat() const { sendMessage } = useChat()
const [message, setMessage] = useState('') const [message, setMessage] = useState('')
const [dropdownToolsAvailable, setDropdownToolsAvailable] = useState(false)
const [tooltipToolsAvailable, setTooltipToolsAvailable] = useState(false)
const [uploadedFiles, setUploadedFiles] = useState< const [uploadedFiles, setUploadedFiles] = useState<
Array<{ Array<{
name: string name: string
@ -407,7 +409,6 @@ const ChatInput = ({
useLastUsedModel={initialMessage} useLastUsedModel={initialMessage}
/> />
)} )}
{/* File attachment - always available */} {/* File attachment - always available */}
<div <div
className="h-6 hidden p-1 items-center justify-center rounded-sm hover:bg-main-view-fg/10 transition-all duration-200 ease-in-out gap-1" className="h-6 hidden p-1 items-center justify-center rounded-sm hover:bg-main-view-fg/10 transition-all duration-200 ease-in-out gap-1"
@ -421,16 +422,14 @@ const ChatInput = ({
onChange={handleFileChange} onChange={handleFileChange}
/> />
</div> </div>
{/* Microphone - always available - Temp Hide */} {/* Microphone - always available - Temp Hide */}
{/* <div className="h-6 p-1 flex items-center justify-center rounded-sm hover:bg-main-view-fg/10 transition-all duration-200 ease-in-out gap-1"> {/* <div className="h-6 p-1 flex items-center justify-center rounded-sm hover:bg-main-view-fg/10 transition-all duration-200 ease-in-out gap-1">
<IconMicrophone size={18} className="text-main-view-fg/50" /> <IconMicrophone size={18} className="text-main-view-fg/50" />
</div> */} </div> */}
{selectedModel?.capabilities?.includes('vision') && ( {selectedModel?.capabilities?.includes('vision') && (
<TooltipProvider> <TooltipProvider>
<Tooltip> <Tooltip>
<TooltipTrigger asChild> <TooltipTrigger disabled={dropdownToolsAvailable}>
<div className="h-6 p-1 flex items-center justify-center rounded-sm hover:bg-main-view-fg/10 transition-all duration-200 ease-in-out gap-1"> <div className="h-6 p-1 flex items-center justify-center rounded-sm hover:bg-main-view-fg/10 transition-all duration-200 ease-in-out gap-1">
<IconEye size={18} className="text-main-view-fg/50" /> <IconEye size={18} className="text-main-view-fg/50" />
</div> </div>
@ -441,7 +440,6 @@ const ChatInput = ({
</Tooltip> </Tooltip>
</TooltipProvider> </TooltipProvider>
)} )}
{selectedModel?.capabilities?.includes('embeddings') && ( {selectedModel?.capabilities?.includes('embeddings') && (
<TooltipProvider> <TooltipProvider>
<Tooltip> <Tooltip>
@ -463,32 +461,49 @@ const ChatInput = ({
{selectedModel?.capabilities?.includes('tools') && {selectedModel?.capabilities?.includes('tools') &&
hasActiveMCPServers && ( hasActiveMCPServers && (
<TooltipProvider> <TooltipProvider>
<Tooltip> <Tooltip
<TooltipTrigger asChild> open={tooltipToolsAvailable}
<div> onOpenChange={setTooltipToolsAvailable}
>
<TooltipTrigger
asChild
disabled={dropdownToolsAvailable}
>
<div
onClick={(e) => {
setDropdownToolsAvailable(false)
e.stopPropagation()
}}
>
<DropdownToolsAvailable <DropdownToolsAvailable
initialMessage={initialMessage} initialMessage={initialMessage}
> >
{(isOpen, toolsCount) => ( {(isOpen, toolsCount) => {
<div setDropdownToolsAvailable(isOpen)
className={cn( if (tooltipToolsAvailable && isOpen) {
'h-6 p-1 flex items-center justify-center rounded-sm hover:bg-main-view-fg/10 transition-all duration-200 ease-in-out gap-1 cursor-pointer relative', setTooltipToolsAvailable(false)
isOpen && 'bg-main-view-fg/10' }
)} return (
> <div
<IconTool className={cn(
size={18} 'h-6 p-1 flex items-center justify-center rounded-sm hover:bg-main-view-fg/10 transition-all duration-200 ease-in-out gap-1 cursor-pointer relative',
className="text-main-view-fg/50" isOpen && 'bg-main-view-fg/10'
/> )}
{toolsCount > 0 && ( >
<div className="absolute -top-1 -right-1.5 bg-accent text-accent-fg text-xs rounded-full size-4 flex items-center justify-center font-medium"> <IconTool
<span className="leading-0"> size={18}
{toolsCount > 99 ? '99+' : toolsCount} className="text-main-view-fg/50"
</span> />
</div> {toolsCount > 0 && (
)} <div className="absolute -top-2 -right-2 bg-accent text-accent-fg text-xs rounded-full size-5 flex items-center justify-center font-medium">
</div> <span className="leading-0 text-xs">
)} {toolsCount > 99 ? '99+' : toolsCount}
</span>
</div>
)}
</div>
)
}}
</DropdownToolsAvailable> </DropdownToolsAvailable>
</div> </div>
</TooltipTrigger> </TooltipTrigger>
@ -498,7 +513,6 @@ const ChatInput = ({
</Tooltip> </Tooltip>
</TooltipProvider> </TooltipProvider>
)} )}
{selectedModel?.capabilities?.includes('web_search') && ( {selectedModel?.capabilities?.includes('web_search') && (
<TooltipProvider> <TooltipProvider>
<Tooltip> <Tooltip>
@ -516,7 +530,6 @@ const ChatInput = ({
</Tooltip> </Tooltip>
</TooltipProvider> </TooltipProvider>
)} )}
{selectedModel?.capabilities?.includes('reasoning') && ( {selectedModel?.capabilities?.includes('reasoning') && (
<TooltipProvider> <TooltipProvider>
<Tooltip> <Tooltip>

View File

@ -99,36 +99,34 @@ export default function DropdownToolsAvailable({
<DropdownMenu onOpenChange={setIsOpen}> <DropdownMenu onOpenChange={setIsOpen}>
<DropdownMenuTrigger asChild>{renderTrigger()}</DropdownMenuTrigger> <DropdownMenuTrigger asChild>{renderTrigger()}</DropdownMenuTrigger>
<DropdownMenuContent <DropdownMenuContent side="top" align="start" className="max-w-64">
side="top"
align="start"
className="max-w-64 max-h-64 "
>
<DropdownMenuLabel className="flex items-center gap-2 sticky -top-1 z-10 bg-main-view px-4 pl-2 py-2"> <DropdownMenuLabel className="flex items-center gap-2 sticky -top-1 z-10 bg-main-view px-4 pl-2 py-2">
Available Tools Available Tools
</DropdownMenuLabel> </DropdownMenuLabel>
<DropdownMenuSeparator /> <DropdownMenuSeparator />
<div> <div className="max-h-64 overflow-y-auto">
{tools.map((tool) => { {tools.map((tool) => {
const isChecked = isToolChecked(tool.name) const isChecked = isToolChecked(tool.name)
return ( return (
<div <div
key={tool.name} key={tool.name}
className="px-2 py-2 hover:bg-main-view-fg/5 rounded-sm" className="py-2 hover:bg-main-view-fg/5 rounded-sm px-2 mx-auto w-full"
> >
<div className="flex items-start justify-between gap-3"> <div className="flex items-start justify-center gap-3">
<div className="flex-1 min-w-0"> <div className="flex items-start justify-between gap-4 w-full">
<div className="flex items-start justify-between gap-4"> <div className="overflow-hidden w-full flex flex-col ">
<div> <div className="truncate">
<h4 className="text-sm font-medium line-clamp-1"> <span className="text-sm font-medium" title={tool.name}>
{tool.name} {tool.name}
</h4> </span>
{tool.description && (
<p className="text-xs text-main-view-fg/70 mt-1 line-clamp-2">
{tool.description}
</p>
)}
</div> </div>
{tool.description && (
<p className="text-xs text-main-view-fg/70 mt-1 line-clamp-2">
{tool.description}
</p>
)}
</div>
<div className="shrink-0 mx-auto">
<Switch <Switch
checked={isChecked} checked={isChecked}
onCheckedChange={(checked) => onCheckedChange={(checked) =>

View File

@ -96,7 +96,9 @@ const ProvidersMenu = ({
} }
> >
<ProvidersAvatar provider={provider} /> <ProvidersAvatar provider={provider} />
<span>{getProviderTitle(provider.provider)}</span> <div className="truncate">
<span>{getProviderTitle(provider.provider)}</span>
</div>
</div> </div>
</div> </div>
) )

View File

@ -80,7 +80,10 @@ function RenderMarkdownComponent({
{getReadableLanguageName(language)} {getReadableLanguageName(language)}
</span> </span>
<button <button
onClick={() => handleCopy(code, codeId)} onClick={(e) => {
e.stopPropagation()
handleCopy(code, codeId)
}}
className="flex items-center gap-1 text-xs font-sans transition-colors cursor-pointer" className="flex items-center gap-1 text-xs font-sans transition-colors cursor-pointer"
> >
{copiedId === codeId ? ( {copiedId === codeId ? (