mirror of
https://github.com/langgenius/dify.git
synced 2026-05-05 18:08:07 +08:00
feat: enhance start node object value check (#30732)
This commit is contained in:
@ -83,7 +83,7 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||
if (!isJsonObject || !tempPayload.json_schema)
|
||||
return ''
|
||||
try {
|
||||
return JSON.stringify(JSON.parse(tempPayload.json_schema), null, 2)
|
||||
return tempPayload.json_schema
|
||||
}
|
||||
catch {
|
||||
return ''
|
||||
|
||||
@ -37,7 +37,7 @@ export const getProcessedInputs = (inputs: Record<string, any>, inputsForm: Inpu
|
||||
return
|
||||
}
|
||||
|
||||
if (!inputValue)
|
||||
if (inputValue == null)
|
||||
return
|
||||
|
||||
if (item.type === InputVarType.singleFile) {
|
||||
@ -52,6 +52,20 @@ export const getProcessedInputs = (inputs: Record<string, any>, inputsForm: Inpu
|
||||
else
|
||||
processedInputs[item.variable] = getProcessedFiles(inputValue)
|
||||
}
|
||||
else if (item.type === InputVarType.jsonObject) {
|
||||
// Prefer sending an object if the user entered valid JSON; otherwise keep the raw string.
|
||||
try {
|
||||
const v = typeof inputValue === 'string' ? JSON.parse(inputValue) : inputValue
|
||||
if (v && typeof v === 'object' && !Array.isArray(v))
|
||||
processedInputs[item.variable] = v
|
||||
else
|
||||
processedInputs[item.variable] = inputValue
|
||||
}
|
||||
catch {
|
||||
// keep original string; backend will parse/validate
|
||||
processedInputs[item.variable] = inputValue
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return processedInputs
|
||||
|
||||
@ -195,7 +195,7 @@ const RunOnce: FC<IRunOnceProps> = ({
|
||||
noWrapper
|
||||
className="bg h-[80px] overflow-y-auto rounded-[10px] bg-components-input-bg-normal p-1"
|
||||
placeholder={
|
||||
<div className="whitespace-pre">{item.json_schema}</div>
|
||||
<div className="whitespace-pre">{typeof item.json_schema === 'string' ? item.json_schema : JSON.stringify(item.json_schema || '', null, 2)}</div>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
||||
@ -48,6 +48,12 @@ const FormItem: FC<Props> = ({
|
||||
const { t } = useTranslation()
|
||||
const { type } = payload
|
||||
const fileSettings = useHooksStore(s => s.configsMap?.fileSettings)
|
||||
const jsonSchemaPlaceholder = React.useMemo(() => {
|
||||
const schema = (payload as any)?.json_schema
|
||||
if (!schema)
|
||||
return ''
|
||||
return typeof schema === 'string' ? schema : JSON.stringify(schema, null, 2)
|
||||
}, [payload])
|
||||
|
||||
const handleArrayItemChange = useCallback((index: number) => {
|
||||
return (newValue: any) => {
|
||||
@ -211,7 +217,7 @@ const FormItem: FC<Props> = ({
|
||||
noWrapper
|
||||
className="bg h-[80px] overflow-y-auto rounded-[10px] bg-components-input-bg-normal p-1"
|
||||
placeholder={
|
||||
<div className="whitespace-pre">{payload.json_schema}</div>
|
||||
<div className="whitespace-pre">{jsonSchemaPlaceholder}</div>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
||||
@ -353,7 +353,7 @@ const formatItem = (
|
||||
try {
|
||||
if (type === VarType.object && v.json_schema) {
|
||||
varRes.children = {
|
||||
schema: JSON.parse(v.json_schema),
|
||||
schema: typeof v.json_schema === 'string' ? JSON.parse(v.json_schema) : v.json_schema,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -223,7 +223,7 @@ export type InputVar = {
|
||||
getVarValueFromDependent?: boolean
|
||||
hide?: boolean
|
||||
isFileItem?: boolean
|
||||
json_schema?: string // for jsonObject type
|
||||
json_schema?: string | Record<string, any> // for jsonObject type
|
||||
} & Partial<UploadFileSetting>
|
||||
|
||||
export type ModelConfig = {
|
||||
|
||||
@ -62,7 +62,7 @@ export type PromptVariable = {
|
||||
icon?: string
|
||||
icon_background?: string
|
||||
hide?: boolean // used in frontend to hide variable
|
||||
json_schema?: string
|
||||
json_schema?: string | Record<string, any>
|
||||
}
|
||||
|
||||
export type CompletionParams = {
|
||||
|
||||
@ -66,7 +66,30 @@ export const sanitizeWorkflowDraftPayload = (params: WorkflowDraftSyncParams): W
|
||||
if (!graph?.nodes?.length)
|
||||
return params
|
||||
|
||||
const sanitizedNodes = graph.nodes.map(node => sanitizeTriggerPluginNode(node as Node<TriggerPluginNodePayload>))
|
||||
const sanitizedNodes = graph.nodes.map((node) => {
|
||||
// First sanitize known node types (TriggerPlugin)
|
||||
const n = sanitizeTriggerPluginNode(node as Node<TriggerPluginNodePayload>) as Node<any>
|
||||
|
||||
// Normalize Start node variable json_schema: ensure dict, not string
|
||||
if ((n.data as any)?.type === BlockEnum.Start && Array.isArray((n.data as any).variables)) {
|
||||
const next = { ...n, data: { ...n.data } }
|
||||
next.data.variables = (n.data as any).variables.map((v: any) => {
|
||||
if (v && v.type === 'json_object' && typeof v.json_schema === 'string') {
|
||||
try {
|
||||
const obj = JSON.parse(v.json_schema)
|
||||
return { ...v, json_schema: obj }
|
||||
}
|
||||
catch {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return v
|
||||
})
|
||||
return next
|
||||
}
|
||||
|
||||
return n
|
||||
})
|
||||
|
||||
return {
|
||||
...params,
|
||||
@ -126,7 +149,25 @@ export const hydrateWorkflowDraftResponse = (draft: FetchWorkflowDraftResponse):
|
||||
if (node.data)
|
||||
removeTempProperties(node.data as Record<string, unknown>)
|
||||
|
||||
return hydrateTriggerPluginNode(node)
|
||||
let n = hydrateTriggerPluginNode(node)
|
||||
// Normalize Start node variable json_schema to object when loading
|
||||
if ((n.data as any)?.type === BlockEnum.Start && Array.isArray((n.data as any).variables)) {
|
||||
const next = { ...n, data: { ...n.data } } as Node<any>
|
||||
next.data.variables = (n.data as any).variables.map((v: any) => {
|
||||
if (v && v.type === 'json_object' && typeof v.json_schema === 'string') {
|
||||
try {
|
||||
const obj = JSON.parse(v.json_schema)
|
||||
return { ...v, json_schema: obj }
|
||||
}
|
||||
catch {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return v
|
||||
})
|
||||
n = next
|
||||
}
|
||||
return n
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ import type {
|
||||
} from '@/types/workflow'
|
||||
import { get, post } from './base'
|
||||
import { getFlowPrefix } from './utils'
|
||||
import { sanitizeWorkflowDraftPayload } from './workflow-payload'
|
||||
|
||||
export const fetchWorkflowDraft = (url: string) => {
|
||||
return get(url, {}, { silent: true }) as Promise<FetchWorkflowDraftResponse>
|
||||
@ -18,7 +19,8 @@ export const syncWorkflowDraft = ({ url, params }: {
|
||||
url: string
|
||||
params: Pick<FetchWorkflowDraftResponse, 'graph' | 'features' | 'environment_variables' | 'conversation_variables'>
|
||||
}) => {
|
||||
return post<CommonResponse & { updated_at: number, hash: string }>(url, { body: params }, { silent: true })
|
||||
const sanitized = sanitizeWorkflowDraftPayload(params)
|
||||
return post<CommonResponse & { updated_at: number, hash: string }>(url, { body: sanitized }, { silent: true })
|
||||
}
|
||||
|
||||
export const fetchNodesDefaultConfigs = (url: string) => {
|
||||
|
||||
Reference in New Issue
Block a user