@@ -12,13 +12,13 @@ import {
1212} from "@ant-design/icons" ;
1313
1414import { TOOL_SOURCE_TYPES } from "@/const/agentConfig" ;
15- import {
16- Tooltip ,
17- TooltipTrigger ,
18- TooltipContent ,
19- } from "@/components/ui/tooltip" ;
2015import log from "@/lib/logger" ;
21- import { Tool , ToolPoolProps , ToolGroup } from "@/types/agentConfig" ;
16+ import {
17+ Tool ,
18+ ToolPoolProps ,
19+ ToolGroup ,
20+ ToolSubGroup ,
21+ } from "@/types/agentConfig" ;
2222import {
2323 fetchTools ,
2424 searchToolConfig ,
@@ -56,6 +56,7 @@ function ToolPool({
5656 const [ isMcpModalOpen , setIsMcpModalOpen ] = useState ( false ) ;
5757 const [ isRefreshing , setIsRefreshing ] = useState ( false ) ;
5858 const [ activeTabKey , setActiveTabKey ] = useState < string > ( "" ) ;
59+ const [ selectedCategory , setSelectedCategory ] = useState < string > ( "" ) ;
5960
6061 // Use useMemo to cache tool grouping
6162 const toolGroups = useMemo ( ( ) => {
@@ -100,6 +101,37 @@ function ToolPool({
100101 return a . create_time . localeCompare ( b . create_time ) ;
101102 } ) ;
102103
104+ // Create secondary grouping for local tools
105+ let subGroups : ToolSubGroup [ ] | undefined ;
106+ if ( key === TOOL_SOURCE_TYPES . LOCAL ) {
107+ const categoryMap = new Map < string , Tool [ ] > ( ) ;
108+
109+ sortedTools . forEach ( ( tool ) => {
110+ const category =
111+ tool . category && tool . category . trim ( ) !== ""
112+ ? tool . category
113+ : t ( "toolPool.category.other" ) ;
114+ if ( ! categoryMap . has ( category ) ) {
115+ categoryMap . set ( category , [ ] ) ;
116+ }
117+ categoryMap . get ( category ) ! . push ( tool ) ;
118+ } ) ;
119+
120+ subGroups = Array . from ( categoryMap . entries ( ) )
121+ . map ( ( [ category , categoryTools ] ) => ( {
122+ key : category ,
123+ label : category ,
124+ tools : categoryTools . sort ( ( a , b ) => a . name . localeCompare ( b . name ) ) , // Sort by name alphabetically
125+ } ) )
126+ . sort ( ( a , b ) => {
127+ // Put "Other" category at the end
128+ const otherKey = t ( "toolPool.category.other" ) ;
129+ if ( a . key === otherKey ) return 1 ;
130+ if ( b . key === otherKey ) return - 1 ;
131+ return a . label . localeCompare ( b . label ) ; // Sort other categories alphabetically
132+ } ) ;
133+ }
134+
103135 groups . push ( {
104136 key,
105137 label : key . startsWith ( "mcp-" )
@@ -110,6 +142,7 @@ function ToolPool({
110142 ? t ( "toolPool.group.langchain" )
111143 : key ,
112144 tools : sortedTools ,
145+ subGroups,
113146 } ) ;
114147 } ) ;
115148
@@ -132,6 +165,20 @@ function ToolPool({
132165 }
133166 } , [ toolGroups , activeTabKey ] ) ;
134167
168+ // Set default category selection for local tools
169+ useEffect ( ( ) => {
170+ const localGroup = toolGroups . find (
171+ ( group ) => group . key === TOOL_SOURCE_TYPES . LOCAL
172+ ) ;
173+ if (
174+ localGroup ?. subGroups &&
175+ localGroup . subGroups . length > 0 &&
176+ ! selectedCategory
177+ ) {
178+ setSelectedCategory ( localGroup . subGroups [ 0 ] . key ) ;
179+ }
180+ } , [ toolGroups , selectedCategory ] ) ;
181+
135182 // Use useMemo to cache the selected tool ID set to improve lookup efficiency
136183 const selectedToolIds = useMemo ( ( ) => {
137184 return new Set ( selectedTools . map ( ( tool ) => tool . id ) ) ;
@@ -511,17 +558,94 @@ function ToolPool({
511558 ) ,
512559 children : (
513560 < div
514- className = "flex flex-col gap-3 pr-2 "
561+ className = "flex h-full flex-col sm:flex-row "
515562 style = { {
516563 height : "100%" ,
517- overflowY : "auto" ,
518- padding : "8px 0" ,
519- maxHeight : "100%" ,
564+ overflow : "hidden" ,
520565 } }
521566 >
522- { group . tools . map ( ( tool ) => (
523- < ToolItem key = { tool . id } tool = { tool } />
524- ) ) }
567+ { group . subGroups ? (
568+ < >
569+ { /* Left sidebar - Category navigation */ }
570+ < div className = "w-auto min-w-fit border-r border-gray-200 flex flex-col hidden sm:flex" >
571+ < div className = "flex-1 overflow-y-auto" >
572+ < div className = "px-2 py-2" >
573+ { /* Individual categories */ }
574+ { group . subGroups . map ( ( subGroup ) => (
575+ < div key = { subGroup . key } >
576+ < div
577+ className = { `h-14 flex items-center px-2 cursor-pointer transition-colors ${
578+ selectedCategory === subGroup . key
579+ ? "text-blue-600 font-medium"
580+ : "text-gray-700 font-normal"
581+ } `}
582+ onClick = { ( ) => setSelectedCategory ( subGroup . key ) }
583+ >
584+ < div className = "whitespace-nowrap" >
585+ { subGroup . label }
586+ </ div >
587+ </ div >
588+ < div className = "border-b border-gray-200 -mx-2" > </ div >
589+ </ div >
590+ ) ) }
591+ </ div >
592+ </ div >
593+ </ div >
594+
595+ { /* Mobile category selector */ }
596+ < div className = "sm:hidden w-full mb-2" >
597+ < select
598+ value = { selectedCategory }
599+ onChange = { ( e ) => setSelectedCategory ( e . target . value ) }
600+ className = "w-full p-2 text-sm border border-gray-300 rounded-md bg-white"
601+ >
602+ { group . subGroups . map ( ( subGroup ) => (
603+ < option key = { subGroup . key } value = { subGroup . key } >
604+ { subGroup . label }
605+ </ option >
606+ ) ) }
607+ </ select >
608+ </ div >
609+
610+ { /* Right content - Tool list */ }
611+ < div className = "flex-1 overflow-hidden" >
612+ < div
613+ className = "h-full overflow-y-auto p-2"
614+ style = { {
615+ maxHeight : "100%" ,
616+ } }
617+ >
618+ { ( ( ) => {
619+ const selectedSubGroup = group . subGroups . find (
620+ ( sg ) => sg . key === selectedCategory
621+ ) ;
622+ return selectedSubGroup ? (
623+ < div className = "space-y-2" >
624+ { selectedSubGroup . tools . map ( ( tool ) => (
625+ < ToolItem key = { tool . id } tool = { tool } />
626+ ) ) }
627+ </ div >
628+ ) : null ;
629+ } ) ( ) }
630+ </ div >
631+ </ div >
632+ </ >
633+ ) : (
634+ // Regular layout for non-local tools
635+ < div
636+ className = "flex flex-col gap-3 pr-2 flex-1"
637+ style = { {
638+ height : "100%" ,
639+ overflowY : "auto" ,
640+ padding : "8px 0" ,
641+ maxHeight : "100%" ,
642+ } }
643+ >
644+ { group . tools . map ( ( tool ) => (
645+ < ToolItem key = { tool . id } tool = { tool } />
646+ ) ) }
647+ </ div >
648+ ) }
525649 </ div >
526650 ) ,
527651 } ;
0 commit comments