merge feat/plugins

pull/12372/head
JzoNg 1 year ago
commit 6f97eb5713

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none">
<path d="M10.3567 3.56405L10.2334 3.84689C10.1432 4.05396 9.8568 4.05396 9.76655 3.84689L9.6433 3.56405C9.42355 3.05973 9.02775 2.6582 8.53385 2.43854L8.154 2.26961C7.94865 2.17826 7.94865 1.8794 8.154 1.78806L8.5126 1.62857C9.0192 1.40325 9.4221 0.986865 9.63805 0.465414L9.76465 0.159767C9.8529 -0.0532556 10.1471 -0.0532556 10.2353 0.159767L10.3619 0.465414C10.5779 0.986865 10.9808 1.40325 11.4874 1.62857L11.846 1.78806C12.0514 1.8794 12.0514 2.17826 11.846 2.26961L11.4662 2.43854C10.9723 2.6582 10.5764 3.05973 10.3567 3.56405ZM4.25 3H3.25V9H4.25V3ZM2 5H1V7H2V5ZM6.5 1H5.5V11H6.5V1ZM8.75 4H7.75V9H8.75V4ZM11 5H10V7H11V5Z" fill="#676F83"/>
</svg>

After

Width:  |  Height:  |  Size: 750 B

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none">
<path d="M10.5 4V10.4966C10.5 10.7751 10.2776 11 10.0033 11H1.9967C1.72248 11 1.5 10.778 1.5 10.5041V1.4959C1.5 1.22766 1.72435 1 2.00111 1H7.4984L10.5 4ZM9.5 4.5H7V2H2.5V10H9.5V4.5ZM4 3.5H5.5V4.5H4V3.5ZM4 5.5H8V6.5H4V5.5ZM4 7.5H8V8.5H4V7.5Z" fill="#676F83"/>
</svg>

After

Width:  |  Height:  |  Size: 364 B

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none">
<path d="M10.2334 4.3469L10.3567 4.06406C10.5764 3.55974 10.9723 3.15821 11.4662 2.93854L11.846 2.76961C12.0514 2.67827 12.0514 2.37941 11.846 2.28806L11.4874 2.12857C10.9808 1.90326 10.5779 1.48687 10.3619 0.965415L10.2353 0.659765C10.1471 0.446745 9.8529 0.446745 9.76465 0.659765L9.63805 0.965415C9.4221 1.48687 9.0192 1.90326 8.5126 2.12857L8.154 2.28806C7.94865 2.37941 7.94865 2.67827 8.154 2.76961L8.53385 2.93854C9.02775 3.15821 9.42355 3.55974 9.6433 4.06406L9.76655 4.3469C9.8568 4.55396 10.1432 4.55396 10.2334 4.3469ZM1.4959 1.5H7V2.5H4V9.5H8V4.5H9V5.5H10H11V10.0033C11 10.2776 10.7723 10.5 10.5041 10.5H1.4959C1.22203 10.5 1 10.2775 1 10.0033V1.9967C1 1.72238 1.22766 1.5 1.4959 1.5ZM2 2.5V3.5H3V2.5H2ZM2 4.5V5.5H3V4.5H2ZM2 6.5V7.5H3V6.5H2ZM9 6.5V7.5H10V6.5H9ZM2 8.5V9.5H3V8.5H2ZM9 8.5V9.5H10V8.5H9Z" fill="#676F83"/>
</svg>

After

Width:  |  Height:  |  Size: 935 B

@ -0,0 +1,26 @@
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"xmlns": "http://www.w3.org/2000/svg",
"width": "12",
"height": "12",
"viewBox": "0 0 12 12",
"fill": "none"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"d": "M10.3567 3.56405L10.2334 3.84689C10.1432 4.05396 9.8568 4.05396 9.76655 3.84689L9.6433 3.56405C9.42355 3.05973 9.02775 2.6582 8.53385 2.43854L8.154 2.26961C7.94865 2.17826 7.94865 1.8794 8.154 1.78806L8.5126 1.62857C9.0192 1.40325 9.4221 0.986865 9.63805 0.465414L9.76465 0.159767C9.8529 -0.0532556 10.1471 -0.0532556 10.2353 0.159767L10.3619 0.465414C10.5779 0.986865 10.9808 1.40325 11.4874 1.62857L11.846 1.78806C12.0514 1.8794 12.0514 2.17826 11.846 2.26961L11.4662 2.43854C10.9723 2.6582 10.5764 3.05973 10.3567 3.56405ZM4.25 3H3.25V9H4.25V3ZM2 5H1V7H2V5ZM6.5 1H5.5V11H6.5V1ZM8.75 4H7.75V9H8.75V4ZM11 5H10V7H11V5Z",
"fill": "currentColor"
},
"children": []
}
]
},
"name": "AudioSupportIcon"
}

@ -0,0 +1,16 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './AudioSupportIcon.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
props,
ref,
) => <IconBase {...props} ref={ref} data={data as IconData} />)
Icon.displayName = 'AudioSupportIcon'
export default Icon

@ -0,0 +1,26 @@
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"xmlns": "http://www.w3.org/2000/svg",
"width": "12",
"height": "12",
"viewBox": "0 0 12 12",
"fill": "none"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"d": "M10.5 4V10.4966C10.5 10.7751 10.2776 11 10.0033 11H1.9967C1.72248 11 1.5 10.778 1.5 10.5041V1.4959C1.5 1.22766 1.72435 1 2.00111 1H7.4984L10.5 4ZM9.5 4.5H7V2H2.5V10H9.5V4.5ZM4 3.5H5.5V4.5H4V3.5ZM4 5.5H8V6.5H4V5.5ZM4 7.5H8V8.5H4V7.5Z",
"fill": "currentColor"
},
"children": []
}
]
},
"name": "DocumentSupportIcon"
}

@ -0,0 +1,16 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './DocumentSupportIcon.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
props,
ref,
) => <IconBase {...props} ref={ref} data={data as IconData} />)
Icon.displayName = 'DocumentSupportIcon'
export default Icon

@ -0,0 +1,26 @@
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"xmlns": "http://www.w3.org/2000/svg",
"width": "12",
"height": "12",
"viewBox": "0 0 12 12",
"fill": "none"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"d": "M10.2334 4.3469L10.3567 4.06406C10.5764 3.55974 10.9723 3.15821 11.4662 2.93854L11.846 2.76961C12.0514 2.67827 12.0514 2.37941 11.846 2.28806L11.4874 2.12857C10.9808 1.90326 10.5779 1.48687 10.3619 0.965415L10.2353 0.659765C10.1471 0.446745 9.8529 0.446745 9.76465 0.659765L9.63805 0.965415C9.4221 1.48687 9.0192 1.90326 8.5126 2.12857L8.154 2.28806C7.94865 2.37941 7.94865 2.67827 8.154 2.76961L8.53385 2.93854C9.02775 3.15821 9.42355 3.55974 9.6433 4.06406L9.76655 4.3469C9.8568 4.55396 10.1432 4.55396 10.2334 4.3469ZM1.4959 1.5H7V2.5H4V9.5H8V4.5H9V5.5H10H11V10.0033C11 10.2776 10.7723 10.5 10.5041 10.5H1.4959C1.22203 10.5 1 10.2775 1 10.0033V1.9967C1 1.72238 1.22766 1.5 1.4959 1.5ZM2 2.5V3.5H3V2.5H2ZM2 4.5V5.5H3V4.5H2ZM2 6.5V7.5H3V6.5H2ZM9 6.5V7.5H10V6.5H9ZM2 8.5V9.5H3V8.5H2ZM9 8.5V9.5H10V8.5H9Z",
"fill": "currentColor"
},
"children": []
}
]
},
"name": "VideoSupportIcon"
}

@ -0,0 +1,16 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './VideoSupportIcon.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
props,
ref,
) => <IconBase {...props} ref={ref} data={data as IconData} />)
Icon.displayName = 'VideoSupportIcon'
export default Icon

@ -1,3 +1,5 @@
export { default as AudioSupportIcon } from './AudioSupportIcon'
export { default as DocumentSupportIcon } from './DocumentSupportIcon'
export { default as MagicBox } from './MagicBox'
export { default as MagicEyes } from './MagicEyes'
export { default as MagicWand } from './MagicWand'
@ -7,3 +9,4 @@ export { default as Robot } from './Robot'
export { default as Sliders02 } from './Sliders02'
export { default as Speaker } from './Speaker'
export { default as StopCircle } from './StopCircle'
export { default as VideoSupportIcon } from './VideoSupportIcon'

@ -23,19 +23,19 @@ const Switch = React.forwardRef<HTMLButtonElement>(({ onChange, size = 'md', def
sm: 'h-3 w-5',
}
// const circleStyle = {
// lg: 'h-5 w-5',
// l: 'h-4 w-4',
// md: 'h-3 w-3',
// sm: 'h-2 w-2',
// }
const circleStyle = {
lg: 'h-5 w-5',
l: 'h-4 w-4',
md: 'h-3 w-3',
sm: 'h-2 w-2',
}
// const translateLeft = {
// lg: 'translate-x-5',
// l: 'translate-x-4',
// md: 'translate-x-3',
// sm: 'translate-x-2',
// }
const translateLeft = {
lg: 'translate-x-5',
l: 'translate-x-4',
md: 'translate-x-3',
sm: 'translate-x-2',
}
return (
<OriginalSwitch
ref={ref}
@ -57,11 +57,9 @@ const Switch = React.forwardRef<HTMLButtonElement>(({ onChange, size = 'md', def
<span
aria-hidden="true"
className={classNames(
wrapStyle[size],
enabled ? 'bg-components-toggle-bg' : 'bg-components-toggle-bg-unchecked',
'relative inline-flex flex-shrink-0 cursor-pointer rounded-[5px] border-2 border-transparent transition-colors duration-200 ease-in-out',
disabled ? '!opacity-50 !cursor-not-allowed' : '',
className,
circleStyle[size],
enabled ? translateLeft[size] : 'translate-x-0',
'pointer-events-none inline-block transform rounded-[3px] bg-components-toggle-knob shadow ring-0 transition duration-200 ease-in-out',
)}
/>
</OriginalSwitch>

@ -9,20 +9,6 @@ import { useWorkspacesContext } from '@/context/workspace-context'
import { useProviderContext } from '@/context/provider-context'
import { ToastContext } from '@/app/components/base/toast'
import PremiumBadge from '@/app/components/base/premium-badge'
import classNames from '@/utils/classnames'
const itemClassName = `
flex items-center px-3 py-2 h-10 cursor-pointer
`
const itemIconClassName = `
shrink-0 mr-2 flex items-center justify-center w-6 h-6 bg-[#EFF4FF] rounded-md text-xs font-medium text-primary-600
`
const itemNameClassName = `
grow mr-2 text-sm text-gray-700 text-left
`
const itemCheckClassName = `
shrink-0 w-4 h-4 text-primary-600
`
const WorkplaceSelector = () => {
const { t } = useTranslation()
@ -30,7 +16,6 @@ const WorkplaceSelector = () => {
const { notify } = useContext(ToastContext)
const { workspaces } = useWorkspacesContext()
const currentWorkspace = workspaces.find(v => v.current)
const isFreePlan = plan.type === 'sandbox'
const handleSwitchWorkspace = async (tenant_id: string) => {
try {
if (currentWorkspace?.id === tenant_id)
@ -51,8 +36,8 @@ const WorkplaceSelector = () => {
<>
<Menu.Button className={cn(
`
${itemClassName} w-full
group hover:bg-state-base-hover cursor-pointer ${open && 'bg-state-base-hover'} rounded-lg
flex items-center p-0.5 gap-1.5 w-full
group hover:bg-state-base-hover cursor-pointer ${open && 'bg-state-base-hover'} rounded-[10px]
`,
)}>
<div className='flex items-center justify-center w-7 h-7 bg-[#EFF4FF] rounded-lg text-xs font-medium text-primary-600'>{currentWorkspace?.name[0].toLocaleUpperCase()}</div>
@ -83,30 +68,18 @@ const WorkplaceSelector = () => {
</div>
{
workspaces.map(workspace => (
<div>
<div className='flex py-1 pl-3 pr-2 items-center gap-2 self-stretch hover:bg-state-base-hover rounded-lg' key={workspace.id} onClick={() => handleSwitchWorkspace(workspace.id)}>
<div className='flex items-center justify-center w-6 h-6 bg-[#EFF4FF] rounded-md text-xs font-medium text-primary-600'>{workspace.name[0].toLocaleUpperCase()}</div>
<div className='line-clamp-1 grow overflow-hidden text-text-secondary text-ellipsis system-md-regular cursor-pointer'>{workspace.name}</div>
{
<PremiumBadge size='s' color='gray' allowHover={false}>
<div className='system-2xs-medium'>
<span className='p-[2px]'>
{plan.type === 'professional' ? 'PRO' : plan.type.toUpperCase()}
</span>
</div>
</PremiumBadge>
}
</div>
<Menu.Item key={workspace.id}>
{({ active }) => <div className={classNames(itemClassName,
active && 'bg-state-base-hover',
)} key={workspace.id} onClick={() => handleSwitchWorkspace(workspace.id)}>
<div className={itemIconClassName}>{workspace.name[0].toLocaleUpperCase()}</div>
<div className={itemNameClassName}>{workspace.name}</div>
{/* {workspace.current && <Check className={itemCheckClassName} />} */}
</div>}
</Menu.Item>
<div className='flex py-1 pl-3 pr-2 items-center gap-2 self-stretch hover:bg-state-base-hover rounded-lg' key={workspace.id} onClick={() => handleSwitchWorkspace(workspace.id)}>
<div className='flex items-center justify-center w-6 h-6 bg-[#EFF4FF] rounded-md text-xs font-medium text-primary-600'>{workspace.name[0].toLocaleUpperCase()}</div>
<div className='line-clamp-1 grow overflow-hidden text-text-secondary text-ellipsis system-md-regular cursor-pointer'>{workspace.name}</div>
{
<PremiumBadge size='s' color='gray' allowHover={false}>
<div className='system-2xs-medium'>
<span className='p-[2px]'>
{plan.type === 'professional' ? 'PRO' : plan.type.toUpperCase()}
</span>
</div>
</PremiumBadge>
}
</div>
))
}

@ -22,14 +22,14 @@ const ModelIcon: FC<ModelIconProps> = ({
}) => {
const language = useLanguage()
if (provider?.provider.includes('openai') && modelName?.includes('gpt-4o'))
return <div className='flex w-6 h-6 items-center justify-center'><OpenaiBlue className={cn('w-5 h-5', className)}/></div>
return <div className='flex items-center justify-center'><OpenaiBlue className={cn('w-5 h-5', className)}/></div>
if (provider?.provider.includes('openai') && modelName?.startsWith('gpt-4'))
return <div className='flex w-6 h-6 items-center justify-center'><OpenaiViolet className={cn('w-5 h-5', className)}/></div>
return <div className='flex items-center justify-center'><OpenaiViolet className={cn('w-5 h-5', className)}/></div>
if (provider?.icon_small) {
return (
<div className={`flex w-6 h-6 items-center justify-center ${isDeprecated ? 'opacity-50' : ''}`}>
<div className={`flex items-center justify-center ${isDeprecated ? 'opacity-50' : ''}`}>
<img
alt='model-icon'
src={`${provider.icon_small[language] || provider.icon_small.en_US}`}
@ -41,7 +41,7 @@ const ModelIcon: FC<ModelIconProps> = ({
return (
<div className={cn(
'flex items-center justify-center w-6 h-6 rounded-md border-[0.5px] border-components-panel-border-subtle bg-background-default-subtle',
'flex items-center justify-center rounded-md border-[0.5px] border-components-panel-border-subtle bg-background-default-subtle',
className,
)}>
<div className='flex w-5 h5 items-center justify-center opacity-35'>

@ -37,7 +37,7 @@ const ModelName: FC<ModelNameProps> = ({
if (!modelItem)
return null
return (
<div className={cn('flex items-center overflow-hidden text-ellipsis truncate text-components-input-text-filled system-sm-regular', className)}>
<div className={cn('flex gap-0.5 items-center overflow-hidden text-ellipsis truncate text-components-input-text-filled system-sm-regular', className)}>
<div
className='truncate'
title={modelItem.label[language] || modelItem.label.en_US}

@ -6,10 +6,13 @@ import {
ModelFeatureTextEnum,
} from '../declarations'
import {
AudioSupportIcon,
DocumentSupportIcon,
// MagicBox,
MagicEyes,
// MagicWand,
// Robot,
VideoSupportIcon,
} from '@/app/components/base/icons/src/vender/solid/mediaAndDevices'
import Tooltip from '@/app/components/base/tooltip'
@ -65,7 +68,7 @@ const FeatureIcon: FC<FeatureIconProps> = ({
popupContent={t('common.modelProvider.featureSupported', { feature: ModelFeatureTextEnum.vision })}
>
<div className='inline-block cursor-help'>
<ModelBadge className={`mr-0.5 !px-0 w-[18px] justify-center text-text-tertiary ${className}`}>
<ModelBadge className={`!px-0 w-[18px] justify-center text-text-tertiary ${className}`}>
<MagicEyes className='w-3 h-3' />
</ModelBadge>
</div>
@ -73,6 +76,48 @@ const FeatureIcon: FC<FeatureIconProps> = ({
)
}
if (feature === ModelFeatureEnum.document) {
return (
<Tooltip
popupContent={t('common.modelProvider.featureSupported', { feature: ModelFeatureTextEnum.document })}
>
<div className='inline-block cursor-help'>
<ModelBadge className={`!px-0 w-[18px] justify-center text-text-tertiary ${className}`}>
<DocumentSupportIcon className='w-3 h-3' />
</ModelBadge>
</div>
</Tooltip>
)
}
if (feature === ModelFeatureEnum.audio) {
return (
<Tooltip
popupContent={t('common.modelProvider.featureSupported', { feature: ModelFeatureTextEnum.audio })}
>
<div className='inline-block cursor-help'>
<ModelBadge className={`!px-0 w-[18px] justify-center text-text-tertiary ${className}`}>
<AudioSupportIcon className='w-3 h-3' />
</ModelBadge>
</div>
</Tooltip>
)
}
if (feature === ModelFeatureEnum.video) {
return (
<Tooltip
popupContent={t('common.modelProvider.featureSupported', { feature: ModelFeatureTextEnum.video })}
>
<div className='inline-block cursor-help'>
<ModelBadge className={`!px-0 w-[18px] justify-center text-text-tertiary ${className}`}>
<VideoSupportIcon className='w-3 h-3' />
</ModelBadge>
</div>
</Tooltip>
)
}
return null
}

@ -34,41 +34,45 @@ const ModelTrigger: FC<ModelTriggerProps> = ({
return (
<div
className={cn(
'group flex items-center p-1 gap-0.5 h-8 rounded-lg bg-components-input-bg-normal',
'group flex items-center p-1 gap-0.5 rounded-lg bg-components-input-bg-normal',
!readonly && 'hover:bg-components-input-bg-hover cursor-pointer',
open && 'bg-components-input-bg-hover',
model.status !== ModelStatusEnum.active && 'bg-components-input-bg-disabled hover:bg-components-input-bg-disabled',
className,
)}
>
<ModelIcon
className='shrink-0 mr-1.5'
provider={provider}
modelName={model.model}
/>
<ModelName
className='grow'
modelItem={model}
showMode
showFeatures
/>
{!readonly && (
<div className='shrink-0 flex items-center justify-center w-4 h-4'>
{
model.status !== ModelStatusEnum.active
? (
<Tooltip popupContent={MODEL_STATUS_TEXT[model.status][language]}>
<AlertTriangle className='w-4 h-4 text-[#F79009]' />
</Tooltip>
)
: (
<RiArrowDownSLine
className='w-3.5 h-3.5 text-text-tertiary'
/>
)
}
</div>
)}
<div className='flex items-center justify-center w-6 h-6'>
<ModelIcon
className='w-5 h-5 m-0.5'
provider={provider}
modelName={model.model}
/>
</div>
<div className='flex px-1 py-[3px] items-center gap-1 grow truncate'>
<ModelName
className='grow'
modelItem={model}
showMode
showFeatures
/>
{!readonly && (
<div className='shrink-0 flex items-center justify-center w-4 h-4'>
{
model.status !== ModelStatusEnum.active
? (
<Tooltip popupContent={MODEL_STATUS_TEXT[model.status][language]}>
<AlertTriangle className='w-4 h-4 text-text-warning-secondary' />
</Tooltip>
)
: (
<RiArrowDownSLine
className='w-3.5 h-3.5 text-text-tertiary'
/>
)
}
</div>
)}
</div>
</div>
)
}

@ -65,7 +65,7 @@ const Card = ({
{/* Header */}
<div className="flex">
<Icon src={icon} installed={installed} installFailed={installFailed} />
<div className="ml-3 grow">
<div className="ml-3 w-0 grow">
<div className="flex items-center h-5">
<Title title={getLocalizedText(label)} />
{verified && <RiVerifiedBadgeLine className="shrink-0 ml-0.5 w-4 h-4 text-text-accent" />}

@ -107,7 +107,7 @@ const ToolSelector: FC<Props> = ({
const [isShowChooseTool, setIsShowChooseTool] = useState(false)
const handleSelectTool = (tool: ToolDefaultValue) => {
const paramValues = addDefaultValue(tool.params, toolParametersToFormSchemas(tool.paramSchemas as any))
const paramValues = addDefaultValue(tool.params, toolParametersToFormSchemas(tool.paramSchemas.filter(param => param.form !== 'llm') as any))
const toolValue = {
provider_name: tool.provider_id,
tool_name: tool.tool_name,
@ -133,7 +133,7 @@ const ToolSelector: FC<Props> = ({
const currentToolParams = useMemo(() => {
if (!currentProvider) return []
return currentProvider.tools.find(tool => tool.name === value?.tool_name)?.parameters || []
return currentProvider.tools.find(tool => tool.name === value?.tool_name)?.parameters.filter(param => param.form !== 'llm') || []
}, [currentProvider, value])
const formSchemas = useMemo(() => toolParametersToFormSchemas(currentToolParams), [currentToolParams])

@ -49,6 +49,7 @@ export type Collection = {
allow_delete: boolean
labels: string[]
plugin_id?: string
letter?: string
}
export type ToolParameter = {

@ -6,31 +6,53 @@ import type { BlockEnum } from '../../../types'
import type { ToolDefaultValue } from '../../types'
import Tool from '../tool'
import { ViewType } from '../../view-type-select'
import { useMemo } from 'react'
type Props = {
payload: ToolWithProvider[]
isShowLetterIndex: boolean
hasSearchText: boolean
onSelect: (type: BlockEnum, tool?: ToolDefaultValue) => void
letters: string[]
toolRefs: any
}
const ToolViewFlatView: FC<Props> = ({
letters,
payload,
isShowLetterIndex,
hasSearchText,
onSelect,
toolRefs,
}) => {
const firstLetterToolIds = useMemo(() => {
const res: Record<string, string> = {}
letters.forEach((letter) => {
const firstToolId = payload.find(tool => tool.letter === letter)?.id
if (firstToolId)
res[firstToolId] = letter
})
return res
}, [payload, letters])
return (
<div>
{payload.map(tool => (
<Tool
<div
key={tool.id}
payload={tool}
viewType={ViewType.flat}
isShowLetterIndex={isShowLetterIndex}
hasSearchText={hasSearchText}
onSelect={onSelect}
/>
ref={(el) => {
const letter = firstLetterToolIds[tool.id]
if (letter)
toolRefs.current[letter] = el
}}
>
<Tool
payload={tool}
viewType={ViewType.flat}
isShowLetterIndex={isShowLetterIndex}
hasSearchText={hasSearchText}
onSelect={onSelect}
/>
</div>
))}
</div>
)

@ -69,13 +69,19 @@ const Blocks = ({
const listViewToolData = useMemo(() => {
const result: ToolWithProvider[] = []
Object.keys(withLetterAndGroupViewToolsData).forEach((letter) => {
letters.forEach((letter) => {
Object.keys(withLetterAndGroupViewToolsData[letter]).forEach((groupName) => {
result.push(...withLetterAndGroupViewToolsData[letter][groupName])
result.push(...withLetterAndGroupViewToolsData[letter][groupName].map((item) => {
return {
...item,
letter,
}
}))
})
})
return result
}, [withLetterAndGroupViewToolsData])
}, [withLetterAndGroupViewToolsData, letters])
const toolRefs = useRef({})
@ -94,6 +100,8 @@ const Blocks = ({
{!!tools.length && (
isFlatView ? (
<ToolListFlatView
toolRefs={toolRefs}
letters={letters}
payload={listViewToolData}
isShowLetterIndex={isShowLetterIndex}
hasSearchText={hasSearchText}

@ -27,6 +27,6 @@ export type ToolDefaultValue = {
title: string
is_team_authorization: boolean
params: Record<string, any>
paramSchemas: Record<string, any>
paramSchemas: Record<string, any>[]
output_schema: Record<string, any>
}

@ -161,6 +161,7 @@ export const AgentStrategy = (props: AgentStrategyProps) => {
} : undefined
}
placeholderClassName='px-2 py-1'
titleClassName='system-sm-semibold-uppercase text-text-secondary text-[13px]'
inputClassName='px-2 py-1 bg-components-input-bg-normal focus:bg-components-input-bg-active focus:border-components-input-border-active focus:border rounded-lg'
/>
}

@ -74,6 +74,7 @@ type Props = {
inputClassName?: string
editorContainerClassName?: string
placeholderClassName?: string
titleClassName?: string
}
const Editor: FC<Props> = ({
@ -107,6 +108,7 @@ const Editor: FC<Props> = ({
titleTooltip,
inputClassName,
placeholderClassName,
titleClassName,
editorContainerClassName,
}) => {
const { t } = useTranslation()
@ -145,7 +147,7 @@ const Editor: FC<Props> = ({
<div className={cn(isFocus ? 'bg-gray-50' : 'bg-gray-100', isExpand && 'h-full flex flex-col', 'rounded-lg', containerClassName)}>
<div className={cn('pt-1 pl-3 pr-2 flex justify-between items-center', headerClassName)}>
<div className='flex gap-2'>
<div className='leading-4 text-xs font-semibold text-gray-700 uppercase'>{title}</div>
<div className={cn('leading-4 text-xs font-semibold text-gray-700 uppercase', titleClassName)}>{title}</div>
{titleTooltip && <Tooltip popupContent={titleTooltip} />}
</div>
<div className='flex items-center'>

@ -8,11 +8,33 @@ import type { ToolIconProps } from './components/tool-icon'
import { ToolIcon } from './components/tool-icon'
import useConfig from './use-config'
import { useTranslation } from 'react-i18next'
import { FormTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { FormTypeEnum, ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { useModelList } from '@/app/components/header/account-setting/model-provider-page/hooks'
const useAllModel = () => {
const { data: textGeneration } = useModelList(ModelTypeEnum.textGeneration)
const { data: moderation } = useModelList(ModelTypeEnum.moderation)
const { data: rerank } = useModelList(ModelTypeEnum.rerank)
const { data: speech2text } = useModelList(ModelTypeEnum.speech2text)
const { data: textEmbedding } = useModelList(ModelTypeEnum.textEmbedding)
const { data: tts } = useModelList(ModelTypeEnum.tts)
const models = useMemo(() => {
return textGeneration
.concat(moderation)
.concat(rerank)
.concat(speech2text)
.concat(textEmbedding)
.concat(tts)
}, [textGeneration, moderation, rerank, speech2text, textEmbedding, tts])
if (!textGeneration || !moderation || !rerank || !speech2text || !textEmbedding || !tts)
return undefined
return models
}
const AgentNode: FC<NodeProps<AgentNodeType>> = (props) => {
const { inputs, currentStrategy } = useConfig(props.id, props.data)
const { t } = useTranslation()
const modelList = useAllModel()
const models = useMemo(() => {
if (!inputs) return []
// if selected, show in node
@ -73,7 +95,7 @@ const AgentNode: FC<NodeProps<AgentNodeType>> = (props) => {
{inputs.agent_strategy_label}
</SettingItem>
: <SettingItem label={t('workflow.nodes.agent.strategyNotSet')} />}
{models.length > 0 && <Group
{models.length > 0 && modelList && <Group
label={<GroupLabel className='mt-1'>
{t('workflow.nodes.agent.model')}
</GroupLabel>}
@ -81,7 +103,8 @@ const AgentNode: FC<NodeProps<AgentNodeType>> = (props) => {
{models.map((model) => {
return <ModelSelector
key={model.param}
modelList={[]}
modelList={modelList}
triggerClassName='bg-workflow-block-parma-bg'
defaultModel={
'provider' in model
? {

@ -1,4 +1,5 @@
import type { FC } from 'react'
import { useMemo } from 'react'
import type { NodePanelProps } from '../../types'
import type { AgentNodeType } from './types'
import Field from '../_base/components/field'
@ -8,6 +9,11 @@ import { useTranslation } from 'react-i18next'
import OutputVars, { VarItem } from '../_base/components/output-vars'
import type { StrategyParamItem } from '@/app/components/plugins/types'
import type { CredentialFormSchema } from '@/app/components/header/account-setting/model-provider-page/declarations'
import BeforeRunForm from '@/app/components/workflow/nodes/_base/components/before-run-form'
import ResultPanel from '@/app/components/workflow/run/result-panel'
import formatTracing from '@/app/components/workflow/run/utils/format-log'
import { useLogs } from '@/app/components/workflow/run/hooks'
import type { Props as FormProps } from '@/app/components/workflow/nodes/_base/components/before-run-form/form'
const i18nPrefix = 'workflow.nodes.agent'
@ -20,10 +26,49 @@ export function strategyParamToCredientialForm(param: StrategyParamItem): Creden
}
const AgentPanel: FC<NodePanelProps<AgentNodeType>> = (props) => {
const { inputs, setInputs, currentStrategy, formData, onFormChange } = useConfig(props.id, props.data)
const {
inputs,
setInputs,
currentStrategy,
formData,
onFormChange,
isShowSingleRun,
hideSingleRun,
runningStatus,
handleRun,
handleStop,
runResult,
runInputData,
setRunInputData,
varInputs,
} = useConfig(props.id, props.data)
const { t } = useTranslation()
const nodeInfo = useMemo(() => {
if (!runResult)
return
return formatTracing([runResult], t)[0]
}, [runResult, t])
const logsParams = useLogs()
const singleRunForms = (() => {
const forms: FormProps[] = []
if (varInputs.length > 0) {
forms.push(
{
label: t(`${i18nPrefix}.singleRun.variable`)!,
inputs: varInputs,
values: runInputData,
onChange: setRunInputData,
},
)
}
return forms
})()
return <div className='my-2'>
<Field title={t('workflow.nodes.agent.strategy.label')} className='px-4' >
<Field title={t('workflow.nodes.agent.strategy.label')} className='px-4 py-2' >
<AgentStrategy
strategy={inputs.agent_strategy_name ? {
agent_strategy_provider_name: inputs.agent_strategy_provider_name!,
@ -72,6 +117,21 @@ const AgentPanel: FC<NodePanelProps<AgentNodeType>> = (props) => {
))}
</OutputVars>
</div>
{
isShowSingleRun && (
<BeforeRunForm
nodeName={inputs.title}
nodeType={inputs.type}
onHide={hideSingleRun}
forms={singleRunForms}
runningStatus={runningStatus}
onRun={handleRun}
onStop={handleStop}
{...logsParams}
result={<ResultPanel {...runResult} nodeInfo={nodeInfo} showSteps={false} {...logsParams} />}
/>
)
}
</div>
}

@ -21,26 +21,6 @@ const useConfig = (id: string, payload: AgentNodeType) => {
inputs.agent_strategy_provider_name || '',
)
// single run
const agentInputKey = `${id}.input_selector`
const {
isShowSingleRun,
showSingleRun,
hideSingleRun,
toVarInputs,
runningStatus,
handleRun,
handleStop,
runInputData,
setRunInputData,
runResult,
} = useOneStepRun<AgentNodeType>({
id,
data: inputs,
defaultRunInputData: {
[agentInputKey]: [''],
},
})
const currentStrategy = strategyProvider.data?.declaration.strategies.find(
str => str.identity.name === inputs.agent_strategy_name,
)
@ -70,6 +50,36 @@ const useConfig = (id: string, payload: AgentNodeType) => {
agent_parameters: res,
})
}
// single run
const {
isShowSingleRun,
showSingleRun,
hideSingleRun,
toVarInputs,
runningStatus,
handleRun,
handleStop,
runInputData,
setRunInputData,
runResult,
getInputVars,
} = useOneStepRun<AgentNodeType>({
id,
data: inputs,
defaultRunInputData: {},
})
const allVarStrArr = (() => {
const arr = ['']
return arr
})()
const varInputs = (() => {
const vars = getInputVars(allVarStrArr)
return vars
})()
return {
readOnly,
inputs,
@ -92,7 +102,7 @@ const useConfig = (id: string, payload: AgentNodeType) => {
runInputData,
setRunInputData,
runResult,
agentInputKey,
varInputs,
}
}

@ -78,10 +78,10 @@ const NodePanel: FC<Props> = ({
setCollapseState(!nodeInfo.expand)
}, [nodeInfo.expand, setCollapseState])
const isIterationNode = nodeInfo.node_type === BlockEnum.Iteration
const isRetryNode = hasRetryNode(nodeInfo.node_type) && nodeInfo.retryDetail
const isAgentNode = nodeInfo.node_type === BlockEnum.Agent
const isToolNode = nodeInfo.node_type === BlockEnum.Tool
const isIterationNode = nodeInfo.node_type === BlockEnum.Iteration && nodeInfo.details?.length
const isRetryNode = hasRetryNode(nodeInfo.node_type) && nodeInfo.retryDetail?.length
const isAgentNode = nodeInfo.node_type === BlockEnum.Agent && nodeInfo.agentLog?.length
const isToolNode = nodeInfo.node_type === BlockEnum.Tool && nodeInfo.agentLog?.length
return (
<div className={cn('px-2 py-1', className)}>

@ -57,10 +57,10 @@ const ResultPanel: FC<ResultPanelProps> = ({
handleShowAgentOrToolLog,
}) => {
const { t } = useTranslation()
const isIterationNode = nodeInfo?.node_type === BlockEnum.Iteration
const isRetryNode = hasRetryNode(nodeInfo?.node_type) && nodeInfo?.retryDetail
const isAgentNode = nodeInfo?.node_type === BlockEnum.Agent
const isToolNode = nodeInfo?.node_type === BlockEnum.Tool
const isIterationNode = nodeInfo?.node_type === BlockEnum.Iteration && nodeInfo?.details?.length
const isRetryNode = hasRetryNode(nodeInfo?.node_type) && nodeInfo?.retryDetail?.length
const isAgentNode = nodeInfo?.node_type === BlockEnum.Agent && nodeInfo?.agentLog?.length
const isToolNode = nodeInfo?.node_type === BlockEnum.Tool && nodeInfo?.agentLog?.length
return (
<div className='bg-components-panel-bg py-2'>

Loading…
Cancel
Save