Merge branch 'feat/model-plugins-implementing' into deploy/dev

This commit is contained in:
yyh
2026-03-13 21:55:37 +08:00
4 changed files with 56 additions and 8 deletions

View File

@ -53,6 +53,7 @@ import {
} from '../hooks' } from '../hooks'
import { getNodeUsedVars, isSpecialVar } from '../nodes/_base/components/variable/utils' import { getNodeUsedVars, isSpecialVar } from '../nodes/_base/components/variable/utils'
import { IndexMethodEnum } from '../nodes/knowledge-base/types' import { IndexMethodEnum } from '../nodes/knowledge-base/types'
import { getLLMModelIssue, isLLMModelProviderInstalled, LLMModelIssueCode } from '../nodes/llm/utils'
import { import {
useStore, useStore,
useWorkflowStore, useWorkflowStore,
@ -223,7 +224,11 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => {
else { else {
if (node.data.type === BlockEnum.LLM) { if (node.data.type === BlockEnum.LLM) {
const modelProvider = (node.data as CommonNodeType<{ model?: ModelConfig }>).model?.provider const modelProvider = (node.data as CommonNodeType<{ model?: ModelConfig }>).model?.provider
if (modelProvider && !installedPluginIds.has(extractPluginId(modelProvider))) const modelIssue = getLLMModelIssue({
modelProvider,
isModelProviderInstalled: isLLMModelProviderInstalled(modelProvider, installedPluginIds),
})
if (modelIssue === LLMModelIssueCode.providerPluginUnavailable)
errorMessages.push(t('errorMsg.configureModel', { ns: 'workflow' })) errorMessages.push(t('errorMsg.configureModel', { ns: 'workflow' }))
} }
@ -469,7 +474,11 @@ export const useChecklistBeforePublish = () => {
if (node.data.type === BlockEnum.LLM) { if (node.data.type === BlockEnum.LLM) {
const modelProvider = (node.data as CommonNodeType<{ model?: ModelConfig }>).model?.provider const modelProvider = (node.data as CommonNodeType<{ model?: ModelConfig }>).model?.provider
if (modelProvider && !installedPluginIds.has(extractPluginId(modelProvider))) { const modelIssue = getLLMModelIssue({
modelProvider,
isModelProviderInstalled: isLLMModelProviderInstalled(modelProvider, installedPluginIds),
})
if (modelIssue === LLMModelIssueCode.providerPluginUnavailable) {
notify({ type: 'error', message: `[${node.data.title}] ${t('errorMsg.configureModel', { ns: 'workflow' })}` }) notify({ type: 'error', message: `[${node.data.title}] ${t('errorMsg.configureModel', { ns: 'workflow' })}` })
return false return false
} }

View File

@ -4,6 +4,7 @@ import { genNodeMetaData } from '@/app/components/workflow/utils'
// import { RETRIEVAL_OUTPUT_STRUCT } from '../../constants' // import { RETRIEVAL_OUTPUT_STRUCT } from '../../constants'
import { AppModeEnum } from '@/types/app' import { AppModeEnum } from '@/types/app'
import { BlockEnum, EditionType, PromptRole } from '../../types' import { BlockEnum, EditionType, PromptRole } from '../../types'
import { getLLMModelIssue, LLMModelIssueCode } from './utils'
const RETRIEVAL_OUTPUT_STRUCT = `{ const RETRIEVAL_OUTPUT_STRUCT = `{
"content": "", "content": "",
@ -60,7 +61,8 @@ const nodeDefault: NodeDefault<LLMNodeType> = {
}, },
checkValid(payload: LLMNodeType, t: any) { checkValid(payload: LLMNodeType, t: any) {
let errorMessages = '' let errorMessages = ''
if (!errorMessages && !payload.model.provider) const modelIssue = getLLMModelIssue({ modelProvider: payload.model.provider })
if (!errorMessages && modelIssue === LLMModelIssueCode.providerRequired)
errorMessages = t(`${i18nPrefix}.fieldRequired`, { ns: 'workflow', field: t(`${i18nPrefix}.fields.model`, { ns: 'workflow' }) }) errorMessages = t(`${i18nPrefix}.fieldRequired`, { ns: 'workflow', field: t(`${i18nPrefix}.fields.model`, { ns: 'workflow' }) })
if (!errorMessages && !payload.memory) { if (!errorMessages && !payload.memory) {

View File

@ -25,6 +25,7 @@ import ConfigPrompt from './components/config-prompt'
import ReasoningFormatConfig from './components/reasoning-format-config' import ReasoningFormatConfig from './components/reasoning-format-config'
import StructureOutput from './components/structure-output' import StructureOutput from './components/structure-output'
import useConfig from './use-config' import useConfig from './use-config'
import { getLLMModelIssue, LLMModelIssueCode } from './utils'
const i18nPrefix = 'nodes.llm' const i18nPrefix = 'nodes.llm'
@ -33,7 +34,6 @@ const Panel: FC<NodePanelProps<LLMNodeType>> = ({
data, data,
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
const modelProviders = useProviderContextSelector(s => s.modelProviders)
const { const {
readOnly, readOnly,
inputs, inputs,
@ -70,10 +70,18 @@ const Panel: FC<NodePanelProps<LLMNodeType>> = ({
} = useConfig(id, data) } = useConfig(id, data)
const model = inputs.model const model = inputs.model
const installedPluginIds = new Set(modelProviders.map(provider => extractPluginId(provider.provider))) const isModelProviderInstalled = useProviderContextSelector((state) => {
const hasModelWarning = !model?.provider const modelIssue = getLLMModelIssue({ modelProvider: model?.provider })
|| !model?.name if (modelIssue === LLMModelIssueCode.providerRequired)
|| (Boolean(model.provider) && !installedPluginIds.has(extractPluginId(model.provider))) return true
const modelProviderPluginId = extractPluginId(model.provider)
return state.modelProviders.some(provider => extractPluginId(provider.provider) === modelProviderPluginId)
})
const hasModelWarning = getLLMModelIssue({
modelProvider: model?.provider,
isModelProviderInstalled,
}) !== null
const handleModelChange = useCallback((model: { const handleModelChange = useCallback((model: {
provider: string provider: string

View File

@ -2,12 +2,41 @@ import type { ValidationError } from 'jsonschema'
import type { ArrayItems, Field, LLMNodeType } from './types' import type { ArrayItems, Field, LLMNodeType } from './types'
import * as z from 'zod' import * as z from 'zod'
import { draft07Validator, forbidBooleanProperties } from '@/utils/validators' import { draft07Validator, forbidBooleanProperties } from '@/utils/validators'
import { extractPluginId } from '../../utils/plugin'
import { ArrayType, Type } from './types' import { ArrayType, Type } from './types'
export const checkNodeValid = (_payload: LLMNodeType) => { export const checkNodeValid = (_payload: LLMNodeType) => {
return true return true
} }
export enum LLMModelIssueCode {
providerRequired = 'provider-required',
providerPluginUnavailable = 'provider-plugin-unavailable',
}
export const getLLMModelIssue = ({
modelProvider,
isModelProviderInstalled = true,
}: {
modelProvider?: string
isModelProviderInstalled?: boolean
}) => {
if (!modelProvider)
return LLMModelIssueCode.providerRequired
if (!isModelProviderInstalled)
return LLMModelIssueCode.providerPluginUnavailable
return null
}
export const isLLMModelProviderInstalled = (modelProvider: string | undefined, installedPluginIds: ReadonlySet<string>) => {
if (!modelProvider)
return true
return installedPluginIds.has(extractPluginId(modelProvider))
}
export const getFieldType = (field: Field) => { export const getFieldType = (field: Field) => {
const { type, items, enum: enums } = field const { type, items, enum: enums } = field
if (field.schemaType === 'file') if (field.schemaType === 'file')