@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.
Files changed (30) hide show
  1. package/README.md +44 -0
  2. package/dist/components/WorkflowBuilder.vue.d.ts +27 -0
  3. package/dist/components/WorkflowBuilder.vue.d.ts.map +1 -0
  4. package/dist/contracts.d.ts +28 -0
  5. package/dist/contracts.d.ts.map +1 -0
  6. package/dist/domain/builder-node-definition.d.ts +786 -0
  7. package/dist/domain/builder-node-definition.d.ts.map +1 -0
  8. package/dist/domain/builder-node-definition.js +1275 -0
  9. package/dist/domain/builder-node-metadata-response.d.ts +61 -0
  10. package/dist/domain/builder-node-metadata-response.d.ts.map +1 -0
  11. package/dist/domain/builder-node-metadata-response.js +0 -0
  12. package/dist/domain/workflow-draft.d.ts +169 -0
  13. package/dist/domain/workflow-draft.d.ts.map +1 -0
  14. package/dist/domain/workflow-draft.js +2115 -0
  15. package/dist/form-schema/form-schema-editor.d.ts +13 -0
  16. package/dist/form-schema/form-schema-editor.d.ts.map +1 -0
  17. package/dist/form-schema/form-schema-editor.js +65 -0
  18. package/dist/index.d.ts +98 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +9298 -0
  21. package/dist/inspector/BuilderNodeSettingsPanel.vue.d.ts +136 -0
  22. package/dist/inspector/BuilderNodeSettingsPanel.vue.d.ts.map +1 -0
  23. package/dist/inspector/builder-node-settings-registry.d.ts +5 -0
  24. package/dist/inspector/builder-node-settings-registry.d.ts.map +1 -0
  25. package/dist/inspector/builder-node-settings-registry.js +37 -0
  26. package/dist/session/create-builder-session.d.ts +27 -0
  27. package/dist/session/create-builder-session.d.ts.map +1 -0
  28. package/dist/session/create-builder-session.js +670 -0
  29. package/dist/workflow-builder.css +112 -0
  30. 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 };