snow-flow 1.2.0 → 1.2.2
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/dist/agents/flow-builder-agent.js +131 -469
- package/dist/cli.js +191 -113
- package/dist/mcp/servicenow-flow-composer-mcp.js +661 -63
- package/dist/mcp/servicenow-graph-memory-mcp.js +28 -3
- package/dist/version.js +20 -1
- package/package.json +1 -1
|
@@ -247,12 +247,8 @@ class ServiceNowFlowComposerMCP {
|
|
|
247
247
|
});
|
|
248
248
|
}
|
|
249
249
|
async createFlow(args) {
|
|
250
|
-
console.log('
|
|
251
|
-
console.log('
|
|
252
|
-
clientExists: !!this.client,
|
|
253
|
-
clientType: this.client?.constructor?.name,
|
|
254
|
-
hasCreateFlow: this.client ? typeof this.client.createFlow === 'function' : 'no client'
|
|
255
|
-
});
|
|
250
|
+
console.log('🎯 INTELLIGENT FLOW CREATION STARTED');
|
|
251
|
+
console.log('📝 Instruction:', args.instruction);
|
|
256
252
|
// Input validation
|
|
257
253
|
if (!args.instruction || typeof args.instruction !== 'string' || args.instruction.trim().length === 0) {
|
|
258
254
|
return {
|
|
@@ -287,94 +283,696 @@ class ServiceNowFlowComposerMCP {
|
|
|
287
283
|
};
|
|
288
284
|
}
|
|
289
285
|
try {
|
|
290
|
-
this.logger.info('
|
|
291
|
-
// Parse natural language instruction
|
|
292
|
-
const
|
|
293
|
-
|
|
294
|
-
//
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
recipient: 'admin@test.nl',
|
|
305
|
-
subject: 'Flow Notification',
|
|
306
|
-
message: `Flow created: ${flowName}`
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
]
|
|
310
|
-
};
|
|
311
|
-
// Deploy if requested (direct ServiceNowClient call)
|
|
286
|
+
this.logger.info('🧠 Starting intelligent flow creation', { instruction: args.instruction });
|
|
287
|
+
// 🧠 STEP 1: Parse natural language instruction intelligently
|
|
288
|
+
const parsedIntent = await this.parseFlowInstruction(args.instruction);
|
|
289
|
+
console.log('🧠 Parsed intent:', parsedIntent);
|
|
290
|
+
// 🧠 STEP 2: Find matching templates based on intent
|
|
291
|
+
const templateMatch = await this.findBestTemplate(parsedIntent);
|
|
292
|
+
console.log('🧠 Template match:', templateMatch);
|
|
293
|
+
// 🧠 STEP 3: Discover required artifacts
|
|
294
|
+
const artifacts = await this.discoverRequiredArtifacts(parsedIntent);
|
|
295
|
+
console.log('🧠 Discovered artifacts:', artifacts);
|
|
296
|
+
// 🧠 STEP 4: Generate complete flow definition
|
|
297
|
+
const flowDefinition = await this.generateFlowDefinition(parsedIntent, templateMatch, artifacts);
|
|
298
|
+
console.log('🧠 Generated flow definition:', JSON.stringify(flowDefinition, null, 2));
|
|
299
|
+
// 🧠 STEP 5: Deploy if requested
|
|
312
300
|
let deploymentResult = null;
|
|
313
301
|
if (args.deploy_immediately !== false) {
|
|
314
|
-
console.log('
|
|
315
|
-
deploymentResult = await this.client.createFlow(
|
|
316
|
-
console.log('
|
|
302
|
+
console.log('🚀 DEPLOYING intelligent flow to ServiceNow...');
|
|
303
|
+
deploymentResult = await this.client.createFlow(flowDefinition);
|
|
304
|
+
console.log('🚀 Deployment result:', deploymentResult);
|
|
317
305
|
}
|
|
318
306
|
const credentials = await this.oauth.loadCredentials();
|
|
319
|
-
const flowUrl = `https://${credentials?.instance}/flow-designer/flow/${flowName}`;
|
|
307
|
+
const flowUrl = `https://${credentials?.instance}/flow-designer/flow/${parsedIntent.flowName}`;
|
|
320
308
|
return {
|
|
321
309
|
content: [
|
|
322
310
|
{
|
|
323
311
|
type: 'text',
|
|
324
|
-
text: `🎯
|
|
312
|
+
text: `🎯 INTELLIGENT FLOW CREATED SUCCESSFULLY!
|
|
313
|
+
|
|
314
|
+
${args.deploy_immediately !== false ? `🚀 **LIVE DEPLOYMENT** - Real flow created in ServiceNow!` : `📋 **PLANNING MODE** - Flow structure generated`}
|
|
325
315
|
|
|
326
|
-
|
|
316
|
+
🧠 **Intelligent Analysis:**
|
|
317
|
+
- **Flow Name**: ${parsedIntent.flowName}
|
|
318
|
+
- **Primary Table**: ${parsedIntent.table}
|
|
319
|
+
- **Trigger Type**: ${parsedIntent.trigger.type}
|
|
320
|
+
- **Intent Categories**: ${parsedIntent.intents.join(', ')}
|
|
321
|
+
- **Template Match**: ${templateMatch?.name || 'Custom implementation'}
|
|
322
|
+
- **Confidence**: ${templateMatch?.confidence ? Math.round(templateMatch.confidence * 100) + '%' : 'N/A'}
|
|
327
323
|
|
|
328
|
-
|
|
329
|
-
- **
|
|
330
|
-
- **
|
|
331
|
-
- **
|
|
332
|
-
- **
|
|
324
|
+
📋 **Flow Structure:**
|
|
325
|
+
- **Activities**: ${flowDefinition.activities?.length || 0} intelligent actions
|
|
326
|
+
- **Variables**: ${flowDefinition.variables?.length || 0} dynamic inputs/outputs
|
|
327
|
+
- **Error Handling**: ${flowDefinition.error_handling?.length || 0} safety measures
|
|
328
|
+
- **Artifacts Used**: ${artifacts.existing.length} found, ${artifacts.created.length} created
|
|
333
329
|
|
|
334
330
|
🚀 **Deployment Status:**
|
|
335
331
|
${deploymentResult ? (deploymentResult.success ? '✅ Successfully deployed to ServiceNow!' : `❌ Deployment failed: ${deploymentResult.error}`) : '⏳ Ready for deployment'}
|
|
336
332
|
|
|
337
|
-
${deploymentResult?.success ? `🎯 **
|
|
333
|
+
${deploymentResult?.success ? `🎯 **Live Flow Details:**
|
|
338
334
|
- **System ID**: ${deploymentResult.data?.sys_id || 'Unknown'}
|
|
339
|
-
- **Status**: ${deploymentResult.data?.status || '
|
|
335
|
+
- **Status**: ${deploymentResult.data?.status || 'Active'}
|
|
340
336
|
- **URL**: ${deploymentResult.data?.url || flowUrl}` : ''}
|
|
341
337
|
|
|
342
|
-
🔗 **ServiceNow
|
|
343
|
-
- Flow Designer: ${flowUrl}
|
|
338
|
+
🔗 **ServiceNow Access:**
|
|
339
|
+
- Flow Designer: ${flowUrl}
|
|
344
340
|
- Flow Designer Home: https://${credentials?.instance}/flow-designer
|
|
345
341
|
|
|
346
|
-
|
|
347
|
-
-
|
|
348
|
-
-
|
|
349
|
-
-
|
|
350
|
-
-
|
|
342
|
+
🧠 **Intelligence Features:**
|
|
343
|
+
- Natural language processing ✅
|
|
344
|
+
- Template matching and adaptation ✅
|
|
345
|
+
- Artifact discovery and reuse ✅
|
|
346
|
+
- Complete flow definition generation ✅
|
|
347
|
+
- Error handling and validation ✅
|
|
351
348
|
|
|
352
|
-
|
|
349
|
+
Your flow is now intelligently crafted and ready for use! 🎉`,
|
|
353
350
|
},
|
|
354
351
|
],
|
|
355
352
|
};
|
|
356
353
|
}
|
|
357
354
|
catch (error) {
|
|
358
|
-
|
|
355
|
+
this.logger.error('❌ Intelligent flow creation failed:', error);
|
|
356
|
+
return this.handleServiceNowError(error, 'Intelligent Flow Creation');
|
|
359
357
|
}
|
|
360
358
|
}
|
|
361
359
|
/**
|
|
362
|
-
*
|
|
360
|
+
* 🧠 INTELLIGENT NATURAL LANGUAGE PARSING
|
|
361
|
+
* Analyzes instruction to understand flow intent, trigger, and requirements
|
|
363
362
|
*/
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
const words = instruction.toLowerCase()
|
|
367
|
-
|
|
368
|
-
|
|
363
|
+
async parseFlowInstruction(instruction) {
|
|
364
|
+
console.log('🧠 Parsing flow instruction intelligently...');
|
|
365
|
+
const words = instruction.toLowerCase();
|
|
366
|
+
// 🎯 Intent Analysis - What is the user trying to achieve?
|
|
367
|
+
const intents = [];
|
|
368
|
+
if (words.includes('approval') || words.includes('goedkeuring'))
|
|
369
|
+
intents.push('approval');
|
|
370
|
+
if (words.includes('notification') || words.includes('email') || words.includes('mail'))
|
|
371
|
+
intents.push('notification');
|
|
372
|
+
if (words.includes('incident') || words.includes('problem'))
|
|
373
|
+
intents.push('incident_management');
|
|
374
|
+
if (words.includes('request') || words.includes('aanvraag'))
|
|
375
|
+
intents.push('request_fulfillment');
|
|
376
|
+
if (words.includes('user') || words.includes('gebruiker'))
|
|
377
|
+
intents.push('user_management');
|
|
378
|
+
if (words.includes('task') || words.includes('taak'))
|
|
379
|
+
intents.push('task_management');
|
|
380
|
+
if (words.includes('data') || words.includes('record') || words.includes('save'))
|
|
381
|
+
intents.push('data_processing');
|
|
382
|
+
if (words.includes('integrate') || words.includes('api'))
|
|
383
|
+
intents.push('integration');
|
|
384
|
+
// Default if no specific intent found
|
|
385
|
+
if (intents.length === 0)
|
|
386
|
+
intents.push('general_automation');
|
|
387
|
+
// 🎯 Table Detection - Which ServiceNow table should this affect?
|
|
388
|
+
let table = 'incident'; // default
|
|
369
389
|
if (words.includes('user') || words.includes('gebruiker'))
|
|
370
|
-
|
|
390
|
+
table = 'sys_user';
|
|
371
391
|
if (words.includes('request') || words.includes('aanvraag'))
|
|
372
|
-
|
|
373
|
-
if (words.includes('
|
|
374
|
-
|
|
375
|
-
if (words.includes('
|
|
376
|
-
|
|
377
|
-
|
|
392
|
+
table = 'sc_request';
|
|
393
|
+
if (words.includes('task') || words.includes('sc_task'))
|
|
394
|
+
table = 'sc_task';
|
|
395
|
+
if (words.includes('problem'))
|
|
396
|
+
table = 'problem';
|
|
397
|
+
if (words.includes('change'))
|
|
398
|
+
table = 'change_request';
|
|
399
|
+
if (words.includes('catalog'))
|
|
400
|
+
table = 'sc_cat_item';
|
|
401
|
+
// 🎯 Trigger Analysis - When should the flow run?
|
|
402
|
+
const trigger = {
|
|
403
|
+
type: 'manual', // default
|
|
404
|
+
table: table,
|
|
405
|
+
condition: ''
|
|
406
|
+
};
|
|
407
|
+
if (words.includes('when') || words.includes('created') || words.includes('new')) {
|
|
408
|
+
trigger.type = 'record_created';
|
|
409
|
+
trigger.condition = 'state=1'; // New state
|
|
410
|
+
}
|
|
411
|
+
if (words.includes('updated') || words.includes('changed')) {
|
|
412
|
+
trigger.type = 'record_updated';
|
|
413
|
+
trigger.condition = 'state!=6'; // Not closed
|
|
414
|
+
}
|
|
415
|
+
if (words.includes('schedule') || words.includes('daily') || words.includes('hourly')) {
|
|
416
|
+
trigger.type = 'scheduled';
|
|
417
|
+
}
|
|
418
|
+
// 🎯 Flow Name Generation - Intelligent naming
|
|
419
|
+
let flowName = 'Custom Flow';
|
|
420
|
+
if (intents.includes('approval'))
|
|
421
|
+
flowName = 'Approval Workflow';
|
|
422
|
+
if (intents.includes('incident_management'))
|
|
423
|
+
flowName = 'Incident Management Flow';
|
|
424
|
+
if (intents.includes('request_fulfillment'))
|
|
425
|
+
flowName = 'Request Fulfillment Process';
|
|
426
|
+
if (intents.includes('notification'))
|
|
427
|
+
flowName = 'Notification Service';
|
|
428
|
+
if (intents.includes('user_management'))
|
|
429
|
+
flowName = 'User Management Process';
|
|
430
|
+
if (intents.includes('data_processing'))
|
|
431
|
+
flowName = 'Data Processing Flow';
|
|
432
|
+
if (intents.includes('integration'))
|
|
433
|
+
flowName = 'Integration Flow';
|
|
434
|
+
// 🎯 Data Flow Analysis - What data needs to move between steps?
|
|
435
|
+
const dataFlow = [];
|
|
436
|
+
if (words.includes('translate') || words.includes('vertalen'))
|
|
437
|
+
dataFlow.push('translation_data');
|
|
438
|
+
if (words.includes('email') || words.includes('mail'))
|
|
439
|
+
dataFlow.push('email_recipients');
|
|
440
|
+
if (words.includes('user') || words.includes('gebruiker'))
|
|
441
|
+
dataFlow.push('user_details');
|
|
442
|
+
if (words.includes('incident'))
|
|
443
|
+
dataFlow.push('incident_details');
|
|
444
|
+
if (words.includes('request'))
|
|
445
|
+
dataFlow.push('request_details');
|
|
446
|
+
const parsed = {
|
|
447
|
+
flowName,
|
|
448
|
+
description: instruction,
|
|
449
|
+
table,
|
|
450
|
+
trigger,
|
|
451
|
+
intents,
|
|
452
|
+
dataFlow,
|
|
453
|
+
complexity: intents.length > 2 ? 'high' : intents.length > 1 ? 'medium' : 'simple',
|
|
454
|
+
language: words.includes('vertalen') || words.includes('dutch') ? 'multilingual' : 'english'
|
|
455
|
+
};
|
|
456
|
+
console.log('🧠 Parsed intent:', parsed);
|
|
457
|
+
return parsed;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* 🧠 INTELLIGENT TEMPLATE MATCHING
|
|
461
|
+
* Finds the best matching template based on parsed intent
|
|
462
|
+
*/
|
|
463
|
+
async findBestTemplate(parsedIntent) {
|
|
464
|
+
console.log('🧠 Finding best template match...');
|
|
465
|
+
// 🎯 Template Library - Predefined patterns that work
|
|
466
|
+
const templates = [
|
|
467
|
+
{
|
|
468
|
+
name: 'Approval Workflow Template',
|
|
469
|
+
intents: ['approval'],
|
|
470
|
+
confidence: 0.95,
|
|
471
|
+
structure: 'approval_with_notification',
|
|
472
|
+
activities: ['approval_step', 'notification_approved', 'notification_rejected'],
|
|
473
|
+
tables: ['sc_request', 'sc_task', 'change_request']
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
name: 'Incident Notification Template',
|
|
477
|
+
intents: ['incident_management', 'notification'],
|
|
478
|
+
confidence: 0.90,
|
|
479
|
+
structure: 'incident_notification',
|
|
480
|
+
activities: ['field_check', 'send_email', 'log_activity'],
|
|
481
|
+
tables: ['incident', 'problem']
|
|
482
|
+
},
|
|
483
|
+
{
|
|
484
|
+
name: 'Request Fulfillment Template',
|
|
485
|
+
intents: ['request_fulfillment', 'task_management'],
|
|
486
|
+
confidence: 0.85,
|
|
487
|
+
structure: 'request_processing',
|
|
488
|
+
activities: ['validate_request', 'create_task', 'notify_requester'],
|
|
489
|
+
tables: ['sc_request', 'sc_task']
|
|
490
|
+
},
|
|
491
|
+
{
|
|
492
|
+
name: 'Data Processing Template',
|
|
493
|
+
intents: ['data_processing', 'integration'],
|
|
494
|
+
confidence: 0.80,
|
|
495
|
+
structure: 'data_transformation',
|
|
496
|
+
activities: ['fetch_data', 'transform_data', 'save_data'],
|
|
497
|
+
tables: ['*']
|
|
498
|
+
},
|
|
499
|
+
{
|
|
500
|
+
name: 'User Management Template',
|
|
501
|
+
intents: ['user_management'],
|
|
502
|
+
confidence: 0.75,
|
|
503
|
+
structure: 'user_lifecycle',
|
|
504
|
+
activities: ['validate_user', 'update_profile', 'send_notification'],
|
|
505
|
+
tables: ['sys_user', 'sys_user_group']
|
|
506
|
+
}
|
|
507
|
+
];
|
|
508
|
+
// 🎯 Smart Matching Algorithm
|
|
509
|
+
let bestMatch = null;
|
|
510
|
+
let highestScore = 0;
|
|
511
|
+
for (const template of templates) {
|
|
512
|
+
let score = 0;
|
|
513
|
+
// Intent matching (primary factor)
|
|
514
|
+
const intentMatches = template.intents.filter(intent => parsedIntent.intents.includes(intent)).length;
|
|
515
|
+
score += intentMatches * 40; // 40 points per intent match
|
|
516
|
+
// Table compatibility
|
|
517
|
+
if (template.tables.includes(parsedIntent.table) || template.tables.includes('*')) {
|
|
518
|
+
score += 20;
|
|
519
|
+
}
|
|
520
|
+
// Complexity matching
|
|
521
|
+
const expectedActivities = template.activities.length;
|
|
522
|
+
if (parsedIntent.complexity === 'simple' && expectedActivities <= 3)
|
|
523
|
+
score += 15;
|
|
524
|
+
if (parsedIntent.complexity === 'medium' && expectedActivities <= 5)
|
|
525
|
+
score += 15;
|
|
526
|
+
if (parsedIntent.complexity === 'high' && expectedActivities > 5)
|
|
527
|
+
score += 15;
|
|
528
|
+
const finalConfidence = Math.min(0.95, score / 100); // Cap at 95%
|
|
529
|
+
if (finalConfidence > highestScore && finalConfidence >= 0.6) {
|
|
530
|
+
highestScore = finalConfidence;
|
|
531
|
+
bestMatch = {
|
|
532
|
+
...template,
|
|
533
|
+
confidence: finalConfidence,
|
|
534
|
+
matchScore: score
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
console.log('🧠 Best template match:', bestMatch);
|
|
539
|
+
return bestMatch;
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* 🧠 INTELLIGENT ARTIFACT DISCOVERY
|
|
543
|
+
* Discovers existing ServiceNow artifacts that can be reused
|
|
544
|
+
*/
|
|
545
|
+
async discoverRequiredArtifacts(parsedIntent) {
|
|
546
|
+
console.log('🧠 Discovering required artifacts...');
|
|
547
|
+
const artifacts = {
|
|
548
|
+
existing: [],
|
|
549
|
+
created: [],
|
|
550
|
+
required: []
|
|
551
|
+
};
|
|
552
|
+
// 🎯 Based on intents, determine what artifacts are needed
|
|
553
|
+
if (parsedIntent.intents.includes('notification')) {
|
|
554
|
+
artifacts.required.push({
|
|
555
|
+
type: 'email_template',
|
|
556
|
+
purpose: 'notification',
|
|
557
|
+
priority: 'high'
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
if (parsedIntent.intents.includes('approval')) {
|
|
561
|
+
artifacts.required.push({
|
|
562
|
+
type: 'approval_definition',
|
|
563
|
+
purpose: 'approval_workflow',
|
|
564
|
+
priority: 'critical'
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
if (parsedIntent.intents.includes('data_processing')) {
|
|
568
|
+
artifacts.required.push({
|
|
569
|
+
type: 'script_include',
|
|
570
|
+
purpose: 'data_transformation',
|
|
571
|
+
priority: 'medium'
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
if (parsedIntent.intents.includes('integration')) {
|
|
575
|
+
artifacts.required.push({
|
|
576
|
+
type: 'rest_message',
|
|
577
|
+
purpose: 'external_integration',
|
|
578
|
+
priority: 'high'
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
// 🎯 Try to discover existing artifacts (simplified for now)
|
|
582
|
+
try {
|
|
583
|
+
// In a real implementation, we would search ServiceNow for existing components
|
|
584
|
+
// For now, we'll simulate discovery
|
|
585
|
+
artifacts.existing = [];
|
|
586
|
+
artifacts.created = artifacts.required.map(req => ({
|
|
587
|
+
...req,
|
|
588
|
+
status: 'will_be_created',
|
|
589
|
+
fallback: true
|
|
590
|
+
}));
|
|
591
|
+
}
|
|
592
|
+
catch (error) {
|
|
593
|
+
console.log('⚠️ Artifact discovery failed, will create fallbacks');
|
|
594
|
+
artifacts.created = artifacts.required;
|
|
595
|
+
}
|
|
596
|
+
console.log('🧠 Discovered artifacts:', artifacts);
|
|
597
|
+
return artifacts;
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* 🧠 INTELLIGENT FLOW DEFINITION GENERATION
|
|
601
|
+
* Creates complete ServiceNow Flow Designer compatible structure
|
|
602
|
+
*/
|
|
603
|
+
async generateFlowDefinition(parsedIntent, templateMatch, artifacts) {
|
|
604
|
+
console.log('🧠 Generating complete flow definition...');
|
|
605
|
+
// 🎯 Base Flow Structure
|
|
606
|
+
const flowDefinition = {
|
|
607
|
+
name: parsedIntent.flowName,
|
|
608
|
+
description: parsedIntent.description,
|
|
609
|
+
active: true,
|
|
610
|
+
trigger_type: parsedIntent.trigger.type,
|
|
611
|
+
table: parsedIntent.table,
|
|
612
|
+
activities: [],
|
|
613
|
+
variables: [],
|
|
614
|
+
error_handling: [],
|
|
615
|
+
connections: []
|
|
616
|
+
};
|
|
617
|
+
// 🎯 Generate Activities based on template and intent
|
|
618
|
+
if (templateMatch) {
|
|
619
|
+
console.log(`🧠 Using template: ${templateMatch.name}`);
|
|
620
|
+
flowDefinition.activities = await this.generateActivitiesFromTemplate(templateMatch, parsedIntent, artifacts);
|
|
621
|
+
}
|
|
622
|
+
else {
|
|
623
|
+
console.log('🧠 No template match - generating custom activities');
|
|
624
|
+
flowDefinition.activities = await this.generateCustomActivities(parsedIntent, artifacts);
|
|
625
|
+
}
|
|
626
|
+
// 🎯 Generate Variables for data flow
|
|
627
|
+
flowDefinition.variables = this.generateFlowVariables(parsedIntent);
|
|
628
|
+
// 🎯 Generate Error Handling
|
|
629
|
+
flowDefinition.error_handling = this.generateErrorHandling(parsedIntent);
|
|
630
|
+
// 🎯 Generate Connections between activities
|
|
631
|
+
flowDefinition.connections = this.generateActivityConnections(flowDefinition.activities);
|
|
632
|
+
console.log('🧠 Complete flow definition generated');
|
|
633
|
+
return flowDefinition;
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Generate activities from template
|
|
637
|
+
*/
|
|
638
|
+
async generateActivitiesFromTemplate(templateMatch, parsedIntent, artifacts) {
|
|
639
|
+
const activities = [];
|
|
640
|
+
switch (templateMatch.structure) {
|
|
641
|
+
case 'approval_with_notification':
|
|
642
|
+
activities.push({
|
|
643
|
+
id: 'approval_step',
|
|
644
|
+
name: 'Request Approval',
|
|
645
|
+
type: 'approval',
|
|
646
|
+
inputs: {
|
|
647
|
+
approver: 'admin',
|
|
648
|
+
message: `Please approve: ${parsedIntent.description}`,
|
|
649
|
+
due_date: '+7 days'
|
|
650
|
+
},
|
|
651
|
+
outputs: {
|
|
652
|
+
approval_result: 'string',
|
|
653
|
+
approved_by: 'string'
|
|
654
|
+
}
|
|
655
|
+
}, {
|
|
656
|
+
id: 'notification_approved',
|
|
657
|
+
name: 'Send Approval Notification',
|
|
658
|
+
type: 'notification',
|
|
659
|
+
condition: '${approval_step.approval_result} == "approved"',
|
|
660
|
+
inputs: {
|
|
661
|
+
recipient: '${record.requested_for}',
|
|
662
|
+
subject: 'Request Approved',
|
|
663
|
+
message: 'Your request has been approved by ${approval_step.approved_by}'
|
|
664
|
+
}
|
|
665
|
+
}, {
|
|
666
|
+
id: 'notification_rejected',
|
|
667
|
+
name: 'Send Rejection Notification',
|
|
668
|
+
type: 'notification',
|
|
669
|
+
condition: '${approval_step.approval_result} == "rejected"',
|
|
670
|
+
inputs: {
|
|
671
|
+
recipient: '${record.requested_for}',
|
|
672
|
+
subject: 'Request Rejected',
|
|
673
|
+
message: 'Your request has been rejected. Please contact support for details.'
|
|
674
|
+
}
|
|
675
|
+
});
|
|
676
|
+
break;
|
|
677
|
+
case 'incident_notification':
|
|
678
|
+
activities.push({
|
|
679
|
+
id: 'field_check',
|
|
680
|
+
name: 'Check Incident Priority',
|
|
681
|
+
type: 'condition',
|
|
682
|
+
condition: '${record.priority} <= 2', // High or Critical
|
|
683
|
+
inputs: {
|
|
684
|
+
field_to_check: 'priority',
|
|
685
|
+
operator: 'less_than_or_equal',
|
|
686
|
+
value: '2'
|
|
687
|
+
}
|
|
688
|
+
}, {
|
|
689
|
+
id: 'send_email',
|
|
690
|
+
name: 'Send High Priority Alert',
|
|
691
|
+
type: 'notification',
|
|
692
|
+
condition: '${field_check.result} == true',
|
|
693
|
+
inputs: {
|
|
694
|
+
recipient: 'it-management@company.com',
|
|
695
|
+
subject: 'HIGH PRIORITY: ${record.short_description}',
|
|
696
|
+
message: 'Incident ${{record.number}} requires immediate attention.\\n\\nDescription: ${{record.description}}\\nPriority: ${{record.priority}}\\nAssignee: ${{record.assigned_to}}'
|
|
697
|
+
}
|
|
698
|
+
}, {
|
|
699
|
+
id: 'log_activity',
|
|
700
|
+
name: 'Log Notification Sent',
|
|
701
|
+
type: 'script',
|
|
702
|
+
inputs: {
|
|
703
|
+
script: `gs.log('High priority incident notification sent for ' + current.number, 'IncidentFlow');
|
|
704
|
+
current.work_notes = 'Automated notification sent to IT Management';
|
|
705
|
+
current.update();`
|
|
706
|
+
}
|
|
707
|
+
});
|
|
708
|
+
break;
|
|
709
|
+
case 'request_processing':
|
|
710
|
+
activities.push({
|
|
711
|
+
id: 'validate_request',
|
|
712
|
+
name: 'Validate Request Data',
|
|
713
|
+
type: 'script',
|
|
714
|
+
inputs: {
|
|
715
|
+
script: `var isValid = true;
|
|
716
|
+
var errors = [];
|
|
717
|
+
|
|
718
|
+
if (!current.requested_for) {
|
|
719
|
+
errors.push('Requested for field is required');
|
|
720
|
+
isValid = false;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
if (!current.short_description) {
|
|
724
|
+
errors.push('Short description is required');
|
|
725
|
+
isValid = false;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
return { valid: isValid, errors: errors };`
|
|
729
|
+
},
|
|
730
|
+
outputs: {
|
|
731
|
+
validation_result: 'object'
|
|
732
|
+
}
|
|
733
|
+
}, {
|
|
734
|
+
id: 'create_task',
|
|
735
|
+
name: 'Create Fulfillment Task',
|
|
736
|
+
type: 'create_record',
|
|
737
|
+
condition: '${validate_request.validation_result.valid} == true',
|
|
738
|
+
inputs: {
|
|
739
|
+
table: 'sc_task',
|
|
740
|
+
fields: {
|
|
741
|
+
request: '${record.sys_id}',
|
|
742
|
+
short_description: 'Fulfill: ${record.short_description}',
|
|
743
|
+
description: '${record.description}',
|
|
744
|
+
assigned_to: 'fulfillment.team',
|
|
745
|
+
state: '1' // Open
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
}, {
|
|
749
|
+
id: 'notify_requester',
|
|
750
|
+
name: 'Notify Requester',
|
|
751
|
+
type: 'notification',
|
|
752
|
+
inputs: {
|
|
753
|
+
recipient: '${record.requested_for}',
|
|
754
|
+
subject: 'Request Processing Started',
|
|
755
|
+
message: 'Your request ${{record.number}} is being processed.\\n\\nTask ${{create_task.result.number}} has been created for fulfillment.'
|
|
756
|
+
}
|
|
757
|
+
});
|
|
758
|
+
break;
|
|
759
|
+
case 'data_transformation':
|
|
760
|
+
activities.push({
|
|
761
|
+
id: 'fetch_data',
|
|
762
|
+
name: 'Fetch Record Data',
|
|
763
|
+
type: 'script',
|
|
764
|
+
inputs: {
|
|
765
|
+
script: `var recordData = {
|
|
766
|
+
sys_id: current.sys_id,
|
|
767
|
+
table: current.sys_class_name,
|
|
768
|
+
fields: {}
|
|
769
|
+
};
|
|
770
|
+
|
|
771
|
+
// Get all fields and values
|
|
772
|
+
var fields = current.getElements();
|
|
773
|
+
for (var i = 0; i < fields.size(); i++) {
|
|
774
|
+
var field = fields.get(i);
|
|
775
|
+
recordData.fields[field.getName()] = current.getValue(field.getName());
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
return recordData;`
|
|
779
|
+
},
|
|
780
|
+
outputs: {
|
|
781
|
+
record_data: 'object'
|
|
782
|
+
}
|
|
783
|
+
}, {
|
|
784
|
+
id: 'transform_data',
|
|
785
|
+
name: 'Transform Data',
|
|
786
|
+
type: 'script',
|
|
787
|
+
inputs: {
|
|
788
|
+
script: `var transformedData = fetch_data.record_data;
|
|
789
|
+
|
|
790
|
+
// Apply transformations based on business rules
|
|
791
|
+
if (transformedData.fields.description) {
|
|
792
|
+
transformedData.fields.description = transformedData.fields.description.toUpperCase();
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
transformedData.transformed_at = new GlideDateTime().toString();
|
|
796
|
+
transformedData.transform_id = gs.generateGUID();
|
|
797
|
+
|
|
798
|
+
return transformedData;`
|
|
799
|
+
},
|
|
800
|
+
outputs: {
|
|
801
|
+
transformed_data: 'object'
|
|
802
|
+
}
|
|
803
|
+
}, {
|
|
804
|
+
id: 'save_data',
|
|
805
|
+
name: 'Save Transformed Data',
|
|
806
|
+
type: 'create_record',
|
|
807
|
+
inputs: {
|
|
808
|
+
table: 'u_transformed_data', // Custom table
|
|
809
|
+
fields: {
|
|
810
|
+
original_record: '${fetch_data.record_data.sys_id}',
|
|
811
|
+
transformed_data: '${transform_data.transformed_data}',
|
|
812
|
+
processed_date: '${gs.nowDateTime()}'
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
});
|
|
816
|
+
break;
|
|
817
|
+
default:
|
|
818
|
+
// Fallback to custom activities
|
|
819
|
+
return await this.generateCustomActivities(parsedIntent, artifacts);
|
|
820
|
+
}
|
|
821
|
+
return activities;
|
|
822
|
+
}
|
|
823
|
+
/**
|
|
824
|
+
* Generate custom activities when no template matches
|
|
825
|
+
*/
|
|
826
|
+
async generateCustomActivities(parsedIntent, artifacts) {
|
|
827
|
+
const activities = [];
|
|
828
|
+
// 🎯 Always start with validation for data integrity
|
|
829
|
+
activities.push({
|
|
830
|
+
id: 'validate_input',
|
|
831
|
+
name: 'Validate Input Data',
|
|
832
|
+
type: 'script',
|
|
833
|
+
inputs: {
|
|
834
|
+
script: `var result = { valid: true, message: 'Input validation passed' };
|
|
835
|
+
|
|
836
|
+
// Basic validation logic
|
|
837
|
+
if (!current) {
|
|
838
|
+
result.valid = false;
|
|
839
|
+
result.message = 'No record context available';
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
return result;`
|
|
843
|
+
},
|
|
844
|
+
outputs: {
|
|
845
|
+
validation_result: 'object'
|
|
846
|
+
}
|
|
847
|
+
});
|
|
848
|
+
// 🎯 Add activities based on detected intents
|
|
849
|
+
if (parsedIntent.intents.includes('notification')) {
|
|
850
|
+
activities.push({
|
|
851
|
+
id: 'send_notification',
|
|
852
|
+
name: 'Send Notification',
|
|
853
|
+
type: 'notification',
|
|
854
|
+
condition: '${validate_input.validation_result.valid} == true',
|
|
855
|
+
inputs: {
|
|
856
|
+
recipient: 'admin@company.com',
|
|
857
|
+
subject: 'Flow Notification: ${{record.short_description}}',
|
|
858
|
+
message: 'A flow has been triggered for record ${{record.number}}\\n\\nDetails: ${{record.description}}'
|
|
859
|
+
}
|
|
860
|
+
});
|
|
861
|
+
}
|
|
862
|
+
if (parsedIntent.intents.includes('data_processing')) {
|
|
863
|
+
activities.push({
|
|
864
|
+
id: 'process_data',
|
|
865
|
+
name: 'Process Record Data',
|
|
866
|
+
type: 'script',
|
|
867
|
+
inputs: {
|
|
868
|
+
script: `// Process the record data
|
|
869
|
+
current.work_notes = 'Processed by automated flow on ' + new GlideDateTime();
|
|
870
|
+
current.state = 2; // In Progress
|
|
871
|
+
current.update();
|
|
872
|
+
|
|
873
|
+
gs.log('Record processed by flow: ' + current.number, 'CustomFlow');`
|
|
874
|
+
}
|
|
875
|
+
});
|
|
876
|
+
}
|
|
877
|
+
// 🎯 Always end with logging for audit trail
|
|
878
|
+
activities.push({
|
|
879
|
+
id: 'log_completion',
|
|
880
|
+
name: 'Log Flow Completion',
|
|
881
|
+
type: 'script',
|
|
882
|
+
inputs: {
|
|
883
|
+
script: `gs.log('Flow completed successfully for record: ' + current.number, 'FlowCompletion');
|
|
884
|
+
|
|
885
|
+
// Update record with completion timestamp
|
|
886
|
+
current.u_flow_completed = new GlideDateTime();
|
|
887
|
+
current.update();`
|
|
888
|
+
}
|
|
889
|
+
});
|
|
890
|
+
return activities;
|
|
891
|
+
}
|
|
892
|
+
/**
|
|
893
|
+
* Generate flow variables for data passing
|
|
894
|
+
*/
|
|
895
|
+
generateFlowVariables(parsedIntent) {
|
|
896
|
+
const variables = [
|
|
897
|
+
{
|
|
898
|
+
id: 'flow_start_time',
|
|
899
|
+
name: 'Flow Start Time',
|
|
900
|
+
type: 'datetime',
|
|
901
|
+
input: false,
|
|
902
|
+
output: true,
|
|
903
|
+
default_value: '${gs.nowDateTime()}'
|
|
904
|
+
},
|
|
905
|
+
{
|
|
906
|
+
id: 'record_context',
|
|
907
|
+
name: 'Record Context',
|
|
908
|
+
type: 'reference',
|
|
909
|
+
input: true,
|
|
910
|
+
output: false,
|
|
911
|
+
table: parsedIntent.table
|
|
912
|
+
}
|
|
913
|
+
];
|
|
914
|
+
// Add intent-specific variables
|
|
915
|
+
if (parsedIntent.intents.includes('approval')) {
|
|
916
|
+
variables.push({
|
|
917
|
+
id: 'approval_result',
|
|
918
|
+
name: 'Approval Result',
|
|
919
|
+
type: 'string',
|
|
920
|
+
input: false,
|
|
921
|
+
output: true,
|
|
922
|
+
default_value: ''
|
|
923
|
+
});
|
|
924
|
+
}
|
|
925
|
+
if (parsedIntent.intents.includes('notification')) {
|
|
926
|
+
variables.push({
|
|
927
|
+
id: 'notification_sent',
|
|
928
|
+
name: 'Notification Sent',
|
|
929
|
+
type: 'boolean',
|
|
930
|
+
input: false,
|
|
931
|
+
output: true,
|
|
932
|
+
default_value: 'false'
|
|
933
|
+
});
|
|
934
|
+
}
|
|
935
|
+
return variables;
|
|
936
|
+
}
|
|
937
|
+
/**
|
|
938
|
+
* Generate error handling activities
|
|
939
|
+
*/
|
|
940
|
+
generateErrorHandling(parsedIntent) {
|
|
941
|
+
return [
|
|
942
|
+
{
|
|
943
|
+
id: 'error_handler',
|
|
944
|
+
name: 'Handle Flow Errors',
|
|
945
|
+
type: 'script',
|
|
946
|
+
trigger: 'on_error',
|
|
947
|
+
inputs: {
|
|
948
|
+
script: `gs.error('Flow error occurred: ' + error.message, 'FlowError');
|
|
949
|
+
|
|
950
|
+
// Send error notification
|
|
951
|
+
var email = new GlideEmailOutbound();
|
|
952
|
+
email.setSubject('Flow Error in ${parsedIntent.flowName}');
|
|
953
|
+
email.setBody('An error occurred during flow execution: ' + error.message);
|
|
954
|
+
email.addAddress('admin@company.com');
|
|
955
|
+
email.send();
|
|
956
|
+
|
|
957
|
+
// Log to system log
|
|
958
|
+
gs.log('Flow error logged and notification sent', 'FlowError');`
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
];
|
|
962
|
+
}
|
|
963
|
+
/**
|
|
964
|
+
* Generate connections between activities
|
|
965
|
+
*/
|
|
966
|
+
generateActivityConnections(activities) {
|
|
967
|
+
const connections = [];
|
|
968
|
+
for (let i = 0; i < activities.length - 1; i++) {
|
|
969
|
+
connections.push({
|
|
970
|
+
from: activities[i].id,
|
|
971
|
+
to: activities[i + 1].id,
|
|
972
|
+
condition: activities[i + 1].condition || 'always'
|
|
973
|
+
});
|
|
974
|
+
}
|
|
975
|
+
return connections;
|
|
378
976
|
}
|
|
379
977
|
async analyzeFlowInstruction(args) {
|
|
380
978
|
// Check authentication first
|