Merge branch 'feat/plugins' into dev/plugin-deploy
This commit is contained in:
commit
f6c1ae52dd
27
web/app/components/base/install-button/index.tsx
Normal file
27
web/app/components/base/install-button/index.tsx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import Button from '../button'
|
||||||
|
import { RiInstallLine, RiLoader2Line } from '@remixicon/react'
|
||||||
|
|
||||||
|
type InstallButtonProps = {
|
||||||
|
loading: boolean
|
||||||
|
onInstall: () => void
|
||||||
|
t: any
|
||||||
|
}
|
||||||
|
|
||||||
|
const InstallButton = ({ loading, onInstall, t }: InstallButtonProps) => {
|
||||||
|
return (
|
||||||
|
<Button size='small' className='z-[100]' onClick={onInstall}>
|
||||||
|
<div className={`flex px-[3px] justify-center items-center gap-1
|
||||||
|
${loading ? 'text-components-button-secondary-text-disabled' : 'text-components-button-secondary-text'}
|
||||||
|
system-xs-medium`}
|
||||||
|
>
|
||||||
|
{loading ? t('workflow.nodes.agent.pluginInstaller.installing') : t('workflow.nodes.agent.pluginInstaller.install')}
|
||||||
|
</div>
|
||||||
|
{loading
|
||||||
|
? <RiLoader2Line className='w-3.5 h-3.5 text-text-quaternary' />
|
||||||
|
: <RiInstallLine className='w-3.5 h-3.5 text-text-secondary' />
|
||||||
|
}
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default InstallButton
|
@ -4,7 +4,7 @@ import type {
|
|||||||
ModelProvider,
|
ModelProvider,
|
||||||
} from '../declarations'
|
} from '../declarations'
|
||||||
import { useLanguage } from '../hooks'
|
import { useLanguage } from '../hooks'
|
||||||
import { CubeOutline } from '@/app/components/base/icons/src/vender/line/shapes'
|
import { Group } from '@/app/components/base/icons/src/vender/other'
|
||||||
import { OpenaiBlue, OpenaiViolet } from '@/app/components/base/icons/src/public/llm'
|
import { OpenaiBlue, OpenaiViolet } from '@/app/components/base/icons/src/public/llm'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
|
|
||||||
@ -41,10 +41,12 @@ const ModelIcon: FC<ModelIconProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn(
|
<div className={cn(
|
||||||
'flex items-center justify-center w-6 h-6 rounded border-[0.5px] border-black/5 bg-gray-50',
|
'flex items-center justify-center w-5 h-5 rounded-md border-[0.5px] border-components-panel-border-subtle bg-background-default-subtle',
|
||||||
className,
|
className,
|
||||||
)}>
|
)}>
|
||||||
<CubeOutline className='w-4 h-4 text-text-quaternary' />
|
<div className='flex w-3 h-3 items-center justify-center opacity-35'>
|
||||||
|
<Group className='text-text-tertiary' />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import type {
|
import type {
|
||||||
CustomConfigurationModelFixedFields,
|
CustomConfigurationModelFixedFields,
|
||||||
@ -10,20 +11,24 @@ import {
|
|||||||
CustomConfigurationStatusEnum,
|
CustomConfigurationStatusEnum,
|
||||||
} from '../declarations'
|
} from '../declarations'
|
||||||
import { UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST } from '../provider-added-card'
|
import { UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST } from '../provider-added-card'
|
||||||
import { ModelStatusEnum } from '../declarations'
|
import type { PluginInfoFromMarketPlace } from '@/app/components/plugins/types'
|
||||||
|
import { useInstallPackageFromMarketPlace } from '@/service/use-plugins'
|
||||||
|
import ConfigurationButton from './configuration-button'
|
||||||
|
import { PluginType } from '@/app/components/plugins/types'
|
||||||
import {
|
import {
|
||||||
useUpdateModelList,
|
useUpdateModelList,
|
||||||
useUpdateModelProviders,
|
useUpdateModelProviders,
|
||||||
} from '../hooks'
|
} from '../hooks'
|
||||||
import ModelIcon from '../model-icon'
|
import ModelIcon from '../model-icon'
|
||||||
import ModelName from '../model-name'
|
import ModelDisplay from './model-display'
|
||||||
import Button from '@/app/components/base/button'
|
import InstallButton from '@/app/components/base/install-button'
|
||||||
|
import StatusIndicators from './status-indicators'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
import { useProviderContext } from '@/context/provider-context'
|
import { useProviderContext } from '@/context/provider-context'
|
||||||
import { useModalContextSelector } from '@/context/modal-context'
|
import { useModalContextSelector } from '@/context/modal-context'
|
||||||
import { useEventEmitterContextContext } from '@/context/event-emitter'
|
import { useEventEmitterContextContext } from '@/context/event-emitter'
|
||||||
import Tooltip from '@/app/components/base/tooltip'
|
import { RiEqualizer2Line } from '@remixicon/react'
|
||||||
import { RiEqualizer2Line, RiErrorWarningFill } from '@remixicon/react'
|
import { fetchPluginInfoFromMarketPlace } from '@/service/plugins'
|
||||||
|
|
||||||
export type AgentModelTriggerProps = {
|
export type AgentModelTriggerProps = {
|
||||||
open?: boolean
|
open?: boolean
|
||||||
@ -56,6 +61,36 @@ const AgentModelTrigger: FC<AgentModelTriggerProps> = ({
|
|||||||
item => item.quota_type === modelProvider.system_configuration.current_quota_type,
|
item => item.quota_type === modelProvider.system_configuration.current_quota_type,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
const [pluginInfo, setPluginInfo] = useState<PluginInfoFromMarketPlace | null>(null)
|
||||||
|
const [isPluginChecked, setIsPluginChecked] = useState(false)
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
const [installed, setInstalled] = useState(false)
|
||||||
|
const { mutateAsync: installPackageFromMarketPlace } = useInstallPackageFromMarketPlace()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
if (providerName && !modelProvider) {
|
||||||
|
const parts = providerName.split('/')
|
||||||
|
const org = parts[0]
|
||||||
|
const name = parts[1]
|
||||||
|
try {
|
||||||
|
const pluginInfo = await fetchPluginInfoFromMarketPlace({ org, name })
|
||||||
|
if (pluginInfo.data.plugin.category === PluginType.model)
|
||||||
|
setPluginInfo(pluginInfo.data.plugin)
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
// pass
|
||||||
|
}
|
||||||
|
setIsPluginChecked(true)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setIsPluginChecked(true)
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
}, [providerName, modelProvider])
|
||||||
|
|
||||||
|
if (modelId && !isPluginChecked)
|
||||||
|
return null
|
||||||
|
|
||||||
const handleOpenModal = (
|
const handleOpenModal = (
|
||||||
provider: ModelProvider,
|
provider: ModelProvider,
|
||||||
@ -97,64 +132,41 @@ const AgentModelTrigger: FC<AgentModelTriggerProps> = ({
|
|||||||
>
|
>
|
||||||
{modelId ? (
|
{modelId ? (
|
||||||
<>
|
<>
|
||||||
{currentProvider && (
|
<ModelIcon
|
||||||
<ModelIcon
|
className="m-0.5"
|
||||||
className="m-0.5"
|
provider={currentProvider || modelProvider}
|
||||||
provider={currentProvider}
|
modelName={currentModel?.model || modelId}
|
||||||
modelName={currentModel?.model}
|
isDeprecated={hasDeprecated}
|
||||||
isDeprecated={hasDeprecated}
|
/>
|
||||||
/>
|
<ModelDisplay
|
||||||
)}
|
currentModel={currentModel}
|
||||||
{!currentProvider && (
|
modelId={modelId}
|
||||||
<ModelIcon
|
/>
|
||||||
className="m-0.5"
|
|
||||||
provider={modelProvider}
|
|
||||||
modelName={modelId}
|
|
||||||
isDeprecated={hasDeprecated}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{currentModel && (
|
|
||||||
<ModelName
|
|
||||||
className="flex px-1 py-[3px] items-center gap-1 grow"
|
|
||||||
modelItem={currentModel}
|
|
||||||
showMode
|
|
||||||
showFeatures
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{!currentModel && (
|
|
||||||
<div className="flex py-[3px] px-1 items-center gap-1 grow opacity-50 truncate">
|
|
||||||
<div className="text-components-input-text-filled text-ellipsis overflow-hidden system-sm-regular">
|
|
||||||
{modelId}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{needsConfiguration && (
|
{needsConfiguration && (
|
||||||
<Button
|
<ConfigurationButton
|
||||||
size="small"
|
modelProvider={modelProvider}
|
||||||
className="z-[100]"
|
handleOpenModal={handleOpenModal}
|
||||||
onClick={(e) => {
|
/>
|
||||||
e.stopPropagation()
|
)}
|
||||||
handleOpenModal(modelProvider, ConfigurationMethodEnum.predefinedModel, undefined)
|
<StatusIndicators
|
||||||
}}
|
needsConfiguration={needsConfiguration}
|
||||||
>
|
modelProvider={!!modelProvider}
|
||||||
<div className="flex px-[3px] justify-center items-center gap-1">
|
disabled={!!disabled}
|
||||||
{t('workflow.nodes.agent.notAuthorized')}
|
pluginInfo={pluginInfo}
|
||||||
</div>
|
t={t}
|
||||||
<div className="flex w-[14px] h-[14px] justify-center items-center">
|
/>
|
||||||
<div className="w-2 h-2 shrink-0 rounded-[3px] border border-components-badge-status-light-warning-border-inner
|
{!installed && !modelProvider && pluginInfo && (
|
||||||
bg-components-badge-status-light-warning-bg shadow-components-badge-status-light-warning-halo" />
|
<InstallButton
|
||||||
</div>
|
loading={loading}
|
||||||
</Button>
|
onInstall={async () => {
|
||||||
|
setLoading(true)
|
||||||
|
const { all_installed } = await installPackageFromMarketPlace(pluginInfo.latest_package_identifier)
|
||||||
|
if (all_installed)
|
||||||
|
setInstalled(true)
|
||||||
|
}}
|
||||||
|
t={t}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
{!needsConfiguration && disabled && (
|
|
||||||
<Tooltip
|
|
||||||
popupContent={t('workflow.nodes.agent.modelSelectorTooltips.deprecated')}
|
|
||||||
asChild={false}
|
|
||||||
>
|
|
||||||
<RiErrorWarningFill className='w-4 h-4 text-text-destructive' />
|
|
||||||
</Tooltip>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
@ -168,11 +180,6 @@ const AgentModelTrigger: FC<AgentModelTriggerProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{currentProvider && currentModel && currentModel.status === ModelStatusEnum.active && (
|
|
||||||
<div className="flex pr-1 items-center">
|
|
||||||
<RiEqualizer2Line className="w-4 h-4 text-text-tertiary group-hover:text-text-secondary" />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
import Button from '@/app/components/base/button'
|
||||||
|
import { ConfigurationMethodEnum } from '../declarations'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
|
type ConfigurationButtonProps = {
|
||||||
|
modelProvider: any
|
||||||
|
handleOpenModal: any
|
||||||
|
}
|
||||||
|
|
||||||
|
const ConfigurationButton = ({ modelProvider, handleOpenModal }: ConfigurationButtonProps) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
className="z-[100]"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
handleOpenModal(modelProvider, ConfigurationMethodEnum.predefinedModel, undefined)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="flex px-[3px] justify-center items-center gap-1">
|
||||||
|
{t('workflow.nodes.agent.notAuthorized')}
|
||||||
|
</div>
|
||||||
|
<div className="flex w-[14px] h-[14px] justify-center items-center">
|
||||||
|
<div className="w-2 h-2 shrink-0 rounded-[3px] border border-components-badge-status-light-warning-border-inner
|
||||||
|
bg-components-badge-status-light-warning-bg shadow-components-badge-status-light-warning-halo" />
|
||||||
|
</div>
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ConfigurationButton
|
@ -0,0 +1,25 @@
|
|||||||
|
import ModelName from '../model-name'
|
||||||
|
|
||||||
|
type ModelDisplayProps = {
|
||||||
|
currentModel: any
|
||||||
|
modelId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const ModelDisplay = ({ currentModel, modelId }: ModelDisplayProps) => {
|
||||||
|
return currentModel ? (
|
||||||
|
<ModelName
|
||||||
|
className="flex px-1 py-[3px] items-center gap-1 grow"
|
||||||
|
modelItem={currentModel}
|
||||||
|
showMode
|
||||||
|
showFeatures
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className="flex py-[3px] px-1 items-center gap-1 grow opacity-50 truncate">
|
||||||
|
<div className="text-components-input-text-filled text-ellipsis overflow-hidden system-sm-regular">
|
||||||
|
{modelId}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ModelDisplay
|
@ -0,0 +1,44 @@
|
|||||||
|
import Tooltip from '@/app/components/base/tooltip'
|
||||||
|
import { RiErrorWarningFill } from '@remixicon/react'
|
||||||
|
|
||||||
|
type StatusIndicatorsProps = {
|
||||||
|
needsConfiguration: boolean
|
||||||
|
modelProvider: boolean
|
||||||
|
disabled: boolean
|
||||||
|
pluginInfo: any
|
||||||
|
t: any
|
||||||
|
}
|
||||||
|
|
||||||
|
const StatusIndicators = ({ needsConfiguration, modelProvider, disabled, pluginInfo, t }: StatusIndicatorsProps) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{!needsConfiguration && modelProvider && disabled && (
|
||||||
|
<Tooltip
|
||||||
|
popupContent={t('workflow.nodes.agent.modelSelectorTooltips.deprecated')}
|
||||||
|
asChild={false}
|
||||||
|
>
|
||||||
|
<RiErrorWarningFill className='w-4 h-4 text-text-destructive' />
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
{!modelProvider && !pluginInfo && (
|
||||||
|
<Tooltip
|
||||||
|
popupContent={
|
||||||
|
<div className='flex w-[240px] max-w-[240px] gap-1 flex-col px-1 py-1.5'>
|
||||||
|
<div className='text-text-primary title-xs-semi-bold'>{t('workflow.nodes.agent.modelNotInMarketplace.title')}</div>
|
||||||
|
<div className='min-w-[200px] text-text-secondary body-xs-regular'>
|
||||||
|
{t('workflow.nodes.agent.modelNotInMarketplace.desc')}
|
||||||
|
</div>
|
||||||
|
<div className='text-text-accent body-xs-regular'>{t('workflow.nodes.agent.modelNotInMarketplace.manageInPlugins')}</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
asChild={false}
|
||||||
|
needsDelay
|
||||||
|
>
|
||||||
|
<RiErrorWarningFill className='w-4 h-4 text-text-destructive' />
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default StatusIndicators
|
@ -7,7 +7,6 @@ import ActionList from './action-list'
|
|||||||
import ModelList from './model-list'
|
import ModelList from './model-list'
|
||||||
import AgentStrategyList from './agent-strategy-list'
|
import AgentStrategyList from './agent-strategy-list'
|
||||||
import Drawer from '@/app/components/base/drawer'
|
import Drawer from '@/app/components/base/drawer'
|
||||||
import MultipleToolSelector from '@/app/components/plugins/plugin-detail-panel/multiple-tool-selector'
|
|
||||||
import type { PluginDetail } from '@/app/components/plugins/types'
|
import type { PluginDetail } from '@/app/components/plugins/types'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
|
|
||||||
@ -28,12 +27,6 @@ const PluginDetailPanel: FC<Props> = ({
|
|||||||
onUpdate()
|
onUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
const [value, setValue] = React.useState<any>(undefined)
|
|
||||||
const testChange = (val: any) => {
|
|
||||||
console.log('tool change', val)
|
|
||||||
setValue(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!detail)
|
if (!detail)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
@ -59,15 +52,6 @@ const PluginDetailPanel: FC<Props> = ({
|
|||||||
{!!detail.declaration.agent_strategy && <AgentStrategyList detail={detail} />}
|
{!!detail.declaration.agent_strategy && <AgentStrategyList detail={detail} />}
|
||||||
{!!detail.declaration.endpoint && <EndpointList detail={detail} />}
|
{!!detail.declaration.endpoint && <EndpointList detail={detail} />}
|
||||||
{!!detail.declaration.model && <ModelList detail={detail} />}
|
{!!detail.declaration.model && <ModelList detail={detail} />}
|
||||||
{false && (
|
|
||||||
<div className='px-4 py-2'>
|
|
||||||
<MultipleToolSelector
|
|
||||||
value={value || []}
|
|
||||||
label='TOOLS'
|
|
||||||
onChange={testChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
import {
|
||||||
|
usePluginManifestInfo,
|
||||||
|
} from '@/service/use-plugins'
|
||||||
|
|
||||||
|
export const usePluginInstalledCheck = (providerName = '') => {
|
||||||
|
const pluginID = providerName?.split('/').splice(0, 2).join('/')
|
||||||
|
|
||||||
|
const { data: manifest } = usePluginManifestInfo(pluginID)
|
||||||
|
|
||||||
|
return {
|
||||||
|
inMarketPlace: !!manifest,
|
||||||
|
manifest: manifest?.data.plugin,
|
||||||
|
}
|
||||||
|
}
|
@ -32,12 +32,15 @@ import {
|
|||||||
useInvalidateAllBuiltInTools,
|
useInvalidateAllBuiltInTools,
|
||||||
useUpdateProviderCredentials,
|
useUpdateProviderCredentials,
|
||||||
} from '@/service/use-tools'
|
} from '@/service/use-tools'
|
||||||
|
import { useInstallPackageFromMarketPlace } from '@/service/use-plugins'
|
||||||
|
import { usePluginInstalledCheck } from '@/app/components/plugins/plugin-detail-panel/tool-selector/hooks'
|
||||||
import { CollectionType } from '@/app/components/tools/types'
|
import { CollectionType } from '@/app/components/tools/types'
|
||||||
import type { ToolDefaultValue } from '@/app/components/workflow/block-selector/types'
|
import type { ToolDefaultValue } from '@/app/components/workflow/block-selector/types'
|
||||||
import type {
|
import type {
|
||||||
OffsetOptions,
|
OffsetOptions,
|
||||||
Placement,
|
Placement,
|
||||||
} from '@floating-ui/react'
|
} from '@floating-ui/react'
|
||||||
|
import { MARKETPLACE_API_PREFIX } from '@/config'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
|
|
||||||
export type ToolValue = {
|
export type ToolValue = {
|
||||||
@ -92,6 +95,9 @@ const ToolSelector: FC<Props> = ({
|
|||||||
const { data: workflowTools } = useAllWorkflowTools()
|
const { data: workflowTools } = useAllWorkflowTools()
|
||||||
const invalidateAllBuiltinTools = useInvalidateAllBuiltInTools()
|
const invalidateAllBuiltinTools = useInvalidateAllBuiltInTools()
|
||||||
|
|
||||||
|
// plugin info check
|
||||||
|
const { inMarketPlace, manifest } = usePluginInstalledCheck(value?.provider_name)
|
||||||
|
|
||||||
const currentProvider = useMemo(() => {
|
const currentProvider = useMemo(() => {
|
||||||
const mergedTools = [...(buildInTools || []), ...(customTools || []), ...(workflowTools || [])]
|
const mergedTools = [...(buildInTools || []), ...(customTools || []), ...(workflowTools || [])]
|
||||||
return mergedTools.find((toolWithProvider) => {
|
return mergedTools.find((toolWithProvider) => {
|
||||||
@ -164,6 +170,25 @@ const ToolSelector: FC<Props> = ({
|
|||||||
onSuccess: handleCredentialSettingUpdate,
|
onSuccess: handleCredentialSettingUpdate,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// install from marketplace
|
||||||
|
const { mutateAsync: installPackageFromMarketPlace, isPending } = useInstallPackageFromMarketPlace()
|
||||||
|
const manifestIcon = useMemo(() => {
|
||||||
|
if (!manifest)
|
||||||
|
return ''
|
||||||
|
return `${MARKETPLACE_API_PREFIX}/plugins/${(manifest as any).plugin_id}/icon`
|
||||||
|
}, [manifest])
|
||||||
|
const handleInstall = async () => {
|
||||||
|
if (!manifest)
|
||||||
|
return
|
||||||
|
try {
|
||||||
|
await installPackageFromMarketPlace(manifest.latest_package_identifier)
|
||||||
|
invalidateAllBuiltinTools()
|
||||||
|
}
|
||||||
|
catch (e: any) {
|
||||||
|
Toast.notify({ type: 'error', message: `${e.message || e}` })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PortalToFollowElem
|
<PortalToFollowElem
|
||||||
@ -188,7 +213,7 @@ const ToolSelector: FC<Props> = ({
|
|||||||
{!trigger && value?.provider_name && (
|
{!trigger && value?.provider_name && (
|
||||||
<ToolItem
|
<ToolItem
|
||||||
open={isShow}
|
open={isShow}
|
||||||
icon={currentProvider?.icon}
|
icon={currentProvider?.icon || manifestIcon}
|
||||||
providerName={value.provider_name}
|
providerName={value.provider_name}
|
||||||
toolName={value.tool_name}
|
toolName={value.tool_name}
|
||||||
showSwitch={supportEnableSwitch}
|
showSwitch={supportEnableSwitch}
|
||||||
@ -197,13 +222,15 @@ const ToolSelector: FC<Props> = ({
|
|||||||
onDelete={onDelete}
|
onDelete={onDelete}
|
||||||
noAuth={currentProvider && !currentProvider.is_team_authorization}
|
noAuth={currentProvider && !currentProvider.is_team_authorization}
|
||||||
onAuth={() => setShowSettingAuth(true)}
|
onAuth={() => setShowSettingAuth(true)}
|
||||||
// uninstalled TODO
|
uninstalled={!currentProvider && inMarketPlace}
|
||||||
// isError TODO
|
isInstalling={isPending}
|
||||||
errorTip={<div className='space-y-1 text-xs'>
|
onInstall={() => handleInstall()}
|
||||||
<h3 className='text-text-primary font-semibold'>{t('workflow.nodes.agent.pluginNotInstalled')}</h3>
|
isError={!currentProvider && !inMarketPlace}
|
||||||
<p className='text-text-secondary tracking-tight'>{t('workflow.nodes.agent.pluginNotInstalledDesc')}</p>
|
errorTip={<div className='space-y-1 max-w-[240px] text-xs'>
|
||||||
|
<h3 className='text-text-primary font-semibold'>{t('plugin.detailPanel.toolSelector.uninstalledTitle')}</h3>
|
||||||
|
<p className='text-text-secondary tracking-tight'>{t('plugin.detailPanel.toolSelector.uninstalledContent')}</p>
|
||||||
<p>
|
<p>
|
||||||
<Link href={'/plugins'} className='text-text-accent tracking-tight'>{t('workflow.nodes.agent.linkToPlugin')}</Link>
|
<Link href={'/plugins'} className='text-text-accent tracking-tight'>{t('plugin.detailPanel.toolSelector.uninstalledLink')}</Link>
|
||||||
</p>
|
</p>
|
||||||
</div>}
|
</div>}
|
||||||
/>
|
/>
|
||||||
|
@ -6,6 +6,7 @@ import {
|
|||||||
RiEqualizer2Line,
|
RiEqualizer2Line,
|
||||||
RiErrorWarningFill,
|
RiErrorWarningFill,
|
||||||
} from '@remixicon/react'
|
} from '@remixicon/react'
|
||||||
|
import { Group } from '@/app/components/base/icons/src/vender/other'
|
||||||
import AppIcon from '@/app/components/base/app-icon'
|
import AppIcon from '@/app/components/base/app-icon'
|
||||||
import Switch from '@/app/components/base/switch'
|
import Switch from '@/app/components/base/switch'
|
||||||
import Button from '@/app/components/base/button'
|
import Button from '@/app/components/base/button'
|
||||||
@ -61,10 +62,21 @@ const ToolItem = ({
|
|||||||
open && 'bg-components-panel-on-panel-item-bg-hover shadow-sm',
|
open && 'bg-components-panel-on-panel-item-bg-hover shadow-sm',
|
||||||
isDeleting && 'hover:bg-state-destructive-hover border-state-destructive-border shadow-xs',
|
isDeleting && 'hover:bg-state-destructive-hover border-state-destructive-border shadow-xs',
|
||||||
)}>
|
)}>
|
||||||
<div className={cn('shrink-0', isTransparent && 'opacity-50')}>
|
{icon && (
|
||||||
{typeof icon === 'string' && <div className='w-7 h-7 bg-cover bg-center border-[0.5px] border-components-panel-border-subtle bg-background-default-dodge rounded-lg' style={{ backgroundImage: `url(${icon})` }} />}
|
<div className={cn('shrink-0', isTransparent && 'opacity-50')}>
|
||||||
{typeof icon !== 'string' && <AppIcon className='w-7 h-7 border-[0.5px] border-components-panel-border-subtle bg-background-default-dodge rounded-lg' size='xs' icon={icon?.content} background={icon?.background} />}
|
{typeof icon === 'string' && <div className='w-7 h-7 bg-cover bg-center border-[0.5px] border-components-panel-border-subtle bg-background-default-dodge rounded-lg' style={{ backgroundImage: `url(${icon})` }} />}
|
||||||
</div>
|
{typeof icon !== 'string' && <AppIcon className='w-7 h-7 border-[0.5px] border-components-panel-border-subtle bg-background-default-dodge rounded-lg' size='xs' icon={icon?.content} background={icon?.background} />}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{!icon && (
|
||||||
|
<div className={cn(
|
||||||
|
'flex items-center justify-center w-7 h-7 rounded-md border-[0.5px] border-components-panel-border-subtle bg-background-default-subtle',
|
||||||
|
)}>
|
||||||
|
<div className='flex w-5 h-5 items-center justify-center opacity-35'>
|
||||||
|
<Group className='text-text-tertiary' />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div className={cn('pl-0.5 grow truncate', isTransparent && 'opacity-50')}>
|
<div className={cn('pl-0.5 grow truncate', isTransparent && 'opacity-50')}>
|
||||||
<div className='text-text-tertiary system-2xs-medium-uppercase'>{providerNameText}</div>
|
<div className='text-text-tertiary system-2xs-medium-uppercase'>{providerNameText}</div>
|
||||||
<div className='text-text-secondary system-xs-medium'>{toolName}</div>
|
<div className='text-text-secondary system-xs-medium'>{toolName}</div>
|
||||||
|
@ -81,7 +81,7 @@ export type PluginManifestInMarket = {
|
|||||||
icon: string
|
icon: string
|
||||||
label: Record<Locale, string>
|
label: Record<Locale, string>
|
||||||
category: PluginType
|
category: PluginType
|
||||||
version: string // conbine the other place to it
|
version: string // combine the other place to it
|
||||||
latest_version: string
|
latest_version: string
|
||||||
brief: Record<Locale, string>
|
brief: Record<Locale, string>
|
||||||
introduction: string
|
introduction: string
|
||||||
@ -108,6 +108,11 @@ export type PluginDetail = {
|
|||||||
meta?: MetaData
|
meta?: MetaData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type PluginInfoFromMarketPlace = {
|
||||||
|
category: PluginType
|
||||||
|
latest_package_identifier: string
|
||||||
|
}
|
||||||
|
|
||||||
export type Plugin = {
|
export type Plugin = {
|
||||||
type: 'plugin' | 'bundle' | 'model' | 'extension' | 'tool' | 'agent_strategy'
|
type: 'plugin' | 'bundle' | 'model' | 'extension' | 'tool' | 'agent_strategy'
|
||||||
org: string
|
org: string
|
||||||
|
@ -83,7 +83,6 @@ export const AgentStrategySelector = (props: AgentStrategySelectorProps) => {
|
|||||||
}, [query, list])
|
}, [query, list])
|
||||||
// TODO: should be replaced by real data
|
// TODO: should be replaced by real data
|
||||||
const isExternalInstalled = true
|
const isExternalInstalled = true
|
||||||
// TODO: 验证这玩意写对了没
|
|
||||||
const icon = list?.find(
|
const icon = list?.find(
|
||||||
coll => coll.tools?.find(tool => tool.name === value?.agent_strategy_name),
|
coll => coll.tools?.find(tool => tool.name === value?.agent_strategy_name),
|
||||||
)?.icon as string | undefined
|
)?.icon as string | undefined
|
||||||
@ -125,9 +124,10 @@ export const AgentStrategySelector = (props: AgentStrategySelectorProps) => {
|
|||||||
onChange({
|
onChange({
|
||||||
agent_strategy_name: tool!.tool_name,
|
agent_strategy_name: tool!.tool_name,
|
||||||
agent_strategy_provider_name: tool!.provider_name,
|
agent_strategy_provider_name: tool!.provider_name,
|
||||||
agent_parameters: tool!.params,
|
|
||||||
agent_strategy_label: tool!.tool_label,
|
agent_strategy_label: tool!.tool_label,
|
||||||
agent_output_schema: tool!.output_schema,
|
agent_output_schema: tool!.output_schema,
|
||||||
|
agent_configurations: {},
|
||||||
|
agent_parameters: {},
|
||||||
})
|
})
|
||||||
setOpen(false)
|
setOpen(false)
|
||||||
}}
|
}}
|
||||||
|
@ -19,7 +19,8 @@ export type Strategy = {
|
|||||||
agent_strategy_provider_name: string
|
agent_strategy_provider_name: string
|
||||||
agent_strategy_name: string
|
agent_strategy_name: string
|
||||||
agent_strategy_label: string
|
agent_strategy_label: string
|
||||||
agent_parameters?: ToolVarInputs
|
agent_configurations?: Record<string, any>
|
||||||
|
agent_parameters?: Record<string, ToolVarInputs>
|
||||||
agent_output_schema: Record<string, any>
|
agent_output_schema: Record<string, any>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,30 +1,40 @@
|
|||||||
import Tooltip from '@/app/components/base/tooltip'
|
import Tooltip from '@/app/components/base/tooltip'
|
||||||
import Indicator from '@/app/components/header/indicator'
|
import Indicator from '@/app/components/header/indicator'
|
||||||
import classNames from '@/utils/classnames'
|
import classNames from '@/utils/classnames'
|
||||||
import { useRef } from 'react'
|
import { useMemo, useRef } from 'react'
|
||||||
|
import { useAllBuiltInTools, useAllCustomTools, useAllWorkflowTools } from '@/service/use-tools'
|
||||||
|
|
||||||
export type ToolIconProps = {
|
export type ToolIconProps = {
|
||||||
src: string
|
|
||||||
alt?: string
|
|
||||||
status?: 'error' | 'warning'
|
status?: 'error' | 'warning'
|
||||||
tooltip?: string
|
tooltip?: string
|
||||||
|
providerName: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ToolIcon = ({ src, status, tooltip, alt }: ToolIconProps) => {
|
export const ToolIcon = ({ status, tooltip, providerName }: ToolIconProps) => {
|
||||||
const indicator = status === 'error' ? 'red' : status === 'warning' ? 'yellow' : undefined
|
const indicator = status === 'error' ? 'red' : status === 'warning' ? 'yellow' : undefined
|
||||||
const containerRef = useRef<HTMLDivElement>(null)
|
const containerRef = useRef<HTMLDivElement>(null)
|
||||||
const notSuccess = (['error', 'warning'] as Array<ToolIconProps['status']>).includes(status)
|
const notSuccess = (['error', 'warning'] as Array<ToolIconProps['status']>).includes(status)
|
||||||
|
const { data: buildInTools } = useAllBuiltInTools()
|
||||||
|
const { data: customTools } = useAllCustomTools()
|
||||||
|
const { data: workflowTools } = useAllWorkflowTools()
|
||||||
|
const currentProvider = useMemo(() => {
|
||||||
|
const mergedTools = [...(buildInTools || []), ...(customTools || []), ...(workflowTools || [])]
|
||||||
|
return mergedTools.find((toolWithProvider) => {
|
||||||
|
return toolWithProvider.name === providerName
|
||||||
|
})
|
||||||
|
}, [providerName, buildInTools, customTools, workflowTools])
|
||||||
return <Tooltip triggerMethod='hover' popupContent={tooltip} disabled={!notSuccess}>
|
return <Tooltip triggerMethod='hover' popupContent={tooltip} disabled={!notSuccess}>
|
||||||
<div className={classNames(
|
<div className={classNames(
|
||||||
'size-5 border-[0.5px] border-components-panel-border-subtle bg-background-default-dodge relative',
|
'size-5 border-[0.5px] border-components-panel-border-subtle bg-background-default-dodge relative flex items-center justify-center rounded-[6px]',
|
||||||
)}
|
)}
|
||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
>
|
>
|
||||||
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||||
<img
|
<img
|
||||||
src={src}
|
src={currentProvider?.icon as string}
|
||||||
alt={alt}
|
alt='tool icon'
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'w-full h-full max-w-5 max-h-5 object-cover rounded-[6px]',
|
'w-full h-full size-3.5 object-cover',
|
||||||
notSuccess && 'opacity-50',
|
notSuccess && 'opacity-50',
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
@ -8,14 +8,11 @@ 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 { useInstalledPluginList } from '@/service/use-plugins'
|
|
||||||
import { FormTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
import { FormTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||||
|
|
||||||
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 pluginList = useInstalledPluginList()
|
|
||||||
// TODO: Implement models
|
|
||||||
const models = useMemo(() => {
|
const models = useMemo(() => {
|
||||||
if (!inputs) return []
|
if (!inputs) return []
|
||||||
// if selected, show in node
|
// if selected, show in node
|
||||||
@ -24,7 +21,7 @@ const AgentNode: FC<NodeProps<AgentNodeType>> = (props) => {
|
|||||||
const models = currentStrategy?.parameters
|
const models = currentStrategy?.parameters
|
||||||
.filter(param => param.type === FormTypeEnum.modelSelector)
|
.filter(param => param.type === FormTypeEnum.modelSelector)
|
||||||
.reduce((acc, param) => {
|
.reduce((acc, param) => {
|
||||||
const item = inputs.agent_parameters?.[param.name]
|
const item = inputs.agent_configurations?.[param.name]
|
||||||
if (!item) {
|
if (!item) {
|
||||||
if (param.required) {
|
if (param.required) {
|
||||||
acc.push({ param: param.name })
|
acc.push({ param: param.name })
|
||||||
@ -41,18 +38,29 @@ const AgentNode: FC<NodeProps<AgentNodeType>> = (props) => {
|
|||||||
const tools = useMemo(() => {
|
const tools = useMemo(() => {
|
||||||
const tools: Array<ToolIconProps> = []
|
const tools: Array<ToolIconProps> = []
|
||||||
currentStrategy?.parameters.forEach((param) => {
|
currentStrategy?.parameters.forEach((param) => {
|
||||||
if (['array[tool]', 'tool'].includes(param.type)) {
|
if (param.type === FormTypeEnum.toolSelector) {
|
||||||
const vari = inputs.agent_parameters?.[param.name]
|
const field = param.name
|
||||||
if (!vari) return
|
const value = inputs.agent_configurations?.[field]
|
||||||
if (Array.isArray(vari.value)) {
|
if (value) {
|
||||||
// TODO: Implement array of tools
|
tools.push({
|
||||||
|
providerName: value.provider_name as any,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
else {
|
}
|
||||||
// TODO: Implement single tool
|
if (param.type === FormTypeEnum.multiToolSelector) {
|
||||||
|
const field = param.name
|
||||||
|
const value = inputs.agent_configurations?.[field]
|
||||||
|
if (value) {
|
||||||
|
(value as unknown as any[]).forEach((item) => {
|
||||||
|
tools.push({
|
||||||
|
providerName: item.provider_name,
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, [currentStrategy, inputs.agent_parameters])
|
return tools
|
||||||
|
}, [currentStrategy?.parameters, inputs.agent_configurations])
|
||||||
return <div className='mb-1 px-3 py-1 space-y-1'>
|
return <div className='mb-1 px-3 py-1 space-y-1'>
|
||||||
{inputs.agent_strategy_name
|
{inputs.agent_strategy_name
|
||||||
? <SettingItem
|
? <SettingItem
|
||||||
@ -65,7 +73,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 && <Group
|
{models.length > 0 && <Group
|
||||||
label={<GroupLabel className='mt-1'>
|
label={<GroupLabel className='mt-1'>
|
||||||
{t('workflow.nodes.agent.model')}
|
{t('workflow.nodes.agent.model')}
|
||||||
</GroupLabel>}
|
</GroupLabel>}
|
||||||
@ -85,25 +93,13 @@ const AgentNode: FC<NodeProps<AgentNodeType>> = (props) => {
|
|||||||
/>
|
/>
|
||||||
})}
|
})}
|
||||||
</Group>}
|
</Group>}
|
||||||
<Group label={<GroupLabel className='mt-1'>
|
{tools.length > 0 && <Group label={<GroupLabel className='mt-1'>
|
||||||
{t('workflow.nodes.agent.toolbox')}
|
{t('workflow.nodes.agent.toolbox')}
|
||||||
</GroupLabel>}>
|
</GroupLabel>}>
|
||||||
<div className='grid grid-cols-10 gap-0.5'>
|
<div className='grid grid-cols-10 gap-0.5'>
|
||||||
<ToolIcon src='/logo/logo.png' />
|
{tools.map(tool => <ToolIcon {...tool} key={Math.random()} />)}
|
||||||
<ToolIcon
|
|
||||||
src='/logo/logo.png'
|
|
||||||
status='error'
|
|
||||||
tooltip={t('workflow.nodes.agent.toolNotInstallTooltip', {
|
|
||||||
tool: 'Gmail Sender',
|
|
||||||
})} />
|
|
||||||
<ToolIcon
|
|
||||||
src='/logo/logo.png'
|
|
||||||
status='warning'
|
|
||||||
tooltip={t('workflow.nodes.agent.toolNotAuthorizedTooltip', {
|
|
||||||
tool: 'DuckDuckGo AI Search',
|
|
||||||
})} />
|
|
||||||
</div>
|
</div>
|
||||||
</Group>
|
</Group>}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,25 +28,27 @@ const AgentPanel: FC<NodePanelProps<AgentNodeType>> = (props) => {
|
|||||||
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!,
|
||||||
agent_strategy_name: inputs.agent_strategy_name!,
|
agent_strategy_name: inputs.agent_strategy_name!,
|
||||||
agent_parameters: inputs.agent_parameters,
|
agent_configurations: inputs.agent_configurations,
|
||||||
agent_strategy_label: inputs.agent_strategy_label!,
|
agent_strategy_label: inputs.agent_strategy_label!,
|
||||||
agent_output_schema: inputs.output_schema,
|
agent_output_schema: inputs.output_schema,
|
||||||
|
agent_parameters: inputs.agent_parameters,
|
||||||
} : undefined}
|
} : undefined}
|
||||||
onStrategyChange={(strategy) => {
|
onStrategyChange={(strategy) => {
|
||||||
setInputs({
|
setInputs({
|
||||||
...inputs,
|
...inputs,
|
||||||
agent_strategy_provider_name: strategy?.agent_strategy_provider_name,
|
agent_strategy_provider_name: strategy?.agent_strategy_provider_name,
|
||||||
agent_strategy_name: strategy?.agent_strategy_name,
|
agent_strategy_name: strategy?.agent_strategy_name,
|
||||||
|
agent_configurations: strategy?.agent_configurations,
|
||||||
agent_parameters: strategy?.agent_parameters,
|
agent_parameters: strategy?.agent_parameters,
|
||||||
agent_strategy_label: strategy?.agent_strategy_label,
|
agent_strategy_label: strategy?.agent_strategy_label,
|
||||||
output_schema: strategy!.agent_output_schema,
|
output_schema: strategy!.agent_output_schema,
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
formSchema={currentStrategy?.parameters?.map(strategyParamToCredientialForm) || []}
|
formSchema={currentStrategy?.parameters?.map(strategyParamToCredientialForm) || []}
|
||||||
formValue={inputs.agent_parameters || {}}
|
formValue={inputs.agent_configurations || {}}
|
||||||
onFormValueChange={value => setInputs({
|
onFormValueChange={value => setInputs({
|
||||||
...inputs,
|
...inputs,
|
||||||
agent_parameters: value,
|
agent_configurations: value,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
|
@ -5,7 +5,7 @@ export type AgentNodeType = CommonNodeType & {
|
|||||||
agent_strategy_provider_name?: string
|
agent_strategy_provider_name?: string
|
||||||
agent_strategy_name?: string
|
agent_strategy_name?: string
|
||||||
agent_strategy_label?: string
|
agent_strategy_label?: string
|
||||||
agent_parameters?: Record<string, any>
|
agent_parameters?: Record<string, ToolVarInputs>
|
||||||
agent_configurations?: Record<string, ToolVarInputs>
|
agent_configurations?: Record<string, any>
|
||||||
output_schema: Record<string, any>
|
output_schema: Record<string, any>
|
||||||
}
|
}
|
||||||
|
@ -74,6 +74,9 @@ const translation = {
|
|||||||
auth: 'AUTHORIZATION',
|
auth: 'AUTHORIZATION',
|
||||||
settings: 'TOOL SETTINGS',
|
settings: 'TOOL SETTINGS',
|
||||||
empty: 'Click the \'+\' button to add tools. You can add multiple tools.',
|
empty: 'Click the \'+\' button to add tools. You can add multiple tools.',
|
||||||
|
uninstalledTitle: 'Tool not installed',
|
||||||
|
uninstalledContent: 'This plugin is installed from the local/GitHub repository. Please use after installation.',
|
||||||
|
uninstalledLink: 'Manage in Plugins',
|
||||||
},
|
},
|
||||||
configureApp: 'Configure App',
|
configureApp: 'Configure App',
|
||||||
configureModel: 'Configure model',
|
configureModel: 'Configure model',
|
||||||
|
@ -714,6 +714,11 @@ const translation = {
|
|||||||
install: 'Install',
|
install: 'Install',
|
||||||
installing: 'Installing',
|
installing: 'Installing',
|
||||||
},
|
},
|
||||||
|
modelNotInMarketplace: {
|
||||||
|
title: 'Model not installed',
|
||||||
|
desc: 'This model is not installed from the marketplace. Please go to Plugins to reinstall.',
|
||||||
|
manageInPlugins: 'Manage in Plugins',
|
||||||
|
},
|
||||||
configureModel: 'Configure Model',
|
configureModel: 'Configure Model',
|
||||||
notAuthorized: 'Not Authorized',
|
notAuthorized: 'Not Authorized',
|
||||||
model: 'model',
|
model: 'model',
|
||||||
|
@ -74,6 +74,9 @@ const translation = {
|
|||||||
auth: '授权',
|
auth: '授权',
|
||||||
settings: '工具设置',
|
settings: '工具设置',
|
||||||
empty: '点击 "+" 按钮添加工具。您可以添加多个工具。',
|
empty: '点击 "+" 按钮添加工具。您可以添加多个工具。',
|
||||||
|
uninstalledTitle: '工具未安装',
|
||||||
|
uninstalledContent: '此插件安装自 本地 / GitHub 仓库,请安装后使用。',
|
||||||
|
uninstalledLink: '在插件中管理',
|
||||||
},
|
},
|
||||||
configureApp: '应用设置',
|
configureApp: '应用设置',
|
||||||
configureModel: '模型设置',
|
configureModel: '模型设置',
|
||||||
|
@ -714,6 +714,11 @@ const translation = {
|
|||||||
install: '安装',
|
install: '安装',
|
||||||
installing: '安装中',
|
installing: '安装中',
|
||||||
},
|
},
|
||||||
|
modelNotInMarketplace: {
|
||||||
|
title: '模型未安装',
|
||||||
|
desc: '此模型未从市场安装。请转到插件重新安装。',
|
||||||
|
manageInPlugins: '在插件中管理',
|
||||||
|
},
|
||||||
model: '模型',
|
model: '模型',
|
||||||
toolbox: '工具箱',
|
toolbox: '工具箱',
|
||||||
strategyNotSet: '代理策略未设置',
|
strategyNotSet: '代理策略未设置',
|
||||||
|
@ -5,6 +5,7 @@ import type {
|
|||||||
InstallPackageResponse,
|
InstallPackageResponse,
|
||||||
Permissions,
|
Permissions,
|
||||||
PluginDeclaration,
|
PluginDeclaration,
|
||||||
|
PluginInfoFromMarketPlace,
|
||||||
PluginManifestInMarket,
|
PluginManifestInMarket,
|
||||||
PluginTasksResponse,
|
PluginTasksResponse,
|
||||||
TaskStatusResponse,
|
TaskStatusResponse,
|
||||||
@ -75,6 +76,13 @@ export const fetchBundleInfoFromMarketPlace = async ({
|
|||||||
return getMarketplace<{ data: { version: { dependencies: Dependency[] } } }>(`/bundles/${org}/${name}/${version}`)
|
return getMarketplace<{ data: { version: { dependencies: Dependency[] } } }>(`/bundles/${org}/${name}/${version}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const fetchPluginInfoFromMarketPlace = async ({
|
||||||
|
org,
|
||||||
|
name,
|
||||||
|
}: Record<string, string>) => {
|
||||||
|
return getMarketplace<{ data: { plugin: PluginInfoFromMarketPlace, version: { version: string } } }>(`/plugins/${org}/${name}`)
|
||||||
|
}
|
||||||
|
|
||||||
export const fetchMarketplaceCollections: Fetcher<MarketplaceCollectionsResponse, { url: string; }> = ({ url }) => {
|
export const fetchMarketplaceCollections: Fetcher<MarketplaceCollectionsResponse, { url: string; }> = ({ url }) => {
|
||||||
return get<MarketplaceCollectionsResponse>(url)
|
return get<MarketplaceCollectionsResponse>(url)
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import type {
|
|||||||
Permissions,
|
Permissions,
|
||||||
Plugin,
|
Plugin,
|
||||||
PluginDetail,
|
PluginDetail,
|
||||||
|
PluginInfoFromMarketPlace,
|
||||||
PluginTask,
|
PluginTask,
|
||||||
PluginsFromMarketplaceByInfoResponse,
|
PluginsFromMarketplaceByInfoResponse,
|
||||||
PluginsFromMarketplaceResponse,
|
PluginsFromMarketplaceResponse,
|
||||||
@ -91,6 +92,7 @@ export const useUpdatePackageFromMarketPlace = () => {
|
|||||||
|
|
||||||
export const useVersionListOfPlugin = (pluginID: string) => {
|
export const useVersionListOfPlugin = (pluginID: string) => {
|
||||||
return useQuery<{ data: VersionListResponse }>({
|
return useQuery<{ data: VersionListResponse }>({
|
||||||
|
enabled: !!pluginID,
|
||||||
queryKey: [NAME_SPACE, 'versions', pluginID],
|
queryKey: [NAME_SPACE, 'versions', pluginID],
|
||||||
queryFn: () => getMarketplace<{ data: VersionListResponse }>(`/plugins/${pluginID}/versions`, { params: { page: 1, page_size: 100 } }),
|
queryFn: () => getMarketplace<{ data: VersionListResponse }>(`/plugins/${pluginID}/versions`, { params: { page: 1, page_size: 100 } }),
|
||||||
})
|
})
|
||||||
@ -399,6 +401,15 @@ export const useMutationClearAllTaskPlugin = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const usePluginManifestInfo = (pluginUID: string) => {
|
||||||
|
return useQuery({
|
||||||
|
enabled: !!pluginUID,
|
||||||
|
queryKey: [[NAME_SPACE, 'manifest', pluginUID]],
|
||||||
|
queryFn: () => getMarketplace<{ data: { plugin: PluginInfoFromMarketPlace, version: { version: string } } }>(`/plugins/${pluginUID}`),
|
||||||
|
retry: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export const useDownloadPlugin = (info: { organization: string; pluginName: string; version: string }, needDownload: boolean) => {
|
export const useDownloadPlugin = (info: { organization: string; pluginName: string; version: string }, needDownload: boolean) => {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: [NAME_SPACE, 'downloadPlugin', info],
|
queryKey: [NAME_SPACE, 'downloadPlugin', info],
|
||||||
|
Loading…
Reference in New Issue
Block a user