From ec5964c4190a3ce72cd6a99a3855eb9c0d1a6fdd Mon Sep 17 00:00:00 2001 From: zhsama Date: Mon, 26 Jan 2026 17:34:01 +0800 Subject: [PATCH] feat: Add support for array[message](List[promptMessage]) variable type in workflow --- .../nodes/_base/components/form-input-item.tsx | 2 +- .../workflow/nodes/_base/components/variable/utils.ts | 3 +++ .../_base/components/variable/var-type-picker.tsx | 2 +- .../trigger-webhook/utils/parameter-type-utils.ts | 3 +++ web/app/components/workflow/types.ts | 1 + .../components/workflow/variable-inspect/group.tsx | 3 ++- .../components/workflow/variable-inspect/right.tsx | 11 +++++++++-- .../components/workflow/variable-inspect/utils.tsx | 8 +++++++- .../workflow/variable-inspect/value-content.tsx | 10 +++++++++- 9 files changed, 36 insertions(+), 7 deletions(-) diff --git a/web/app/components/workflow/nodes/_base/components/form-input-item.tsx b/web/app/components/workflow/nodes/_base/components/form-input-item.tsx index 0abfeb9bbd..77bb6b43cd 100644 --- a/web/app/components/workflow/nodes/_base/components/form-input-item.tsx +++ b/web/app/components/workflow/nodes/_base/components/form-input-item.tsx @@ -224,7 +224,7 @@ const FormInputItem: FC = ({ else if (isObject) return (varPayload: any) => varPayload.type === VarType.object else if (isArray) - return (varPayload: any) => [VarType.array, VarType.arrayString, VarType.arrayNumber, VarType.arrayObject].includes(varPayload.type) + return (varPayload: any) => [VarType.array, VarType.arrayString, VarType.arrayNumber, VarType.arrayObject, VarType.arrayMessage].includes(varPayload.type) return undefined } diff --git a/web/app/components/workflow/nodes/_base/components/variable/utils.ts b/web/app/components/workflow/nodes/_base/components/variable/utils.ts index 04a77bbc16..d49cee7647 100644 --- a/web/app/components/workflow/nodes/_base/components/variable/utils.ts +++ b/web/app/components/workflow/nodes/_base/components/variable/utils.ts @@ -162,6 +162,7 @@ export const varTypeToStructType = (type: VarType): Type => { [VarType.arrayNumber]: Type.array, [VarType.arrayObject]: Type.array, [VarType.arrayFile]: Type.array, + [VarType.arrayMessage]: Type.array, } as any )[type] || Type.string ) @@ -940,6 +941,7 @@ const getIterationItemType = ({ case VarType.arrayBoolean: return VarType.boolean case VarType.arrayObject: + case VarType.arrayMessage: return VarType.object case VarType.array: return VarType.arrayObject // Use more specific type instead of any @@ -994,6 +996,7 @@ const getLoopItemType = ({ case VarType.arrayNumber: return VarType.number case VarType.arrayObject: + case VarType.arrayMessage: return VarType.object case VarType.arrayBoolean: return VarType.boolean diff --git a/web/app/components/workflow/nodes/_base/components/variable/var-type-picker.tsx b/web/app/components/workflow/nodes/_base/components/variable/var-type-picker.tsx index 3af95587cb..45e12cc733 100644 --- a/web/app/components/workflow/nodes/_base/components/variable/var-type-picker.tsx +++ b/web/app/components/workflow/nodes/_base/components/variable/var-type-picker.tsx @@ -19,7 +19,7 @@ type Props = { onChange: (value: string) => void } -const TYPES = [VarType.string, VarType.number, VarType.boolean, VarType.arrayNumber, VarType.arrayString, VarType.arrayBoolean, VarType.arrayObject, VarType.object] +const TYPES = [VarType.string, VarType.number, VarType.boolean, VarType.arrayNumber, VarType.arrayString, VarType.arrayBoolean, VarType.arrayObject, VarType.arrayMessage, VarType.object] const VarReferencePicker: FC = ({ readonly, className, diff --git a/web/app/components/workflow/nodes/trigger-webhook/utils/parameter-type-utils.ts b/web/app/components/workflow/nodes/trigger-webhook/utils/parameter-type-utils.ts index 10f61a5e22..a1088eabee 100644 --- a/web/app/components/workflow/nodes/trigger-webhook/utils/parameter-type-utils.ts +++ b/web/app/components/workflow/nodes/trigger-webhook/utils/parameter-type-utils.ts @@ -21,6 +21,7 @@ const TYPE_DISPLAY_NAMES: Record = { [VarType.arrayNumber]: 'Array[Number]', [VarType.arrayBoolean]: 'Array[Boolean]', [VarType.arrayObject]: 'Array[Object]', + [VarType.arrayMessage]: 'Array[Message]', [VarType.secret]: 'Secret', [VarType.array]: 'Array', 'array[file]': 'Array[File]', @@ -73,6 +74,8 @@ export const normalizeParameterType = (input: string | undefined | null): VarTyp return VarType.arrayBoolean else if (trimmed === 'array[object]') return VarType.arrayObject + else if (trimmed === 'array[message]') + return VarType.arrayMessage else if (trimmed === 'array') // Migrate legacy 'array' type to 'array[string]' return VarType.arrayString diff --git a/web/app/components/workflow/types.ts b/web/app/components/workflow/types.ts index 737a3f9799..274d315480 100644 --- a/web/app/components/workflow/types.ts +++ b/web/app/components/workflow/types.ts @@ -307,6 +307,7 @@ export enum VarType { arrayObject = 'array[object]', arrayBoolean = 'array[boolean]', arrayFile = 'array[file]', + arrayMessage = 'array[message]', any = 'any', arrayAny = 'array[any]', } diff --git a/web/app/components/workflow/variable-inspect/group.tsx b/web/app/components/workflow/variable-inspect/group.tsx index 66c64790be..dad8168d2b 100644 --- a/web/app/components/workflow/variable-inspect/group.tsx +++ b/web/app/components/workflow/variable-inspect/group.tsx @@ -17,6 +17,7 @@ import { VariableIconWithColor } from '@/app/components/workflow/nodes/_base/com import { VarInInspectType } from '@/types/workflow' import { cn } from '@/utils/classnames' import { useToolIcon } from '../hooks' +import { formatVarTypeLabel } from './utils' type Props = { nodeData?: NodeWithVar @@ -161,7 +162,7 @@ const Group = ({ className="size-4" />
{varItem.name}
-
{varItem.value_type}
+
{formatVarTypeLabel(varItem.value_type)}
))} diff --git a/web/app/components/workflow/variable-inspect/right.tsx b/web/app/components/workflow/variable-inspect/right.tsx index af939d41ea..687d8a8361 100644 --- a/web/app/components/workflow/variable-inspect/right.tsx +++ b/web/app/components/workflow/variable-inspect/right.tsx @@ -34,6 +34,7 @@ import { CodeLanguage } from '../nodes/code/types' import { useStore } from '../store' import { BlockEnum } from '../types' import Empty from './empty' +import { formatVarTypeLabel } from './utils' import ValueContent from './value-content' type Props = { @@ -159,7 +160,13 @@ const Right = ({ handleHidePromptGenerator() }, [setInputs, blockType, nodeId, node?.data, handleHidePromptGenerator]) - const displaySchemaType = currentNodeVar?.var.schemaType ? (`(${currentNodeVar.var.schemaType})`) : '' + const schemaType = currentNodeVar?.var.schemaType + const valueType = currentNodeVar?.var.value_type + const valueTypeLabel = formatVarTypeLabel(valueType) + const shouldShowSchemaType = !!schemaType + && schemaType !== valueType + && schemaType !== valueTypeLabel + const displaySchemaType = shouldShowSchemaType ? (`(${schemaType})`) : '' return (
@@ -198,7 +205,7 @@ const Right = ({ )}
{currentNodeVar.var.name}
- {`${currentNodeVar.var.value_type}${displaySchemaType}`} + {`${valueTypeLabel}${displaySchemaType}`} {isTruncated && ( <> ยท diff --git a/web/app/components/workflow/variable-inspect/utils.tsx b/web/app/components/workflow/variable-inspect/utils.tsx index 482ed46c68..bfeef37a59 100644 --- a/web/app/components/workflow/variable-inspect/utils.tsx +++ b/web/app/components/workflow/variable-inspect/utils.tsx @@ -23,7 +23,7 @@ export const validateJSONSchema = (schema: any, type: string) => { const result = jsonSchema.safeParse(schema) return result } - else if (type === 'array[object]') { + else if (type === 'array[object]' || type === 'array[message]') { const result = arrayJsonSchema.safeParse(schema) return result } @@ -31,3 +31,9 @@ export const validateJSONSchema = (schema: any, type: string) => { return { success: true } as any } } + +export const formatVarTypeLabel = (valueType?: string) => { + if (valueType === 'array[message]') + return 'List[promptMessage]' + return valueType || '' +} diff --git a/web/app/components/workflow/variable-inspect/value-content.tsx b/web/app/components/workflow/variable-inspect/value-content.tsx index 1d4f1cfd13..f2b9df54d3 100644 --- a/web/app/components/workflow/variable-inspect/value-content.tsx +++ b/web/app/components/workflow/variable-inspect/value-content.tsx @@ -46,7 +46,15 @@ const ValueContent = ({ const showBoolEditor = typeof currentVar.value === 'boolean' const showBoolArrayEditor = Array.isArray(currentVar.value) && currentVar.value.every(v => typeof v === 'boolean') const isSysFiles = currentVar.type === VarInInspectType.system && currentVar.name === 'files' - const showJSONEditor = !isSysFiles && (currentVar.value_type === 'object' || currentVar.value_type === 'array[string]' || currentVar.value_type === 'array[number]' || currentVar.value_type === 'array[object]' || currentVar.value_type === 'array[any]') + // FIXME: use enum to instead hardcode string + const showJSONEditor = !isSysFiles && ( + currentVar.value_type === 'object' + || currentVar.value_type === 'array[string]' + || currentVar.value_type === 'array[number]' + || currentVar.value_type === 'array[object]' + || currentVar.value_type === 'array[message]' + || currentVar.value_type === 'array[any]' + ) const showFileEditor = isSysFiles || currentVar.value_type === 'file' || currentVar.value_type === 'array[file]' const textEditorDisabled = currentVar.type === VarInInspectType.environment || (currentVar.type === VarInInspectType.system && currentVar.name !== 'query' && currentVar.name !== 'files') const JSONEditorDisabled = currentVar.value_type === 'array[any]'