snow-flow-test 10.0.1-test.172 → 10.0.1-test.176

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-test.172",
3
+ "version": "10.0.1-test.176",
4
4
  "name": "snow-flow-test",
5
5
  "description": "Snow-Flow Test - ServiceNow Multi-Agent Development Framework",
6
6
  "license": "Elastic-2.0",
@@ -206,20 +206,39 @@ async function buildFlowLogicInputsForInsert(
206
206
  defId: string,
207
207
  defRecord: { name?: string; type?: string; description?: string; order?: string; attributes?: string; compilation_class?: string; quiescence?: string; visible?: string; category?: string; connected_to?: string },
208
208
  userValues?: Record<string, string>
209
- ): Promise<{ inputs: any[]; flowLogicDefinition: any; resolvedInputs: Record<string, string> }> {
209
+ ): Promise<{ inputs: any[]; flowLogicDefinition: any; resolvedInputs: Record<string, string>; inputQueryError?: string; defParamsCount: number }> {
210
210
  // Query sys_hub_flow_logic_input for this definition's inputs (separate table from sys_hub_action_input)
211
+ // Field names verified from actual sys_hub_flow_logic_input XML schema
211
212
  var defParams: any[] = [];
213
+ var inputQueryError = '';
212
214
  try {
213
215
  var resp = await client.get('/api/now/table/sys_hub_flow_logic_input', {
214
216
  params: {
215
217
  sysparm_query: 'model=' + defId,
216
- sysparm_fields: 'sys_id,element,label,internal_type,mandatory,default_value,order,max_length,hint,read_only,extended,data_structure,reference,reference_display,ref_qual,choice_option,table_name,column_name,use_dependent,dependent_on,show_ref_finder,local,attributes,sys_class_name',
218
+ sysparm_fields: 'sys_id,element,label,internal_type,mandatory,default_value,order,max_length,hint,read_only,attributes,sys_class_name,reference,choice,dependent,dependent_on_field,use_dependent_field,column_label',
217
219
  sysparm_display_value: 'false',
218
220
  sysparm_limit: 50
219
221
  }
220
222
  });
221
223
  defParams = resp.data.result || [];
222
- } catch (_) {}
224
+ } catch (e: any) {
225
+ inputQueryError = e.message || 'unknown error';
226
+ // Fallback: try with minimal fields
227
+ try {
228
+ var resp2 = await client.get('/api/now/table/sys_hub_flow_logic_input', {
229
+ params: {
230
+ sysparm_query: 'model=' + defId,
231
+ sysparm_fields: 'sys_id,element,label,internal_type,mandatory,order,max_length,attributes',
232
+ sysparm_display_value: 'false',
233
+ sysparm_limit: 50
234
+ }
235
+ });
236
+ defParams = resp2.data.result || [];
237
+ inputQueryError = '';
238
+ } catch (e2: any) {
239
+ inputQueryError += '; fallback also failed: ' + (e2.message || '');
240
+ }
241
+ }
223
242
 
224
243
  // Fuzzy-match user-provided values to actual field names
225
244
  var resolvedInputs: Record<string, string> = {};
@@ -304,7 +323,7 @@ async function buildFlowLogicInputsForInsert(
304
323
  variables: '[]'
305
324
  };
306
325
 
307
- return { inputs, flowLogicDefinition, resolvedInputs };
326
+ return { inputs, flowLogicDefinition, resolvedInputs, inputQueryError: inputQueryError || undefined, defParamsCount: defParams.length };
308
327
  }
309
328
 
310
329
  // Note: reordering of existing elements is NOT possible via Table API because
@@ -446,7 +465,8 @@ async function addTriggerViaGraphQL(
446
465
  },
447
466
  {
448
467
  name: 'condition',
449
- displayValue: { schemaless: false, schemalessValue: '', value: condition || '^EQ' }
468
+ displayValue: { schemaless: false, schemalessValue: '', value: condition || '^EQ' },
469
+ value: { schemaless: false, schemalessValue: '', value: condition || '^EQ' }
450
470
  }
451
471
  ];
452
472
  try {
@@ -474,22 +494,53 @@ async function addActionViaGraphQL(
474
494
  actionName: string,
475
495
  inputs?: Record<string, string>,
476
496
  parentUiId?: string,
477
- order?: number
497
+ order?: number,
498
+ spoke?: string
478
499
  ): Promise<{ success: boolean; actionId?: string; steps?: any; error?: string }> {
479
500
  const steps: any = {};
480
501
 
481
502
  // Dynamically look up action definition in sys_hub_action_type_snapshot
503
+ // Prefer global/core actions over spoke-specific ones (e.g. core "Update Record" vs spoke-specific "Update Record")
504
+ const snapshotFields = 'sys_id,internal_name,name,sys_scope,sys_package';
482
505
  let actionDefId: string | null = null;
506
+
507
+ // Helper: pick the best match from candidates — prefer spoke filter, then global scope
508
+ const pickBest = (candidates: any[]): any => {
509
+ if (!candidates || candidates.length === 0) return null;
510
+ if (candidates.length === 1) return candidates[0];
511
+ // If spoke filter is specified, match against scope or package name
512
+ if (spoke) {
513
+ var spokeLC = spoke.toLowerCase();
514
+ var spokeMatch = candidates.find((c: any) =>
515
+ str(c.sys_scope).toLowerCase().includes(spokeLC) ||
516
+ str(c.sys_package).toLowerCase().includes(spokeLC) ||
517
+ str(c.internal_name).toLowerCase().includes(spokeLC)
518
+ );
519
+ if (spokeMatch) return spokeMatch;
520
+ }
521
+ // Prefer global scope
522
+ var global = candidates.find((c: any) => str(c.sys_scope) === 'global' || str(c.sys_scope) === 'rhino.global');
523
+ if (global) return global;
524
+ // Prefer records without "spoke" in the package name
525
+ var nonSpoke = candidates.find((c: any) => !str(c.sys_package).toLowerCase().includes('spoke'));
526
+ if (nonSpoke) return nonSpoke;
527
+ return candidates[0];
528
+ };
529
+
483
530
  for (const field of ['internal_name', 'name']) {
484
531
  if (actionDefId) break;
485
532
  try {
486
533
  const resp = await client.get('/api/now/table/sys_hub_action_type_snapshot', {
487
- params: { sysparm_query: field + '=' + actionType, sysparm_fields: 'sys_id,internal_name,name', sysparm_limit: 1 }
534
+ params: { sysparm_query: field + '=' + actionType, sysparm_fields: snapshotFields, sysparm_limit: 10 }
488
535
  });
489
- const found = resp.data.result?.[0];
536
+ const results = resp.data.result || [];
537
+ if (results.length > 1) {
538
+ steps.def_lookup_candidates = results.map((r: any) => ({ sys_id: r.sys_id, internal_name: str(r.internal_name), name: str(r.name), scope: str(r.sys_scope), package: str(r.sys_package) }));
539
+ }
540
+ const found = pickBest(results);
490
541
  if (found?.sys_id) {
491
542
  actionDefId = found.sys_id;
492
- steps.def_lookup = { id: found.sys_id, internal_name: found.internal_name, name: found.name, matched: field + '=' + actionType };
543
+ steps.def_lookup = { id: found.sys_id, internal_name: str(found.internal_name), name: str(found.name), scope: str(found.sys_scope), package: str(found.sys_package), matched: field + '=' + actionType };
493
544
  }
494
545
  } catch (_) {}
495
546
  }
@@ -498,14 +549,15 @@ async function addActionViaGraphQL(
498
549
  const resp = await client.get('/api/now/table/sys_hub_action_type_snapshot', {
499
550
  params: {
500
551
  sysparm_query: 'internal_nameLIKE' + actionType + '^ORnameLIKE' + actionType,
501
- sysparm_fields: 'sys_id,internal_name,name', sysparm_limit: 5
552
+ sysparm_fields: snapshotFields, sysparm_limit: 10
502
553
  }
503
554
  });
504
555
  const results = resp.data.result || [];
505
- steps.def_lookup_fallback_candidates = results.map((r: any) => ({ sys_id: r.sys_id, internal_name: r.internal_name, name: r.name }));
506
- if (results[0]?.sys_id) {
507
- actionDefId = results[0].sys_id;
508
- steps.def_lookup = { id: results[0].sys_id, internal_name: results[0].internal_name, name: results[0].name, matched: 'LIKE ' + actionType };
556
+ steps.def_lookup_fallback_candidates = results.map((r: any) => ({ sys_id: r.sys_id, internal_name: str(r.internal_name), name: str(r.name), scope: str(r.sys_scope), package: str(r.sys_package) }));
557
+ const found = pickBest(results);
558
+ if (found?.sys_id) {
559
+ actionDefId = found.sys_id;
560
+ steps.def_lookup = { id: found.sys_id, internal_name: str(found.internal_name), name: str(found.name), scope: str(found.sys_scope), package: str(found.sys_package), matched: 'LIKE ' + actionType };
509
561
  }
510
562
  } catch (_) {}
511
563
  }
@@ -630,6 +682,7 @@ async function addFlowLogicViaGraphQL(
630
682
  const inputResult = await buildFlowLogicInputsForInsert(client, defId, defRecord, inputs);
631
683
  steps.available_inputs = inputResult.inputs.map((i: any) => ({ name: i.name, label: i.parameter?.label }));
632
684
  steps.resolved_inputs = inputResult.resolvedInputs;
685
+ steps.input_query_stats = { defParamsFound: inputResult.defParamsCount, inputsBuilt: inputResult.inputs.length, error: inputResult.inputQueryError };
633
686
 
634
687
  // Calculate insertion order
635
688
  const resolvedOrder = await calculateInsertOrder(client, flowId, parentUiId, order);
@@ -1106,6 +1159,10 @@ export const toolDefinition: MCPToolDefinition = {
1106
1159
  type: 'string',
1107
1160
  description: 'Display name for the action (for add_action)'
1108
1161
  },
1162
+ spoke: {
1163
+ type: 'string',
1164
+ description: 'Spoke/scope filter for action lookup (for add_action). Use to disambiguate when multiple spokes have actions with the same name (e.g. "global" for core actions, "spoke-specific" for spoke-specific Spoke actions). Matched against sys_scope and sys_package fields.'
1165
+ },
1109
1166
  action_inputs: {
1110
1167
  type: 'object',
1111
1168
  description: 'Key-value pairs for action inputs (e.g. {log_message: "test", log_level: "info"})'
@@ -1999,7 +2056,7 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
1999
2056
  var addActName = args.action_name || args.name || addActType;
2000
2057
  var addActInputs = args.action_inputs || args.inputs || {};
2001
2058
 
2002
- var addActResult = await addActionViaGraphQL(client, addActFlowId, addActType, addActName, addActInputs, args.parent_ui_id, args.order);
2059
+ var addActResult = await addActionViaGraphQL(client, addActFlowId, addActType, addActName, addActInputs, args.parent_ui_id, args.order, args.spoke);
2003
2060
 
2004
2061
  var addActSummary = summary();
2005
2062
  if (addActResult.success) {