@legatoacc3/workflow-builder 0.1.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -0
- package/dist/components/WorkflowBuilder.vue.d.ts +27 -0
- package/dist/components/WorkflowBuilder.vue.d.ts.map +1 -0
- package/dist/contracts.d.ts +28 -0
- package/dist/contracts.d.ts.map +1 -0
- package/dist/domain/builder-node-definition.d.ts +786 -0
- package/dist/domain/builder-node-definition.d.ts.map +1 -0
- package/dist/domain/builder-node-definition.js +1275 -0
- package/dist/domain/builder-node-metadata-response.d.ts +61 -0
- package/dist/domain/builder-node-metadata-response.d.ts.map +1 -0
- package/dist/domain/builder-node-metadata-response.js +0 -0
- package/dist/domain/workflow-draft.d.ts +169 -0
- package/dist/domain/workflow-draft.d.ts.map +1 -0
- package/dist/domain/workflow-draft.js +2115 -0
- package/dist/form-schema/form-schema-editor.d.ts +13 -0
- package/dist/form-schema/form-schema-editor.d.ts.map +1 -0
- package/dist/form-schema/form-schema-editor.js +65 -0
- package/dist/index.d.ts +98 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9298 -0
- package/dist/inspector/BuilderNodeSettingsPanel.vue.d.ts +136 -0
- package/dist/inspector/BuilderNodeSettingsPanel.vue.d.ts.map +1 -0
- package/dist/inspector/builder-node-settings-registry.d.ts +5 -0
- package/dist/inspector/builder-node-settings-registry.d.ts.map +1 -0
- package/dist/inspector/builder-node-settings-registry.js +37 -0
- package/dist/session/create-builder-session.d.ts +27 -0
- package/dist/session/create-builder-session.d.ts.map +1 -0
- package/dist/session/create-builder-session.js +670 -0
- package/dist/workflow-builder.css +112 -0
- package/package.json +71 -0
|
@@ -0,0 +1,2115 @@
|
|
|
1
|
+
import { buildBranchConditionsFromIfElseCases, buildIfElseCasesFromBranchConditions, buildNormalizedBranchConditions, createDefaultNodeConfigurationV2 } from "./builder-node-definition.js";
|
|
2
|
+
import { createWorkflowGraph } from "@legatoacc3/workflow-canvas/graph";
|
|
3
|
+
//#region src/domain/workflow-draft.ts
|
|
4
|
+
var workflowFieldInputTypes = [
|
|
5
|
+
"short-text",
|
|
6
|
+
"long-text",
|
|
7
|
+
"number",
|
|
8
|
+
"date",
|
|
9
|
+
"select",
|
|
10
|
+
"checkbox",
|
|
11
|
+
"email",
|
|
12
|
+
"file",
|
|
13
|
+
"file-list",
|
|
14
|
+
"json_object"
|
|
15
|
+
];
|
|
16
|
+
function mapStartVariableTypeToFormFieldType(type) {
|
|
17
|
+
switch (type) {
|
|
18
|
+
case "paragraph": return "long-text";
|
|
19
|
+
case "number": return "number";
|
|
20
|
+
case "select": return "select";
|
|
21
|
+
case "checkbox": return "checkbox";
|
|
22
|
+
case "file": return "file";
|
|
23
|
+
case "file-list":
|
|
24
|
+
case "files": return "file-list";
|
|
25
|
+
case "json":
|
|
26
|
+
case "json_object": return "json_object";
|
|
27
|
+
default: return "short-text";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function readStartVariableLabel(variable) {
|
|
31
|
+
if (typeof variable.label === "string") return variable.label.trim();
|
|
32
|
+
return variable.label.variable.trim() || variable.label.nodeName.trim() || variable.label.nodeType.trim();
|
|
33
|
+
}
|
|
34
|
+
function buildFormFieldFromStartVariable(variable) {
|
|
35
|
+
const variableName = variable.variable.trim();
|
|
36
|
+
const variableLabel = readStartVariableLabel(variable);
|
|
37
|
+
const options = variable.options;
|
|
38
|
+
return {
|
|
39
|
+
id: variableName || variable.id,
|
|
40
|
+
label: variableLabel || variableName || variable.id,
|
|
41
|
+
type: mapStartVariableTypeToFormFieldType(variable.type),
|
|
42
|
+
helperText: variable.hint?.trim() ?? "",
|
|
43
|
+
required: variable.required,
|
|
44
|
+
placeholder: variable.placeholder?.trim() || void 0,
|
|
45
|
+
options: Array.isArray(options) && options.length > 0 ? options.map((option) => {
|
|
46
|
+
const normalizedOption = option.trim();
|
|
47
|
+
return {
|
|
48
|
+
label: normalizedOption,
|
|
49
|
+
value: normalizedOption
|
|
50
|
+
};
|
|
51
|
+
}) : void 0,
|
|
52
|
+
validation: { maxLength: variable.maxLength }
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function getStartNodeConfiguration(draft) {
|
|
56
|
+
const startNode = draft.graphState.nodes.find((node) => node.data?.kind === "start");
|
|
57
|
+
if (!startNode) return null;
|
|
58
|
+
const config = draft.nodeConfigurations[startNode.id];
|
|
59
|
+
return config?.kind === "start" ? config : null;
|
|
60
|
+
}
|
|
61
|
+
function buildFormSchemaFromStartNode(draft) {
|
|
62
|
+
const startConfig = getStartNodeConfiguration(draft);
|
|
63
|
+
const fallbackSchema = normalizeWorkflowFormSchema(draft.formSchema);
|
|
64
|
+
if (!startConfig) return fallbackSchema;
|
|
65
|
+
const visibleVariables = startConfig.variables.filter((variable) => !variable.hide && variable.variable.trim());
|
|
66
|
+
if (visibleVariables.length === 0) return fallbackSchema;
|
|
67
|
+
return normalizeWorkflowFormSchema({
|
|
68
|
+
title: fallbackSchema.title,
|
|
69
|
+
description: fallbackSchema.description,
|
|
70
|
+
fields: visibleVariables.map(buildFormFieldFromStartVariable)
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function isInternalWorkflowNodeKind(kind) {
|
|
74
|
+
return kind === "note" || kind === "iteration-start" || kind === "loop-start";
|
|
75
|
+
}
|
|
76
|
+
function buildInitialGraphState() {
|
|
77
|
+
return createWorkflowGraph({
|
|
78
|
+
nodes: [],
|
|
79
|
+
edges: []
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function buildInitialFormSchema() {
|
|
83
|
+
return {
|
|
84
|
+
title: "Request form",
|
|
85
|
+
description: "Collect the structured information required to start this workflow.",
|
|
86
|
+
fields: []
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function buildInitialValidationResult() {
|
|
90
|
+
return {
|
|
91
|
+
status: "idle",
|
|
92
|
+
validatedAt: null,
|
|
93
|
+
issues: []
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function normalizeWorkflowFormField(input) {
|
|
97
|
+
return {
|
|
98
|
+
id: input.id,
|
|
99
|
+
label: input.label ?? "",
|
|
100
|
+
type: input.type ?? "short-text",
|
|
101
|
+
helperText: input.helperText ?? "",
|
|
102
|
+
required: Boolean(input.required),
|
|
103
|
+
placeholder: input.placeholder ?? "",
|
|
104
|
+
options: input.options?.map((option) => ({
|
|
105
|
+
label: option.label ?? "",
|
|
106
|
+
value: option.value ?? ""
|
|
107
|
+
})),
|
|
108
|
+
validation: {
|
|
109
|
+
pattern: input.validation?.pattern ?? void 0,
|
|
110
|
+
minLength: input.validation?.minLength ?? void 0,
|
|
111
|
+
maxLength: input.validation?.maxLength ?? void 0,
|
|
112
|
+
min: input.validation?.min ?? void 0,
|
|
113
|
+
max: input.validation?.max ?? void 0
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function normalizeWorkflowFormSchema(input) {
|
|
118
|
+
if (!input) return buildInitialFormSchema();
|
|
119
|
+
return {
|
|
120
|
+
title: input.title?.trim() || "Request form",
|
|
121
|
+
description: input.description?.trim() || "Collect the structured information required to start this workflow.",
|
|
122
|
+
fields: (input.fields ?? []).map((field) => normalizeWorkflowFormField(field))
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
function isRecord(value) {
|
|
126
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
127
|
+
}
|
|
128
|
+
function readRecordProperty(value, key) {
|
|
129
|
+
return isRecord(value) ? value[key] : void 0;
|
|
130
|
+
}
|
|
131
|
+
function normalizeStringValue(value) {
|
|
132
|
+
return typeof value === "string" ? value.trim() : "";
|
|
133
|
+
}
|
|
134
|
+
function normalizeLegacyFieldInputType(value) {
|
|
135
|
+
switch (String(value ?? "").trim().toLowerCase()) {
|
|
136
|
+
case "long-text": return "paragraph";
|
|
137
|
+
case "number": return "number";
|
|
138
|
+
case "select": return "select";
|
|
139
|
+
case "checkbox": return "checkbox";
|
|
140
|
+
case "email":
|
|
141
|
+
case "url": return "url";
|
|
142
|
+
case "file": return "file";
|
|
143
|
+
case "file-list": return "file-list";
|
|
144
|
+
case "contexts": return "contexts";
|
|
145
|
+
case "iterator": return "iterator";
|
|
146
|
+
case "loop": return "loop";
|
|
147
|
+
case "json": return "json";
|
|
148
|
+
default: return "text-input";
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
function normalizeBooleanValue(value, fallback = false) {
|
|
152
|
+
return typeof value === "boolean" ? value : fallback;
|
|
153
|
+
}
|
|
154
|
+
function normalizePositiveNumber(value, fallback) {
|
|
155
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
|
|
156
|
+
}
|
|
157
|
+
function parseOptionalNumber(value) {
|
|
158
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
159
|
+
if (typeof value !== "string") return;
|
|
160
|
+
const normalized = value.trim();
|
|
161
|
+
if (!normalized) return;
|
|
162
|
+
const parsed = Number(normalized);
|
|
163
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
164
|
+
}
|
|
165
|
+
function normalizeSelectorPath(value) {
|
|
166
|
+
if (typeof value === "string") return value.split(".").map((entry) => entry.trim()).filter(Boolean);
|
|
167
|
+
if (Array.isArray(value)) return value.map((entry) => String(entry ?? "").trim()).filter(Boolean);
|
|
168
|
+
if (isRecord(value)) {
|
|
169
|
+
const singleValue = normalizeStringValue(value.name) || normalizeStringValue(value.variable) || normalizeStringValue(value.id);
|
|
170
|
+
return singleValue ? [singleValue] : [];
|
|
171
|
+
}
|
|
172
|
+
return [];
|
|
173
|
+
}
|
|
174
|
+
function deriveVariableNameFromSelector(selector) {
|
|
175
|
+
return selector.map((entry) => entry.trim()).filter(Boolean).at(-1) ?? "";
|
|
176
|
+
}
|
|
177
|
+
function deriveEndOutputNameFromSelector(selector) {
|
|
178
|
+
return selector.map((entry) => entry.trim()).filter(Boolean).join(".");
|
|
179
|
+
}
|
|
180
|
+
function normalizeVariableLabel(value) {
|
|
181
|
+
if (typeof value === "string") return value.trim() || void 0;
|
|
182
|
+
if (!isRecord(value)) return;
|
|
183
|
+
const nodeType = normalizeStringValue(value.nodeType);
|
|
184
|
+
const nodeName = normalizeStringValue(value.nodeName);
|
|
185
|
+
const variable = normalizeStringValue(value.variable);
|
|
186
|
+
if (!nodeType || !nodeName || !variable) return;
|
|
187
|
+
return {
|
|
188
|
+
nodeType,
|
|
189
|
+
nodeName,
|
|
190
|
+
variable,
|
|
191
|
+
isChatVar: typeof value.isChatVar === "boolean" ? value.isChatVar : void 0
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
function normalizeModelReference(value) {
|
|
195
|
+
if (typeof value === "string") return value.trim();
|
|
196
|
+
if (!isRecord(value)) return "";
|
|
197
|
+
const provider = normalizeStringValue(value.provider);
|
|
198
|
+
const name = normalizeStringValue(value.name);
|
|
199
|
+
const model = normalizeStringValue(value.model);
|
|
200
|
+
if (provider && model) return `${provider}/${model}`;
|
|
201
|
+
return model || name;
|
|
202
|
+
}
|
|
203
|
+
function normalizeModelConfig(value) {
|
|
204
|
+
if (typeof value === "string") return {
|
|
205
|
+
provider: "",
|
|
206
|
+
name: value.trim()
|
|
207
|
+
};
|
|
208
|
+
if (!isRecord(value)) return {
|
|
209
|
+
provider: "",
|
|
210
|
+
name: ""
|
|
211
|
+
};
|
|
212
|
+
return {
|
|
213
|
+
provider: normalizeStringValue(value.provider),
|
|
214
|
+
name: normalizeStringValue(value.name ?? value.model ?? value.modelId),
|
|
215
|
+
mode: normalizeStringValue(value.mode) || void 0,
|
|
216
|
+
completion_params: isRecord(value.completion_params ?? value.completionParams) ? structuredClone(value.completion_params ?? value.completionParams) : void 0
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
function normalizeKnowledgeRetrievalRerankingModelConfig(value) {
|
|
220
|
+
if (typeof value === "string") return {
|
|
221
|
+
provider: "",
|
|
222
|
+
model: value.trim()
|
|
223
|
+
};
|
|
224
|
+
if (!isRecord(value)) return {
|
|
225
|
+
provider: "",
|
|
226
|
+
model: ""
|
|
227
|
+
};
|
|
228
|
+
return {
|
|
229
|
+
provider: normalizeStringValue(value.provider),
|
|
230
|
+
model: normalizeStringValue(value.model ?? value.name ?? value.modelId)
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
function normalizeNodeMemoryConfig(value, fallbackWindowSize = 3) {
|
|
234
|
+
if (!isRecord(value)) return {
|
|
235
|
+
enabled: false,
|
|
236
|
+
windowSize: fallbackWindowSize
|
|
237
|
+
};
|
|
238
|
+
return {
|
|
239
|
+
enabled: normalizeBooleanValue(value.enabled, false),
|
|
240
|
+
windowSize: typeof value.windowSize === "number" && Number.isFinite(value.windowSize) ? value.windowSize : typeof value.window_size === "number" && Number.isFinite(value.window_size) ? value.window_size : fallbackWindowSize
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
function normalizeDifyMemoryConfig(value, fallbackWindowSize = 3) {
|
|
244
|
+
const record = isRecord(value) ? value : null;
|
|
245
|
+
const rolePrefix = isRecord(record?.role_prefix) ? record.role_prefix : null;
|
|
246
|
+
const windowConfig = isRecord(record?.window) ? record.window : null;
|
|
247
|
+
const normalizedMemory = windowConfig ? {
|
|
248
|
+
enabled: normalizeBooleanValue(windowConfig.enabled, false),
|
|
249
|
+
windowSize: typeof windowConfig.size === "number" && Number.isFinite(windowConfig.size) ? windowConfig.size : fallbackWindowSize
|
|
250
|
+
} : normalizeNodeMemoryConfig(value, fallbackWindowSize);
|
|
251
|
+
return {
|
|
252
|
+
role_prefix: rolePrefix ? {
|
|
253
|
+
user: normalizeStringValue(rolePrefix.user) || void 0,
|
|
254
|
+
assistant: normalizeStringValue(rolePrefix.assistant) || void 0
|
|
255
|
+
} : void 0,
|
|
256
|
+
window: {
|
|
257
|
+
enabled: normalizedMemory.enabled,
|
|
258
|
+
size: normalizedMemory.windowSize
|
|
259
|
+
},
|
|
260
|
+
query_prompt_template: normalizeStringValue(record?.query_prompt_template) || void 0
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
function normalizeLlmVisionConfig(value) {
|
|
264
|
+
if (!isRecord(value)) return {
|
|
265
|
+
enabled: false,
|
|
266
|
+
configs: {
|
|
267
|
+
variable_selector: [],
|
|
268
|
+
detail: "low"
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
const configs = isRecord(value.configs) ? value.configs : value;
|
|
272
|
+
return {
|
|
273
|
+
enabled: normalizeBooleanValue(value.enabled, false),
|
|
274
|
+
configs: {
|
|
275
|
+
variable_selector: normalizeSelectorPath(configs.variable_selector),
|
|
276
|
+
detail: normalizeStringValue(configs.detail ?? configs.resolution).toLowerCase() === "high" ? "high" : "low"
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
function normalizePromptVariables(value) {
|
|
281
|
+
if (!Array.isArray(value)) return [];
|
|
282
|
+
return value.map((entry, index) => {
|
|
283
|
+
if (isRecord(entry)) {
|
|
284
|
+
const variable = normalizeStringValue(entry.variable ?? entry.name);
|
|
285
|
+
const valueSelector = normalizeSelectorPath(entry.value_selector ?? entry.valueSelector);
|
|
286
|
+
if (!variable) return null;
|
|
287
|
+
return {
|
|
288
|
+
id: normalizeStringValue(entry.id) || `llm-prompt-variable-${index + 1}`,
|
|
289
|
+
variable,
|
|
290
|
+
value_selector: valueSelector,
|
|
291
|
+
label: normalizeStringValue(entry.label) || void 0
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
const variable = normalizeStringValue(entry);
|
|
295
|
+
if (!variable) return null;
|
|
296
|
+
return {
|
|
297
|
+
id: `llm-prompt-variable-${index + 1}`,
|
|
298
|
+
variable,
|
|
299
|
+
value_selector: []
|
|
300
|
+
};
|
|
301
|
+
}).filter((entry) => Boolean(entry));
|
|
302
|
+
}
|
|
303
|
+
function normalizePromptTemplate(value) {
|
|
304
|
+
if (typeof value === "string") return value.trim();
|
|
305
|
+
if (!Array.isArray(value)) return "";
|
|
306
|
+
return value.map((entry) => {
|
|
307
|
+
if (!isRecord(entry)) return "";
|
|
308
|
+
const role = normalizeStringValue(entry.role || entry.type);
|
|
309
|
+
const text = normalizeStringValue(entry.text ?? entry.content);
|
|
310
|
+
if (!text) return "";
|
|
311
|
+
return role ? `[${role}] ${text}` : text;
|
|
312
|
+
}).filter(Boolean).join("\n\n");
|
|
313
|
+
}
|
|
314
|
+
function normalizeKnowledgeRetrievalMetadataConditions(value) {
|
|
315
|
+
const record = isRecord(value) ? value : null;
|
|
316
|
+
const conditions = Array.isArray(record?.conditions) ? record.conditions : [];
|
|
317
|
+
return {
|
|
318
|
+
logical_operator: normalizeStringValue(record?.logical_operator ?? record?.logicalOperator).toLowerCase() === "or" ? "or" : "and",
|
|
319
|
+
conditions: conditions.flatMap((entry, index) => {
|
|
320
|
+
if (!isRecord(entry)) return [];
|
|
321
|
+
return [{
|
|
322
|
+
id: normalizeStringValue(entry.id) || `metadata-condition-${index + 1}`,
|
|
323
|
+
name: normalizeStringValue(entry.name ?? entry.metadata_id),
|
|
324
|
+
metadata_id: normalizeStringValue(entry.metadata_id),
|
|
325
|
+
type: normalizeStringValue(entry.type).toLowerCase() === "number" ? "number" : normalizeStringValue(entry.type).toLowerCase() === "time" ? "time" : normalizeStringValue(entry.type).toLowerCase() === "select" ? "select" : normalizeStringValue(entry.type).toLowerCase() === "string" ? "string" : void 0,
|
|
326
|
+
comparison_operator: normalizeStringValue(entry.comparisonOperator ?? entry.comparison_operator),
|
|
327
|
+
value: typeof entry.value === "number" ? entry.value : normalizeStringValue(entry.value)
|
|
328
|
+
}];
|
|
329
|
+
})
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
function normalizeQuestionClassifierClasses(value) {
|
|
333
|
+
if (!Array.isArray(value)) return [];
|
|
334
|
+
return value.flatMap((entry, index) => {
|
|
335
|
+
if (!isRecord(entry)) return [];
|
|
336
|
+
const label = normalizeStringValue(entry.label ?? entry.description ?? entry.name);
|
|
337
|
+
const name = Object.prototype.hasOwnProperty.call(entry, "name") ? normalizeStringValue(entry.name) : normalizeStringValue(entry.label) || (label ? label.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "") : "");
|
|
338
|
+
return [{
|
|
339
|
+
id: normalizeStringValue(entry.id) || `class-${index + 1}`,
|
|
340
|
+
name,
|
|
341
|
+
label
|
|
342
|
+
}];
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
function normalizeHumanInputDeliveryMethods(value) {
|
|
346
|
+
if (!Array.isArray(value)) return [];
|
|
347
|
+
return value.flatMap((entry, index) => {
|
|
348
|
+
if (!isRecord(entry)) return [];
|
|
349
|
+
const type = normalizeStringValue(entry.type).toLowerCase();
|
|
350
|
+
const normalizedType = type === "email" || type === "slack" || type === "teams" || type === "discord" ? type : "webapp";
|
|
351
|
+
const config = isRecord(entry.config) ? entry.config : null;
|
|
352
|
+
const recipients = isRecord(config?.recipients) ? config?.recipients : null;
|
|
353
|
+
const recipientItems = Array.isArray(recipients?.items) ? recipients.items : [];
|
|
354
|
+
return [{
|
|
355
|
+
id: normalizeStringValue(entry.id) || `human-input-delivery-${index + 1}`,
|
|
356
|
+
type: normalizedType,
|
|
357
|
+
enabled: normalizeBooleanValue(entry.enabled, normalizedType === "webapp"),
|
|
358
|
+
config: normalizedType === "email" ? {
|
|
359
|
+
recipients: {
|
|
360
|
+
whole_workspace: normalizeBooleanValue(recipients?.whole_workspace, false),
|
|
361
|
+
items: recipientItems.flatMap((recipient) => {
|
|
362
|
+
if (!isRecord(recipient)) return [];
|
|
363
|
+
return [{
|
|
364
|
+
type: normalizeStringValue(recipient.type).toLowerCase() === "external" ? "external" : "member",
|
|
365
|
+
email: normalizeStringValue(recipient.email) || void 0,
|
|
366
|
+
user_id: normalizeStringValue(recipient.user_id ?? recipient.userId) || void 0
|
|
367
|
+
}];
|
|
368
|
+
})
|
|
369
|
+
},
|
|
370
|
+
subject: normalizeStringValue(config?.subject),
|
|
371
|
+
body: normalizeStringValue(config?.body),
|
|
372
|
+
debug_mode: normalizeBooleanValue(config?.debug_mode ?? config?.debugMode, false)
|
|
373
|
+
} : void 0
|
|
374
|
+
}];
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
function normalizeHumanInputItems(value) {
|
|
378
|
+
if (!Array.isArray(value)) return [];
|
|
379
|
+
return value.flatMap((entry, index) => {
|
|
380
|
+
if (!isRecord(entry)) return [];
|
|
381
|
+
const defaultValue = isRecord(entry.default) ? entry.default : null;
|
|
382
|
+
const rawType = normalizeStringValue(entry.type);
|
|
383
|
+
return [{
|
|
384
|
+
type: rawType === "text-input" || rawType === "paragraph" || rawType === "select" || rawType === "number" || rawType === "url" || rawType === "file" || rawType === "file-list" || rawType === "json" || rawType === "files" || rawType === "json_object" || rawType === "contexts" || rawType === "iterator" || rawType === "loop" || rawType === "checkbox" ? rawType : "text-input",
|
|
385
|
+
output_variable_name: normalizeStringValue(entry.output_variable_name ?? entry.outputVariableName) || `field_${index + 1}`,
|
|
386
|
+
default: {
|
|
387
|
+
selector: normalizeSelectorPath(defaultValue?.selector),
|
|
388
|
+
type: normalizeStringValue(defaultValue?.type).toLowerCase() === "constant" ? "constant" : "variable",
|
|
389
|
+
value: normalizeStringValue(defaultValue?.value)
|
|
390
|
+
}
|
|
391
|
+
}];
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
function normalizeHumanInputActions(value) {
|
|
395
|
+
if (!Array.isArray(value)) return [];
|
|
396
|
+
return value.flatMap((entry, index) => {
|
|
397
|
+
if (!isRecord(entry)) return [];
|
|
398
|
+
const rawStyle = normalizeStringValue(entry.button_style ?? entry.buttonStyle).toLowerCase();
|
|
399
|
+
const buttonStyle = rawStyle === "primary" || rawStyle === "accent" || rawStyle === "ghost" ? rawStyle : "default";
|
|
400
|
+
return [{
|
|
401
|
+
id: normalizeStringValue(entry.id) || `action_${index + 1}`,
|
|
402
|
+
title: normalizeStringValue(entry.title) || `Button Text ${index + 1}`,
|
|
403
|
+
button_style: buttonStyle
|
|
404
|
+
}];
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
function buildQuestionClassifierConditionalBranches(classes) {
|
|
408
|
+
return classes.map((item, index) => {
|
|
409
|
+
const label = normalizeStringValue(item.label) || `CLASS ${index + 1}`;
|
|
410
|
+
return {
|
|
411
|
+
id: normalizeStringValue(item.id) || `class-${index + 1}`,
|
|
412
|
+
type: "if",
|
|
413
|
+
label,
|
|
414
|
+
description: `${label} branch`
|
|
415
|
+
};
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
function normalizeParameterDataType(value) {
|
|
419
|
+
switch (String(value ?? "").trim().toLowerCase()) {
|
|
420
|
+
case "number": return "number";
|
|
421
|
+
case "select": return "select";
|
|
422
|
+
case "array[number]": return "array[number]";
|
|
423
|
+
case "boolean":
|
|
424
|
+
case "bool": return "boolean";
|
|
425
|
+
case "array[boolean]":
|
|
426
|
+
case "array[bool]": return "array[boolean]";
|
|
427
|
+
case "object": return "object";
|
|
428
|
+
case "array[object]": return "array[object]";
|
|
429
|
+
case "array[string]": return "array[string]";
|
|
430
|
+
case "array": return "array";
|
|
431
|
+
default: return "string";
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
function normalizeParameterOptions(value) {
|
|
435
|
+
if (!Array.isArray(value)) return;
|
|
436
|
+
const options = value.map((entry) => String(entry ?? "").trim()).filter(Boolean);
|
|
437
|
+
return options.length ? options : void 0;
|
|
438
|
+
}
|
|
439
|
+
function normalizeParameterExtractorParameters(value) {
|
|
440
|
+
if (!Array.isArray(value)) return [];
|
|
441
|
+
return value.flatMap((entry, index) => {
|
|
442
|
+
if (!isRecord(entry)) return [];
|
|
443
|
+
return [{
|
|
444
|
+
id: normalizeStringValue(entry.id) || `parameter-${index + 1}`,
|
|
445
|
+
name: normalizeStringValue(entry.name),
|
|
446
|
+
dataType: normalizeParameterDataType(entry.dataType ?? entry.type),
|
|
447
|
+
description: normalizeStringValue(entry.description ?? entry.llm_description),
|
|
448
|
+
required: normalizeBooleanValue(entry.required, false),
|
|
449
|
+
options: normalizeParameterOptions(entry.options)
|
|
450
|
+
}];
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
function normalizeParameterSchemaFields(value) {
|
|
454
|
+
return normalizeParameterExtractorParameters(value);
|
|
455
|
+
}
|
|
456
|
+
function normalizeListOperatorComparisonOperator(value) {
|
|
457
|
+
switch (String(value ?? "").trim().toLowerCase()) {
|
|
458
|
+
case "contains": return "contains";
|
|
459
|
+
case "not contains":
|
|
460
|
+
case "not-contains": return "not-contains";
|
|
461
|
+
case "is":
|
|
462
|
+
case "=":
|
|
463
|
+
case "equal": return "is";
|
|
464
|
+
case "is not":
|
|
465
|
+
case "is-not":
|
|
466
|
+
case "!=":
|
|
467
|
+
case "≠":
|
|
468
|
+
case "not equal": return "is-not";
|
|
469
|
+
case ">":
|
|
470
|
+
case "larger than": return ">";
|
|
471
|
+
case "<":
|
|
472
|
+
case "less than": return "<";
|
|
473
|
+
case ">=":
|
|
474
|
+
case "≥":
|
|
475
|
+
case "larger than or equal": return ">=";
|
|
476
|
+
case "<=":
|
|
477
|
+
case "≤":
|
|
478
|
+
case "less than or equal": return "<=";
|
|
479
|
+
case "empty":
|
|
480
|
+
case "is null": return "empty";
|
|
481
|
+
case "not empty":
|
|
482
|
+
case "is not null": return "not-empty";
|
|
483
|
+
case "exists": return "exists";
|
|
484
|
+
case "not exists":
|
|
485
|
+
case "not-exists": return "not-exists";
|
|
486
|
+
case "in": return "in";
|
|
487
|
+
case "not in":
|
|
488
|
+
case "not-in": return "not-in";
|
|
489
|
+
case "all of":
|
|
490
|
+
case "all-of": return "all-of";
|
|
491
|
+
default: return "contains";
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
function normalizeListOperatorValue(value) {
|
|
495
|
+
if (Array.isArray(value)) return value.map((entry) => String(entry ?? "").trim()).filter(Boolean).join(", ");
|
|
496
|
+
if (typeof value === "boolean" || typeof value === "number") return String(value);
|
|
497
|
+
return normalizeStringValue(value);
|
|
498
|
+
}
|
|
499
|
+
function normalizeDifyResourceConstantValue(value) {
|
|
500
|
+
if (typeof value === "boolean" || typeof value === "number") return value;
|
|
501
|
+
if (Array.isArray(value)) return value.map((entry) => isRecord(entry) ? structuredClone(entry) : entry);
|
|
502
|
+
if (isRecord(value)) return structuredClone(value);
|
|
503
|
+
return normalizeStringValue(value);
|
|
504
|
+
}
|
|
505
|
+
function normalizeAssignerValue(value, inputType) {
|
|
506
|
+
if (inputType === "variable") return normalizeSelectorPath(value);
|
|
507
|
+
if (typeof value === "boolean" || typeof value === "number") return value;
|
|
508
|
+
if (Array.isArray(value)) return value.map((entry) => String(entry ?? "").trim()).filter(Boolean);
|
|
509
|
+
return normalizeStringValue(value);
|
|
510
|
+
}
|
|
511
|
+
function normalizeValueType(value) {
|
|
512
|
+
switch (String(value ?? "").trim().toLowerCase()) {
|
|
513
|
+
case "string": return "string";
|
|
514
|
+
case "number": return "number";
|
|
515
|
+
case "integer": return "integer";
|
|
516
|
+
case "secret": return "secret";
|
|
517
|
+
case "boolean":
|
|
518
|
+
case "bool": return "boolean";
|
|
519
|
+
case "object": return "object";
|
|
520
|
+
case "array": return "array";
|
|
521
|
+
case "array[string]": return "array[string]";
|
|
522
|
+
case "array[number]": return "array[number]";
|
|
523
|
+
case "array[object]": return "array[object]";
|
|
524
|
+
case "array[boolean]":
|
|
525
|
+
case "array[bool]": return "array[boolean]";
|
|
526
|
+
case "array[file]": return "array[file]";
|
|
527
|
+
case "file": return "file";
|
|
528
|
+
default: return "any";
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
function normalizeConcreteValueType(value, fallback = "string") {
|
|
532
|
+
const normalized = normalizeValueType(value);
|
|
533
|
+
return normalized === "any" ? fallback : normalized;
|
|
534
|
+
}
|
|
535
|
+
function normalizeAggregatorOutputType(value) {
|
|
536
|
+
const normalized = normalizeValueType(value);
|
|
537
|
+
if (normalized === "number" || normalized === "boolean" || normalized === "object" || normalized === "array" || normalized === "file") return normalized;
|
|
538
|
+
return "string";
|
|
539
|
+
}
|
|
540
|
+
function normalizeStartVariableOptions(value) {
|
|
541
|
+
if (!Array.isArray(value)) return;
|
|
542
|
+
const options = value.map((entry) => {
|
|
543
|
+
if (isRecord(entry)) return normalizeStringValue(entry.value ?? entry.label);
|
|
544
|
+
return normalizeStringValue(entry);
|
|
545
|
+
}).filter(Boolean);
|
|
546
|
+
return options.length ? options : void 0;
|
|
547
|
+
}
|
|
548
|
+
function normalizeStringArray(value) {
|
|
549
|
+
if (!Array.isArray(value)) return;
|
|
550
|
+
const entries = value.map((entry) => normalizeStringValue(entry)).filter(Boolean);
|
|
551
|
+
return entries.length ? entries : void 0;
|
|
552
|
+
}
|
|
553
|
+
function normalizeStartVariableDefaultValue(value) {
|
|
554
|
+
if (typeof value === "string") return value;
|
|
555
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
556
|
+
if (typeof value === "boolean") return value;
|
|
557
|
+
}
|
|
558
|
+
function normalizeStartVariableType(value) {
|
|
559
|
+
const normalized = normalizeStringValue(value);
|
|
560
|
+
return normalized === "text-input" || normalized === "paragraph" || normalized === "select" || normalized === "number" || normalized === "url" || normalized === "file" || normalized === "file-list" || normalized === "files" || normalized === "json" || normalized === "json_object" || normalized === "contexts" || normalized === "iterator" || normalized === "loop" || normalized === "checkbox" ? normalized : "text-input";
|
|
561
|
+
}
|
|
562
|
+
function normalizeStartVariables(value) {
|
|
563
|
+
if (!Array.isArray(value)) return [];
|
|
564
|
+
return value.flatMap((entry, index) => {
|
|
565
|
+
if (!isRecord(entry)) return [];
|
|
566
|
+
return [{
|
|
567
|
+
id: normalizeStringValue(entry.id) || `start-variable-${index + 1}`,
|
|
568
|
+
variable: normalizeStringValue(entry.variable ?? entry.name),
|
|
569
|
+
label: normalizeVariableLabel(entry.label) || normalizeStringValue(entry.variable ?? entry.name),
|
|
570
|
+
type: normalizeStartVariableType(entry.type),
|
|
571
|
+
required: normalizeBooleanValue(entry.required, false),
|
|
572
|
+
hint: normalizeStringValue(entry.hint ?? entry.helperText) || void 0,
|
|
573
|
+
placeholder: normalizeStringValue(entry.placeholder) || void 0,
|
|
574
|
+
options: normalizeStartVariableOptions(entry.options),
|
|
575
|
+
defaultValue: normalizeStartVariableDefaultValue(entry.default ?? entry.defaultValue),
|
|
576
|
+
maxLength: typeof entry.max_length === "number" && Number.isFinite(entry.max_length) ? entry.max_length : typeof entry.maxLength === "number" && Number.isFinite(entry.maxLength) ? entry.maxLength : void 0,
|
|
577
|
+
unit: normalizeStringValue(entry.unit) || void 0,
|
|
578
|
+
value_selector: normalizeSelectorPath(entry.value_selector ?? entry.valueSelector),
|
|
579
|
+
getVarValueFromDependent: normalizeBooleanValue(entry.getVarValueFromDependent, false),
|
|
580
|
+
hide: normalizeBooleanValue(entry.hide, false),
|
|
581
|
+
isFileItem: normalizeBooleanValue(entry.isFileItem, false),
|
|
582
|
+
json_schema: typeof entry.json_schema === "string" ? entry.json_schema : isRecord(entry.json_schema) ? structuredClone(entry.json_schema) : void 0,
|
|
583
|
+
allowed_file_upload_methods: normalizeStringArray(entry.allowed_file_upload_methods),
|
|
584
|
+
allowed_upload_methods: normalizeStringArray(entry.allowed_upload_methods),
|
|
585
|
+
allowed_file_types: normalizeStringArray(entry.allowed_file_types),
|
|
586
|
+
allowed_file_extensions: normalizeStringArray(entry.allowed_file_extensions),
|
|
587
|
+
number_limits: typeof entry.number_limits === "number" && Number.isFinite(entry.number_limits) ? entry.number_limits : void 0
|
|
588
|
+
}];
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
function normalizeLegacyStartFieldVariables(value) {
|
|
592
|
+
if (!Array.isArray(value)) return [];
|
|
593
|
+
return value.flatMap((entry, index) => {
|
|
594
|
+
if (!isRecord(entry)) return [];
|
|
595
|
+
const validation = isRecord(entry.validation) ? entry.validation : null;
|
|
596
|
+
return [{
|
|
597
|
+
id: normalizeStringValue(entry.id) || `start-variable-${index + 1}`,
|
|
598
|
+
variable: normalizeStringValue(entry.variableName ?? entry.variable ?? entry.name),
|
|
599
|
+
label: normalizeVariableLabel(entry.label) || normalizeStringValue(entry.variableName ?? entry.variable ?? entry.name),
|
|
600
|
+
type: normalizeLegacyFieldInputType(entry.type),
|
|
601
|
+
required: normalizeBooleanValue(entry.required, false),
|
|
602
|
+
hint: normalizeStringValue(entry.helperText ?? entry.hint) || void 0,
|
|
603
|
+
placeholder: normalizeStringValue(entry.placeholder) || void 0,
|
|
604
|
+
options: normalizeStartVariableOptions(entry.options),
|
|
605
|
+
defaultValue: normalizeStartVariableDefaultValue(entry.default ?? entry.defaultValue),
|
|
606
|
+
maxLength: typeof entry.max_length === "number" && Number.isFinite(entry.max_length) ? entry.max_length : typeof entry.maxLength === "number" && Number.isFinite(entry.maxLength) ? entry.maxLength : typeof validation?.maxLength === "number" && Number.isFinite(validation.maxLength) ? validation.maxLength : void 0,
|
|
607
|
+
unit: normalizeStringValue(entry.unit) || void 0,
|
|
608
|
+
value_selector: normalizeSelectorPath(entry.value_selector ?? entry.valueSelector),
|
|
609
|
+
getVarValueFromDependent: normalizeBooleanValue(entry.getVarValueFromDependent, false),
|
|
610
|
+
hide: normalizeBooleanValue(entry.hide, false),
|
|
611
|
+
isFileItem: normalizeBooleanValue(entry.isFileItem, false),
|
|
612
|
+
json_schema: typeof entry.json_schema === "string" ? entry.json_schema : isRecord(entry.json_schema) ? structuredClone(entry.json_schema) : void 0,
|
|
613
|
+
allowed_file_upload_methods: normalizeStringArray(entry.allowed_file_upload_methods),
|
|
614
|
+
allowed_upload_methods: normalizeStringArray(entry.allowed_upload_methods),
|
|
615
|
+
allowed_file_types: normalizeStringArray(entry.allowed_file_types),
|
|
616
|
+
allowed_file_extensions: normalizeStringArray(entry.allowed_file_extensions),
|
|
617
|
+
number_limits: typeof entry.number_limits === "number" && Number.isFinite(entry.number_limits) ? entry.number_limits : void 0
|
|
618
|
+
}];
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
function normalizeWebhookVariableType(value) {
|
|
622
|
+
switch (String(value ?? "").trim().toLowerCase()) {
|
|
623
|
+
case "number": return "number";
|
|
624
|
+
case "boolean":
|
|
625
|
+
case "bool": return "boolean";
|
|
626
|
+
case "object":
|
|
627
|
+
case "json": return "object";
|
|
628
|
+
case "array": return "array";
|
|
629
|
+
case "file":
|
|
630
|
+
case "files": return "file";
|
|
631
|
+
default: return "string";
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
function normalizeWebhookParameters(value) {
|
|
635
|
+
if (!Array.isArray(value)) return [];
|
|
636
|
+
return value.flatMap((entry, index) => {
|
|
637
|
+
if (!isRecord(entry)) return [];
|
|
638
|
+
return [{
|
|
639
|
+
id: normalizeStringValue(entry.id) || `webhook-variable-${index + 1}`,
|
|
640
|
+
name: normalizeStringValue(entry.name),
|
|
641
|
+
required: normalizeBooleanValue(entry.required, false),
|
|
642
|
+
type: normalizeWebhookVariableType(entry.type ?? entry.dataType)
|
|
643
|
+
}];
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
function normalizeWebhookHeaders(value) {
|
|
647
|
+
if (!Array.isArray(value)) return [];
|
|
648
|
+
return value.flatMap((entry, index) => {
|
|
649
|
+
if (!isRecord(entry)) return [];
|
|
650
|
+
return [{
|
|
651
|
+
id: normalizeStringValue(entry.id) || `webhook-header-${index + 1}`,
|
|
652
|
+
name: normalizeStringValue(entry.name),
|
|
653
|
+
required: normalizeBooleanValue(entry.required, false)
|
|
654
|
+
}];
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
function normalizeHttpMethod(value) {
|
|
658
|
+
switch (String(value ?? "").trim().toLowerCase()) {
|
|
659
|
+
case "get":
|
|
660
|
+
case "post":
|
|
661
|
+
case "put":
|
|
662
|
+
case "patch":
|
|
663
|
+
case "delete":
|
|
664
|
+
case "head": return String(value).trim().toLowerCase();
|
|
665
|
+
default: return "get";
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
function normalizeWebhookMethod(value) {
|
|
669
|
+
switch (String(value ?? "").trim().toUpperCase()) {
|
|
670
|
+
case "GET":
|
|
671
|
+
case "POST":
|
|
672
|
+
case "PUT":
|
|
673
|
+
case "PATCH":
|
|
674
|
+
case "DELETE":
|
|
675
|
+
case "HEAD": return String(value).trim().toUpperCase();
|
|
676
|
+
default: return "POST";
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
function normalizeWebhookContentType(value) {
|
|
680
|
+
const normalized = normalizeStringValue(value);
|
|
681
|
+
switch (normalized) {
|
|
682
|
+
case "application/json":
|
|
683
|
+
case "application/x-www-form-urlencoded":
|
|
684
|
+
case "text/plain":
|
|
685
|
+
case "application/octet-stream":
|
|
686
|
+
case "multipart/form-data": return normalized;
|
|
687
|
+
default: return "application/json";
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
function normalizeHttpKeyValueEntries(value, fallbackPrefix) {
|
|
691
|
+
if (Array.isArray(value)) return value.flatMap((entry, index) => {
|
|
692
|
+
if (!isRecord(entry)) return [];
|
|
693
|
+
return [{
|
|
694
|
+
id: normalizeStringValue(entry.id) || `${fallbackPrefix}-${index + 1}`,
|
|
695
|
+
key: normalizeStringValue(entry.key ?? entry.name),
|
|
696
|
+
value: normalizeListOperatorValue(entry.value),
|
|
697
|
+
type: normalizeStringValue(entry.type) === "secret" ? "secret" : normalizeStringValue(entry.type) === "variable" ? "variable" : void 0,
|
|
698
|
+
file: normalizeSelectorPath(entry.file ?? entry.fileVariable)
|
|
699
|
+
}];
|
|
700
|
+
});
|
|
701
|
+
if (typeof value === "string") return value.split("\n").map((line) => line.trim()).filter(Boolean).map((line, index) => {
|
|
702
|
+
const separatorIndex = line.indexOf(":");
|
|
703
|
+
const key = separatorIndex >= 0 ? line.slice(0, separatorIndex) : line;
|
|
704
|
+
const rawValue = separatorIndex >= 0 ? line.slice(separatorIndex + 1) : "";
|
|
705
|
+
return {
|
|
706
|
+
id: `${fallbackPrefix}-${index + 1}`,
|
|
707
|
+
key: key.trim(),
|
|
708
|
+
value: rawValue.trim()
|
|
709
|
+
};
|
|
710
|
+
});
|
|
711
|
+
return [];
|
|
712
|
+
}
|
|
713
|
+
function normalizeHttpBodyType(value) {
|
|
714
|
+
switch (String(value ?? "").trim().toLowerCase()) {
|
|
715
|
+
case "form-data": return "form-data";
|
|
716
|
+
case "x-www-form-urlencoded": return "x-www-form-urlencoded";
|
|
717
|
+
case "raw-text": return "raw-text";
|
|
718
|
+
case "binary": return "binary";
|
|
719
|
+
case "json": return "json";
|
|
720
|
+
default: return "none";
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
function normalizeHttpBodyPayloadEntries(value) {
|
|
724
|
+
if (!Array.isArray(value)) return [];
|
|
725
|
+
return value.flatMap((entry, index) => {
|
|
726
|
+
if (!isRecord(entry)) return [];
|
|
727
|
+
return [{
|
|
728
|
+
id: normalizeStringValue(entry.id) || `body-entry-${index + 1}`,
|
|
729
|
+
key: normalizeStringValue(entry.key),
|
|
730
|
+
type: normalizeStringValue(entry.type) === "file" ? "file" : "text",
|
|
731
|
+
value: normalizeListOperatorValue(entry.value) || void 0,
|
|
732
|
+
file: normalizeSelectorPath(entry.file ?? entry.fileVariable)
|
|
733
|
+
}];
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
function normalizeRecordEntries(value) {
|
|
737
|
+
if (!isRecord(value)) return [];
|
|
738
|
+
return Object.entries(value).map(([key, entry], index) => {
|
|
739
|
+
const normalizedEntry = isRecord(entry) ? entry : null;
|
|
740
|
+
const normalizedValueType = normalizeStringValue(normalizedEntry?.type ?? normalizedEntry?.valueType) === "variable" ? "variable" : "constant";
|
|
741
|
+
const rawValue = normalizedEntry && "value" in normalizedEntry ? normalizedEntry.value : entry;
|
|
742
|
+
const normalizedValue = normalizedValueType === "variable" ? normalizeSelectorPath(rawValue) : normalizeDifyResourceConstantValue(rawValue);
|
|
743
|
+
return {
|
|
744
|
+
id: `${key || "entry"}-${index + 1}`,
|
|
745
|
+
name: key,
|
|
746
|
+
valueType: normalizedValueType,
|
|
747
|
+
value: normalizedValue
|
|
748
|
+
};
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
function normalizeToolProviderType(value) {
|
|
752
|
+
const normalizedValue = normalizeStringValue(value);
|
|
753
|
+
return normalizedValue === "builtin" || normalizedValue === "custom" || normalizedValue === "workflow" || normalizedValue === "mcp" ? normalizedValue : "";
|
|
754
|
+
}
|
|
755
|
+
function normalizeTriggerPluginProviderType(value) {
|
|
756
|
+
return normalizeToolProviderType(value);
|
|
757
|
+
}
|
|
758
|
+
function normalizeResourceParameters(value) {
|
|
759
|
+
return Object.fromEntries(normalizeRecordEntries(value).filter((entry) => entry.name.trim()).map((entry) => [entry.name, {
|
|
760
|
+
type: entry.valueType,
|
|
761
|
+
value: entry.value
|
|
762
|
+
}]));
|
|
763
|
+
}
|
|
764
|
+
function normalizeResourceConfigurations(value) {
|
|
765
|
+
if (Array.isArray(value)) return Object.fromEntries(value.flatMap((entry, index) => {
|
|
766
|
+
if (!isRecord(entry)) return [];
|
|
767
|
+
return [[normalizeStringValue(entry.name) || `config_${index + 1}`, normalizeDifyResourceConstantValue(entry.value)]];
|
|
768
|
+
}));
|
|
769
|
+
return isRecord(value) ? structuredClone(value) : {};
|
|
770
|
+
}
|
|
771
|
+
function normalizeFileExtensions(value) {
|
|
772
|
+
if (Array.isArray(value)) return value.map((entry) => normalizeStringValue(entry)).filter(Boolean);
|
|
773
|
+
return normalizeStringValue(value).split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
774
|
+
}
|
|
775
|
+
function normalizeKnowledgeBaseChunkStructure(value) {
|
|
776
|
+
const normalized = normalizeStringValue(value);
|
|
777
|
+
return normalized === "text_model" || normalized === "hierarchical_model" || normalized === "qa_model" ? normalized : void 0;
|
|
778
|
+
}
|
|
779
|
+
function normalizeKnowledgeBaseRetrievalModel(value, fallback) {
|
|
780
|
+
const raw = isRecord(value) ? value : null;
|
|
781
|
+
const rawRerankingModel = isRecord(raw?.reranking_model) ? raw?.reranking_model : null;
|
|
782
|
+
return {
|
|
783
|
+
search_method: normalizeStringValue(raw?.search_method) || void 0,
|
|
784
|
+
reranking_enable: normalizeBooleanValue(raw?.reranking_enable, false),
|
|
785
|
+
reranking_model: rawRerankingModel ? {
|
|
786
|
+
reranking_provider_name: normalizeStringValue(rawRerankingModel.reranking_provider_name),
|
|
787
|
+
reranking_model_name: normalizeStringValue(rawRerankingModel.reranking_model_name)
|
|
788
|
+
} : void 0,
|
|
789
|
+
weights: isRecord(raw?.weights) ? structuredClone(raw.weights) : void 0,
|
|
790
|
+
top_k: normalizePositiveNumber(raw?.top_k, fallback.top_k),
|
|
791
|
+
score_threshold_enabled: normalizeBooleanValue(raw?.score_threshold_enabled, fallback.score_threshold_enabled),
|
|
792
|
+
score_threshold: typeof raw?.score_threshold === "number" && Number.isFinite(raw.score_threshold) ? raw.score_threshold : fallback.score_threshold,
|
|
793
|
+
reranking_mode: normalizeStringValue(raw?.reranking_mode) || void 0
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
function normalizeToolConfigurationEntries(value) {
|
|
797
|
+
if (Array.isArray(value)) return value.map((entry, index) => ({
|
|
798
|
+
id: normalizeStringValue(isRecord(entry) ? entry.id : void 0) || `tool-config-${index + 1}`,
|
|
799
|
+
name: normalizeStringValue(isRecord(entry) ? entry.name : void 0),
|
|
800
|
+
value: normalizeDifyResourceConstantValue(isRecord(entry) ? entry.value : entry)
|
|
801
|
+
}));
|
|
802
|
+
return normalizeRecordEntries(value).map((entry, index) => ({
|
|
803
|
+
id: entry.id || `tool-config-${index + 1}`,
|
|
804
|
+
name: entry.name,
|
|
805
|
+
value: Array.isArray(entry.value) ? structuredClone(entry.value) : entry.value
|
|
806
|
+
}));
|
|
807
|
+
}
|
|
808
|
+
function normalizeVariableAggregatorGroups(value) {
|
|
809
|
+
if (!Array.isArray(value)) return [];
|
|
810
|
+
return value.flatMap((entry, index) => {
|
|
811
|
+
if (!isRecord(entry)) return [];
|
|
812
|
+
const rawVariables = entry.variables ?? entry.sourceVariables;
|
|
813
|
+
const hasExplicitGroupName = Object.prototype.hasOwnProperty.call(entry, "groupName") || Object.prototype.hasOwnProperty.call(entry, "group_name") || Object.prototype.hasOwnProperty.call(entry, "outputVariable");
|
|
814
|
+
const variables = Array.isArray(rawVariables) ? rawVariables.map((variable) => normalizeSelectorPath(variable)) : [];
|
|
815
|
+
return [{
|
|
816
|
+
groupId: normalizeStringValue(entry.id ?? entry.groupId) || `group-${index + 1}`,
|
|
817
|
+
group_name: hasExplicitGroupName ? normalizeStringValue(entry.groupName ?? entry.group_name ?? entry.outputVariable) : `group_${index + 1}`,
|
|
818
|
+
output_type: normalizeAggregatorOutputType(entry.valueType ?? entry.output_type),
|
|
819
|
+
variables
|
|
820
|
+
}];
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
function normalizeLoopVariables(value) {
|
|
824
|
+
if (!Array.isArray(value)) return [];
|
|
825
|
+
return value.flatMap((entry, index) => {
|
|
826
|
+
if (!isRecord(entry)) return [];
|
|
827
|
+
return [{
|
|
828
|
+
id: normalizeStringValue(entry.id) || `loop-variable-${index + 1}`,
|
|
829
|
+
name: normalizeStringValue(entry.name ?? entry.label),
|
|
830
|
+
dataType: normalizeConcreteValueType(entry.dataType ?? entry.var_type),
|
|
831
|
+
valueType: normalizeStringValue(entry.valueType ?? entry.value_type) === "variable" ? "variable" : "constant",
|
|
832
|
+
value: normalizeStringValue(entry.valueType ?? entry.value_type) === "variable" ? normalizeSelectorPath(entry.value) : typeof entry.value === "boolean" || typeof entry.value === "number" ? entry.value : Array.isArray(entry.value) ? entry.value.map((item) => String(item ?? "").trim()).filter(Boolean) : isRecord(entry) && "value" in entry ? normalizeListOperatorValue(entry.value) : ""
|
|
833
|
+
}];
|
|
834
|
+
});
|
|
835
|
+
}
|
|
836
|
+
function normalizeOutputSchema(value) {
|
|
837
|
+
if (Array.isArray(value)) return value.flatMap((entry, index) => {
|
|
838
|
+
if (!isRecord(entry)) return [];
|
|
839
|
+
return [{
|
|
840
|
+
id: normalizeStringValue(entry.id) || `output-${index + 1}`,
|
|
841
|
+
name: normalizeStringValue(entry.name ?? entry.variable),
|
|
842
|
+
type: normalizeParameterDataType(entry.type),
|
|
843
|
+
description: normalizeStringValue(entry.description)
|
|
844
|
+
}];
|
|
845
|
+
});
|
|
846
|
+
if (!isRecord(value)) return [];
|
|
847
|
+
const schemaProperties = isRecord(value.properties) ? value.properties : value;
|
|
848
|
+
return Object.entries(schemaProperties).map(([key, entry], index) => ({
|
|
849
|
+
id: `${key || "output"}-${index + 1}`,
|
|
850
|
+
name: key,
|
|
851
|
+
type: normalizeParameterDataType(isRecord(entry) ? entry.type : void 0),
|
|
852
|
+
description: normalizeStringValue(isRecord(entry) ? entry.description : void 0)
|
|
853
|
+
}));
|
|
854
|
+
}
|
|
855
|
+
function buildPublishedOutputSchema(fields) {
|
|
856
|
+
return {
|
|
857
|
+
type: "object",
|
|
858
|
+
properties: Object.fromEntries(fields.filter((field) => field.name.trim()).map((field) => [field.name, {
|
|
859
|
+
type: normalizeParameterDataType(field.type),
|
|
860
|
+
...field.description.trim() ? { description: field.description.trim() } : {}
|
|
861
|
+
}]))
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
function normalizeScheduleFrequency(value) {
|
|
865
|
+
switch (normalizeStringValue(value).toLowerCase()) {
|
|
866
|
+
case "hourly":
|
|
867
|
+
case "weekly":
|
|
868
|
+
case "monthly": return normalizeStringValue(value).toLowerCase();
|
|
869
|
+
default: return "daily";
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
function normalizeScheduleVisualConfig(value) {
|
|
873
|
+
if (!isRecord(value)) return {
|
|
874
|
+
time: "09:00",
|
|
875
|
+
weekdays: ["1"],
|
|
876
|
+
onMinute: 0,
|
|
877
|
+
monthlyDays: [1]
|
|
878
|
+
};
|
|
879
|
+
return {
|
|
880
|
+
time: normalizeStringValue(value.time) || void 0,
|
|
881
|
+
weekdays: Array.isArray(value.weekdays) ? value.weekdays.map((entry) => normalizeStringValue(entry)).filter(Boolean) : void 0,
|
|
882
|
+
onMinute: typeof value.on_minute === "number" && Number.isFinite(value.on_minute) ? value.on_minute : typeof value.onMinute === "number" && Number.isFinite(value.onMinute) ? value.onMinute : void 0,
|
|
883
|
+
monthlyDays: Array.isArray(value.monthly_days) ? value.monthly_days.flatMap((entry) => entry === "last" || typeof entry === "number" && Number.isFinite(entry) ? [entry] : []) : Array.isArray(value.monthlyDays) ? value.monthlyDays.flatMap((entry) => entry === "last" || typeof entry === "number" && Number.isFinite(entry) ? [entry] : []) : void 0
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
function normalizeTemplateVariables(value) {
|
|
887
|
+
if (!Array.isArray(value)) return [];
|
|
888
|
+
return value.flatMap((entry, index) => {
|
|
889
|
+
if (!isRecord(entry)) return [];
|
|
890
|
+
return [{
|
|
891
|
+
id: normalizeStringValue(entry.id) || `template-variable-${index + 1}`,
|
|
892
|
+
variable: normalizeStringValue(entry.variable ?? entry.name),
|
|
893
|
+
value_selector: normalizeSelectorPath(entry.value_selector ?? entry.valueSelector ?? entry.value),
|
|
894
|
+
label: normalizeVariableLabel(entry.label),
|
|
895
|
+
value_type: normalizeWebhookVariableType(entry.value_type ?? entry.valueType),
|
|
896
|
+
variable_type: normalizeStringValue(entry.variable_type ?? entry.variableType) || void 0,
|
|
897
|
+
value: normalizeStringValue(entry.value),
|
|
898
|
+
options: normalizeStartVariableOptions(entry.options),
|
|
899
|
+
required: normalizeBooleanValue(entry.required, false),
|
|
900
|
+
isParagraph: normalizeBooleanValue(entry.isParagraph, false)
|
|
901
|
+
}];
|
|
902
|
+
});
|
|
903
|
+
}
|
|
904
|
+
function normalizeCodeLanguage(value) {
|
|
905
|
+
return normalizeStringValue(value).toLowerCase() === "javascript" ? "javascript" : "python";
|
|
906
|
+
}
|
|
907
|
+
function normalizeCodeInputVariables(value) {
|
|
908
|
+
if (Array.isArray(value)) return value.map((entry) => {
|
|
909
|
+
if (isRecord(entry)) return normalizeStringValue(entry.name ?? entry.variable);
|
|
910
|
+
return normalizeStringValue(entry);
|
|
911
|
+
}).filter(Boolean);
|
|
912
|
+
return [];
|
|
913
|
+
}
|
|
914
|
+
function normalizeCodeVariables(value) {
|
|
915
|
+
if (!Array.isArray(value)) return [];
|
|
916
|
+
return value.flatMap((entry, index) => {
|
|
917
|
+
if (!isRecord(entry)) return [];
|
|
918
|
+
const variable = normalizeStringValue(entry.variable ?? entry.name);
|
|
919
|
+
if (!variable) return [];
|
|
920
|
+
return [{
|
|
921
|
+
id: normalizeStringValue(entry.id) || `code-variable-${index + 1}`,
|
|
922
|
+
variable,
|
|
923
|
+
value_selector: normalizeSelectorPath(entry.value_selector ?? entry.valueSelector ?? variable)
|
|
924
|
+
}];
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
function normalizeCodeOutputVariables(value) {
|
|
928
|
+
if (Array.isArray(value)) return value.flatMap((entry, index) => {
|
|
929
|
+
if (!isRecord(entry)) return [];
|
|
930
|
+
return [{
|
|
931
|
+
id: normalizeStringValue(entry.id) || `output-${index + 1}`,
|
|
932
|
+
name: normalizeStringValue(entry.name ?? entry.variable),
|
|
933
|
+
dataType: normalizeParameterDataType(entry.dataType ?? entry.type)
|
|
934
|
+
}];
|
|
935
|
+
});
|
|
936
|
+
if (!isRecord(value)) return [];
|
|
937
|
+
return Object.entries(value).map(([key, entry], index) => ({
|
|
938
|
+
id: `${key || "output"}-${index + 1}`,
|
|
939
|
+
name: key,
|
|
940
|
+
dataType: normalizeParameterDataType(isRecord(entry) ? entry.type : void 0)
|
|
941
|
+
}));
|
|
942
|
+
}
|
|
943
|
+
function normalizeEndOutputs(value) {
|
|
944
|
+
if (Array.isArray(value)) return value.flatMap((entry, index) => {
|
|
945
|
+
if (!isRecord(entry)) return [];
|
|
946
|
+
const selector = normalizeSelectorPath(entry.valueSelector ?? entry.value_selector ?? entry.sourceVariable ?? entry.source_variable);
|
|
947
|
+
const variable = normalizeStringValue(entry.variable) || normalizeStringValue(entry.outputName ?? entry.name) || deriveEndOutputNameFromSelector(selector);
|
|
948
|
+
return [{
|
|
949
|
+
id: normalizeStringValue(entry.id) || `output-${index + 1}`,
|
|
950
|
+
variable,
|
|
951
|
+
value_selector: selector,
|
|
952
|
+
label: normalizeVariableLabel(entry.label),
|
|
953
|
+
value_type: normalizeWebhookVariableType(entry.value_type ?? entry.valueType),
|
|
954
|
+
required: normalizeBooleanValue(entry.required, false)
|
|
955
|
+
}];
|
|
956
|
+
});
|
|
957
|
+
return [];
|
|
958
|
+
}
|
|
959
|
+
function normalizeDifyVariables(value, fallbackPrefix) {
|
|
960
|
+
if (Array.isArray(value)) return value.flatMap((entry, index) => {
|
|
961
|
+
if (!isRecord(entry)) return [];
|
|
962
|
+
const selector = normalizeSelectorPath(entry.valueSelector ?? entry.value_selector ?? entry.sourceVariable ?? entry.source_variable);
|
|
963
|
+
const variable = normalizeStringValue(entry.variable ?? entry.name ?? entry.outputName) || deriveVariableNameFromSelector(selector);
|
|
964
|
+
if (!variable) return [];
|
|
965
|
+
return [{
|
|
966
|
+
id: normalizeStringValue(entry.id) || `${fallbackPrefix}-${index + 1}`,
|
|
967
|
+
variable,
|
|
968
|
+
value_selector: selector,
|
|
969
|
+
label: normalizeVariableLabel(entry.label),
|
|
970
|
+
value_type: normalizeWebhookVariableType(entry.value_type ?? entry.valueType),
|
|
971
|
+
required: normalizeBooleanValue(entry.required, false)
|
|
972
|
+
}];
|
|
973
|
+
});
|
|
974
|
+
return [];
|
|
975
|
+
}
|
|
976
|
+
var WEBHOOK_RAW_VARIABLE_NAME = "_webhook_raw";
|
|
977
|
+
function normalizeWebhookVariableKey(name, sourceType) {
|
|
978
|
+
return sourceType === "header" ? name.replace(/-/g, "_") : name;
|
|
979
|
+
}
|
|
980
|
+
function normalizeWebhookVariables(value, params, headers, body) {
|
|
981
|
+
const rawVariable = {
|
|
982
|
+
id: "webhook-raw",
|
|
983
|
+
variable: WEBHOOK_RAW_VARIABLE_NAME,
|
|
984
|
+
label: "raw",
|
|
985
|
+
value_selector: [],
|
|
986
|
+
value_type: "object",
|
|
987
|
+
required: true
|
|
988
|
+
};
|
|
989
|
+
const existing = Array.isArray(value) ? value.flatMap((entry, index) => {
|
|
990
|
+
if (!isRecord(entry)) return [];
|
|
991
|
+
const variable = normalizeStringValue(entry.variable ?? entry.name);
|
|
992
|
+
if (!variable) return [];
|
|
993
|
+
return [{
|
|
994
|
+
id: normalizeStringValue(entry.id) || `webhook-existing-${index + 1}`,
|
|
995
|
+
variable,
|
|
996
|
+
label: normalizeVariableLabel(entry.label),
|
|
997
|
+
value_selector: normalizeSelectorPath(entry.value_selector ?? entry.valueSelector),
|
|
998
|
+
value_type: normalizeWebhookVariableType(entry.value_type ?? entry.valueType),
|
|
999
|
+
required: normalizeBooleanValue(entry.required, false)
|
|
1000
|
+
}];
|
|
1001
|
+
}) : [];
|
|
1002
|
+
const existingByVariable = new Map(existing.map((entry) => [entry.variable, entry]));
|
|
1003
|
+
const mapped = [
|
|
1004
|
+
...params.map((entry, index) => {
|
|
1005
|
+
const variable = normalizeWebhookVariableKey(entry.name, "param");
|
|
1006
|
+
const existingEntry = existingByVariable.get(variable);
|
|
1007
|
+
return {
|
|
1008
|
+
id: existingEntry?.id || `webhook-param-${index + 1}`,
|
|
1009
|
+
variable,
|
|
1010
|
+
label: "param",
|
|
1011
|
+
value_selector: existingEntry?.value_selector ?? [],
|
|
1012
|
+
value_type: entry.type,
|
|
1013
|
+
required: entry.required
|
|
1014
|
+
};
|
|
1015
|
+
}),
|
|
1016
|
+
...headers.map((entry, index) => {
|
|
1017
|
+
const variable = normalizeWebhookVariableKey(entry.name, "header");
|
|
1018
|
+
const existingEntry = existingByVariable.get(variable);
|
|
1019
|
+
return {
|
|
1020
|
+
id: existingEntry?.id || `webhook-header-${index + 1}`,
|
|
1021
|
+
variable,
|
|
1022
|
+
label: "header",
|
|
1023
|
+
value_selector: existingEntry?.value_selector ?? [],
|
|
1024
|
+
value_type: "string",
|
|
1025
|
+
required: entry.required
|
|
1026
|
+
};
|
|
1027
|
+
}),
|
|
1028
|
+
...body.map((entry, index) => {
|
|
1029
|
+
const variable = normalizeWebhookVariableKey(entry.name, "body");
|
|
1030
|
+
const existingEntry = existingByVariable.get(variable);
|
|
1031
|
+
return {
|
|
1032
|
+
id: existingEntry?.id || `webhook-body-${index + 1}`,
|
|
1033
|
+
variable,
|
|
1034
|
+
label: "body",
|
|
1035
|
+
value_selector: existingEntry?.value_selector ?? [],
|
|
1036
|
+
value_type: entry.type,
|
|
1037
|
+
required: entry.required
|
|
1038
|
+
};
|
|
1039
|
+
})
|
|
1040
|
+
];
|
|
1041
|
+
return existing.some((entry) => entry.variable === WEBHOOK_RAW_VARIABLE_NAME) ? [...mapped, existingByVariable.get(WEBHOOK_RAW_VARIABLE_NAME) ?? rawVariable] : [...mapped, rawVariable];
|
|
1042
|
+
}
|
|
1043
|
+
function normalizeNodeConfigurationByKind(kind, value) {
|
|
1044
|
+
const defaultConfig = structuredClone(createDefaultNodeConfigurationV2(kind) ?? createDefaultNodeConfigurationV2("note"));
|
|
1045
|
+
if (!isRecord(value)) return defaultConfig;
|
|
1046
|
+
switch (kind) {
|
|
1047
|
+
case "start": {
|
|
1048
|
+
const normalizedConfig = defaultConfig.kind === "start" ? defaultConfig : null;
|
|
1049
|
+
if (!normalizedConfig) return defaultConfig;
|
|
1050
|
+
const variables = normalizeStartVariables(value.variables);
|
|
1051
|
+
const legacyVariables = normalizeLegacyStartFieldVariables(value.fields);
|
|
1052
|
+
return {
|
|
1053
|
+
...normalizedConfig,
|
|
1054
|
+
variables: variables.length ? variables : legacyVariables
|
|
1055
|
+
};
|
|
1056
|
+
}
|
|
1057
|
+
case "webhook-trigger": {
|
|
1058
|
+
const normalizedConfig = defaultConfig.kind === "webhook-trigger" ? defaultConfig : null;
|
|
1059
|
+
if (!normalizedConfig) return defaultConfig;
|
|
1060
|
+
const legacyParameters = Array.isArray(value.parameters) ? value.parameters : [];
|
|
1061
|
+
const params = Array.isArray(value.params) ? normalizeWebhookParameters(value.params) : normalizeWebhookParameters(legacyParameters.filter((entry) => isRecord(entry) && normalizeStringValue(entry.source) === "query"));
|
|
1062
|
+
const body = Array.isArray(value.body) ? normalizeWebhookParameters(value.body) : normalizeWebhookParameters(legacyParameters.filter((entry) => isRecord(entry) && normalizeStringValue(entry.source) === "body"));
|
|
1063
|
+
const headers = Array.isArray(value.headers) ? normalizeWebhookHeaders(value.headers) : [];
|
|
1064
|
+
const webhookUrl = normalizeStringValue(value.webhookUrl ?? value.webhook_url);
|
|
1065
|
+
const webhookDebugUrl = normalizeStringValue(value.webhookDebugUrl ?? value.webhook_debug_url);
|
|
1066
|
+
return {
|
|
1067
|
+
...normalizedConfig,
|
|
1068
|
+
webhook_url: webhookUrl || normalizeStringValue(value.path),
|
|
1069
|
+
webhook_debug_url: webhookDebugUrl,
|
|
1070
|
+
method: normalizeWebhookMethod(value.method),
|
|
1071
|
+
content_type: normalizeWebhookContentType(value.contentType ?? value.content_type),
|
|
1072
|
+
headers,
|
|
1073
|
+
params,
|
|
1074
|
+
body,
|
|
1075
|
+
async_mode: typeof value.asyncMode === "boolean" ? value.asyncMode : normalizeBooleanValue(value.async_mode, true),
|
|
1076
|
+
status_code: typeof value.response === "object" && value.response && "statusCode" in value.response ? Number(value.response.statusCode) || 200 : typeof value.status_code === "number" ? value.status_code : normalizedConfig.status_code,
|
|
1077
|
+
response_body: typeof value.response === "object" && value.response && "body" in value.response ? normalizeStringValue(value.response.body) : normalizeStringValue(value.response_body),
|
|
1078
|
+
variables: normalizeWebhookVariables(value.variables, params, headers, body)
|
|
1079
|
+
};
|
|
1080
|
+
}
|
|
1081
|
+
case "schedule-trigger": {
|
|
1082
|
+
const normalizedConfig = defaultConfig.kind === "schedule-trigger" ? defaultConfig : null;
|
|
1083
|
+
if (!normalizedConfig) return defaultConfig;
|
|
1084
|
+
const schedule = normalizeStringValue(value.schedule ?? value.cron_expression);
|
|
1085
|
+
const visualConfig = normalizeScheduleVisualConfig(value.visualConfig ?? value.visual_config);
|
|
1086
|
+
return {
|
|
1087
|
+
...normalizedConfig,
|
|
1088
|
+
schedule,
|
|
1089
|
+
cron_expression: schedule,
|
|
1090
|
+
mode: normalizeStringValue(value.mode).toLowerCase() === "cron" ? "cron" : "visual",
|
|
1091
|
+
frequency: normalizeScheduleFrequency(value.frequency),
|
|
1092
|
+
visualConfig,
|
|
1093
|
+
visual_config: {
|
|
1094
|
+
time: visualConfig.time,
|
|
1095
|
+
weekdays: visualConfig.weekdays,
|
|
1096
|
+
on_minute: visualConfig.onMinute,
|
|
1097
|
+
monthly_days: visualConfig.monthlyDays
|
|
1098
|
+
},
|
|
1099
|
+
timezone: normalizeStringValue(value.timezone) || void 0
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
case "end": {
|
|
1103
|
+
const normalizedConfig = defaultConfig.kind === "end" ? defaultConfig : null;
|
|
1104
|
+
if (!normalizedConfig) return defaultConfig;
|
|
1105
|
+
return {
|
|
1106
|
+
...normalizedConfig,
|
|
1107
|
+
outputs: normalizeEndOutputs(value.outputs).length ? normalizeEndOutputs(value.outputs) : normalizedConfig.outputs
|
|
1108
|
+
};
|
|
1109
|
+
}
|
|
1110
|
+
case "llm": {
|
|
1111
|
+
const normalizedConfig = defaultConfig.kind === "llm" ? defaultConfig : null;
|
|
1112
|
+
if (!normalizedConfig) return defaultConfig;
|
|
1113
|
+
const promptConfig = isRecord(value.prompt_config) ? value.prompt_config : null;
|
|
1114
|
+
const contextConfig = isRecord(value.context) ? value.context : null;
|
|
1115
|
+
const memoryConfig = isRecord(value.memory) ? value.memory : null;
|
|
1116
|
+
const memoryWindowConfig = memoryConfig && isRecord(memoryConfig.window) ? memoryConfig.window : null;
|
|
1117
|
+
const structuredOutput = isRecord(value.structured_output) ? value.structured_output : null;
|
|
1118
|
+
const normalizedMemoryConfig = normalizeNodeMemoryConfig(value.memory, normalizedConfig.memory.window.size ?? 3);
|
|
1119
|
+
return {
|
|
1120
|
+
...normalizedConfig,
|
|
1121
|
+
model: normalizeModelConfig(value.model),
|
|
1122
|
+
prompt_template: normalizePromptTemplate(promptConfig?.prompt_template ?? value.prompt_template ?? value.promptTemplate ?? value.prompt),
|
|
1123
|
+
prompt_config: { jinja2_variables: normalizePromptVariables(promptConfig?.jinja2_variables ?? value.promptVariables) },
|
|
1124
|
+
context: {
|
|
1125
|
+
enabled: typeof value.contextEnabled === "boolean" ? value.contextEnabled : normalizeBooleanValue(contextConfig?.enabled, false),
|
|
1126
|
+
variable_selector: Array.isArray(value.contextBindings) ? value.contextBindings.map((entry) => normalizeStringValue(entry)).filter(Boolean) : isRecord(contextConfig) && Array.isArray(contextConfig.variableBindings) ? contextConfig.variableBindings.map((entry) => normalizeStringValue(entry)).filter(Boolean) : Array.isArray(contextConfig?.variable_selector) ? contextConfig.variable_selector.map((entry) => normalizeStringValue(entry)).filter(Boolean) : []
|
|
1127
|
+
},
|
|
1128
|
+
memory: {
|
|
1129
|
+
window: {
|
|
1130
|
+
enabled: typeof value.memoryEnabled === "boolean" ? value.memoryEnabled : normalizeBooleanValue(memoryWindowConfig?.enabled, normalizedMemoryConfig.enabled),
|
|
1131
|
+
size: typeof memoryWindowConfig?.size === "number" && Number.isFinite(memoryWindowConfig.size) ? memoryWindowConfig.size : normalizedMemoryConfig.windowSize
|
|
1132
|
+
},
|
|
1133
|
+
query_prompt_template: normalizeStringValue(memoryConfig?.query_prompt_template) || void 0
|
|
1134
|
+
},
|
|
1135
|
+
vision: typeof value.visionEnabled === "boolean" ? {
|
|
1136
|
+
enabled: value.visionEnabled,
|
|
1137
|
+
configs: {
|
|
1138
|
+
variable_selector: normalizedConfig.vision.configs.variable_selector,
|
|
1139
|
+
detail: normalizedConfig.vision.configs.detail
|
|
1140
|
+
}
|
|
1141
|
+
} : normalizeLlmVisionConfig(value.vision),
|
|
1142
|
+
structured_output_enabled: typeof value.structuredOutputEnabled === "boolean" ? value.structuredOutputEnabled : typeof value.structured_output_enabled === "boolean" ? value.structured_output_enabled : isRecord(value.structuredOutput) ? normalizeBooleanValue(value.structuredOutput.enabled, false) : false,
|
|
1143
|
+
structured_output: { schema: normalizeStringValue(value.structuredOutputSchema) || normalizeStringValue(isRecord(value.structuredOutput) ? value.structuredOutput.schema : void 0) || normalizeStringValue(structuredOutput?.schema ? JSON.stringify(structuredOutput.schema, null, 2) : "") },
|
|
1144
|
+
reasoning_format: normalizeStringValue(value.reasoningFormat ?? value.reasoning_format).toLowerCase() === "separated" ? "separated" : "tagged"
|
|
1145
|
+
};
|
|
1146
|
+
}
|
|
1147
|
+
case "knowledge-retrieval": {
|
|
1148
|
+
const normalizedConfig = defaultConfig.kind === "knowledge-retrieval" ? defaultConfig : null;
|
|
1149
|
+
if (!normalizedConfig) return defaultConfig;
|
|
1150
|
+
const multipleRetrievalConfig = isRecord(value.multiple_retrieval_config) ? value.multiple_retrieval_config : null;
|
|
1151
|
+
const singleRetrievalConfig = isRecord(value.single_retrieval_config) ? value.single_retrieval_config : null;
|
|
1152
|
+
return {
|
|
1153
|
+
...normalizedConfig,
|
|
1154
|
+
query_variable_selector: normalizeSelectorPath(value.queryVariableSelector ?? value.query_variable_selector ?? value.queryVariable),
|
|
1155
|
+
query_attachment_selector: normalizeSelectorPath(value.queryAttachmentSelector ?? value.query_attachment_selector),
|
|
1156
|
+
dataset_ids: Array.isArray(value.datasetIds) ? value.datasetIds.map((entry) => normalizeStringValue(entry)).filter(Boolean) : Array.isArray(value.dataset_ids) ? value.dataset_ids.map((entry) => normalizeStringValue(entry)).filter(Boolean) : Array.isArray(value.datasets) ? value.datasets.map((entry) => normalizeStringValue(entry)).filter(Boolean) : [],
|
|
1157
|
+
retrieval_mode: normalizeStringValue(value.retrievalMode ?? value.retrieval_mode).toLowerCase() === "single" ? "single" : "multiple",
|
|
1158
|
+
multiple_retrieval_config: {
|
|
1159
|
+
top_k: normalizePositiveNumber(value.topK ?? multipleRetrievalConfig?.top_k, normalizedConfig.multiple_retrieval_config.top_k),
|
|
1160
|
+
score_threshold: parseOptionalNumber(value.scoreThreshold ?? multipleRetrievalConfig?.score_threshold),
|
|
1161
|
+
reranking_enable: typeof value.rerankingEnabled === "boolean" ? value.rerankingEnabled : normalizeBooleanValue(multipleRetrievalConfig?.reranking_enable, false),
|
|
1162
|
+
reranking_model: normalizeModelReference(value.rerankModel ?? multipleRetrievalConfig?.reranking_model) ? normalizeKnowledgeRetrievalRerankingModelConfig(value.rerankModel ?? multipleRetrievalConfig?.reranking_model) : null,
|
|
1163
|
+
reranking_mode: normalizeStringValue(value.rerankingMode ?? multipleRetrievalConfig?.reranking_mode) || void 0
|
|
1164
|
+
},
|
|
1165
|
+
single_retrieval_config: { model: normalizeModelReference(value.singleRetrievalModel ?? singleRetrievalConfig?.model) ? normalizeModelConfig(value.singleRetrievalModel ?? singleRetrievalConfig?.model) : null },
|
|
1166
|
+
metadata_filtering_mode: normalizeStringValue(value.metadataFilteringMode ?? value.metadata_filtering_mode).toLowerCase() === "automatic" ? "automatic" : normalizeStringValue(value.metadataFilteringMode ?? value.metadata_filtering_mode).toLowerCase() === "manual" ? "manual" : "disabled",
|
|
1167
|
+
metadata_filtering_conditions: normalizeKnowledgeRetrievalMetadataConditions(value.metadataFilteringConditions ?? value.metadata_filtering_conditions),
|
|
1168
|
+
metadata_model_config: normalizeModelReference(value.metadataModelConfig ?? value.metadata_model_config) ? normalizeModelConfig(value.metadataModelConfig ?? value.metadata_model_config) : null
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
case "question-classifier": {
|
|
1172
|
+
const normalizedConfig = defaultConfig.kind === "question-classifier" ? defaultConfig : null;
|
|
1173
|
+
if (!normalizedConfig) return defaultConfig;
|
|
1174
|
+
return {
|
|
1175
|
+
...normalizedConfig,
|
|
1176
|
+
query_variable_selector: normalizeSelectorPath(value.queryVariableSelector ?? value.query_variable_selector ?? value.inputVariable),
|
|
1177
|
+
model: normalizeModelConfig(value.model),
|
|
1178
|
+
classes: normalizeQuestionClassifierClasses(value.classes ?? value.categories),
|
|
1179
|
+
instruction: normalizeStringValue(value.instruction ?? value.instructions),
|
|
1180
|
+
memory: normalizeDifyMemoryConfig(typeof value.memoryEnabled === "boolean" ? { window: {
|
|
1181
|
+
enabled: value.memoryEnabled,
|
|
1182
|
+
size: normalizedConfig.memory.window.size
|
|
1183
|
+
} } : isRecord(value.memory) && typeof value.memory.enabled === "boolean" ? {
|
|
1184
|
+
...value.memory,
|
|
1185
|
+
window: {
|
|
1186
|
+
enabled: value.memory.enabled,
|
|
1187
|
+
size: typeof value.memory.windowSize === "number" && Number.isFinite(value.memory.windowSize) ? value.memory.windowSize : typeof value.memory.window_size === "number" && Number.isFinite(value.memory.window_size) ? value.memory.window_size : normalizedConfig.memory.window.size
|
|
1188
|
+
}
|
|
1189
|
+
} : value.memory, normalizedConfig.memory.window.size ?? 3),
|
|
1190
|
+
vision: typeof value.visionEnabled === "boolean" ? {
|
|
1191
|
+
enabled: value.visionEnabled,
|
|
1192
|
+
configs: {
|
|
1193
|
+
variable_selector: normalizedConfig.vision.configs.variable_selector,
|
|
1194
|
+
detail: normalizedConfig.vision.configs.detail
|
|
1195
|
+
}
|
|
1196
|
+
} : normalizeLlmVisionConfig(typeof value.visionEnabled === "boolean" ? {
|
|
1197
|
+
enabled: value.visionEnabled,
|
|
1198
|
+
configs: {
|
|
1199
|
+
variable_selector: normalizedConfig.vision.configs.variable_selector,
|
|
1200
|
+
detail: normalizedConfig.vision.configs.detail
|
|
1201
|
+
}
|
|
1202
|
+
} : value.vision)
|
|
1203
|
+
};
|
|
1204
|
+
}
|
|
1205
|
+
case "if-else": {
|
|
1206
|
+
const normalizedConfig = defaultConfig.kind === "if-else" ? defaultConfig : null;
|
|
1207
|
+
if (!normalizedConfig) return defaultConfig;
|
|
1208
|
+
const targetBranches = Array.isArray(value._targetBranches) ? value._targetBranches.flatMap((entry, index) => {
|
|
1209
|
+
if (!isRecord(entry)) return [];
|
|
1210
|
+
return [{
|
|
1211
|
+
id: normalizeStringValue(entry.id) || (index === 0 ? "true" : index === 1 ? "false" : `branch-${index + 1}`),
|
|
1212
|
+
name: normalizeStringValue(entry.name) || (index === 0 ? "IF" : index === 1 ? "ELSE" : `ELIF ${index}`)
|
|
1213
|
+
}];
|
|
1214
|
+
}) : normalizedConfig._targetBranches ?? [];
|
|
1215
|
+
const normalizedCases = Array.isArray(value.cases) && value.cases.length > 0 ? structuredClone(value.cases) : normalizedConfig.cases;
|
|
1216
|
+
const normalizedBranchConditions = Array.isArray(value.branchConditions) && value.branchConditions.length > 0 ? structuredClone(value.branchConditions) : normalizedConfig.branchConditions;
|
|
1217
|
+
return {
|
|
1218
|
+
...normalizedConfig,
|
|
1219
|
+
branchConditions: normalizedBranchConditions,
|
|
1220
|
+
_targetBranches: targetBranches.length > 0 ? targetBranches : normalizedConfig._targetBranches,
|
|
1221
|
+
cases: normalizedCases,
|
|
1222
|
+
logical_operator: normalizeStringValue(value.logical_operator).toLowerCase() === "or" ? "or" : "and",
|
|
1223
|
+
conditions: Array.isArray(value.conditions) ? structuredClone(value.conditions) : normalizedConfig.conditions,
|
|
1224
|
+
isInIteration: normalizeBooleanValue(value.isInIteration, false),
|
|
1225
|
+
isInLoop: normalizeBooleanValue(value.isInLoop, false)
|
|
1226
|
+
};
|
|
1227
|
+
}
|
|
1228
|
+
case "parameter-extractor": {
|
|
1229
|
+
const normalizedConfig = defaultConfig.kind === "parameter-extractor" ? defaultConfig : null;
|
|
1230
|
+
if (!normalizedConfig) return defaultConfig;
|
|
1231
|
+
return {
|
|
1232
|
+
...normalizedConfig,
|
|
1233
|
+
query: normalizeSelectorPath(value.inputVariable ?? value.query),
|
|
1234
|
+
model: normalizeModelConfig(value.model),
|
|
1235
|
+
parameters: normalizeParameterExtractorParameters(value.parameters),
|
|
1236
|
+
instruction: normalizeStringValue(value.extractionInstructions ?? value.instruction),
|
|
1237
|
+
reasoning_mode: String(value.reasoningMode ?? value.reasoning_mode).trim() === "function_call" ? "function_call" : "prompt",
|
|
1238
|
+
memory: normalizeDifyMemoryConfig(typeof value.memoryEnabled === "boolean" ? { window: {
|
|
1239
|
+
enabled: value.memoryEnabled,
|
|
1240
|
+
size: normalizedConfig.memory.window.size
|
|
1241
|
+
} } : isRecord(value.memory) && typeof value.memory.enabled === "boolean" ? {
|
|
1242
|
+
...value.memory,
|
|
1243
|
+
window: {
|
|
1244
|
+
enabled: value.memory.enabled,
|
|
1245
|
+
size: typeof value.memory.windowSize === "number" && Number.isFinite(value.memory.windowSize) ? value.memory.windowSize : typeof value.memory.window_size === "number" && Number.isFinite(value.memory.window_size) ? value.memory.window_size : normalizedConfig.memory.window.size
|
|
1246
|
+
}
|
|
1247
|
+
} : value.memory, normalizedConfig.memory.window.size ?? 3),
|
|
1248
|
+
vision: typeof value.visionEnabled === "boolean" ? {
|
|
1249
|
+
enabled: value.visionEnabled,
|
|
1250
|
+
configs: {
|
|
1251
|
+
variable_selector: normalizedConfig.vision.configs.variable_selector,
|
|
1252
|
+
detail: normalizedConfig.vision.configs.detail
|
|
1253
|
+
}
|
|
1254
|
+
} : normalizeLlmVisionConfig(value.vision)
|
|
1255
|
+
};
|
|
1256
|
+
}
|
|
1257
|
+
case "doc-extractor": {
|
|
1258
|
+
const normalizedConfig = defaultConfig.kind === "doc-extractor" ? defaultConfig : null;
|
|
1259
|
+
if (!normalizedConfig) return defaultConfig;
|
|
1260
|
+
return {
|
|
1261
|
+
...normalizedConfig,
|
|
1262
|
+
variable_selector: normalizeSelectorPath(value.sourceVariable ?? value.variable_selector),
|
|
1263
|
+
is_array_file: typeof value.isArrayFile === "boolean" ? value.isArrayFile : normalizeBooleanValue(value.is_array_file, false)
|
|
1264
|
+
};
|
|
1265
|
+
}
|
|
1266
|
+
case "human-input": {
|
|
1267
|
+
const normalizedConfig = defaultConfig.kind === "human-input" ? defaultConfig : null;
|
|
1268
|
+
if (!normalizedConfig) return defaultConfig;
|
|
1269
|
+
return {
|
|
1270
|
+
...normalizedConfig,
|
|
1271
|
+
delivery_methods: normalizeHumanInputDeliveryMethods(value.delivery_methods ?? value.deliveryMethods),
|
|
1272
|
+
form_content: normalizeStringValue(value.form_content ?? value.formContent),
|
|
1273
|
+
inputs: normalizeHumanInputItems(value.inputs),
|
|
1274
|
+
user_actions: normalizeHumanInputActions(value.user_actions ?? value.userActions),
|
|
1275
|
+
timeout: normalizePositiveNumber(value.timeout, normalizedConfig.timeout),
|
|
1276
|
+
timeout_unit: normalizeStringValue(value.timeout_unit ?? value.timeoutUnit).toLowerCase() === "hour" ? "hour" : "day"
|
|
1277
|
+
};
|
|
1278
|
+
}
|
|
1279
|
+
case "data-source": {
|
|
1280
|
+
const normalizedConfig = defaultConfig.kind === "data-source" ? defaultConfig : null;
|
|
1281
|
+
if (!normalizedConfig) return defaultConfig;
|
|
1282
|
+
return {
|
|
1283
|
+
...normalizedConfig,
|
|
1284
|
+
fileExtensions: normalizeFileExtensions(value.fileExtensions ?? value.file_extensions ?? value.fileExtensions),
|
|
1285
|
+
plugin_id: normalizeStringValue(value.plugin_id ?? value.pluginId),
|
|
1286
|
+
provider_type: normalizeStringValue(value.provider_type ?? value.providerType),
|
|
1287
|
+
provider_name: normalizeStringValue(value.provider_name ?? value.providerName),
|
|
1288
|
+
datasource_name: normalizeStringValue(value.datasource_name ?? value.datasourceName),
|
|
1289
|
+
datasource_label: normalizeStringValue(value.datasource_label ?? value.datasourceLabel),
|
|
1290
|
+
datasource_parameters: normalizeResourceParameters(value.datasource_parameters ?? value.datasourceParameters),
|
|
1291
|
+
datasource_configurations: normalizeResourceConfigurations(value.datasource_configurations ?? value.datasourceConfigurations),
|
|
1292
|
+
output_schema: isRecord(value.output_schema) ? structuredClone(value.output_schema) : normalizeOutputSchema(value.outputSchema ?? value.output_schema),
|
|
1293
|
+
plugin_unique_identifier: normalizeStringValue(value.plugin_unique_identifier ?? value.pluginUniqueIdentifier) || void 0
|
|
1294
|
+
};
|
|
1295
|
+
}
|
|
1296
|
+
case "knowledge-base": {
|
|
1297
|
+
const normalizedConfig = defaultConfig.kind === "knowledge-base" ? defaultConfig : null;
|
|
1298
|
+
if (!normalizedConfig) return defaultConfig;
|
|
1299
|
+
const summaryIndexSettingValue = value.summary_index_setting ?? value.summaryIndexSetting;
|
|
1300
|
+
const rawSummaryIndexSetting = isRecord(summaryIndexSettingValue) ? summaryIndexSettingValue : null;
|
|
1301
|
+
return {
|
|
1302
|
+
...normalizedConfig,
|
|
1303
|
+
index_chunk_variable_selector: normalizeSelectorPath(value.index_chunk_variable_selector ?? value.indexChunkVariableSelector),
|
|
1304
|
+
chunk_structure: normalizeKnowledgeBaseChunkStructure(value.chunk_structure ?? value.chunkStructure),
|
|
1305
|
+
indexing_technique: normalizeStringValue(value.indexing_technique ?? value.indexingTechnique) || void 0,
|
|
1306
|
+
embedding_model: normalizeStringValue(value.embedding_model ?? value.embeddingModel) || void 0,
|
|
1307
|
+
embedding_model_provider: normalizeStringValue(value.embedding_model_provider ?? value.embeddingModelProvider) || void 0,
|
|
1308
|
+
keyword_number: normalizePositiveNumber(value.keyword_number ?? value.keywordNumber, normalizedConfig.keyword_number),
|
|
1309
|
+
retrieval_model: normalizeKnowledgeBaseRetrievalModel(value.retrieval_model ?? value.retrievalModel, normalizedConfig.retrieval_model),
|
|
1310
|
+
summary_index_setting: rawSummaryIndexSetting ? {
|
|
1311
|
+
enable: normalizeBooleanValue(rawSummaryIndexSetting.enable, false),
|
|
1312
|
+
model_name: normalizeStringValue(rawSummaryIndexSetting.model_name ?? rawSummaryIndexSetting.modelName) || void 0,
|
|
1313
|
+
model_provider_name: normalizeStringValue(rawSummaryIndexSetting.model_provider_name ?? rawSummaryIndexSetting.modelProviderName) || void 0,
|
|
1314
|
+
summary_prompt: normalizeStringValue(rawSummaryIndexSetting.summary_prompt ?? rawSummaryIndexSetting.summaryPrompt) || void 0
|
|
1315
|
+
} : void 0
|
|
1316
|
+
};
|
|
1317
|
+
}
|
|
1318
|
+
case "trigger-plugin": {
|
|
1319
|
+
const normalizedConfig = defaultConfig.kind === "trigger-plugin" ? defaultConfig : null;
|
|
1320
|
+
if (!normalizedConfig) return defaultConfig;
|
|
1321
|
+
const normalizedEventParameters = normalizeResourceParameters(value.event_parameters ?? value.eventParameters);
|
|
1322
|
+
const normalizedLegacyConfigParameters = normalizeResourceParameters(value.config);
|
|
1323
|
+
return {
|
|
1324
|
+
...normalizedConfig,
|
|
1325
|
+
provider_id: normalizeStringValue(value.provider_id ?? value.providerId),
|
|
1326
|
+
provider_type: normalizeTriggerPluginProviderType(value.provider_type ?? value.providerType),
|
|
1327
|
+
provider_name: normalizeStringValue(value.provider_name ?? value.providerName),
|
|
1328
|
+
event_name: normalizeStringValue(value.event_name ?? value.eventName),
|
|
1329
|
+
event_label: normalizeStringValue(value.event_label ?? value.eventLabel),
|
|
1330
|
+
event_parameters: Object.keys(normalizedEventParameters).length > 0 ? normalizedEventParameters : normalizedLegacyConfigParameters,
|
|
1331
|
+
event_configurations: normalizeResourceConfigurations(value.event_configurations ?? value.eventConfigurations),
|
|
1332
|
+
output_schema: isRecord(value.output_schema) ? structuredClone(value.output_schema) : normalizeOutputSchema(value.outputSchema ?? value.output_schema),
|
|
1333
|
+
parameters_schema: normalizeParameterSchemaFields(value.parameters_schema ?? value.parametersSchema),
|
|
1334
|
+
version: normalizeStringValue(value.version) || void 0,
|
|
1335
|
+
event_node_version: normalizeStringValue(value.event_node_version ?? value.eventNodeVersion) || "2",
|
|
1336
|
+
plugin_id: normalizeStringValue(value.plugin_id ?? value.pluginId) || void 0,
|
|
1337
|
+
config: isRecord(value.config) ? structuredClone(value.config) : {},
|
|
1338
|
+
plugin_unique_identifier: normalizeStringValue(value.plugin_unique_identifier ?? value.pluginUniqueIdentifier) || void 0,
|
|
1339
|
+
subscription_id: normalizeStringValue(value.subscription_id ?? value.subscriptionId) || void 0
|
|
1340
|
+
};
|
|
1341
|
+
}
|
|
1342
|
+
case "list-operator": {
|
|
1343
|
+
const normalizedConfig = defaultConfig.kind === "list-operator" ? defaultConfig : null;
|
|
1344
|
+
const rawFilterBy = isRecord(value.filter_by) ? value.filter_by : null;
|
|
1345
|
+
const rawFilterCondition = isRecord(value.filterCondition) ? value.filterCondition : Array.isArray(rawFilterBy?.conditions) && isRecord(rawFilterBy.conditions[0]) ? rawFilterBy.conditions[0] : null;
|
|
1346
|
+
const rawExtractBy = isRecord(value.extract_by) ? value.extract_by : null;
|
|
1347
|
+
const rawOrderBy = isRecord(value.order_by) ? value.order_by : null;
|
|
1348
|
+
const rawLimit = isRecord(value.limit) ? value.limit : null;
|
|
1349
|
+
if (!normalizedConfig) return defaultConfig;
|
|
1350
|
+
const inputArrayVariable = normalizeSelectorPath(value.inputArrayVariable ?? value.variable);
|
|
1351
|
+
const filterEnabled = typeof value.filterEnabled === "boolean" ? value.filterEnabled : normalizeBooleanValue(rawFilterBy?.enabled, false);
|
|
1352
|
+
const filterCondition = {
|
|
1353
|
+
key: normalizeStringValue(rawFilterCondition?.key),
|
|
1354
|
+
operator: normalizeListOperatorComparisonOperator(rawFilterCondition?.operator ?? rawFilterCondition?.comparison_operator),
|
|
1355
|
+
value: normalizeListOperatorValue(rawFilterCondition?.value)
|
|
1356
|
+
};
|
|
1357
|
+
const extractEnabled = typeof value.extractEnabled === "boolean" ? value.extractEnabled : normalizeBooleanValue(rawExtractBy?.enabled, false);
|
|
1358
|
+
const extractTemplate = normalizeStringValue(value.extractTemplate ?? rawExtractBy?.serial) || normalizedConfig.extractTemplate;
|
|
1359
|
+
const orderByEnabled = typeof value.orderByEnabled === "boolean" ? value.orderByEnabled : normalizeBooleanValue(rawOrderBy?.enabled, false);
|
|
1360
|
+
const orderByKey = normalizeSelectorPath(value.orderByKey ?? rawOrderBy?.key);
|
|
1361
|
+
const orderByDirection = String(value.orderByDirection ?? rawOrderBy?.value).trim().toLowerCase() === "desc" ? "desc" : "asc";
|
|
1362
|
+
return {
|
|
1363
|
+
...normalizedConfig,
|
|
1364
|
+
inputArrayVariable,
|
|
1365
|
+
operation: value.operation === "map" || value.operation === "filter" || value.operation === "flatten" || value.operation === "deduplicate" || value.operation === "aggregate" ? value.operation : normalizeBooleanValue(rawFilterBy?.enabled, false) ? "filter" : normalizedConfig.operation,
|
|
1366
|
+
operationConfig: normalizeStringValue(value.operationConfig),
|
|
1367
|
+
variable: inputArrayVariable,
|
|
1368
|
+
var_type: normalizeStringValue(value.var_type),
|
|
1369
|
+
item_var_type: normalizeStringValue(value.item_var_type),
|
|
1370
|
+
filterEnabled,
|
|
1371
|
+
filterCondition,
|
|
1372
|
+
filter_by: {
|
|
1373
|
+
enabled: filterEnabled,
|
|
1374
|
+
conditions: filterEnabled && (filterCondition.key || filterCondition.operator || filterCondition.value) ? [{
|
|
1375
|
+
key: filterCondition.key,
|
|
1376
|
+
comparison_operator: filterCondition.operator,
|
|
1377
|
+
value: filterCondition.value
|
|
1378
|
+
}] : []
|
|
1379
|
+
},
|
|
1380
|
+
extractEnabled,
|
|
1381
|
+
extractTemplate,
|
|
1382
|
+
extract_by: {
|
|
1383
|
+
enabled: extractEnabled,
|
|
1384
|
+
serial: extractTemplate || void 0
|
|
1385
|
+
},
|
|
1386
|
+
orderByEnabled,
|
|
1387
|
+
orderByKey,
|
|
1388
|
+
orderByDirection,
|
|
1389
|
+
order_by: {
|
|
1390
|
+
enabled: orderByEnabled,
|
|
1391
|
+
key: orderByKey,
|
|
1392
|
+
value: orderByDirection
|
|
1393
|
+
},
|
|
1394
|
+
limit: {
|
|
1395
|
+
enabled: isRecord(value.limit) && typeof value.limit.enabled === "boolean" ? value.limit.enabled : normalizeBooleanValue(rawLimit?.enabled, false),
|
|
1396
|
+
size: normalizePositiveNumber(isRecord(value.limit) ? value.limit.size : rawLimit?.size, normalizedConfig.limit.size)
|
|
1397
|
+
}
|
|
1398
|
+
};
|
|
1399
|
+
}
|
|
1400
|
+
case "iteration": {
|
|
1401
|
+
const normalizedConfig = defaultConfig.kind === "iteration" ? defaultConfig : null;
|
|
1402
|
+
if (!normalizedConfig) return defaultConfig;
|
|
1403
|
+
return {
|
|
1404
|
+
...normalizedConfig,
|
|
1405
|
+
startNodeType: normalizeStringValue(value.startNodeType) || normalizedConfig.startNodeType,
|
|
1406
|
+
start_node_id: normalizeStringValue(value.start_node_id),
|
|
1407
|
+
iterator_selector: normalizeSelectorPath(value.inputArrayVariable ?? value.iterator_selector),
|
|
1408
|
+
iterator_input_type: normalizeConcreteValueType(value.iterator_input_type, "array"),
|
|
1409
|
+
output_selector: normalizeSelectorPath(value.outputVariable ?? value.output_selector),
|
|
1410
|
+
output_type: normalizeConcreteValueType(value.output_type, "array"),
|
|
1411
|
+
is_parallel: value.executionMode === "parallel" ? true : value.executionMode === "sequential" ? false : normalizeBooleanValue(value.is_parallel, false),
|
|
1412
|
+
parallel_nums: normalizePositiveNumber(value.parallelCount ?? value.parallel_nums, normalizedConfig.parallel_nums),
|
|
1413
|
+
error_handle_mode: value.failureMode === "continue" ? "continue-on-error" : value.failureMode === "remove-failed-results" ? "remove-abnormal-output" : value.failureMode === "terminate" ? "terminated" : normalizeStringValue(value.error_handle_mode) === "continue-on-error" ? "continue-on-error" : normalizeStringValue(value.error_handle_mode) === "remove-abnormal-output" ? "remove-abnormal-output" : "terminated",
|
|
1414
|
+
flatten_output: typeof value.flattenOutput === "boolean" ? value.flattenOutput : normalizeBooleanValue(value.flatten_output, true),
|
|
1415
|
+
iteration_id: normalizeStringValue(value.iteration_id) || void 0,
|
|
1416
|
+
_isShowTips: typeof value._isShowTips === "boolean" ? value._isShowTips : normalizedConfig._isShowTips ?? false
|
|
1417
|
+
};
|
|
1418
|
+
}
|
|
1419
|
+
case "code": {
|
|
1420
|
+
const normalizedConfig = defaultConfig.kind === "code" ? defaultConfig : null;
|
|
1421
|
+
if (!normalizedConfig) return defaultConfig;
|
|
1422
|
+
const language = normalizeCodeLanguage(value.language ?? value.code_language);
|
|
1423
|
+
const script = normalizeStringValue(value.script ?? value.code);
|
|
1424
|
+
const inputVariables = normalizeCodeInputVariables(value.inputVariables ?? value.variables);
|
|
1425
|
+
const normalizedVariables = normalizeCodeVariables(value.variables);
|
|
1426
|
+
const outputVariables = normalizeCodeOutputVariables(value.outputVariables ?? value.outputs);
|
|
1427
|
+
return {
|
|
1428
|
+
...normalizedConfig,
|
|
1429
|
+
language,
|
|
1430
|
+
code_language: language === "python" ? "python3" : "javascript",
|
|
1431
|
+
script,
|
|
1432
|
+
code: script,
|
|
1433
|
+
inputVariables: normalizedVariables.length > 0 ? normalizedVariables.map((entry) => entry.variable) : inputVariables,
|
|
1434
|
+
variables: normalizedVariables.length > 0 ? normalizedVariables : inputVariables.map((variable, index) => ({
|
|
1435
|
+
id: `code-variable-${index + 1}`,
|
|
1436
|
+
variable,
|
|
1437
|
+
value_selector: normalizeSelectorPath(variable)
|
|
1438
|
+
})),
|
|
1439
|
+
outputVariables,
|
|
1440
|
+
outputs: Object.fromEntries(outputVariables.filter((entry) => entry.name.trim()).map((entry) => [entry.name, {
|
|
1441
|
+
type: entry.dataType,
|
|
1442
|
+
children: null
|
|
1443
|
+
}])),
|
|
1444
|
+
retryCount: normalizePositiveNumber(value.retryCount, normalizedConfig.retryCount ?? 0),
|
|
1445
|
+
retryIntervalMs: normalizePositiveNumber(value.retryIntervalMs, normalizedConfig.retryIntervalMs ?? 1e3),
|
|
1446
|
+
errorHandling: normalizeStringValue(value.errorHandling).toLowerCase() === "continue-on-error" ? "continue-on-error" : normalizeStringValue(value.errorHandling).toLowerCase() === "fallback-branch" ? "fallback-branch" : normalizedConfig.errorHandling
|
|
1447
|
+
};
|
|
1448
|
+
}
|
|
1449
|
+
case "template": {
|
|
1450
|
+
const normalizedConfig = defaultConfig.kind === "template" ? defaultConfig : null;
|
|
1451
|
+
if (!normalizedConfig) return defaultConfig;
|
|
1452
|
+
return {
|
|
1453
|
+
...normalizedConfig,
|
|
1454
|
+
variables: normalizeTemplateVariables(value.variables),
|
|
1455
|
+
template: normalizeStringValue(value.templateBody ?? value.template)
|
|
1456
|
+
};
|
|
1457
|
+
}
|
|
1458
|
+
case "variable-aggregator": {
|
|
1459
|
+
const normalizedConfig = defaultConfig.kind === "variable-aggregator" ? defaultConfig : null;
|
|
1460
|
+
const advancedSettings = isRecord(value.advanced_settings) ? value.advanced_settings : null;
|
|
1461
|
+
if (!normalizedConfig) return defaultConfig;
|
|
1462
|
+
const rawSourceVariables = value.sourceVariables ?? value.variables;
|
|
1463
|
+
const normalizedSourceVariables = Array.isArray(rawSourceVariables) ? rawSourceVariables.map((variable) => normalizeSelectorPath(variable)) : [];
|
|
1464
|
+
return {
|
|
1465
|
+
...normalizedConfig,
|
|
1466
|
+
output_type: normalizeAggregatorOutputType(value.valueType ?? value.output_type),
|
|
1467
|
+
variables: normalizedSourceVariables,
|
|
1468
|
+
advanced_settings: {
|
|
1469
|
+
group_enabled: typeof value.groupEnabled === "boolean" ? value.groupEnabled : normalizeBooleanValue(advancedSettings?.group_enabled, false),
|
|
1470
|
+
groups: normalizeVariableAggregatorGroups(value.groups ?? advancedSettings?.groups)
|
|
1471
|
+
}
|
|
1472
|
+
};
|
|
1473
|
+
}
|
|
1474
|
+
case "variable-assigner": {
|
|
1475
|
+
const normalizedConfig = defaultConfig.kind === "variable-assigner" ? defaultConfig : null;
|
|
1476
|
+
if (!normalizedConfig) return defaultConfig;
|
|
1477
|
+
const normalizedItems = Array.isArray(value.items) ? value.items : Array.isArray(value.assignments) ? value.assignments : Array.isArray(value.variables) ? value.variables.map((variable, index) => ({
|
|
1478
|
+
id: `assignment-${index + 1}`,
|
|
1479
|
+
variable_selector: normalizeSelectorPath(variable),
|
|
1480
|
+
input_type: "variable",
|
|
1481
|
+
operation: "over-write",
|
|
1482
|
+
value: ""
|
|
1483
|
+
})) : normalizedConfig.items;
|
|
1484
|
+
return {
|
|
1485
|
+
...normalizedConfig,
|
|
1486
|
+
version: normalizeStringValue(value.version) === "1" ? "1" : "2",
|
|
1487
|
+
items: normalizedItems.map((assignment, index) => ({
|
|
1488
|
+
input_type: normalizeStringValue(assignment.valueType ?? assignment.input_type).toLowerCase() === "constant" ? "constant" : "variable",
|
|
1489
|
+
id: normalizeStringValue(assignment.id) || `assignment-${index + 1}`,
|
|
1490
|
+
variable_selector: normalizeSelectorPath(assignment.variable ?? assignment.variable_selector),
|
|
1491
|
+
operation: assignment.operation === "over-write" || assignment.operation === "clear" || assignment.operation === "append" || assignment.operation === "extend" || assignment.operation === "set" || assignment.operation === "remove-first" || assignment.operation === "remove-last" || assignment.operation === "+=" || assignment.operation === "-=" || assignment.operation === "*=" || assignment.operation === "/=" ? assignment.operation : assignment.operation === "increment" ? "+=" : assignment.operation === "decrement" ? "-=" : assignment.operation === "multiply" ? "*=" : assignment.operation === "divide" ? "/=" : "over-write",
|
|
1492
|
+
value: normalizeAssignerValue(assignment.value, normalizeStringValue(assignment.valueType ?? assignment.input_type).toLowerCase() === "constant" ? "constant" : "variable")
|
|
1493
|
+
}))
|
|
1494
|
+
};
|
|
1495
|
+
}
|
|
1496
|
+
case "tool": {
|
|
1497
|
+
const normalizedConfig = defaultConfig.kind === "tool" ? defaultConfig : null;
|
|
1498
|
+
if (!normalizedConfig) return defaultConfig;
|
|
1499
|
+
const reference = isRecord(value.reference) ? value.reference : null;
|
|
1500
|
+
const rawToolParameterValue = value.parameters ?? value.dynamicInputs;
|
|
1501
|
+
const rawToolParameters = Array.isArray(rawToolParameterValue) ? rawToolParameterValue : null;
|
|
1502
|
+
const normalizedToolParameters = rawToolParameters && rawToolParameters.length > 0 ? rawToolParameters.map((entry, index) => ({
|
|
1503
|
+
id: normalizeStringValue(readRecordProperty(entry, "id")) || `tool-input-${index + 1}`,
|
|
1504
|
+
name: normalizeStringValue(readRecordProperty(entry, "name")),
|
|
1505
|
+
valueType: normalizeStringValue(readRecordProperty(entry, "valueType") ?? readRecordProperty(entry, "type")) === "variable" ? "variable" : "constant",
|
|
1506
|
+
value: normalizeStringValue(readRecordProperty(entry, "valueType") ?? readRecordProperty(entry, "type")) === "variable" ? normalizeSelectorPath(readRecordProperty(entry, "value")) : normalizeDifyResourceConstantValue(readRecordProperty(entry, "value"))
|
|
1507
|
+
})) : normalizeRecordEntries(value.tool_parameters);
|
|
1508
|
+
return {
|
|
1509
|
+
...normalizedConfig,
|
|
1510
|
+
reference: {
|
|
1511
|
+
id: normalizeStringValue(reference?.id ?? value.toolReferenceId ?? value.provider_id),
|
|
1512
|
+
providerType: normalizeToolProviderType(reference?.providerType ?? value.toolProviderType ?? value.provider_type),
|
|
1513
|
+
providerName: normalizeStringValue(reference?.providerName ?? value.toolReferenceSource ?? value.provider_name),
|
|
1514
|
+
toolName: normalizeStringValue(reference?.toolName ?? value.toolName ?? value.tool_name),
|
|
1515
|
+
label: normalizeStringValue(reference?.label ?? value.toolReferenceLabel ?? value.tool_label),
|
|
1516
|
+
version: normalizeStringValue(reference?.version ?? value.toolReferenceVersion ?? value.version) || void 0,
|
|
1517
|
+
description: normalizeStringValue(reference?.description ?? value.tool_description) || void 0,
|
|
1518
|
+
pluginUniqueIdentifier: normalizeStringValue(reference?.pluginUniqueIdentifier ?? value.plugin_unique_identifier) || void 0
|
|
1519
|
+
},
|
|
1520
|
+
credentialBinding: normalizeStringValue(value.credentialBinding),
|
|
1521
|
+
parameters: normalizedToolParameters,
|
|
1522
|
+
configurations: normalizeToolConfigurationEntries(value.configurations ?? value.toolConfigurations ?? value.tool_configurations),
|
|
1523
|
+
outputSchema: normalizeOutputSchema(value.outputSchema ?? value.output_schema),
|
|
1524
|
+
provider_id: normalizeStringValue(reference?.id ?? value.toolReferenceId ?? value.provider_id),
|
|
1525
|
+
provider_type: normalizeToolProviderType(reference?.providerType ?? value.toolProviderType ?? value.provider_type),
|
|
1526
|
+
provider_name: normalizeStringValue(reference?.providerName ?? value.toolReferenceSource ?? value.provider_name),
|
|
1527
|
+
tool_name: normalizeStringValue(reference?.toolName ?? value.toolName ?? value.tool_name),
|
|
1528
|
+
tool_label: normalizeStringValue(reference?.label ?? value.toolReferenceLabel ?? value.tool_label),
|
|
1529
|
+
tool_parameters: Object.fromEntries(normalizedToolParameters.filter((entry) => entry.name.trim()).map((entry) => [entry.name, {
|
|
1530
|
+
type: entry.valueType,
|
|
1531
|
+
value: entry.value
|
|
1532
|
+
}])),
|
|
1533
|
+
tool_configurations: Object.fromEntries(normalizeToolConfigurationEntries(value.configurations ?? value.toolConfigurations ?? value.tool_configurations).filter((entry) => entry.name.trim()).map((entry) => [entry.name, entry.value])),
|
|
1534
|
+
output_schema: normalizeOutputSchema(value.outputSchema ?? value.output_schema),
|
|
1535
|
+
version: normalizeStringValue(reference?.version ?? value.toolReferenceVersion ?? value.version) || void 0,
|
|
1536
|
+
tool_description: normalizeStringValue(reference?.description ?? value.tool_description) || void 0,
|
|
1537
|
+
is_team_authorization: typeof value.is_team_authorization === "boolean" ? value.is_team_authorization : void 0,
|
|
1538
|
+
params: isRecord(value.params) ? structuredClone(value.params) : void 0,
|
|
1539
|
+
provider_icon: typeof value.provider_icon === "string" || isRecord(value.provider_icon) ? structuredClone(value.provider_icon) : void 0,
|
|
1540
|
+
provider_icon_dark: typeof value.provider_icon_dark === "string" || isRecord(value.provider_icon_dark) ? structuredClone(value.provider_icon_dark) : void 0,
|
|
1541
|
+
plugin_unique_identifier: normalizeStringValue(reference?.pluginUniqueIdentifier ?? value.plugin_unique_identifier) || void 0,
|
|
1542
|
+
tool_node_version: normalizeStringValue(value.tool_node_version) || "2"
|
|
1543
|
+
};
|
|
1544
|
+
}
|
|
1545
|
+
case "agent": {
|
|
1546
|
+
const normalizedConfig = defaultConfig.kind === "agent" ? defaultConfig : null;
|
|
1547
|
+
if (!normalizedConfig) return defaultConfig;
|
|
1548
|
+
const strategy = isRecord(value.strategy) ? value.strategy : null;
|
|
1549
|
+
const rawStrategyParameters = Array.isArray(value.strategyParameters) ? value.strategyParameters : null;
|
|
1550
|
+
const strategyParameters = rawStrategyParameters && rawStrategyParameters.length > 0 ? rawStrategyParameters.map((entry, index) => ({
|
|
1551
|
+
id: normalizeStringValue(readRecordProperty(entry, "id")) || `agent-parameter-${index + 1}`,
|
|
1552
|
+
name: normalizeStringValue(readRecordProperty(entry, "name")),
|
|
1553
|
+
valueType: normalizeStringValue(readRecordProperty(entry, "valueType") ?? readRecordProperty(entry, "type")) === "variable" ? "variable" : "constant",
|
|
1554
|
+
value: normalizeStringValue(readRecordProperty(entry, "valueType") ?? readRecordProperty(entry, "type")) === "variable" ? normalizeSelectorPath(readRecordProperty(entry, "value")) : normalizeDifyResourceConstantValue(readRecordProperty(entry, "value"))
|
|
1555
|
+
})) : normalizeRecordEntries(value.agent_parameters);
|
|
1556
|
+
const normalizedMemory = normalizeDifyMemoryConfig(value.memory, normalizedConfig.memory.windowSize ?? 3);
|
|
1557
|
+
return {
|
|
1558
|
+
...normalizedConfig,
|
|
1559
|
+
model: normalizeModelConfig(value.model),
|
|
1560
|
+
strategy: {
|
|
1561
|
+
mode: normalizeStringValue(strategy?.mode ?? value.strategy).toLowerCase() === "react" ? "react" : normalizedConfig.strategy.mode,
|
|
1562
|
+
providerName: normalizeStringValue(strategy?.providerName ?? value.strategyProviderName ?? value.agent_strategy_provider_name),
|
|
1563
|
+
name: normalizeStringValue(strategy?.name ?? value.strategyName ?? value.agent_strategy_name),
|
|
1564
|
+
label: normalizeStringValue(strategy?.label ?? value.strategyLabel ?? value.agent_strategy_label),
|
|
1565
|
+
pluginUniqueIdentifier: normalizeStringValue(strategy?.pluginUniqueIdentifier ?? value.plugin_unique_identifier) || void 0,
|
|
1566
|
+
version: normalizeStringValue(strategy?.version ?? value.version ?? value.tool_node_version) || void 0,
|
|
1567
|
+
meta: isRecord(strategy?.meta) ? structuredClone(strategy.meta) : isRecord(value.meta) ? structuredClone(value.meta) : null
|
|
1568
|
+
},
|
|
1569
|
+
instructions: normalizeStringValue(value.instructions),
|
|
1570
|
+
enabledTools: Array.isArray(value.enabledTools) ? value.enabledTools.map((entry) => normalizeStringValue(entry)).filter(Boolean) : [],
|
|
1571
|
+
maxIterations: typeof value.maxIterations === "number" && Number.isFinite(value.maxIterations) ? value.maxIterations : normalizedConfig.maxIterations,
|
|
1572
|
+
memory: typeof value.memoryEnabled === "boolean" ? {
|
|
1573
|
+
enabled: value.memoryEnabled,
|
|
1574
|
+
windowSize: normalizedConfig.memory.windowSize,
|
|
1575
|
+
window: {
|
|
1576
|
+
enabled: value.memoryEnabled,
|
|
1577
|
+
size: normalizedConfig.memory.windowSize
|
|
1578
|
+
}
|
|
1579
|
+
} : {
|
|
1580
|
+
enabled: normalizedMemory.window.enabled,
|
|
1581
|
+
windowSize: normalizedMemory.window.size,
|
|
1582
|
+
window: normalizedMemory.window,
|
|
1583
|
+
role_prefix: normalizedMemory.role_prefix,
|
|
1584
|
+
query_prompt_template: normalizedMemory.query_prompt_template
|
|
1585
|
+
},
|
|
1586
|
+
strategyParameters,
|
|
1587
|
+
outputSchema: normalizeOutputSchema(value.outputSchema ?? value.output_schema),
|
|
1588
|
+
agent_strategy_provider_name: normalizeStringValue(strategy?.providerName ?? value.strategyProviderName ?? value.agent_strategy_provider_name),
|
|
1589
|
+
agent_strategy_name: normalizeStringValue(strategy?.name ?? value.strategyName ?? value.agent_strategy_name),
|
|
1590
|
+
agent_strategy_label: normalizeStringValue(strategy?.label ?? value.strategyLabel ?? value.agent_strategy_label),
|
|
1591
|
+
agent_parameters: Object.fromEntries(strategyParameters.filter((entry) => entry.name.trim()).map((entry) => [entry.name, {
|
|
1592
|
+
type: entry.valueType,
|
|
1593
|
+
value: entry.value
|
|
1594
|
+
}])),
|
|
1595
|
+
output_schema: isRecord(value.output_schema) ? structuredClone(value.output_schema) : normalizeOutputSchema(value.outputSchema ?? value.output_schema),
|
|
1596
|
+
plugin_unique_identifier: normalizeStringValue(strategy?.pluginUniqueIdentifier ?? value.plugin_unique_identifier) || void 0,
|
|
1597
|
+
meta: isRecord(strategy?.meta) ? structuredClone(strategy.meta) : isRecord(value.meta) ? structuredClone(value.meta) : null,
|
|
1598
|
+
version: normalizeStringValue(strategy?.version ?? value.version ?? value.tool_node_version) || void 0,
|
|
1599
|
+
tool_node_version: normalizeStringValue(value.tool_node_version) || "2"
|
|
1600
|
+
};
|
|
1601
|
+
}
|
|
1602
|
+
case "loop": {
|
|
1603
|
+
const normalizedConfig = defaultConfig.kind === "loop" ? defaultConfig : null;
|
|
1604
|
+
if (!normalizedConfig) return defaultConfig;
|
|
1605
|
+
const breakConditions = Array.isArray(value.break_conditions) ? value.break_conditions : [];
|
|
1606
|
+
isRecord(breakConditions[0]) && breakConditions[0];
|
|
1607
|
+
return {
|
|
1608
|
+
...normalizedConfig,
|
|
1609
|
+
startNodeType: normalizeStringValue(value.startNodeType) || normalizedConfig.startNodeType,
|
|
1610
|
+
start_node_id: normalizeStringValue(value.start_node_id),
|
|
1611
|
+
logical_operator: normalizeStringValue(value.logical_operator).toLowerCase() === "or" ? "or" : "and",
|
|
1612
|
+
break_conditions: breakConditions.length > 0 ? breakConditions.map((entry, index) => ({
|
|
1613
|
+
id: normalizeStringValue(isRecord(entry) ? entry.id : void 0) || `loop-condition-${index + 1}`,
|
|
1614
|
+
varType: normalizeConcreteValueType(isRecord(entry) ? entry.varType ?? entry.var_type : void 0),
|
|
1615
|
+
variable_selector: normalizeSelectorPath(isRecord(entry) ? entry.variable_selector : void 0),
|
|
1616
|
+
key: normalizeStringValue(isRecord(entry) ? entry.key : void 0) || void 0,
|
|
1617
|
+
comparison_operator: normalizeStringValue(isRecord(entry) ? entry.comparison_operator ?? entry.comparisonOperator : void 0) || void 0,
|
|
1618
|
+
value: typeof (isRecord(entry) ? entry.value : void 0) === "boolean" ? Boolean(entry.value) : Array.isArray(isRecord(entry) ? entry.value : void 0) ? entry.value : normalizeListOperatorValue(isRecord(entry) ? entry.value : void 0),
|
|
1619
|
+
numberVarType: normalizeStringValue(isRecord(entry) ? entry.numberVarType : void 0) || void 0,
|
|
1620
|
+
sub_variable_condition: isRecord(isRecord(entry) ? entry.sub_variable_condition : void 0) ? {
|
|
1621
|
+
logical_operator: normalizeStringValue(entry.sub_variable_condition && isRecord(entry.sub_variable_condition) ? entry.sub_variable_condition.logical_operator : void 0).toLowerCase() === "or" ? "or" : "and",
|
|
1622
|
+
conditions: Array.isArray(entry.sub_variable_condition && isRecord(entry.sub_variable_condition) ? entry.sub_variable_condition.conditions : void 0) ? (entry.sub_variable_condition.conditions ?? []).flatMap((subEntry, subIndex) => {
|
|
1623
|
+
if (!isRecord(subEntry)) return [];
|
|
1624
|
+
return [{
|
|
1625
|
+
id: normalizeStringValue(subEntry.id) || `loop-sub-condition-${index + 1}-${subIndex + 1}`,
|
|
1626
|
+
varType: normalizeConcreteValueType(subEntry.varType ?? subEntry.var_type),
|
|
1627
|
+
variable_selector: normalizeSelectorPath(subEntry.variable_selector),
|
|
1628
|
+
key: normalizeStringValue(subEntry.key) || void 0,
|
|
1629
|
+
comparison_operator: normalizeStringValue(subEntry.comparison_operator ?? subEntry.comparisonOperator) || void 0,
|
|
1630
|
+
value: typeof subEntry.value === "boolean" ? subEntry.value : Array.isArray(subEntry.value) ? subEntry.value.map((item) => normalizeStringValue(item)).filter(Boolean) : normalizeListOperatorValue(subEntry.value)
|
|
1631
|
+
}];
|
|
1632
|
+
}) : []
|
|
1633
|
+
} : void 0
|
|
1634
|
+
})) : normalizeStringValue(value.exitCondition ?? value.breakCondition) ? [{
|
|
1635
|
+
id: "loop-condition-1",
|
|
1636
|
+
varType: "string",
|
|
1637
|
+
variable_selector: normalizeSelectorPath(value.exitCondition ?? value.breakCondition),
|
|
1638
|
+
comparison_operator: "exists",
|
|
1639
|
+
value: ""
|
|
1640
|
+
}] : normalizedConfig.break_conditions,
|
|
1641
|
+
loop_count: normalizePositiveNumber(value.maxIterations ?? value.loop_count, normalizedConfig.loop_count ?? 10),
|
|
1642
|
+
error_handle_mode: value.failureMode === "continue" ? "continue-on-error" : value.failureMode === "remove-failed-results" ? "remove-abnormal-output" : value.failureMode === "terminate" ? "terminated" : normalizeStringValue(value.error_handle_mode) === "continue-on-error" ? "continue-on-error" : normalizeStringValue(value.error_handle_mode) === "remove-abnormal-output" ? "remove-abnormal-output" : "terminated",
|
|
1643
|
+
loop_variables: normalizeLoopVariables(value.loopVariables ?? value.loop_variables).map((entry) => ({
|
|
1644
|
+
id: entry.id,
|
|
1645
|
+
label: entry.name,
|
|
1646
|
+
var_type: normalizeConcreteValueType(entry.dataType),
|
|
1647
|
+
value_type: entry.valueType === "variable" ? "variable" : "constant",
|
|
1648
|
+
value: entry.value
|
|
1649
|
+
})),
|
|
1650
|
+
loop_id: normalizeStringValue(value.loop_id) || void 0
|
|
1651
|
+
};
|
|
1652
|
+
}
|
|
1653
|
+
case "answer": {
|
|
1654
|
+
const normalizedConfig = defaultConfig.kind === "answer" ? defaultConfig : null;
|
|
1655
|
+
if (!normalizedConfig) return defaultConfig;
|
|
1656
|
+
return {
|
|
1657
|
+
...normalizedConfig,
|
|
1658
|
+
variables: Array.isArray(value.variables) ? normalizeDifyVariables(value.variables, "answer-variable") : normalizedConfig.variables,
|
|
1659
|
+
answer: normalizeStringValue(value.answer ?? value.answerContent ?? value.content)
|
|
1660
|
+
};
|
|
1661
|
+
}
|
|
1662
|
+
case "http-request": {
|
|
1663
|
+
const normalizedConfig = defaultConfig.kind === "http-request" ? defaultConfig : null;
|
|
1664
|
+
if (!normalizedConfig) return defaultConfig;
|
|
1665
|
+
const rawAuthorization = isRecord(value.authorization) ? value.authorization : null;
|
|
1666
|
+
const authorizationConfig = isRecord(rawAuthorization?.config) ? rawAuthorization.config : rawAuthorization;
|
|
1667
|
+
const bodyConfig = isRecord(value.body) ? value.body : null;
|
|
1668
|
+
const timeoutConfig = isRecord(value.timeout) ? value.timeout : null;
|
|
1669
|
+
const retryConfig = isRecord(value.retry_config) ? value.retry_config : null;
|
|
1670
|
+
const variables = Array.isArray(value.variables) ? normalizeDifyVariables(value.variables, "http-variable") : [];
|
|
1671
|
+
return {
|
|
1672
|
+
...normalizedConfig,
|
|
1673
|
+
variables,
|
|
1674
|
+
method: normalizeHttpMethod(value.method),
|
|
1675
|
+
url: normalizeStringValue(value.url),
|
|
1676
|
+
headers: typeof value.headers === "string" ? value.headers : normalizeHttpKeyValueEntries(value.headers, "header").map((entry) => `${entry.key}: ${entry.value}`).join("\n"),
|
|
1677
|
+
params: typeof value.params === "string" ? value.params : normalizeHttpKeyValueEntries(value.params ?? value.query, "param").map((entry) => `${entry.key}: ${entry.value}`).join("\n"),
|
|
1678
|
+
body: {
|
|
1679
|
+
type: normalizeHttpBodyType(bodyConfig?.type),
|
|
1680
|
+
data: Array.isArray(bodyConfig?.data) ? normalizeHttpBodyPayloadEntries(bodyConfig?.data) : typeof bodyConfig?.data === "string" ? bodyConfig.data : normalizeStringValue(bodyConfig?.data ?? value.body)
|
|
1681
|
+
},
|
|
1682
|
+
authorization: {
|
|
1683
|
+
type: normalizeStringValue(rawAuthorization?.type ?? value.authType).toLowerCase() === "api-key" ? "api-key" : "no-auth",
|
|
1684
|
+
config: authorizationConfig ? {
|
|
1685
|
+
type: normalizeStringValue(authorizationConfig.type).toLowerCase() === "basic" ? "basic" : normalizeStringValue(authorizationConfig.type).toLowerCase() === "bearer" ? "bearer" : "custom",
|
|
1686
|
+
api_key: normalizeStringValue(authorizationConfig.api_key ?? authorizationConfig.apiKey),
|
|
1687
|
+
header: normalizeStringValue(authorizationConfig.header) || void 0
|
|
1688
|
+
} : null
|
|
1689
|
+
},
|
|
1690
|
+
timeout: {
|
|
1691
|
+
connect: typeof timeoutConfig?.connect === "number" ? timeoutConfig.connect : typeof value.timeoutMs === "number" ? Math.max(1, Math.round(value.timeoutMs / 1e3)) : normalizedConfig.timeout.connect,
|
|
1692
|
+
read: typeof timeoutConfig?.read === "number" ? timeoutConfig.read : normalizedConfig.timeout.read,
|
|
1693
|
+
write: typeof timeoutConfig?.write === "number" ? timeoutConfig.write : normalizedConfig.timeout.write,
|
|
1694
|
+
max_connect_timeout: typeof timeoutConfig?.max_connect_timeout === "number" ? timeoutConfig.max_connect_timeout : typeof timeoutConfig?.maxConnect === "number" ? timeoutConfig.maxConnect : normalizedConfig.timeout.max_connect_timeout,
|
|
1695
|
+
max_read_timeout: typeof timeoutConfig?.max_read_timeout === "number" ? timeoutConfig.max_read_timeout : typeof timeoutConfig?.maxRead === "number" ? timeoutConfig.maxRead : normalizedConfig.timeout.max_read_timeout,
|
|
1696
|
+
max_write_timeout: typeof timeoutConfig?.max_write_timeout === "number" ? timeoutConfig.max_write_timeout : typeof timeoutConfig?.maxWrite === "number" ? timeoutConfig.maxWrite : normalizedConfig.timeout.max_write_timeout
|
|
1697
|
+
},
|
|
1698
|
+
retry_config: {
|
|
1699
|
+
retry_enabled: typeof retryConfig?.retry_enabled === "boolean" ? retryConfig.retry_enabled : typeof value.retryEnabled === "boolean" ? value.retryEnabled : normalizedConfig.retry_config.retry_enabled,
|
|
1700
|
+
max_retries: typeof retryConfig?.max_retries === "number" && Number.isFinite(retryConfig.max_retries) ? Math.max(1, Math.min(10, Math.round(retryConfig.max_retries))) : typeof value.maxRetries === "number" && Number.isFinite(value.maxRetries) ? Math.max(1, Math.min(10, Math.round(value.maxRetries))) : normalizedConfig.retry_config.max_retries,
|
|
1701
|
+
retry_interval: typeof retryConfig?.retry_interval === "number" && Number.isFinite(retryConfig.retry_interval) ? Math.max(100, Math.min(5e3, Math.round(retryConfig.retry_interval))) : typeof value.retryInterval === "number" && Number.isFinite(value.retryInterval) ? Math.max(100, Math.min(5e3, Math.round(value.retryInterval))) : normalizedConfig.retry_config.retry_interval
|
|
1702
|
+
},
|
|
1703
|
+
ssl_verify: typeof value.ssl_verify === "boolean" ? value.ssl_verify : typeof value.sslVerify === "boolean" ? value.sslVerify : normalizeBooleanValue(value.ssl_verify, true)
|
|
1704
|
+
};
|
|
1705
|
+
}
|
|
1706
|
+
default: return {
|
|
1707
|
+
...defaultConfig,
|
|
1708
|
+
...value,
|
|
1709
|
+
kind
|
|
1710
|
+
};
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
function readRequiredString(value, path, options = {}) {
|
|
1714
|
+
if (typeof value !== "string") throw new Error(`${path} must be a string.`);
|
|
1715
|
+
if (options.allowEmpty === false && !value.trim()) throw new Error(`${path} must not be empty.`);
|
|
1716
|
+
return value;
|
|
1717
|
+
}
|
|
1718
|
+
function readOptionalString(value, path) {
|
|
1719
|
+
if (value === void 0) return;
|
|
1720
|
+
return readRequiredString(value, path);
|
|
1721
|
+
}
|
|
1722
|
+
function readOptionalBoolean(value, path) {
|
|
1723
|
+
if (value === void 0) return;
|
|
1724
|
+
if (typeof value !== "boolean") throw new Error(`${path} must be a boolean.`);
|
|
1725
|
+
return value;
|
|
1726
|
+
}
|
|
1727
|
+
function readOptionalNumber(value, path) {
|
|
1728
|
+
if (value === void 0) return;
|
|
1729
|
+
if (typeof value !== "number" || !Number.isFinite(value)) throw new Error(`${path} must be a finite number.`);
|
|
1730
|
+
return value;
|
|
1731
|
+
}
|
|
1732
|
+
function isWorkflowFieldInputType(value) {
|
|
1733
|
+
return typeof value === "string" && workflowFieldInputTypes.includes(value);
|
|
1734
|
+
}
|
|
1735
|
+
function parseWorkflowFormFieldValidation(value, path) {
|
|
1736
|
+
if (value === void 0) return {};
|
|
1737
|
+
if (!isRecord(value)) throw new Error(`${path} must be an object.`);
|
|
1738
|
+
return {
|
|
1739
|
+
pattern: readOptionalString(value.pattern, `${path}.pattern`),
|
|
1740
|
+
minLength: readOptionalNumber(value.minLength, `${path}.minLength`),
|
|
1741
|
+
maxLength: readOptionalNumber(value.maxLength, `${path}.maxLength`),
|
|
1742
|
+
min: readOptionalNumber(value.min, `${path}.min`),
|
|
1743
|
+
max: readOptionalNumber(value.max, `${path}.max`)
|
|
1744
|
+
};
|
|
1745
|
+
}
|
|
1746
|
+
function parseWorkflowFormFieldOption(value, path) {
|
|
1747
|
+
if (!isRecord(value)) throw new Error(`${path} must be an object.`);
|
|
1748
|
+
return {
|
|
1749
|
+
label: readRequiredString(value.label, `${path}.label`),
|
|
1750
|
+
value: readRequiredString(value.value, `${path}.value`)
|
|
1751
|
+
};
|
|
1752
|
+
}
|
|
1753
|
+
function parseWorkflowFormSchema(value) {
|
|
1754
|
+
if (!isRecord(value)) throw new Error("formSchema must be an object.");
|
|
1755
|
+
if (!Array.isArray(value.fields)) throw new Error("formSchema.fields must be an array.");
|
|
1756
|
+
const seenFieldIds = /* @__PURE__ */ new Set();
|
|
1757
|
+
const fields = value.fields.map((field, index) => {
|
|
1758
|
+
const path = `formSchema.fields[${index}]`;
|
|
1759
|
+
if (!isRecord(field)) throw new Error(`${path} must be an object.`);
|
|
1760
|
+
if (!isWorkflowFieldInputType(field.type)) throw new Error(`${path}.type must be one of: ${workflowFieldInputTypes.join(", ")}.`);
|
|
1761
|
+
if (field.options !== void 0 && !Array.isArray(field.options)) throw new Error(`${path}.options must be an array when provided.`);
|
|
1762
|
+
const parsedField = {
|
|
1763
|
+
id: readRequiredString(field.id, `${path}.id`, { allowEmpty: false }),
|
|
1764
|
+
label: readRequiredString(field.label, `${path}.label`),
|
|
1765
|
+
type: field.type,
|
|
1766
|
+
helperText: readOptionalString(field.helperText, `${path}.helperText`) ?? "",
|
|
1767
|
+
required: readOptionalBoolean(field.required, `${path}.required`) ?? false,
|
|
1768
|
+
placeholder: readOptionalString(field.placeholder, `${path}.placeholder`),
|
|
1769
|
+
options: field.options?.map((option, optionIndex) => parseWorkflowFormFieldOption(option, `${path}.options[${optionIndex}]`)),
|
|
1770
|
+
validation: parseWorkflowFormFieldValidation(field.validation, `${path}.validation`)
|
|
1771
|
+
};
|
|
1772
|
+
if (seenFieldIds.has(parsedField.id)) throw new Error(`formSchema.fields contains a duplicate id: ${parsedField.id}.`);
|
|
1773
|
+
seenFieldIds.add(parsedField.id);
|
|
1774
|
+
return parsedField;
|
|
1775
|
+
});
|
|
1776
|
+
return normalizeWorkflowFormSchema({
|
|
1777
|
+
title: readRequiredString(value.title, "formSchema.title"),
|
|
1778
|
+
description: readRequiredString(value.description, "formSchema.description"),
|
|
1779
|
+
fields
|
|
1780
|
+
});
|
|
1781
|
+
}
|
|
1782
|
+
function buildWorkflowFormSchemaDocument(formSchema) {
|
|
1783
|
+
return {
|
|
1784
|
+
schemaVersion: "1.0",
|
|
1785
|
+
kind: "lsflow.workflow-form-schema",
|
|
1786
|
+
formSchema: normalizeWorkflowFormSchema(formSchema)
|
|
1787
|
+
};
|
|
1788
|
+
}
|
|
1789
|
+
function stringifyWorkflowFormSchema(formSchema) {
|
|
1790
|
+
return JSON.stringify(buildWorkflowFormSchemaDocument(formSchema), null, 2);
|
|
1791
|
+
}
|
|
1792
|
+
function parseWorkflowFormSchemaJson(input) {
|
|
1793
|
+
let parsed;
|
|
1794
|
+
try {
|
|
1795
|
+
parsed = JSON.parse(input);
|
|
1796
|
+
} catch {
|
|
1797
|
+
throw new Error("The imported form schema file is not valid JSON.");
|
|
1798
|
+
}
|
|
1799
|
+
if (!isRecord(parsed)) throw new Error("The imported form schema document must be a JSON object.");
|
|
1800
|
+
if (parsed.schemaVersion !== "1.0") throw new Error("The imported form schema document must use schemaVersion \"1.0\".");
|
|
1801
|
+
if (parsed.kind !== "lsflow.workflow-form-schema") throw new Error("The imported form schema document must have kind \"lsflow.workflow-form-schema\".");
|
|
1802
|
+
return parseWorkflowFormSchema(parsed.formSchema);
|
|
1803
|
+
}
|
|
1804
|
+
function normalizeWorkflowValidationResult(validation) {
|
|
1805
|
+
const initialValidation = buildInitialValidationResult();
|
|
1806
|
+
return {
|
|
1807
|
+
status: validation?.status ?? initialValidation.status,
|
|
1808
|
+
validatedAt: validation?.validatedAt ?? initialValidation.validatedAt,
|
|
1809
|
+
issues: validation?.issues ?? initialValidation.issues
|
|
1810
|
+
};
|
|
1811
|
+
}
|
|
1812
|
+
function buildInitialWorkflowAuditLog(workflowId, scope) {
|
|
1813
|
+
return [buildAuditRecord(workflowId, scope, "draft-created", "Draft created in builder.")];
|
|
1814
|
+
}
|
|
1815
|
+
function buildAuditRecord(workflowId, scope, action, detail) {
|
|
1816
|
+
return {
|
|
1817
|
+
id: crypto.randomUUID(),
|
|
1818
|
+
workflowId,
|
|
1819
|
+
actorId: "admin-demo",
|
|
1820
|
+
tenantId: scope.tenantId,
|
|
1821
|
+
workspaceId: scope.workspaceId,
|
|
1822
|
+
action,
|
|
1823
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1824
|
+
detail
|
|
1825
|
+
};
|
|
1826
|
+
}
|
|
1827
|
+
function createInitialWorkflowDraft(input) {
|
|
1828
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1829
|
+
const workflowId = crypto.randomUUID();
|
|
1830
|
+
return {
|
|
1831
|
+
id: workflowId,
|
|
1832
|
+
schemaVersion: "2.0",
|
|
1833
|
+
tenantId: input.tenantId,
|
|
1834
|
+
workspaceId: input.workspaceId,
|
|
1835
|
+
status: "draft",
|
|
1836
|
+
metadata: {
|
|
1837
|
+
name: input.name?.trim() || "Untitled workflow draft",
|
|
1838
|
+
description: input.description?.trim() || "Draft workflow opened in the LSFlow builder."
|
|
1839
|
+
},
|
|
1840
|
+
graphState: buildInitialGraphState(),
|
|
1841
|
+
formSchema: buildInitialFormSchema(),
|
|
1842
|
+
nodeConfigurations: {},
|
|
1843
|
+
validation: buildInitialValidationResult(),
|
|
1844
|
+
createdAt: now,
|
|
1845
|
+
updatedAt: now,
|
|
1846
|
+
publishedVersionId: null,
|
|
1847
|
+
publishedVersions: [],
|
|
1848
|
+
auditLog: buildInitialWorkflowAuditLog(workflowId, {
|
|
1849
|
+
tenantId: input.tenantId,
|
|
1850
|
+
workspaceId: input.workspaceId
|
|
1851
|
+
})
|
|
1852
|
+
};
|
|
1853
|
+
}
|
|
1854
|
+
function normalizeWorkflowDraft(input) {
|
|
1855
|
+
const normalizedDraft = structuredClone(input);
|
|
1856
|
+
const normalizedGraphState = createWorkflowGraph(normalizedDraft.graphState);
|
|
1857
|
+
if (normalizedDraft.schemaVersion !== "2.0") throw new Error("Legacy workflow drafts are not supported by the redesigned builder.");
|
|
1858
|
+
normalizedGraphState.nodes = normalizedGraphState.nodes.map((node) => {
|
|
1859
|
+
const rawNodeData = node.data;
|
|
1860
|
+
const rawKind = typeof rawNodeData?.kind === "string" ? rawNodeData.kind : void 0;
|
|
1861
|
+
const rawLabel = typeof rawNodeData?.label === "string" ? rawNodeData.label : void 0;
|
|
1862
|
+
const rawDescription = typeof rawNodeData?.description === "string" ? rawNodeData.description : void 0;
|
|
1863
|
+
const normalizedKind = rawKind === "outcome" ? "end" : rawKind;
|
|
1864
|
+
return {
|
|
1865
|
+
...node,
|
|
1866
|
+
type: normalizedKind === "end" ? "output" : node.type,
|
|
1867
|
+
data: rawNodeData ? {
|
|
1868
|
+
...rawNodeData,
|
|
1869
|
+
kind: normalizedKind ?? rawNodeData.kind,
|
|
1870
|
+
label: rawKind === "outcome" && rawLabel === "Outcome" ? "Output" : rawLabel,
|
|
1871
|
+
description: rawKind === "outcome" && rawDescription === "Published behavior stays separate from mutable draft edits." ? "Finish the workflow and expose the final outputs for downstream use." : rawDescription
|
|
1872
|
+
} : node.data
|
|
1873
|
+
};
|
|
1874
|
+
});
|
|
1875
|
+
normalizedDraft.status = "draft";
|
|
1876
|
+
normalizedDraft.schemaVersion = "2.0";
|
|
1877
|
+
normalizedDraft.metadata = {
|
|
1878
|
+
name: normalizedDraft.metadata?.name?.trim() || "Untitled workflow draft",
|
|
1879
|
+
description: normalizedDraft.metadata?.description?.trim() || "Draft workflow opened in the LSFlow builder."
|
|
1880
|
+
};
|
|
1881
|
+
normalizedDraft.graphState = normalizedGraphState;
|
|
1882
|
+
normalizedDraft.formSchema = normalizeWorkflowFormSchema(normalizedDraft.formSchema);
|
|
1883
|
+
normalizedDraft.nodeConfigurations = normalizedDraft.nodeConfigurations ?? {};
|
|
1884
|
+
for (const node of normalizedDraft.graphState.nodes) {
|
|
1885
|
+
const kind = node.data?.kind;
|
|
1886
|
+
if (!kind || isInternalWorkflowNodeKind(kind)) continue;
|
|
1887
|
+
if (!normalizedDraft.nodeConfigurations[node.id]) {
|
|
1888
|
+
const defaultConfig = createDefaultNodeConfigurationV2(kind);
|
|
1889
|
+
if (defaultConfig) normalizedDraft.nodeConfigurations[node.id] = structuredClone(defaultConfig);
|
|
1890
|
+
}
|
|
1891
|
+
normalizedDraft.nodeConfigurations[node.id] = normalizeNodeConfigurationByKind(kind, normalizedDraft.nodeConfigurations[node.id]);
|
|
1892
|
+
if (kind === "question-classifier" && node.data) {
|
|
1893
|
+
const existingConfig = normalizedDraft.nodeConfigurations[node.id];
|
|
1894
|
+
if (existingConfig?.kind === "question-classifier") node.data = {
|
|
1895
|
+
...node.data,
|
|
1896
|
+
conditionalBranches: buildQuestionClassifierConditionalBranches(existingConfig.classes)
|
|
1897
|
+
};
|
|
1898
|
+
}
|
|
1899
|
+
if (kind === "if-else") {
|
|
1900
|
+
const existingConfig = normalizedDraft.nodeConfigurations[node.id];
|
|
1901
|
+
const conditionalBranches = node.data?.conditionalBranches ?? [];
|
|
1902
|
+
if (existingConfig?.kind === "if-else") {
|
|
1903
|
+
const nextBranchConditions = Array.isArray(existingConfig.cases) && existingConfig.cases.length > 0 ? buildBranchConditionsFromIfElseCases(conditionalBranches, existingConfig.cases, existingConfig.branchConditions) : buildNormalizedBranchConditions(conditionalBranches, existingConfig.branchConditions);
|
|
1904
|
+
existingConfig.branchConditions = nextBranchConditions;
|
|
1905
|
+
existingConfig.cases = buildIfElseCasesFromBranchConditions(conditionalBranches, nextBranchConditions);
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
}
|
|
1909
|
+
normalizedDraft.validation = normalizeWorkflowValidationResult(normalizedDraft.validation);
|
|
1910
|
+
normalizedDraft.publishedVersionId = normalizedDraft.publishedVersionId ?? null;
|
|
1911
|
+
normalizedDraft.publishedVersions = normalizedDraft.publishedVersions ?? [];
|
|
1912
|
+
normalizedDraft.auditLog = normalizedDraft.auditLog?.length ? normalizedDraft.auditLog : buildInitialWorkflowAuditLog(normalizedDraft.id, {
|
|
1913
|
+
tenantId: normalizedDraft.tenantId,
|
|
1914
|
+
workspaceId: normalizedDraft.workspaceId
|
|
1915
|
+
});
|
|
1916
|
+
return normalizedDraft;
|
|
1917
|
+
}
|
|
1918
|
+
function buildWorkflowPublishSnapshot(draft) {
|
|
1919
|
+
const effectiveFormSchema = draft.formSchema.fields.length > 0 ? structuredClone(draft.formSchema) : buildFormSchemaFromStartNode(draft);
|
|
1920
|
+
return {
|
|
1921
|
+
metadata: structuredClone(draft.metadata),
|
|
1922
|
+
graphState: structuredClone(draft.graphState),
|
|
1923
|
+
formSchema: effectiveFormSchema,
|
|
1924
|
+
nodeConfigurations: structuredClone(draft.nodeConfigurations),
|
|
1925
|
+
validation: structuredClone(draft.validation)
|
|
1926
|
+
};
|
|
1927
|
+
}
|
|
1928
|
+
function getNodeParentId(node) {
|
|
1929
|
+
return node.parentNodeId ?? node.parentNode;
|
|
1930
|
+
}
|
|
1931
|
+
function getEdgeBranchLabel(edge) {
|
|
1932
|
+
const data = edge.data;
|
|
1933
|
+
return typeof data?.branchLabel === "string" ? data.branchLabel : void 0;
|
|
1934
|
+
}
|
|
1935
|
+
function getTriggerKind(kind) {
|
|
1936
|
+
switch (kind) {
|
|
1937
|
+
case "start": return "user-input";
|
|
1938
|
+
case "schedule-trigger": return "schedule";
|
|
1939
|
+
case "webhook-trigger": return "webhook";
|
|
1940
|
+
case "trigger-plugin": return "plugin";
|
|
1941
|
+
case "data-source": return "data-source";
|
|
1942
|
+
default: return null;
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
function buildPublishedNodeConfiguration(kind, configuration) {
|
|
1946
|
+
const normalizedConfiguration = structuredClone(configuration ?? buildDefaultNodeConfiguration(kind));
|
|
1947
|
+
if (normalizedConfiguration.kind === "start") return {
|
|
1948
|
+
kind: "start",
|
|
1949
|
+
variables: normalizedConfiguration.variables.map((variable) => ({
|
|
1950
|
+
id: variable.id,
|
|
1951
|
+
variable: variable.variable,
|
|
1952
|
+
label: variable.label,
|
|
1953
|
+
type: variable.type,
|
|
1954
|
+
required: variable.required,
|
|
1955
|
+
hint: variable.hint,
|
|
1956
|
+
placeholder: variable.placeholder,
|
|
1957
|
+
options: variable.options,
|
|
1958
|
+
default: variable.defaultValue,
|
|
1959
|
+
max_length: variable.maxLength,
|
|
1960
|
+
unit: variable.unit,
|
|
1961
|
+
value_selector: variable.value_selector,
|
|
1962
|
+
getVarValueFromDependent: variable.getVarValueFromDependent,
|
|
1963
|
+
hide: variable.hide,
|
|
1964
|
+
isFileItem: variable.isFileItem,
|
|
1965
|
+
json_schema: variable.json_schema,
|
|
1966
|
+
allowed_file_upload_methods: variable.allowed_file_upload_methods,
|
|
1967
|
+
allowed_upload_methods: variable.allowed_upload_methods,
|
|
1968
|
+
allowed_file_types: variable.allowed_file_types,
|
|
1969
|
+
allowed_file_extensions: variable.allowed_file_extensions,
|
|
1970
|
+
number_limits: variable.number_limits
|
|
1971
|
+
}))
|
|
1972
|
+
};
|
|
1973
|
+
if (normalizedConfiguration.kind === "end") return {
|
|
1974
|
+
kind: "end",
|
|
1975
|
+
outputs: normalizedConfiguration.outputs.map((output) => {
|
|
1976
|
+
const sourceVariable = deriveEndOutputNameFromSelector(normalizeSelectorPath(output.value_selector));
|
|
1977
|
+
return {
|
|
1978
|
+
outputName: normalizeStringValue(output.variable) || sourceVariable,
|
|
1979
|
+
sourceVariable
|
|
1980
|
+
};
|
|
1981
|
+
}).filter((output) => output.outputName && output.sourceVariable)
|
|
1982
|
+
};
|
|
1983
|
+
if (normalizedConfiguration.kind === "tool") {
|
|
1984
|
+
const toolReference = normalizedConfiguration.reference;
|
|
1985
|
+
return {
|
|
1986
|
+
kind: "tool",
|
|
1987
|
+
provider_id: normalizedConfiguration.provider_id ?? toolReference.id,
|
|
1988
|
+
provider_type: normalizedConfiguration.provider_type ?? toolReference.providerType,
|
|
1989
|
+
provider_name: normalizedConfiguration.provider_name ?? toolReference.providerName,
|
|
1990
|
+
tool_name: normalizedConfiguration.tool_name ?? toolReference.toolName,
|
|
1991
|
+
tool_label: normalizedConfiguration.tool_label ?? toolReference.label,
|
|
1992
|
+
tool_parameters: normalizedConfiguration.tool_parameters ?? Object.fromEntries(normalizedConfiguration.parameters.filter((entry) => entry.name.trim()).map((entry) => [entry.name, {
|
|
1993
|
+
type: entry.valueType,
|
|
1994
|
+
value: entry.value
|
|
1995
|
+
}])),
|
|
1996
|
+
tool_configurations: normalizedConfiguration.tool_configurations ?? Object.fromEntries(normalizedConfiguration.configurations.filter((entry) => entry.name.trim()).map((entry) => [entry.name, entry.value])),
|
|
1997
|
+
output_schema: normalizedConfiguration.output_schema && normalizedConfiguration.output_schema.length > 0 ? normalizedConfiguration.output_schema : normalizedConfiguration.outputSchema,
|
|
1998
|
+
version: normalizedConfiguration.version ?? toolReference.version,
|
|
1999
|
+
tool_description: normalizedConfiguration.tool_description ?? toolReference.description,
|
|
2000
|
+
is_team_authorization: normalizedConfiguration.is_team_authorization,
|
|
2001
|
+
params: normalizedConfiguration.params,
|
|
2002
|
+
provider_icon: normalizedConfiguration.provider_icon,
|
|
2003
|
+
provider_icon_dark: normalizedConfiguration.provider_icon_dark,
|
|
2004
|
+
plugin_unique_identifier: normalizedConfiguration.plugin_unique_identifier ?? toolReference.pluginUniqueIdentifier,
|
|
2005
|
+
tool_node_version: normalizedConfiguration.tool_node_version ?? "2"
|
|
2006
|
+
};
|
|
2007
|
+
}
|
|
2008
|
+
if (normalizedConfiguration.kind === "agent") {
|
|
2009
|
+
const publishedOutputFields = Array.isArray(normalizedConfiguration.output_schema) && normalizedConfiguration.output_schema.length > 0 ? normalizedConfiguration.output_schema : normalizedConfiguration.outputSchema;
|
|
2010
|
+
return {
|
|
2011
|
+
kind: "agent",
|
|
2012
|
+
agent_strategy_provider_name: normalizedConfiguration.agent_strategy_provider_name ?? normalizedConfiguration.strategy.providerName,
|
|
2013
|
+
agent_strategy_name: normalizedConfiguration.agent_strategy_name ?? normalizedConfiguration.strategy.name,
|
|
2014
|
+
agent_strategy_label: normalizedConfiguration.agent_strategy_label ?? normalizedConfiguration.strategy.label,
|
|
2015
|
+
agent_parameters: normalizedConfiguration.agent_parameters ?? Object.fromEntries(normalizedConfiguration.strategyParameters.filter((entry) => entry.name.trim()).map((entry) => [entry.name, {
|
|
2016
|
+
type: entry.valueType === "variable" ? "variable" : "constant",
|
|
2017
|
+
value: entry.value
|
|
2018
|
+
}])),
|
|
2019
|
+
output_schema: normalizedConfiguration.output_schema && !Array.isArray(normalizedConfiguration.output_schema) ? structuredClone(normalizedConfiguration.output_schema) : buildPublishedOutputSchema(publishedOutputFields),
|
|
2020
|
+
plugin_unique_identifier: normalizedConfiguration.plugin_unique_identifier ?? normalizedConfiguration.strategy.pluginUniqueIdentifier,
|
|
2021
|
+
meta: normalizedConfiguration.meta ?? normalizedConfiguration.strategy.meta ?? null,
|
|
2022
|
+
memory: {
|
|
2023
|
+
enabled: normalizedConfiguration.memory.enabled,
|
|
2024
|
+
window: {
|
|
2025
|
+
enabled: normalizedConfiguration.memory.enabled,
|
|
2026
|
+
size: normalizedConfiguration.memory.windowSize
|
|
2027
|
+
}
|
|
2028
|
+
},
|
|
2029
|
+
version: normalizedConfiguration.version ?? normalizedConfiguration.strategy.version ?? normalizedConfiguration.tool_node_version,
|
|
2030
|
+
tool_node_version: normalizedConfiguration.tool_node_version ?? "2"
|
|
2031
|
+
};
|
|
2032
|
+
}
|
|
2033
|
+
return normalizedConfiguration;
|
|
2034
|
+
}
|
|
2035
|
+
function buildPublishedConditionalBranches(kind, branches) {
|
|
2036
|
+
if (kind !== "human-input") return structuredClone(branches);
|
|
2037
|
+
return branches.map((branch) => ({
|
|
2038
|
+
...structuredClone(branch),
|
|
2039
|
+
expression: `__action_id == "${escapeBranchExpressionValue(branch.id)}"`
|
|
2040
|
+
}));
|
|
2041
|
+
}
|
|
2042
|
+
function escapeBranchExpressionValue(value) {
|
|
2043
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
|
|
2044
|
+
}
|
|
2045
|
+
function buildPublishedWorkflowDefinition(draft, input) {
|
|
2046
|
+
const effectiveFormSchema = draft.formSchema.fields.length > 0 ? structuredClone(draft.formSchema) : buildFormSchemaFromStartNode(draft);
|
|
2047
|
+
const executableNodes = draft.graphState.nodes.filter((node) => {
|
|
2048
|
+
const kind = node.data?.kind;
|
|
2049
|
+
return Boolean(kind) && !isInternalWorkflowNodeKind(kind);
|
|
2050
|
+
});
|
|
2051
|
+
const childNodeIdsByParent = /* @__PURE__ */ new Map();
|
|
2052
|
+
executableNodes.forEach((node) => {
|
|
2053
|
+
const parentNodeId = getNodeParentId(node);
|
|
2054
|
+
if (!parentNodeId) return;
|
|
2055
|
+
const currentChildNodeIds = childNodeIdsByParent.get(parentNodeId) ?? [];
|
|
2056
|
+
currentChildNodeIds.push(node.id);
|
|
2057
|
+
childNodeIdsByParent.set(parentNodeId, currentChildNodeIds);
|
|
2058
|
+
});
|
|
2059
|
+
const graphNodes = executableNodes.flatMap((node) => {
|
|
2060
|
+
const nodeData = node.data;
|
|
2061
|
+
const kind = nodeData?.kind;
|
|
2062
|
+
if (!kind) return [];
|
|
2063
|
+
return [{
|
|
2064
|
+
id: node.id,
|
|
2065
|
+
kind,
|
|
2066
|
+
label: nodeData.label,
|
|
2067
|
+
description: nodeData.description,
|
|
2068
|
+
parentNodeId: getNodeParentId(node),
|
|
2069
|
+
childNodeIds: childNodeIdsByParent.get(node.id) ?? [],
|
|
2070
|
+
configuration: buildPublishedNodeConfiguration(kind, draft.nodeConfigurations[node.id]),
|
|
2071
|
+
conditionalBranches: nodeData.conditionalBranches ? buildPublishedConditionalBranches(kind, nodeData.conditionalBranches) : void 0
|
|
2072
|
+
}];
|
|
2073
|
+
});
|
|
2074
|
+
const graphEdges = draft.graphState.edges.map((edge) => ({
|
|
2075
|
+
id: edge.id,
|
|
2076
|
+
sourceNodeId: edge.source,
|
|
2077
|
+
sourceHandleId: edge.sourceHandle,
|
|
2078
|
+
targetNodeId: edge.target,
|
|
2079
|
+
targetHandleId: edge.targetHandle,
|
|
2080
|
+
branchLabel: getEdgeBranchLabel(edge)
|
|
2081
|
+
}));
|
|
2082
|
+
const triggers = graphNodes.flatMap((node) => {
|
|
2083
|
+
const triggerType = getTriggerKind(node.kind);
|
|
2084
|
+
if (!triggerType) return [];
|
|
2085
|
+
return [{
|
|
2086
|
+
id: `${node.id}::trigger`,
|
|
2087
|
+
nodeId: node.id,
|
|
2088
|
+
type: triggerType,
|
|
2089
|
+
name: node.label,
|
|
2090
|
+
configuration: structuredClone(node.configuration)
|
|
2091
|
+
}];
|
|
2092
|
+
});
|
|
2093
|
+
return {
|
|
2094
|
+
schemaVersion: "2.0",
|
|
2095
|
+
workflowId: draft.id,
|
|
2096
|
+
draftId: draft.id,
|
|
2097
|
+
versionId: input.versionId,
|
|
2098
|
+
versionNumber: input.versionNumber,
|
|
2099
|
+
publishedAt: input.publishedAt,
|
|
2100
|
+
metadata: structuredClone(draft.metadata),
|
|
2101
|
+
formSchema: effectiveFormSchema,
|
|
2102
|
+
validation: structuredClone(draft.validation),
|
|
2103
|
+
triggers,
|
|
2104
|
+
graph: {
|
|
2105
|
+
triggerNodeIds: triggers.map((trigger) => trigger.nodeId),
|
|
2106
|
+
nodes: graphNodes,
|
|
2107
|
+
edges: graphEdges
|
|
2108
|
+
}
|
|
2109
|
+
};
|
|
2110
|
+
}
|
|
2111
|
+
function buildDefaultNodeConfiguration(kind) {
|
|
2112
|
+
return structuredClone(createDefaultNodeConfigurationV2(kind) ?? { kind: "note" });
|
|
2113
|
+
}
|
|
2114
|
+
//#endregion
|
|
2115
|
+
export { buildDefaultNodeConfiguration, buildFormSchemaFromStartNode, buildPublishedWorkflowDefinition, buildQuestionClassifierConditionalBranches, buildWorkflowFormSchemaDocument, buildWorkflowPublishSnapshot, createInitialWorkflowDraft, getStartNodeConfiguration, normalizeWorkflowDraft, parseWorkflowFormSchemaJson, stringifyWorkflowFormSchema };
|