@@ -627,12 +627,9 @@ function createBlockFromParams(
627627
628628 let sanitizedValue = value
629629
630- // Special handling for inputFormat - ensure it's an array
631- if ( key === 'inputFormat' && value !== null && value !== undefined ) {
632- if ( ! Array . isArray ( value ) ) {
633- // Invalid format, default to empty array
634- sanitizedValue = [ ]
635- }
630+ // Normalize array subblocks with id fields (inputFormat, table rows, etc.)
631+ if ( shouldNormalizeArrayIds ( key ) ) {
632+ sanitizedValue = normalizeArrayWithIds ( value )
636633 }
637634
638635 // Special handling for tools - normalize and filter disallowed
@@ -720,6 +717,55 @@ function normalizeTools(tools: any[]): any[] {
720717 } )
721718}
722719
720+ /** UUID v4 regex pattern for validation */
721+ const UUID_REGEX = / ^ [ 0 - 9 a - f ] { 8 } - [ 0 - 9 a - f ] { 4 } - [ 0 - 9 a - f ] { 4 } - [ 0 - 9 a - f ] { 4 } - [ 0 - 9 a - f ] { 12 } $ / i
722+
723+ /**
724+ * Subblock types that store arrays of objects with `id` fields.
725+ * The LLM may generate arbitrary IDs which need to be converted to proper UUIDs.
726+ */
727+ const ARRAY_WITH_ID_SUBBLOCK_TYPES = new Set ( [
728+ 'inputFormat' , // input-format: Fields with id, name, type, value, collapsed
729+ 'headers' , // table: Rows with id, cells (used for HTTP headers)
730+ 'params' , // table: Rows with id, cells (used for query params)
731+ 'variables' , // table or variables-input: Rows/assignments with id
732+ 'tagFilters' , // knowledge-tag-filters: Filters with id, tagName, etc.
733+ 'documentTags' , // document-tag-entry: Tags with id, tagName, etc.
734+ 'metrics' , // eval-input: Metrics with id, name, description, range
735+ ] )
736+
737+ /**
738+ * Normalizes array subblock values by ensuring each item has a valid UUID.
739+ * The LLM may generate arbitrary IDs like "input-desc-001" or "row-1" which need
740+ * to be converted to proper UUIDs for consistency with UI-created items.
741+ */
742+ function normalizeArrayWithIds ( value : unknown ) : any [ ] {
743+ if ( ! Array . isArray ( value ) ) {
744+ return [ ]
745+ }
746+
747+ return value . map ( ( item : any ) => {
748+ if ( ! item || typeof item !== 'object' ) {
749+ return item
750+ }
751+
752+ // Check if id is missing or not a valid UUID
753+ const hasValidUUID = typeof item . id === 'string' && UUID_REGEX . test ( item . id )
754+ if ( ! hasValidUUID ) {
755+ return { ...item , id : crypto . randomUUID ( ) }
756+ }
757+
758+ return item
759+ } )
760+ }
761+
762+ /**
763+ * Checks if a subblock key should have its array items normalized with UUIDs.
764+ */
765+ function shouldNormalizeArrayIds ( key : string ) : boolean {
766+ return ARRAY_WITH_ID_SUBBLOCK_TYPES . has ( key )
767+ }
768+
723769/**
724770 * Normalize responseFormat to ensure consistent storage
725771 * Handles both string (JSON) and object formats
@@ -1360,12 +1406,9 @@ function applyOperationsToWorkflowState(
13601406 }
13611407 let sanitizedValue = value
13621408
1363- // Special handling for inputFormat - ensure it's an array
1364- if ( key === 'inputFormat' && value !== null && value !== undefined ) {
1365- if ( ! Array . isArray ( value ) ) {
1366- // Invalid format, default to empty array
1367- sanitizedValue = [ ]
1368- }
1409+ // Normalize array subblocks with id fields (inputFormat, table rows, etc.)
1410+ if ( shouldNormalizeArrayIds ( key ) ) {
1411+ sanitizedValue = normalizeArrayWithIds ( value )
13691412 }
13701413
13711414 // Special handling for tools - normalize and filter disallowed
@@ -2011,10 +2054,9 @@ function applyOperationsToWorkflowState(
20112054
20122055 let sanitizedValue = value
20132056
2014- if ( key === 'inputFormat' && value !== null && value !== undefined ) {
2015- if ( ! Array . isArray ( value ) ) {
2016- sanitizedValue = [ ]
2017- }
2057+ // Normalize array subblocks with id fields (inputFormat, table rows, etc.)
2058+ if ( shouldNormalizeArrayIds ( key ) ) {
2059+ sanitizedValue = normalizeArrayWithIds ( value )
20182060 }
20192061
20202062 // Special handling for tools - normalize and filter disallowed
0 commit comments