From a430284aa21e3ae1f0d5654e55b2ad2852519cc2 Mon Sep 17 00:00:00 2001 From: wwf <yearningwang@iqtogether.com> Date: 星期三, 04 六月 2025 15:17:49 +0800 Subject: [PATCH] 初始化 --- app/components/app/configuration/config/agent/agent-tools/index.tsx | 289 ++++++++++++++++++++------------------------------------- 1 files changed, 103 insertions(+), 186 deletions(-) diff --git a/app/components/app/configuration/config/agent/agent-tools/index.tsx b/app/components/app/configuration/config/agent/agent-tools/index.tsx index 4b773c0..52e5d5d 100644 --- a/app/components/app/configuration/config/agent/agent-tools/index.tsx +++ b/app/components/app/configuration/config/agent/agent-tools/index.tsx @@ -1,24 +1,21 @@ 'use client' import type { FC } from 'react' -import React, { useMemo, useState } from 'react' +import React, { useState } 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, - RiInformation2Line, + RiHammerFill, } 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' @@ -26,12 +23,7 @@ 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 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' -import { canFindTool } from '@/utils' +import AddToolModal from '@/app/components/tools/add-tool-modal' type AgentToolWithMoreInfo = AgentTool & { icon: any; collection?: Collection } | null const AgentTools: FC = () => { @@ -41,19 +33,9 @@ const formattingChangedDispatcher = useFormattingChangedDispatcher() const [currentTool, setCurrentTool] = useState<AgentToolWithMoreInfo>(null) - const currentCollection = useMemo(() => { - if (!currentTool) return null - const collection = collectionList.find(collection => canFindTool(collection.id, currentTool?.provider_id) && 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 => - canFindTool(collection.id, item.provider_id) - && collection.type === item.provider_type, - ) + const collection = collectionList.find(collection => collection.id === item.provider_id && collection.type === item.provider_type) const icon = collection?.icon return { ...item, @@ -73,40 +55,14 @@ formattingChangedDispatcher() } - const handleToolAuthSetting = (value: AgentToolWithMoreInfo) => { - 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={cn('mt-2', tools.length === 0 && 'pb-2')} + className="mt-2" noBodySpacing={tools.length === 0} + headerIcon={ + <RiHammerFill className='w-4 h-4 text-primary-500' /> + } title={ <div className='flex items-center'> <div className='mr-1'>{t('appDebug.agent.tools.name')}</div> @@ -121,181 +77,142 @@ } headerRight={ <div className='flex items-center'> - <div className='text-xs font-normal leading-[18px] text-text-tertiary'>{tools.filter(item => !!item.enabled).length}/{tools.length} {t('appDebug.agent.tools.enabled')}</div> + <div className='leading-[18px] text-xs font-normal text-gray-500'>{tools.filter((item: any) => !!item.enabled).length}/{tools.length} {t('appDebug.agent.tools.enabled')}</div> {tools.length < MAX_TOOLS_NUM && ( <> - <div className='ml-3 mr-1 h-3.5 w-px bg-divider-regular'></div> - <ToolPicker - trigger={<OperationBtn type="add" />} - isShow={isShowChooseTool} - onShowChange={setIsShowChooseTool} - disabled={false} - supportAddCustomTool - onSelect={handleSelectTool} - selectedTools={tools} - /> + <div className='ml-3 mr-1 h-3.5 w-px bg-gray-200'></div> + <OperationBtn type="add" onClick={() => setIsShowChooseTool(true)} /> </> )} </div> } > - <div className='grid grid-cols-1 flex-wrap items-center justify-between gap-1 2xl:grid-cols-2'> + <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( - 'cursor group relative flex w-full items-center justify-between rounded-lg border-[0.5px] border-components-panel-border-subtle bg-components-panel-on-panel-item-bg p-1.5 pr-2 shadow-xs last-of-type:mb-0 hover:bg-components-panel-on-panel-item-bg-hover hover:shadow-sm', - isDeleting === index && 'border-state-destructive-border hover:bg-state-destructive-hover', - )} + 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 ')} > - <div className='flex w-0 grow items-center'> - {item.isDeleted && <DefaultToolIcon className='h-5 w-5' />} - {!item.isDeleted && ( - <div className={cn((item.notAuthor || !item.enabled) && 'opacity-50')}> - {typeof item.icon === 'string' && <div className='h-5 w-5 rounded-md bg-cover bg-center' 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='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} + /> + ))} <div - className={cn( - 'system-xs-regular ml-1.5 flex w-0 grow items-center truncate', - (item.isDeleted || item.notAuthor || !item.enabled) ? 'opacity-50' : '', - )} + 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')} > - <span className='system-xs-medium pr-1.5 text-text-secondary'>{item.provider_type === CollectionType.builtIn ? item.provider_name.split('/').pop() : item.tool_label}</span> - <span className='text-text-tertiary'>{item.tool_label}</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='cursor-pointer text-text-accent' onClick={() => copy(item.tool_name)}>{t('tools.copyToolName')}</div> - </div> - } - > - <div className='h-4 w-4'> - <div className='ml-0.5 hidden group-hover:inline-block'> - <RiInformation2Line className='h-4 w-4 text-text-tertiary' /> - </div> - </div> - </Tooltip> - )} + <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> </div> </div> - <div className='ml-1 flex shrink-0 items-center'> - {item.isDeleted && ( - <div className='mr-2 flex items-center'> - <Tooltip - popupContent={t('tools.toolRemoved')} - needsDelay - > - <div className='mr-1 cursor-pointer rounded-md p-1 hover:bg-black/5'> - <AlertTriangle className='h-4 w-4 text-[#F79009]' /> - </div> - </Tooltip> - <div - className='cursor-pointer rounded-md p-1 text-text-tertiary hover:text-text-destructive' - onClick={() => { + <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={() => { const newModelConfig = produce(modelConfig, (draft) => { draft.agentConfig.tools.splice(index, 1) }) setModelConfig(newModelConfig) formattingChangedDispatcher() - }} - onMouseOver={() => setIsDeleting(index)} - onMouseLeave={() => setIsDeleting(-1)} - > - <RiDeleteBinLine className='h-4 w-4' /> + }}> + <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> </div> - </div> - )} - {!item.isDeleted && ( - <div className='mr-2 hidden items-center gap-1 group-hover:flex'> - {!item.notAuthor && ( + ) + : ( + <div className='hidden group-hover:flex items-center'> <Tooltip popupContent={t('tools.setBuiltInTools.infoAndSetting')} needsDelay > - <div className='cursor-pointer rounded-md p-1 hover:bg-black/5' onClick={() => { + <div className='p-1 rounded-md hover:bg-black/5 cursor-pointer' onClick={() => { setCurrentTool(item) setIsShowSettingTool(true) }}> - <RiEqualizer2Line className='h-4 w-4 text-text-tertiary' /> + <InfoCircle className='w-4 h-4 text-gray-500' /> </div> </Tooltip> - )} - <div - className='cursor-pointer rounded-md p-1 text-text-tertiary hover:text-text-destructive' - onClick={() => { + + <div className='p-1 rounded-md hover:bg-black/5 cursor-pointer' onClick={() => { const newModelConfig = produce(modelConfig, (draft) => { draft.agentConfig.tools.splice(index, 1) }) setModelConfig(newModelConfig) formattingChangedDispatcher() - }} - onMouseOver={() => setIsDeleting(index)} - onMouseLeave={() => setIsDeleting(-1)} - > - <RiDeleteBinLine className='h-4 w-4' /> + }}> + <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> </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> ))} </div > </Panel > - {isShowSettingTool && ( - <SettingBuiltInTool - toolName={currentTool?.tool_name as string} - setting={currentTool?.tool_parameters} - collection={currentTool?.collection as Collection} - isBuiltIn={currentTool?.collection?.type === CollectionType.builtIn} - isModel={currentTool?.collection?.type === CollectionType.model} - onSave={handleToolSettingChange} - onHide={() => setIsShowSettingTool(false)} - /> + {isShowChooseTool && ( + <AddToolModal onHide={() => setIsShowChooseTool(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) - 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)} + />) + } </> ) } -- Gitblit v1.8.0