feat: Add file type support to LLM node JSON schema editor

This commit is contained in:
zhsama
2026-01-27 19:39:32 +08:00
parent ea37904c75
commit 39ec2b3277
5 changed files with 87 additions and 17 deletions

View File

@ -44,17 +44,21 @@ const TYPE_OPTIONS = [
{ value: Type.number, text: 'number' },
{ value: Type.boolean, text: 'boolean' },
{ value: Type.object, text: 'object' },
{ value: Type.file, text: 'file' },
{ value: ArrayType.string, text: 'array[string]' },
{ value: ArrayType.number, text: 'array[number]' },
{ value: ArrayType.object, text: 'array[object]' },
{ value: ArrayType.file, text: 'array[file]' },
]
const MAXIMUM_DEPTH_TYPE_OPTIONS = [
{ value: Type.string, text: 'string' },
{ value: Type.number, text: 'number' },
{ value: Type.boolean, text: 'boolean' },
{ value: Type.file, text: 'file' },
{ value: ArrayType.string, text: 'array[string]' },
{ value: ArrayType.number, text: 'array[number]' },
{ value: ArrayType.file, text: 'array[file]' },
]
const EditCard: FC<EditCardProps> = ({

View File

@ -4,7 +4,7 @@ import type { EditData } from './edit-card'
import { noop } from 'es-toolkit/function'
import { produce } from 'immer'
import Toast from '@/app/components/base/toast'
import { ArrayType, Type } from '../../../types'
import { ArrayType, FILE_REF_FORMAT, Type } from '../../../types'
import { findPropertyWithPath } from '../../../utils'
import { useMittContext } from './context'
import { useVisualEditorStore } from './store'
@ -133,6 +133,7 @@ export const useSchemaNodeOperations = (props: VisualEditorProps) => {
}
if (schema.type === Type.array)
delete schema.items
delete schema.format
switch (newType) {
case Type.object:
schema.type = Type.object
@ -140,6 +141,10 @@ export const useSchemaNodeOperations = (props: VisualEditorProps) => {
schema.required = []
schema.additionalProperties = false
break
case Type.file:
schema.type = Type.string
schema.format = FILE_REF_FORMAT
break
case ArrayType.string:
schema.type = Type.array
schema.items = {
@ -167,6 +172,13 @@ export const useSchemaNodeOperations = (props: VisualEditorProps) => {
additionalProperties: false,
}
break
case ArrayType.file:
schema.type = Type.array
schema.items = {
type: Type.string,
format: FILE_REF_FORMAT,
}
break
default:
schema.type = newType as Type
}
@ -309,6 +321,7 @@ export const useSchemaNodeOperations = (props: VisualEditorProps) => {
}
if (schema.type === Type.array)
delete schema.items
delete schema.format
switch (newType) {
case Type.object:
schema.type = Type.object
@ -316,6 +329,10 @@ export const useSchemaNodeOperations = (props: VisualEditorProps) => {
schema.required = []
schema.additionalProperties = false
break
case Type.file:
schema.type = Type.string
schema.format = FILE_REF_FORMAT
break
case ArrayType.string:
schema.type = Type.array
schema.items = {
@ -343,6 +360,13 @@ export const useSchemaNodeOperations = (props: VisualEditorProps) => {
additionalProperties: false,
}
break
case ArrayType.file:
schema.type = Type.array
schema.items = {
type: Type.string,
format: FILE_REF_FORMAT,
}
break
default:
schema.type = newType as Type
}
@ -398,6 +422,7 @@ export const useSchemaNodeOperations = (props: VisualEditorProps) => {
}
if (schema.type === Type.array)
delete schema.items
delete schema.format
switch (newType) {
case Type.object:
schema.type = Type.object
@ -405,6 +430,10 @@ export const useSchemaNodeOperations = (props: VisualEditorProps) => {
schema.required = []
schema.additionalProperties = false
break
case Type.file:
schema.type = Type.string
schema.format = FILE_REF_FORMAT
break
case ArrayType.string:
schema.type = Type.array
schema.items = {
@ -432,6 +461,13 @@ export const useSchemaNodeOperations = (props: VisualEditorProps) => {
additionalProperties: false,
}
break
case ArrayType.file:
schema.type = Type.array
schema.items = {
type: Type.string,
format: FILE_REF_FORMAT,
}
break
default:
schema.type = newType as Type
}

View File

@ -20,6 +20,8 @@ export type LLMNodeType = CommonNodeType & {
reasoning_format?: 'tagged' | 'separated'
}
export const FILE_REF_FORMAT = 'dify-file-ref'
export enum Type {
string = 'string',
number = 'number',
@ -38,12 +40,13 @@ export enum ArrayType {
number = 'array[number]',
boolean = 'array[boolean]',
object = 'array[object]',
file = 'array[file]',
}
export type TypeWithArray = Type | ArrayType
type ArrayItemType = Exclude<Type, Type.array>
export type ArrayItems = Omit<Field, 'type'> & { type: ArrayItemType }
export type ArrayItems = Omit<Field, 'type' | 'format'> & { type: ArrayItemType; format?: string }
export type SchemaEnumType = string[] | number[]
@ -54,6 +57,7 @@ export type Field = {
}
required?: string[] // Key of required properties in object
description?: string
format?: string
items?: ArrayItems // Array has items. Define the item type
enum?: SchemaEnumType // Enum values
additionalProperties?: false // Required in object by api. Just set false

View File

@ -2,21 +2,24 @@ import type { ValidationError } from 'jsonschema'
import type { ArrayItems, Field, LLMNodeType } from './types'
import { z } from 'zod'
import { draft07Validator, forbidBooleanProperties } from '@/utils/validators'
import { ArrayType, Type } from './types'
import { ArrayType, FILE_REF_FORMAT, Type } from './types'
export const checkNodeValid = (_payload: LLMNodeType) => {
return true
}
export const getFieldType = (field: Field) => {
const { type, items, enum: enums } = field
const { type, items, enum: enums, format } = field
if (format === FILE_REF_FORMAT)
return Type.file
if (field.schemaType === 'file')
return Type.file
if (enums && enums.length > 0)
return Type.enumType
if (type !== Type.array || !items)
return type
if (items.format === FILE_REF_FORMAT || items.type === Type.file)
return ArrayType.file
return ArrayType[items.type as keyof typeof ArrayType]
}