diff --git a/web/app/components/header/account-setting/index.tsx b/web/app/components/header/account-setting/index.tsx index b3409c226a..90a441a72d 100644 --- a/web/app/components/header/account-setting/index.tsx +++ b/web/app/components/header/account-setting/index.tsx @@ -36,6 +36,10 @@ const iconClassName = ` w-5 h-5 mr-2 ` +const scrolledClassName = ` + border-b shadow-xs bg-white/[.98] +` + type IAccountSettingProps = { onCancel: () => void activeTab?: string diff --git a/web/app/components/header/account-setting/model-provider-page/model-icon/index.tsx b/web/app/components/header/account-setting/model-provider-page/model-icon/index.tsx index 9f8dbd79d8..d8af591904 100644 --- a/web/app/components/header/account-setting/model-provider-page/model-icon/index.tsx +++ b/web/app/components/header/account-setting/model-provider-page/model-icon/index.tsx @@ -5,32 +5,37 @@ import type { } from '../declarations' import { useLanguage } from '../hooks' import { CubeOutline } from '@/app/components/base/icons/src/vender/line/shapes' -import { 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' type ModelIconProps = { provider?: Model | ModelProvider modelName?: string className?: string + isDeprecated?: boolean } const ModelIcon: FC = ({ provider, className, modelName, + isDeprecated = false, }) => { const language = useLanguage() - - if (provider?.provider.includes('openai') && (modelName?.startsWith('gpt-4') || modelName?.includes('4o'))) - return + if (provider?.provider.includes('openai') && modelName?.includes('gpt-4o')) + return + if (provider?.provider.includes('openai') && modelName?.startsWith('gpt-4')) + return if (provider?.icon_small) { return ( - // eslint-disable-next-line @next/next/no-img-element - model-icon + +
+ model-icon +
) } diff --git a/web/app/components/header/account-setting/model-provider-page/model-modal/Form.tsx b/web/app/components/header/account-setting/model-provider-page/model-modal/Form.tsx index 6e54b939c3..6ade065af2 100644 --- a/web/app/components/header/account-setting/model-provider-page/model-modal/Form.tsx +++ b/web/app/components/header/account-setting/model-provider-page/model-modal/Form.tsx @@ -35,6 +35,7 @@ type FormProps< validatedSuccess?: boolean showOnVariableMap: Record isEditMode: boolean + isAgentStrategy?: boolean readonly?: boolean inputClassName?: string isShowDefaultValue?: boolean @@ -60,6 +61,7 @@ function Form< validatedSuccess, showOnVariableMap, isEditMode, + isAgentStrategy = false, readonly, inputClassName, isShowDefaultValue = false, @@ -278,6 +280,7 @@ function Form< popupClassName='!w-[387px]' isAdvancedMode isInWorkflow + isAgentStrategy={isAgentStrategy} value={value[variable]} setModel={model => handleModelChanged(variable, model)} readonly={readonly} diff --git a/web/app/components/header/account-setting/model-provider-page/model-name/index.tsx b/web/app/components/header/account-setting/model-provider-page/model-name/index.tsx index a955d9804a..bf25c49256 100644 --- a/web/app/components/header/account-setting/model-provider-page/model-name/index.tsx +++ b/web/app/components/header/account-setting/model-provider-page/model-name/index.tsx @@ -37,43 +37,45 @@ const ModelName: FC = ({ if (!modelItem) return null return ( -
+
{modelItem.label[language] || modelItem.label.en_US}
- { - showModelType && modelItem.model_type && ( - - {modelTypeFormat(modelItem.model_type)} - - ) - } - { - modelItem.model_properties.mode && showMode && ( - - {(modelItem.model_properties.mode as string).toLocaleUpperCase()} - - ) - } - { - showFeatures && modelItem.features?.map(feature => ( - - )) - } - { - showContextSize && modelItem.model_properties.context_size && ( - - {sizeFormat(modelItem.model_properties.context_size as number)} - - ) - } +
+ { + showModelType && modelItem.model_type && ( + + {modelTypeFormat(modelItem.model_type)} + + ) + } + { + modelItem.model_properties.mode && showMode && ( + + {(modelItem.model_properties.mode as string).toLocaleUpperCase()} + + ) + } + { + showFeatures && modelItem.features?.map(feature => ( + + )) + } + { + showContextSize && modelItem.model_properties.context_size && ( + + {sizeFormat(modelItem.model_properties.context_size as number)} + + ) + } +
{children}
) diff --git a/web/app/components/header/account-setting/model-provider-page/model-parameter-modal/agent-model-trigger.tsx b/web/app/components/header/account-setting/model-provider-page/model-parameter-modal/agent-model-trigger.tsx new file mode 100644 index 0000000000..4e03264ffd --- /dev/null +++ b/web/app/components/header/account-setting/model-provider-page/model-parameter-modal/agent-model-trigger.tsx @@ -0,0 +1,180 @@ +import type { FC } from 'react' +import { useTranslation } from 'react-i18next' +import type { + CustomConfigurationModelFixedFields, + ModelItem, + ModelProvider, +} from '../declarations' +import { + ConfigurationMethodEnum, + CustomConfigurationStatusEnum, +} from '../declarations' +import { UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST } from '../provider-added-card' +import { ModelStatusEnum } from '../declarations' +import { + useUpdateModelList, + useUpdateModelProviders, +} from '../hooks' +import ModelIcon from '../model-icon' +import ModelName from '../model-name' +import Button from '@/app/components/base/button' +import cn from '@/utils/classnames' +import { useProviderContext } from '@/context/provider-context' +import { useModalContextSelector } from '@/context/modal-context' +import { useEventEmitterContextContext } from '@/context/event-emitter' +import Tooltip from '@/app/components/base/tooltip' +import { RiEqualizer2Line, RiErrorWarningFill } from '@remixicon/react' + +export type AgentModelTriggerProps = { + open?: boolean + disabled?: boolean + currentProvider?: ModelProvider + currentModel?: ModelItem + providerName?: string + modelId?: string + hasDeprecated?: boolean +} + +const AgentModelTrigger: FC = ({ + disabled, + currentProvider, + currentModel, + providerName, + modelId, + hasDeprecated, +}) => { + const { t } = useTranslation() + const { modelProviders } = useProviderContext() + const setShowModelModal = useModalContextSelector(state => state.setShowModelModal) + const updateModelProviders = useUpdateModelProviders() + const updateModelList = useUpdateModelList() + const { eventEmitter } = useEventEmitterContextContext() + const modelProvider = modelProviders.find(item => item.provider === providerName) + const needsConfiguration = modelProvider?.custom_configuration.status === CustomConfigurationStatusEnum.noConfigure && !( + modelProvider.system_configuration.enabled === true + && modelProvider.system_configuration.quota_configurations.find( + item => item.quota_type === modelProvider.system_configuration.current_quota_type, + ) + ) + + const handleOpenModal = ( + provider: ModelProvider, + configurationMethod: ConfigurationMethodEnum, + CustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields, + ) => { + setShowModelModal({ + payload: { + currentProvider: provider, + currentConfigurationMethod: configurationMethod, + currentCustomConfigurationModelFixedFields: CustomConfigurationModelFixedFields, + }, + onSaveCallback: () => { + updateModelProviders() + + provider.supported_model_types.forEach((type) => { + updateModelList(type) + }) + + if (configurationMethod === ConfigurationMethodEnum.customizableModel + && provider.custom_configuration.status === CustomConfigurationStatusEnum.active) { + eventEmitter?.emit({ + type: UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST, + payload: provider.provider, + } as any) + + if (CustomConfigurationModelFixedFields?.__model_type) + updateModelList(CustomConfigurationModelFixedFields.__model_type) + } + }, + }) + } + + return ( +
+ {modelId ? ( + <> + {currentProvider && ( + + )} + {!currentProvider && ( + + )} + {currentModel && ( + + )} + {!currentModel && ( +
+
+ {modelId} +
+
+ )} + {needsConfiguration && ( + + )} + {!needsConfiguration && disabled && ( + + + + ) + } + + ) : ( + <> +
+ + {t('workflow.nodes.agent.configureModel')} + +
+
+ +
+ + )} + {currentProvider && currentModel && currentModel.status === ModelStatusEnum.active && ( +
+ +
+ )} +
+ ) +} + +export default AgentModelTrigger diff --git a/web/app/components/header/account-setting/model-provider-page/model-selector/popup-item.tsx b/web/app/components/header/account-setting/model-provider-page/model-selector/popup-item.tsx index 425fc2e34a..78e1d68357 100644 --- a/web/app/components/header/account-setting/model-provider-page/model-selector/popup-item.tsx +++ b/web/app/components/header/account-setting/model-provider-page/model-selector/popup-item.tsx @@ -77,28 +77,30 @@ const PopupItem: FC = ({
handleSelect(model.provider, modelItem)} > - - +
+ + +
{ defaultModel?.model === modelItem.model && defaultModel.provider === currentProvider.provider && ( diff --git a/web/app/components/plugins/card/index.tsx b/web/app/components/plugins/card/index.tsx index 9491d710f3..09b4ca73cb 100644 --- a/web/app/components/plugins/card/index.tsx +++ b/web/app/components/plugins/card/index.tsx @@ -44,7 +44,7 @@ const Card = ({ const locale = localeFromProps ? getLanguage(localeFromProps) : defaultLocale const { categoriesMap } = useCategories() const { category, type, name, org, label, brief, icon, verified } = payload - const isBundle = !['plugin', 'model', 'tool', 'extension', 'agent-strategy'].includes(type) + const isBundle = !['plugin', 'model', 'tool', 'extension', 'agent_strategy'].includes(type) const cornerMark = isBundle ? categoriesMap.bundle?.label : categoriesMap[category]?.label const getLocalizedText = (obj: Record | undefined) => obj?.[locale] || obj?.['en-US'] || obj?.en_US || '' diff --git a/web/app/components/plugins/hooks.ts b/web/app/components/plugins/hooks.ts index ab6bbf14fe..7c3003497b 100644 --- a/web/app/components/plugins/hooks.ts +++ b/web/app/components/plugins/hooks.ts @@ -44,7 +44,7 @@ export const useCategories = (translateFromOut?: TFunction) => { const categories = categoryKeys.map((category) => { if (category === 'agent') { return { - name: 'agent-strategy', + name: 'agent_strategy', label: t(`plugin.category.${category}s`), } } diff --git a/web/app/components/plugins/marketplace/utils.ts b/web/app/components/plugins/marketplace/utils.ts index 78d4437681..d8201156de 100644 --- a/web/app/components/plugins/marketplace/utils.ts +++ b/web/app/components/plugins/marketplace/utils.ts @@ -102,7 +102,7 @@ export const getMarketplaceListCondition = (pluginType: string) => { return 'category=tool' if (pluginType === PluginType.agent) - return 'category=agent-strategy' + return 'category=agent_strategy' if (pluginType === PluginType.model) return 'category=model' diff --git a/web/app/components/plugins/plugin-detail-panel/model-selector/index.tsx b/web/app/components/plugins/plugin-detail-panel/model-selector/index.tsx index 6bd750c8c3..a0917d93fa 100644 --- a/web/app/components/plugins/plugin-detail-panel/model-selector/index.tsx +++ b/web/app/components/plugins/plugin-detail-panel/model-selector/index.tsx @@ -13,6 +13,7 @@ import ModelSelector from '@/app/components/header/account-setting/model-provide import { useModelList, } from '@/app/components/header/account-setting/model-provider-page/hooks' +import AgentModelTrigger from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal/agent-model-trigger' import Trigger from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal/trigger' import type { TriggerProps } from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal/trigger' import { @@ -34,6 +35,7 @@ export type ModelParameterModalProps = { renderTrigger?: (v: TriggerProps) => ReactNode readonly?: boolean isInWorkflow?: boolean + isAgentStrategy?: boolean scope?: string } @@ -46,6 +48,7 @@ const ModelParameterModal: FC = ({ renderTrigger, readonly, isInWorkflow, + isAgentStrategy, scope = ModelTypeEnum.textGeneration, }) => { const { t } = useTranslation() @@ -168,8 +171,16 @@ const ModelParameterModal: FC = ({ providerName: value?.provider, modelId: value?.model, }) - : ( - + : { validating={false} showOnVariableMap={{}} isEditMode={true} + isAgentStrategy={true} fieldLabelClassName='uppercase' customRenderField={renderField} /> diff --git a/web/i18n/en-US/workflow.ts b/web/i18n/en-US/workflow.ts index ecce13b5b2..30e13b527d 100644 --- a/web/i18n/en-US/workflow.ts +++ b/web/i18n/en-US/workflow.ts @@ -714,6 +714,8 @@ const translation = { install: 'Install', installing: 'Installing', }, + configureModel: 'Configure Model', + notAuthorized: 'Not Authorized', model: 'model', toolbox: 'toolbox', strategyNotSet: 'Agentic strategy Not Set', @@ -723,6 +725,9 @@ const translation = { toolNotInstallTooltip: '{{tool}} is not installed', toolNotAuthorizedTooltip: '{{tool}} Not Authorized', strategyNotInstallTooltip: '{{strategy}} is not installed', + modelSelectorTooltips: { + deprecated: 'This model is deprecated', + }, }, }, tracing: { diff --git a/web/i18n/zh-Hans/workflow.ts b/web/i18n/zh-Hans/workflow.ts index 0935791136..b4291c64fc 100644 --- a/web/i18n/zh-Hans/workflow.ts +++ b/web/i18n/zh-Hans/workflow.ts @@ -717,12 +717,17 @@ const translation = { model: '模型', toolbox: '工具箱', strategyNotSet: '代理策略未设置', + configureModel: '配置模型', + notAuthorized: '未授权', tools: '工具', maxIterations: '最大迭代次数', modelNotInstallTooltip: '此模型未安装', toolNotInstallTooltip: '{{tool}} 未安装', toolNotAuthorizedTooltip: '{{tool}} 未授权', strategyNotInstallTooltip: '{{strategy}} 未安装', + modelSelectorTooltips: { + deprecated: '此模型已弃用', + }, }, }, tracing: { diff --git a/web/service/use-strategy.ts b/web/service/use-strategy.ts index e6f6c4b607..cbc09509b3 100644 --- a/web/service/use-strategy.ts +++ b/web/service/use-strategy.ts @@ -7,7 +7,7 @@ import { useQuery, } from '@tanstack/react-query' -const NAME_SPACE = 'agent-strategy' +const NAME_SPACE = 'agent_strategy' const useStrategyListKey = [NAME_SPACE, 'strategyList'] export const useStrategyProviders = () => {