snow-flow 10.0.1-dev.470 → 10.0.1-dev.471

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
- "version": "10.0.1-dev.470",
3
+ "version": "10.0.1-dev.471",
4
4
  "name": "snow-flow",
5
5
  "description": "Snow-Flow - ServiceNow Multi-Agent Development Framework powered by AI",
6
6
  "license": "Elastic-2.0",
@@ -1009,7 +1009,7 @@ async function addActionViaGraphQL(
1009
1009
  inputResult.actionParams, uuid
1010
1010
  );
1011
1011
  steps.record_action = recordActionResult.steps;
1012
- var hasRecordPills = recordActionResult.labelCacheEntries.length > 0;
1012
+ var hasRecordPills = (recordActionResult.labelCacheUpdates.length + recordActionResult.labelCacheInserts.length) > 0;
1013
1013
 
1014
1014
  // For record actions: clear data pill values from INSERT — they'll be set via separate UPDATE
1015
1015
  // (Flow Designer's GraphQL API ignores labelCache during INSERT, it only works with UPDATE)
@@ -1064,19 +1064,30 @@ async function addActionViaGraphQL(
1064
1064
  if (!actionId) return { success: false, steps, error: 'GraphQL action INSERT returned no ID' };
1065
1065
 
1066
1066
  // Step 2: UPDATE with data pill values + labelCache (separate mutation, matching UI behavior)
1067
- // The Flow Designer UI always sets data pill references via a separate UPDATE.
1067
+ // The Flow Designer UI uses labelCache UPDATE for existing pills (record-level)
1068
+ // and labelCache INSERT for new pills (field-level in values).
1068
1069
  if (hasRecordPills) {
1069
1070
  var updateInputs: any[] = [];
1070
- // Collect all inputs that have data pill values
1071
+ // Collect inputs for the UPDATE mutation
1071
1072
  for (var ri = 0; ri < recordActionResult.inputs.length; ri++) {
1072
1073
  var inp = recordActionResult.inputs[ri];
1073
1074
  var val = inp.value?.value || '';
1074
1075
  if (inp.name === 'record' && val.startsWith('{{')) {
1075
1076
  updateInputs.push({ name: 'record', value: { schemaless: false, schemalessValue: '', value: val } });
1076
1077
  } else if (inp.name === 'table_name') {
1077
- updateInputs.push({ name: 'table_name', displayValue: inp.displayValue || { value: '' }, value: inp.value || { value: '' } });
1078
- } else if (inp.name === 'values' && val) {
1079
- updateInputs.push({ name: 'values', value: { schemaless: false, schemalessValue: '', value: val } });
1078
+ // displayValue must use full schemaless format: {schemaless, schemalessValue, value}
1079
+ updateInputs.push({
1080
+ name: 'table_name',
1081
+ displayValue: inp.displayValue || { schemaless: false, schemalessValue: '', value: '' },
1082
+ value: inp.value || { schemaless: false, schemalessValue: '', value: '' }
1083
+ });
1084
+ } else if (inp.name === 'values') {
1085
+ // UI sends {name: "values"} without value property when empty, with value when set
1086
+ if (val) {
1087
+ updateInputs.push({ name: 'values', value: { schemaless: false, schemalessValue: '', value: val } });
1088
+ } else {
1089
+ updateInputs.push({ name: 'values' });
1090
+ }
1080
1091
  }
1081
1092
  }
1082
1093
 
@@ -1084,7 +1095,7 @@ async function addActionViaGraphQL(
1084
1095
  try {
1085
1096
  var updatePatch: any = {
1086
1097
  flowId: flowId,
1087
- labelCache: { insert: recordActionResult.labelCacheEntries },
1098
+ labelCache: {} as any,
1088
1099
  actions: {
1089
1100
  update: [{
1090
1101
  uiUniqueIdentifier: uuid,
@@ -1093,6 +1104,14 @@ async function addActionViaGraphQL(
1093
1104
  }]
1094
1105
  }
1095
1106
  };
1107
+ // Record-level pills → labelCache UPDATE (already exist from trigger)
1108
+ if (recordActionResult.labelCacheUpdates.length > 0) {
1109
+ updatePatch.labelCache.update = recordActionResult.labelCacheUpdates;
1110
+ }
1111
+ // Field-level pills → labelCache INSERT (new entries)
1112
+ if (recordActionResult.labelCacheInserts.length > 0) {
1113
+ updatePatch.labelCache.insert = recordActionResult.labelCacheInserts;
1114
+ }
1096
1115
  await executeFlowPatchMutation(client, updatePatch, actionResponseFields);
1097
1116
  steps.record_update = { success: true, inputCount: updateInputs.length };
1098
1117
  } catch (ue: any) {
@@ -1558,31 +1577,29 @@ async function transformActionInputsForRecordAction(
1558
1577
  }
1559
1578
 
1560
1579
  // ── 4. Build labelCache entries for data pills ────────────────────
1580
+ // The record-level pill (e.g. "Created or Updated_1.current") already exists in the
1581
+ // flow's labelCache from the trigger. The UI sends a labelCache UPDATE (not INSERT)
1582
+ // with just name + usedInstances to register this action's usage.
1583
+ // Field-level pills (e.g. "Created or Updated_1.current.assigned_to") are new and need INSERT.
1584
+ var labelCacheUpdates: any[] = [];
1585
+ var labelCacheInserts: any[] = [];
1586
+
1561
1587
  if (dataPillBase && usedInstances.length > 0) {
1562
1588
  var tableRef = triggerInfo.tableRef || triggerInfo.table || '';
1563
1589
  var tblLabel = triggerInfo.tableLabel || '';
1564
1590
 
1565
- // Record-level data pill entry (for the `record` input selecting the whole record)
1566
- labelCacheEntries.push({
1591
+ // Record-level pill — UPDATE existing entry with new usedInstances (minimal: name + usedInstances only)
1592
+ labelCacheUpdates.push({
1567
1593
  name: dataPillBase,
1568
- label: 'Trigger - Record ' + triggerInfo.triggerName + '\u27a1' + tblLabel + ' Record',
1569
- reference: tableRef,
1570
- reference_display: tblLabel,
1571
- type: 'reference',
1572
- base_type: 'reference',
1573
- parent_table_name: tableRef,
1574
- column_name: '',
1575
- usedInstances: usedInstances,
1576
- choices: {}
1594
+ usedInstances: usedInstances
1577
1595
  });
1578
1596
 
1579
- // Field-level data pill entries for any field references in the `values` string
1597
+ // Field-level data pill entries for any field references in the `values` string → INSERT (new pills)
1580
1598
  var valuesStr = '';
1581
1599
  var valuesInp = actionInputs.find(function (inp: any) { return inp.name === 'values'; });
1582
1600
  if (valuesInp) valuesStr = valuesInp.value?.value || '';
1583
1601
 
1584
1602
  if (valuesStr && valuesStr.includes('{{')) {
1585
- // Extract field-level pills from values like "assigned_to={{dataPillBase.assigned_to}}"
1586
1603
  var pillRegex = /\{\{([^}]+)\}\}/g;
1587
1604
  var pillMatch;
1588
1605
  var seenPills: Record<string, boolean> = {};
@@ -1593,12 +1610,10 @@ async function transformActionInputsForRecordAction(
1593
1610
  if (seenPills[fullPillName]) continue;
1594
1611
  seenPills[fullPillName] = true;
1595
1612
 
1596
- // Extract field name from pill (e.g. "Created or Updated_1.current.assigned_to" → "assigned_to")
1597
1613
  var dotParts = fullPillName.split('.');
1598
1614
  var fieldCol = dotParts.length > 2 ? dotParts[dotParts.length - 1] : '';
1599
1615
 
1600
1616
  if (fieldCol) {
1601
- // Look up field metadata from sys_dictionary
1602
1617
  var fMeta: { type: string; label: string } = { type: 'string', label: fieldCol.replace(/_/g, ' ').replace(/\b\w/g, function (c: string) { return c.toUpperCase(); }) };
1603
1618
  try {
1604
1619
  var dictResp = await client.get('/api/now/table/sys_dictionary', {
@@ -1616,7 +1631,7 @@ async function transformActionInputsForRecordAction(
1616
1631
  }
1617
1632
  } catch (_) {}
1618
1633
 
1619
- labelCacheEntries.push({
1634
+ labelCacheInserts.push({
1620
1635
  name: fullPillName,
1621
1636
  label: 'Trigger - Record ' + triggerInfo.triggerName + '\u27a1' + tblLabel + ' Record\u27a1' + fMeta.label,
1622
1637
  reference: '',
@@ -1632,10 +1647,14 @@ async function transformActionInputsForRecordAction(
1632
1647
  }
1633
1648
  }
1634
1649
 
1635
- steps.label_cache = { count: labelCacheEntries.length, pills: labelCacheEntries.map(function (e: any) { return e.name; }), usedInstances: usedInstances.length };
1650
+ steps.label_cache = {
1651
+ updates: labelCacheUpdates.map(function (e: any) { return e.name; }),
1652
+ inserts: labelCacheInserts.map(function (e: any) { return e.name; }),
1653
+ usedInstances: usedInstances.length
1654
+ };
1636
1655
  }
1637
1656
 
1638
- return { inputs: actionInputs, labelCacheEntries, steps };
1657
+ return { inputs: actionInputs, labelCacheUpdates, labelCacheInserts, steps };
1639
1658
  }
1640
1659
 
1641
1660
  // ── FLOW LOGIC (If/Else, For Each, etc.) ─────────────────────────────