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

@ -9,20 +9,6 @@ import { useWorkspacesContext } from '@/context/workspace-context'
import { useProviderContext } from '@/context/provider-context' import { useProviderContext } from '@/context/provider-context'
import { ToastContext } from '@/app/components/base/toast' import { ToastContext } from '@/app/components/base/toast'
import PremiumBadge from '@/app/components/base/premium-badge' 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 WorkplaceSelector = () => {
const { t } = useTranslation() const { t } = useTranslation()
@ -30,7 +16,6 @@ const WorkplaceSelector = () => {
const { notify } = useContext(ToastContext) const { notify } = useContext(ToastContext)
const { workspaces } = useWorkspacesContext() const { workspaces } = useWorkspacesContext()
const currentWorkspace = workspaces.find(v => v.current) const currentWorkspace = workspaces.find(v => v.current)
const isFreePlan = plan.type === 'sandbox'
const handleSwitchWorkspace = async (tenant_id: string) => { const handleSwitchWorkspace = async (tenant_id: string) => {
try { try {
if (currentWorkspace?.id === tenant_id) if (currentWorkspace?.id === tenant_id)
@ -51,8 +36,8 @@ const WorkplaceSelector = () => {
<> <>
<Menu.Button className={cn( <Menu.Button className={cn(
` `
${itemClassName} w-full 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-lg 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> <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> </div>
{ {
workspaces.map(workspace => ( 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 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='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>
<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}>
<PremiumBadge size='s' color='gray' allowHover={false}> <div className='system-2xs-medium'>
<div className='system-2xs-medium'> <span className='p-[2px]'>
<span className='p-[2px]'> {plan.type === 'professional' ? 'PRO' : plan.type.toUpperCase()}
{plan.type === 'professional' ? 'PRO' : plan.type.toUpperCase()} </span>
</span> </div>
</div> </PremiumBadge>
</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> </div>
)) ))
} }

@ -22,14 +22,14 @@ const ModelIcon: FC<ModelIconProps> = ({
}) => { }) => {
const language = useLanguage() const language = useLanguage()
if (provider?.provider.includes('openai') && modelName?.includes('gpt-4o')) 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')) 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) { if (provider?.icon_small) {
return ( 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 <img
alt='model-icon' alt='model-icon'
src={`${provider.icon_small[language] || provider.icon_small.en_US}`} src={`${provider.icon_small[language] || provider.icon_small.en_US}`}
@ -41,7 +41,7 @@ const ModelIcon: FC<ModelIconProps> = ({
return ( return (
<div className={cn( <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, className,
)}> )}>
<div className='flex w-5 h5 items-center justify-center opacity-35'> <div className='flex w-5 h5 items-center justify-center opacity-35'>

@ -37,7 +37,7 @@ const ModelName: FC<ModelNameProps> = ({
if (!modelItem) if (!modelItem)
return null return null
return ( 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 <div
className='truncate' className='truncate'
title={modelItem.label[language] || modelItem.label.en_US} title={modelItem.label[language] || modelItem.label.en_US}

@ -6,10 +6,13 @@ import {
ModelFeatureTextEnum, ModelFeatureTextEnum,
} from '../declarations' } from '../declarations'
import { import {
AudioSupportIcon,
DocumentSupportIcon,
// MagicBox, // MagicBox,
MagicEyes, MagicEyes,
// MagicWand, // MagicWand,
// Robot, // Robot,
VideoSupportIcon,
} from '@/app/components/base/icons/src/vender/solid/mediaAndDevices' } from '@/app/components/base/icons/src/vender/solid/mediaAndDevices'
import Tooltip from '@/app/components/base/tooltip' import Tooltip from '@/app/components/base/tooltip'
@ -65,7 +68,7 @@ const FeatureIcon: FC<FeatureIconProps> = ({
popupContent={t('common.modelProvider.featureSupported', { feature: ModelFeatureTextEnum.vision })} popupContent={t('common.modelProvider.featureSupported', { feature: ModelFeatureTextEnum.vision })}
> >
<div className='inline-block cursor-help'> <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' /> <MagicEyes className='w-3 h-3' />
</ModelBadge> </ModelBadge>
</div> </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 return null
} }

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

@ -65,7 +65,7 @@ const Card = ({
{/* Header */} {/* Header */}
<div className="flex"> <div className="flex">
<Icon src={icon} installed={installed} installFailed={installFailed} /> <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"> <div className="flex items-center h-5">
<Title title={getLocalizedText(label)} /> <Title title={getLocalizedText(label)} />
{verified && <RiVerifiedBadgeLine className="shrink-0 ml-0.5 w-4 h-4 text-text-accent" />} {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 [isShowChooseTool, setIsShowChooseTool] = useState(false)
const handleSelectTool = (tool: ToolDefaultValue) => { 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 = { const toolValue = {
provider_name: tool.provider_id, provider_name: tool.provider_id,
tool_name: tool.tool_name, tool_name: tool.tool_name,
@ -133,7 +133,7 @@ const ToolSelector: FC<Props> = ({
const currentToolParams = useMemo(() => { const currentToolParams = useMemo(() => {
if (!currentProvider) return [] 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]) }, [currentProvider, value])
const formSchemas = useMemo(() => toolParametersToFormSchemas(currentToolParams), [currentToolParams]) const formSchemas = useMemo(() => toolParametersToFormSchemas(currentToolParams), [currentToolParams])

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

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

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

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

@ -161,6 +161,7 @@ export const AgentStrategy = (props: AgentStrategyProps) => {
} : undefined } : undefined
} }
placeholderClassName='px-2 py-1' 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' 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 inputClassName?: string
editorContainerClassName?: string editorContainerClassName?: string
placeholderClassName?: string placeholderClassName?: string
titleClassName?: string
} }
const Editor: FC<Props> = ({ const Editor: FC<Props> = ({
@ -107,6 +108,7 @@ const Editor: FC<Props> = ({
titleTooltip, titleTooltip,
inputClassName, inputClassName,
placeholderClassName, placeholderClassName,
titleClassName,
editorContainerClassName, editorContainerClassName,
}) => { }) => {
const { t } = useTranslation() 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(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={cn('pt-1 pl-3 pr-2 flex justify-between items-center', headerClassName)}>
<div className='flex gap-2'> <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} />} {titleTooltip && <Tooltip popupContent={titleTooltip} />}
</div> </div>
<div className='flex items-center'> <div className='flex items-center'>

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

@ -1,4 +1,5 @@
import type { FC } from 'react' import type { FC } from 'react'
import { useMemo } from 'react'
import type { NodePanelProps } from '../../types' import type { NodePanelProps } from '../../types'
import type { AgentNodeType } from './types' import type { AgentNodeType } from './types'
import Field from '../_base/components/field' import Field from '../_base/components/field'
@ -8,6 +9,11 @@ import { useTranslation } from 'react-i18next'
import OutputVars, { VarItem } from '../_base/components/output-vars' import OutputVars, { VarItem } from '../_base/components/output-vars'
import type { StrategyParamItem } from '@/app/components/plugins/types' import type { StrategyParamItem } from '@/app/components/plugins/types'
import type { CredentialFormSchema } from '@/app/components/header/account-setting/model-provider-page/declarations' 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' const i18nPrefix = 'workflow.nodes.agent'
@ -20,10 +26,49 @@ export function strategyParamToCredientialForm(param: StrategyParamItem): Creden
} }
const AgentPanel: FC<NodePanelProps<AgentNodeType>> = (props) => { 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 { 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'> 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 <AgentStrategy
strategy={inputs.agent_strategy_name ? { strategy={inputs.agent_strategy_name ? {
agent_strategy_provider_name: inputs.agent_strategy_provider_name!, agent_strategy_provider_name: inputs.agent_strategy_provider_name!,
@ -72,6 +117,21 @@ const AgentPanel: FC<NodePanelProps<AgentNodeType>> = (props) => {
))} ))}
</OutputVars> </OutputVars>
</div> </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> </div>
} }

@ -21,26 +21,6 @@ const useConfig = (id: string, payload: AgentNodeType) => {
inputs.agent_strategy_provider_name || '', 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( const currentStrategy = strategyProvider.data?.declaration.strategies.find(
str => str.identity.name === inputs.agent_strategy_name, str => str.identity.name === inputs.agent_strategy_name,
) )
@ -70,6 +50,36 @@ const useConfig = (id: string, payload: AgentNodeType) => {
agent_parameters: res, 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 { return {
readOnly, readOnly,
inputs, inputs,
@ -92,7 +102,7 @@ const useConfig = (id: string, payload: AgentNodeType) => {
runInputData, runInputData,
setRunInputData, setRunInputData,
runResult, runResult,
agentInputKey, varInputs,
} }
} }

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

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

Loading…
Cancel
Save