(serializedBlock: SerializedBlock)
| 337 | } |
| 338 | |
| 339 | private deserializeBlock(serializedBlock: SerializedBlock): BlockState { |
| 340 | const blockType = serializedBlock.metadata?.id |
| 341 | if (!blockType) { |
| 342 | throw new Error(`Invalid block type: ${serializedBlock.metadata?.id}`) |
| 343 | } |
| 344 | |
| 345 | // Special handling for subflow blocks (loops, parallels, etc.) |
| 346 | if (blockType === 'loop' || blockType === 'parallel') { |
| 347 | return { |
| 348 | id: serializedBlock.id, |
| 349 | type: blockType, |
| 350 | name: serializedBlock.metadata?.name || (blockType === 'loop' ? 'Loop' : 'Parallel'), |
| 351 | position: serializedBlock.position, |
| 352 | subBlocks: {}, // Loops and parallels don't have traditional subBlocks |
| 353 | outputs: serializedBlock.outputs, |
| 354 | enabled: serializedBlock.enabled ?? true, |
| 355 | data: serializedBlock.config.params, // Preserve the data (parallelType, count, etc.) |
| 356 | } |
| 357 | } |
| 358 | |
| 359 | const blockConfig = getBlock(blockType) |
| 360 | if (!blockConfig) { |
| 361 | throw new Error(`Invalid block type: ${blockType}`) |
| 362 | } |
| 363 | |
| 364 | const subBlocks: Record<string, any> = {} |
| 365 | blockConfig.subBlocks.forEach((subBlock) => { |
| 366 | subBlocks[subBlock.id] = { |
| 367 | id: subBlock.id, |
| 368 | type: subBlock.type, |
| 369 | value: serializedBlock.config.params[subBlock.id] ?? null, |
| 370 | } |
| 371 | }) |
| 372 | |
| 373 | // Migration logic for agent blocks: Transform old systemPrompt/userPrompt to messages array |
| 374 | if (blockType === 'agent') { |
| 375 | migrateAgentParamsToMessages(serializedBlock.config.params, subBlocks, serializedBlock.id) |
| 376 | } |
| 377 | |
| 378 | return { |
| 379 | id: serializedBlock.id, |
| 380 | type: blockType, |
| 381 | name: serializedBlock.metadata?.name || blockConfig.name, |
| 382 | position: serializedBlock.position, |
| 383 | subBlocks, |
| 384 | outputs: serializedBlock.outputs, |
| 385 | enabled: true, |
| 386 | triggerMode: |
| 387 | serializedBlock.config?.params?.triggerMode === true || |
| 388 | serializedBlock.metadata?.category === 'triggers', |
| 389 | advancedMode: serializedBlock.config?.params?.advancedMode === true, |
| 390 | } |
| 391 | } |
| 392 | } |
| 393 | |
| 394 | /** A canonical pair where the active member is empty but an inactive member holds a value that will be silently dropped. */ |
no test coverage detected