@ -1,21 +1,25 @@
'use client'
import type { FC } from 'react'
import React , { use State } from 'react'
import React , { use Memo, use State } from 'react'
import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector'
import copy from 'copy-to-clipboard'
import produce from 'immer'
import {
RiDeleteBinLine ,
RiEqualizer2Line ,
RiHammerFill ,
RiInformation2Line ,
} from '@remixicon/react'
import { useFormattingChangedDispatcher } from '../../../debug/hooks'
import SettingBuiltInTool from './setting-built-in-tool'
import cn from '@/utils/classnames'
import Panel from '@/app/components/app/configuration/base/feature-panel'
import { InfoCircle } from '@/app/components/base/icons/src/vender/line/general'
import OperationBtn from '@/app/components/app/configuration/base/operation-btn'
import AppIcon from '@/app/components/base/app-icon'
import Button from '@/app/components/base/button'
import Indicator from '@/app/components/header/indicator'
import Switch from '@/app/components/base/switch'
import Toast from '@/app/components/base/toast'
import ConfigContext from '@/context/debug-configuration'
import type { AgentTool } from '@/types/app'
import { type Collection , CollectionType } from '@/app/components/tools/types'
@ -23,7 +27,12 @@ import { MAX_TOOLS_NUM } from '@/config'
import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
import Tooltip from '@/app/components/base/tooltip'
import { DefaultToolIcon } from '@/app/components/base/icons/src/public/other'
import AddToolModal from '@/app/components/tools/add-tool-modal'
// import AddToolModal from '@/app/components/tools/add-tool-modal'
import ConfigCredential from '@/app/components/tools/setting/build-in/config-credentials'
import { updateBuiltInToolCredential } from '@/service/tools'
import cn from '@/utils/classnames'
import ToolPicker from '@/app/components/workflow/block-selector/tool-picker'
import type { ToolDefaultValue } from '@/app/components/workflow/block-selector/types'
type AgentToolWithMoreInfo = AgentTool & { icon : any ; collection? : Collection } | null
const AgentTools : FC = ( ) = > {
@ -33,9 +42,19 @@ const AgentTools: FC = () => {
const formattingChangedDispatcher = useFormattingChangedDispatcher ( )
const [ currentTool , setCurrentTool ] = useState < AgentToolWithMoreInfo > ( null )
const currentCollection = useMemo ( ( ) = > {
if ( ! currentTool ) return null
const collection = collectionList . find ( collection = > collection . id . split ( '/' ) . pop ( ) === currentTool ? . provider_id . split ( '/' ) . pop ( ) && collection . type === currentTool ? . provider_type )
return collection
} , [ currentTool , collectionList ] )
const [ isShowSettingTool , setIsShowSettingTool ] = useState ( false )
const [ isShowSettingAuth , setShowSettingAuth ] = useState ( false )
const tools = ( modelConfig ? . agentConfig ? . tools as AgentTool [ ] || [ ] ) . map ( ( item ) = > {
const collection = collectionList . find ( collection = > collection . id === item . provider_id && collection . type === item . provider_type )
const collection = collectionList . find (
collection = >
collection . id . split ( '/' ) . pop ( ) === item . provider_id . split ( '/' ) . pop ( )
&& collection . type === item . provider_type ,
)
const icon = collection ? . icon
return {
. . . item ,
@ -55,10 +74,39 @@ const AgentTools: FC = () => {
formattingChangedDispatcher ( )
}
const handleToolAuthSetting = ( value : any ) = > {
const newModelConfig = produce ( modelConfig , ( draft ) = > {
const tool = ( draft . agentConfig . tools ) . find ( ( item : any ) = > item . provider_id === value ? . collection ? . id && item . tool_name === value ? . tool_name )
if ( tool )
( tool as AgentTool ) . notAuthor = false
} )
setModelConfig ( newModelConfig )
setIsShowSettingTool ( false )
formattingChangedDispatcher ( )
}
const [ isDeleting , setIsDeleting ] = useState < number > ( - 1 )
const handleSelectTool = ( tool : ToolDefaultValue ) = > {
const newModelConfig = produce ( modelConfig , ( draft ) = > {
draft . agentConfig . tools . push ( {
provider_id : tool.provider_id ,
provider_type : tool.provider_type as CollectionType ,
provider_name : tool.provider_name ,
tool_name : tool.tool_name ,
tool_label : tool.tool_label ,
tool_parameters : tool.params ,
notAuthor : ! tool . is_team_authorization ,
enabled : true ,
} )
} )
setModelConfig ( newModelConfig )
}
return (
< >
< Panel
className = "mt-2"
className = { cn ( 'mt-2' , tools . length === 0 && 'pb-2' ) }
noBodySpacing = { tools . length === 0 }
headerIcon = {
< RiHammerFill className = 'w-4 h-4 text-primary-500' / >
@ -81,7 +129,14 @@ const AgentTools: FC = () => {
{ tools . length < MAX_TOOLS_NUM && (
< >
< div className = 'ml-3 mr-1 h-3.5 w-px bg-gray-200' > < / div >
< OperationBtn type = "add" onClick = { ( ) = > setIsShowChooseTool ( true ) } / >
< ToolPicker
trigger = { < OperationBtn type = "add" / > }
isShow = { isShowChooseTool }
onShowChange = { setIsShowChooseTool }
disabled = { false }
supportAddCustomTool
onSelect = { handleSelectTool }
/ >
< / >
) }
< / div >
@ -90,72 +145,77 @@ const AgentTools: FC = () => {
< div className = 'grid gap-1 grid-cols-1 2xl:grid-cols-2 items-center flex-wrap justify-between' >
{ tools . map ( ( item : AgentTool & { icon : any ; collection? : Collection } , index ) = > (
< div key = { index }
className = { cn ( ( item . isDeleted || item . notAuthor ) ? 'bg-white/50' : 'bg-white' , ( item . enabled && ! item . isDeleted && ! item . notAuthor ) && 'shadow-xs' , index > 1 && 'mt-1' , 'group relative flex justify-between items-center last-of-type:mb-0 pl-2.5 py-2 pr-3 w-full rounded-lg border-[0.5px] border-gray-200 ' ) }
className = { cn (
'group relative flex justify-between items-center last-of-type:mb-0 p-1.5 pr-2 w-full bg-components-panel-on-panel-item-bg rounded-lg border-[0.5px] border-components-panel-border-subtle shadow-xs hover:bg-components-panel-on-panel-item-bg-hover hover:shadow-sm cursor' ,
isDeleting === index && 'hover:bg-state-destructive-hover border-state-destructive-border' ,
) }
>
< div className = 'grow w-0 flex items-center' >
{ ( item . isDeleted || item . notAuthor )
? (
< DefaultToolIcon className = 'w-6 h-6' / >
)
: (
typeof item . icon === 'string'
? (
< div
className = 'w-6 h-6 bg-cover bg-center rounded-md'
style = { {
backgroundImage : ` url( ${ item . icon } ) ` ,
} }
> < / div >
)
: (
< AppIcon
className = 'rounded-md'
size = 'tiny'
icon = { item . icon ? . content }
background = { item . icon ? . background }
/ >
) ) }
{ item . isDeleted && < DefaultToolIcon className = 'w-5 h-5' / > }
{ ! item . isDeleted && (
< div className = { cn ( ( item . notAuthor || ! item . enabled ) && 'opacity-50' ) } >
{ typeof item . icon === 'string' && < div className = 'w-5 h-5 bg-cover bg-center rounded-md' style = { { backgroundImage : ` url( ${ item . icon } ) ` } } / > }
{ typeof item . icon !== 'string' && < AppIcon className = 'rounded-md' size = 'xs' icon = { item . icon ? . content } background = { item . icon ? . background } / > }
< / div >
) }
< div
className = { cn ( ( item . isDeleted || item . notAuthor ) ? 'line-through opacity-50' : '' , 'grow w-0 ml-2 leading-[18px] text-[13px] font-medium text-gray-800 truncate' ) }
className = { cn (
'grow w-0 ml-1.5 flex items-center system-xs-regular truncate' ,
( item . isDeleted || item . notAuthor || ! item . enabled ) ? 'opacity-50' : '' ,
) }
>
< span className = 'text-gray-800 pr-2' > { item . provider_type === CollectionType . builtIn ? item.provider_name : item.tool_label } < / span >
< Tooltip
popupContent = { t ( 'tools.toolNameUsageTip' ) }
>
< span className = 'text-gray-500' > { item . tool_name } < / span >
< / Tooltip >
< span className = 'text-text-secondary system-xs-medium pr-1.5' > { item . provider_type === CollectionType . builtIn ? item . provider_name . split ( '/' ) . pop ( ) : item . tool_label } < / span >
< span className = 'text-text-tertiary' > { item . tool_name } < / span >
{ ! item . isDeleted && (
< Tooltip
needsDelay
popupContent = {
< div className = 'w-[180px]' >
< div className = 'mb-1.5 text-text-secondary' > { item . tool_name } < / div >
< div className = 'mb-1.5 text-text-tertiary' > { t ( 'tools.toolNameUsageTip' ) } < / div >
< div className = 'text-text-accent cursor-pointer' onClick = { ( ) = > copy ( item . tool_name ) } > { t ( 'tools.copyToolName' ) } < / div >
< / div >
}
>
< div className = 'w-4 h-4' >
< div className = 'hidden group-hover:inline-block ml-0.5' >
< RiInformation2Line className = 'w-4 h-4 text-text-tertiary' / >
< / div >
< / div >
< / Tooltip >
) }
< / div >
< / div >
< div className = 'shrink-0 ml-1 flex items-center' >
{ ( item . isDeleted || item . notAuthor )
? (
< div className = 'flex items-center' >
< Tooltip
popupContent = { t ( ` tools. ${ item . isDeleted ? 'toolRemoved' : 'notAuthorized' } ` ) }
needsDelay
>
< div className = 'mr-1 p-1 rounded-md hover:bg-black/5 cursor-pointer' onClick = { ( ) = > {
if ( item . notAuthor )
setIsShowChooseTool ( true )
} } >
< AlertTriangle className = 'w-4 h-4 text-[#F79009]' / >
< / div >
< / Tooltip >
< div className = 'p-1 rounded-md hover:bg-black/5 cursor-pointer' onClick = { ( ) = > {
{ item . isDeleted && (
< div className = 'flex items-center mr-2' >
< Tooltip
popupContent = { t ( 'tools.toolRemoved' ) }
needsDelay
>
< div className = 'mr-1 p-1 rounded-md hover:bg-black/5 cursor-pointer' >
< AlertTriangle className = 'w-4 h-4 text-[#F79009]' / >
< / div >
< / Tooltip >
< div
className = 'p-1 rounded-md text-text-tertiary cursor-pointer hover:text-text-destructive'
onClick = { ( ) = > {
const newModelConfig = produce ( modelConfig , ( draft ) = > {
draft . agentConfig . tools . splice ( index , 1 )
} )
setModelConfig ( newModelConfig )
formattingChangedDispatcher ( )
} } >
< RiDeleteBinLine className = 'w-4 h-4 text-gray-500' / >
< / div >
< div className = 'ml-2 mr-3 w-px h-3.5 bg-gray-200' > < / div >
} }
onMouseOver = { ( ) = > setIsDeleting ( index ) }
onMouseLeave = { ( ) = > setIsDeleting ( - 1 ) }
>
< RiDeleteBinLine className = 'w-4 h-4' / >
< / div >
)
: (
< div className = 'hidden group-hover:flex items-center' >
< / div >
) }
{ ! item . isDeleted && (
< div className = 'hidden group-hover:flex items-center gap-1 mr-2' >
{ ! item . notAuthor && (
< Tooltip
popupContent = { t ( 'tools.setBuiltInTools.infoAndSetting' ) }
needsDelay
@ -164,55 +224,81 @@ const AgentTools: FC = () => {
setCurrentTool ( item )
setIsShowSettingTool ( true )
} } >
< InfoCircle className = 'w-4 h-4 text-gray-500 ' / >
< RiEqualizer2Line className = 'w-4 h-4 text-text-tertiary ' / >
< / div >
< / Tooltip >
< div className = 'p-1 rounded-md hover:bg-black/5 cursor-pointer' onClick = { ( ) = > {
) }
< div
className = 'p-1 rounded-md text-text-tertiary cursor-pointer hover:text-text-destructive'
onClick = { ( ) = > {
const newModelConfig = produce ( modelConfig , ( draft ) = > {
draft . agentConfig . tools . splice ( index , 1 )
} )
setModelConfig ( newModelConfig )
formattingChangedDispatcher ( )
} } >
< RiDeleteBinLine className = 'w-4 h-4 text-gray-500' / >
< / div >
< div className = 'ml-2 mr-3 w-px h-3.5 bg-gray-200' > < / div >
} }
onMouseOver = { ( ) = > setIsDeleting ( index ) }
onMouseLeave = { ( ) = > setIsDeleting ( - 1 ) }
>
< RiDeleteBinLine className = 'w-4 h-4' / >
< / div >
< / div >
) }
< div className = { cn ( item . isDeleted && 'opacity-50' ) } >
{ ! item . notAuthor && (
< Switch
defaultValue = { item . isDeleted ? false : item . enabled }
disabled = { item . isDeleted }
size = 'md'
onChange = { ( enabled ) = > {
const newModelConfig = produce ( modelConfig , ( draft ) = > {
( draft . agentConfig . tools [ index ] as any ) . enabled = enabled
} )
setModelConfig ( newModelConfig )
formattingChangedDispatcher ( )
} } / >
) }
{ item . notAuthor && (
< Button variant = 'secondary' size = 'small' onClick = { ( ) = > {
setCurrentTool ( item )
setShowSettingAuth ( true )
} } >
{ t ( 'tools.notAuthorized' ) }
< Indicator className = 'ml-2' color = 'orange' / >
< / Button >
) }
< div className = { cn ( ( item . isDeleted || item . notAuthor ) && 'opacity-50' ) } >
< Switch
defaultValue = { ( item . isDeleted || item . notAuthor ) ? false : item . enabled }
disabled = { ( item . isDeleted || item . notAuthor ) }
size = 'md'
onChange = { ( enabled ) = > {
const newModelConfig = produce ( modelConfig , ( draft ) = > {
( draft . agentConfig . tools [ index ] as any ) . enabled = enabled
} )
setModelConfig ( newModelConfig )
formattingChangedDispatcher ( )
} } / >
< / div >
< / div >
< / div >
) ) }
< / d i v >
< / P a n e l >
{ isShowChooseTool && (
< AddToolModal onHide = { ( ) = > setIsShowChooseTool ( false ) } / >
{ isShowSettingTool && (
< SettingBuiltInTool
toolName = { currentTool ? . tool_name as string }
setting = { currentTool ? . tool_parameters as any }
collection = { currentTool ? . collection as Collection }
isBuiltIn = { currentTool ? . collection ? . type === CollectionType . builtIn }
isModel = { currentTool ? . collection ? . type === CollectionType . model }
onSave = { handleToolSettingChange }
onHide = { ( ) = > setIsShowSettingTool ( false ) }
/ >
) }
{ isShowSettingAuth && (
< ConfigCredential
collection = { currentCollection as any }
onCancel = { ( ) = > setShowSettingAuth ( false ) }
onSaved = { async ( value ) = > {
await updateBuiltInToolCredential ( ( currentCollection as any ) . name , value )
Toast . notify ( {
type : 'success' ,
message : t ( 'common.api.actionSuccess' ) ,
} )
handleToolAuthSetting ( currentTool as any )
setShowSettingAuth ( false )
} }
/ >
) }
{
isShowSettingTool && (
< SettingBuiltInTool
toolName = { currentTool ? . tool_name as string }
setting = { currentTool ? . tool_parameters as any }
collection = { currentTool ? . collection as Collection }
isBuiltIn = { currentTool ? . collection ? . type === CollectionType . builtIn }
isModel = { currentTool ? . collection ? . type === CollectionType . model }
onSave = { handleToolSettingChange }
onHide = { ( ) = > setIsShowSettingTool ( false ) }
/ > )
}
< / >
)
}