snow-flow 1.2.1 → 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/mcp/servicenow-flow-composer-mcp.js +661 -63
- package/dist/version.js +12 -1
- package/package.json +1 -1
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.FlowBuilderAgent = void 0;
|
|
8
8
|
const base_agent_1 = require("./base-agent");
|
|
9
|
+
const mcp_execution_bridge_1 = require("../queen/mcp-execution-bridge");
|
|
9
10
|
class FlowBuilderAgent extends base_agent_1.BaseAgent {
|
|
10
|
-
constructor(config) {
|
|
11
|
+
constructor(config, mcpBridge) {
|
|
11
12
|
super({
|
|
12
13
|
type: 'flow-builder',
|
|
13
14
|
capabilities: [
|
|
@@ -32,504 +33,165 @@ class FlowBuilderAgent extends base_agent_1.BaseAgent {
|
|
|
32
33
|
],
|
|
33
34
|
...config
|
|
34
35
|
});
|
|
36
|
+
// Initialize MCP bridge for real ServiceNow deployment
|
|
37
|
+
this.mcpBridge = mcpBridge || new mcp_execution_bridge_1.MCPExecutionBridge(this.memory);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Create MCP recommendation for tool execution
|
|
41
|
+
*/
|
|
42
|
+
createMCPRecommendation(tool, params, action) {
|
|
43
|
+
return {
|
|
44
|
+
agentId: this.id,
|
|
45
|
+
agentType: this.type,
|
|
46
|
+
action: action,
|
|
47
|
+
tool: tool,
|
|
48
|
+
server: this.getServerForTool(tool),
|
|
49
|
+
params: params,
|
|
50
|
+
reasoning: `Flow builder executing ${action}`,
|
|
51
|
+
confidence: 0.9,
|
|
52
|
+
dependencies: []
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Map MCP tools to their respective servers
|
|
57
|
+
*/
|
|
58
|
+
getServerForTool(tool) {
|
|
59
|
+
const toolServerMap = {
|
|
60
|
+
'snow_create_flow': 'flow-composer',
|
|
61
|
+
'snow_test_flow_with_mock': 'operations',
|
|
62
|
+
'snow_comprehensive_flow_test': 'intelligent',
|
|
63
|
+
'snow_validate_flow_definition': 'deployment',
|
|
64
|
+
'snow_discover_existing_flows': 'intelligent',
|
|
65
|
+
'snow_link_catalog_to_flow': 'operations'
|
|
66
|
+
};
|
|
67
|
+
return toolServerMap[tool] || 'deployment';
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Execute MCP tool with error handling and fallbacks
|
|
71
|
+
*/
|
|
72
|
+
async executeWithFallback(tool, params, action) {
|
|
73
|
+
const recommendation = this.createMCPRecommendation(tool, params, action);
|
|
74
|
+
try {
|
|
75
|
+
const result = await this.mcpBridge.executeAgentRecommendation({ id: this.id, type: this.type }, recommendation);
|
|
76
|
+
if (!result.success) {
|
|
77
|
+
return {
|
|
78
|
+
success: false,
|
|
79
|
+
error: result.error || `MCP tool ${tool} execution failed`
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
if (result.fallbackUsed) {
|
|
83
|
+
console.warn(`⚠️ MCP tool ${tool} used fallback strategy`);
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
success: true,
|
|
87
|
+
result: result.toolResult
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
return {
|
|
92
|
+
success: false,
|
|
93
|
+
error: error instanceof Error ? error.message : String(error)
|
|
94
|
+
};
|
|
95
|
+
}
|
|
35
96
|
}
|
|
36
97
|
async execute(instruction, context) {
|
|
37
98
|
try {
|
|
38
99
|
this.setStatus('working');
|
|
39
|
-
await this.reportProgress('Starting flow creation', 0);
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
await this.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
100
|
+
await this.reportProgress('🚀 Starting MCP-powered flow creation', 0);
|
|
101
|
+
// 🔍 STEP 1: Check for existing flows to avoid duplication
|
|
102
|
+
await this.reportProgress('🔍 Discovering existing flows', 10);
|
|
103
|
+
const discoveryResult = await this.executeWithFallback('snow_discover_existing_flows', { flow_purpose: instruction }, 'discover-existing-flows');
|
|
104
|
+
let existingFlowsCount = 0;
|
|
105
|
+
if (discoveryResult.success && discoveryResult.result?.found) {
|
|
106
|
+
existingFlowsCount = discoveryResult.result.found.length;
|
|
107
|
+
if (existingFlowsCount > 0) {
|
|
108
|
+
await this.reportProgress(`📊 Found ${existingFlowsCount} similar flows for reference`, 20);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// 🧠 STEP 2: CREATE FLOW VIA MCP TOOL (This is the key fix!)
|
|
112
|
+
await this.reportProgress('🧠 Creating flow via intelligent MCP system', 30);
|
|
113
|
+
const createResult = await this.executeWithFallback('snow_create_flow', {
|
|
114
|
+
instruction: instruction,
|
|
115
|
+
deploy_immediately: true,
|
|
116
|
+
enable_intelligent_analysis: true,
|
|
117
|
+
create_missing_artifacts: true,
|
|
118
|
+
validation_level: 'standard'
|
|
119
|
+
}, 'create-flow');
|
|
120
|
+
if (!createResult.success) {
|
|
121
|
+
throw new Error(`❌ Flow creation via MCP failed: ${createResult.error}`);
|
|
122
|
+
}
|
|
123
|
+
await this.reportProgress('✅ Flow created and deployed to ServiceNow!', 60);
|
|
124
|
+
// 🧪 STEP 3: Test the created flow with mock data
|
|
125
|
+
await this.reportProgress('🧪 Testing flow with mock data', 70);
|
|
126
|
+
const testResult = await this.executeWithFallback('snow_test_flow_with_mock', {
|
|
127
|
+
flow_id: createResult.result.sys_id || createResult.result.flow_sys_id,
|
|
128
|
+
create_test_user: true,
|
|
129
|
+
cleanup_after_test: true,
|
|
130
|
+
simulate_approvals: true
|
|
131
|
+
}, 'test-flow');
|
|
132
|
+
let testStatus = '❓ Test status unknown';
|
|
133
|
+
if (testResult.success) {
|
|
134
|
+
testStatus = '✅ Flow tested successfully';
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
testStatus = `⚠️ Flow test failed: ${testResult.error}`;
|
|
47
138
|
}
|
|
48
|
-
//
|
|
49
|
-
const
|
|
50
|
-
await this.reportProgress('Designed flow structure', 40);
|
|
51
|
-
// Create flow definition
|
|
52
|
-
const flowDefinition = await this.createFlowDefinition(requirements, flowStructure);
|
|
53
|
-
await this.reportProgress('Created flow definition', 60);
|
|
54
|
-
// Configure triggers
|
|
55
|
-
const triggers = await this.configureTriggers(requirements);
|
|
56
|
-
await this.reportProgress('Configured flow triggers', 70);
|
|
57
|
-
// Set up actions
|
|
58
|
-
const actions = await this.setupActions(requirements, flowStructure);
|
|
59
|
-
await this.reportProgress('Set up flow actions', 80);
|
|
60
|
-
// Create flow artifact
|
|
139
|
+
// 🎯 STEP 4: Create artifact with REAL ServiceNow data
|
|
140
|
+
const realFlowData = createResult.result;
|
|
61
141
|
const artifact = {
|
|
62
142
|
type: 'flow',
|
|
63
|
-
name:
|
|
143
|
+
name: realFlowData.name || realFlowData.flow_name || 'created_flow',
|
|
144
|
+
sys_id: realFlowData.sys_id || realFlowData.flow_sys_id, // ✅ REAL sys_id from ServiceNow!
|
|
64
145
|
config: {
|
|
65
|
-
definition
|
|
66
|
-
|
|
67
|
-
|
|
146
|
+
// Store the actual flow definition returned from ServiceNow
|
|
147
|
+
definition: realFlowData.definition || realFlowData,
|
|
148
|
+
deployed: true,
|
|
149
|
+
tested: testResult.success,
|
|
150
|
+
created_via: 'snow_create_flow_mcp',
|
|
68
151
|
metadata: {
|
|
69
|
-
description:
|
|
70
|
-
|
|
71
|
-
|
|
152
|
+
description: instruction,
|
|
153
|
+
type: realFlowData.type || 'flow',
|
|
154
|
+
active: realFlowData.active || true
|
|
72
155
|
}
|
|
73
156
|
},
|
|
74
|
-
dependencies:
|
|
157
|
+
dependencies: realFlowData.dependencies || []
|
|
75
158
|
};
|
|
76
159
|
// Store artifact for other agents
|
|
77
160
|
await this.storeArtifact(artifact);
|
|
78
|
-
await this.reportProgress('Flow artifact
|
|
79
|
-
|
|
80
|
-
const deploymentInstructions = this.prepareDeploymentInstructions(requirements, artifact);
|
|
81
|
-
await this.reportProgress('Flow creation completed', 100);
|
|
161
|
+
await this.reportProgress('📦 Flow artifact stored with real ServiceNow data', 90);
|
|
162
|
+
await this.reportProgress('🎉 MCP-powered flow creation completed!', 100);
|
|
82
163
|
this.setStatus('completed');
|
|
83
|
-
await this.logActivity('
|
|
84
|
-
flowName:
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
164
|
+
await this.logActivity('flow_creation_mcp', true, {
|
|
165
|
+
flowName: artifact.name,
|
|
166
|
+
sys_id: artifact.sys_id,
|
|
167
|
+
tested: testResult.success,
|
|
168
|
+
deployedToServiceNow: true,
|
|
169
|
+
discoveredSimilar: existingFlowsCount
|
|
88
170
|
});
|
|
89
171
|
return {
|
|
90
172
|
success: true,
|
|
91
173
|
artifacts: [artifact],
|
|
92
|
-
message:
|
|
174
|
+
message: `✅ Flow "${artifact.name}" created and deployed to ServiceNow successfully! ${testStatus}`,
|
|
93
175
|
metadata: {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
176
|
+
sys_id: artifact.sys_id, // ✅ Real ServiceNow sys_id!
|
|
177
|
+
deployed_to_servicenow: true,
|
|
178
|
+
tested: testResult.success,
|
|
179
|
+
test_details: testResult.result,
|
|
180
|
+
discovered_similar_flows: existingFlowsCount,
|
|
181
|
+
mcp_powered: true,
|
|
182
|
+
has_content: true // ✅ No more empty flows!
|
|
100
183
|
}
|
|
101
184
|
};
|
|
102
185
|
}
|
|
103
186
|
catch (error) {
|
|
104
187
|
this.setStatus('failed');
|
|
105
|
-
await this.logActivity('
|
|
188
|
+
await this.logActivity('flow_creation_mcp', false, { error: error.message });
|
|
106
189
|
return {
|
|
107
190
|
success: false,
|
|
108
191
|
error: error,
|
|
109
|
-
message:
|
|
192
|
+
message: `❌ MCP-powered flow creation failed: ${error.message}`
|
|
110
193
|
};
|
|
111
194
|
}
|
|
112
195
|
}
|
|
113
|
-
async analyzeFlowRequirements(instruction) {
|
|
114
|
-
const requirements = {
|
|
115
|
-
name: '',
|
|
116
|
-
description: instruction,
|
|
117
|
-
flowType: 'flow', // flow, subflow, or action
|
|
118
|
-
category: 'custom',
|
|
119
|
-
triggerType: '',
|
|
120
|
-
targetTable: '',
|
|
121
|
-
needsApproval: false,
|
|
122
|
-
needsNotification: false,
|
|
123
|
-
needsIntegration: false,
|
|
124
|
-
needsCatalogLink: false,
|
|
125
|
-
conditions: [],
|
|
126
|
-
dependencies: [],
|
|
127
|
-
steps: []
|
|
128
|
-
};
|
|
129
|
-
// Extract flow name
|
|
130
|
-
const nameMatch = instruction.match(/(?:create|build|design)\s+(?:a\s+)?([a-zA-Z0-9_\s]+)\s*(?:flow|workflow|process)/i);
|
|
131
|
-
if (nameMatch) {
|
|
132
|
-
requirements.name = nameMatch[1].trim().toLowerCase().replace(/\s+/g, '_') + '_flow';
|
|
133
|
-
}
|
|
134
|
-
// Determine flow type
|
|
135
|
-
if (/subflow/i.test(instruction)) {
|
|
136
|
-
requirements.flowType = 'subflow';
|
|
137
|
-
}
|
|
138
|
-
else if (/action/i.test(instruction)) {
|
|
139
|
-
requirements.flowType = 'action';
|
|
140
|
-
}
|
|
141
|
-
// Detect trigger type
|
|
142
|
-
if (/when\s+(?:a\s+)?(?:new\s+)?record\s+is\s+created/i.test(instruction)) {
|
|
143
|
-
requirements.triggerType = 'record_created';
|
|
144
|
-
}
|
|
145
|
-
else if (/when\s+(?:a\s+)?record\s+is\s+updated/i.test(instruction)) {
|
|
146
|
-
requirements.triggerType = 'record_updated';
|
|
147
|
-
}
|
|
148
|
-
else if (/scheduled|daily|weekly|monthly/i.test(instruction)) {
|
|
149
|
-
requirements.triggerType = 'scheduled';
|
|
150
|
-
}
|
|
151
|
-
else if (/manual|on[\s-]?demand/i.test(instruction)) {
|
|
152
|
-
requirements.triggerType = 'manual';
|
|
153
|
-
}
|
|
154
|
-
// Detect target table
|
|
155
|
-
if (/incident/i.test(instruction)) {
|
|
156
|
-
requirements.targetTable = 'incident';
|
|
157
|
-
requirements.category = 'itsm';
|
|
158
|
-
}
|
|
159
|
-
else if (/request|catalog/i.test(instruction)) {
|
|
160
|
-
requirements.targetTable = 'sc_request';
|
|
161
|
-
requirements.category = 'service_catalog';
|
|
162
|
-
requirements.needsCatalogLink = true;
|
|
163
|
-
}
|
|
164
|
-
else if (/change/i.test(instruction)) {
|
|
165
|
-
requirements.targetTable = 'change_request';
|
|
166
|
-
requirements.category = 'change_management';
|
|
167
|
-
}
|
|
168
|
-
else if (/task/i.test(instruction)) {
|
|
169
|
-
requirements.targetTable = 'task';
|
|
170
|
-
requirements.category = 'task_management';
|
|
171
|
-
}
|
|
172
|
-
// Feature detection
|
|
173
|
-
if (/approval|approve|manager/i.test(instruction)) {
|
|
174
|
-
requirements.needsApproval = true;
|
|
175
|
-
requirements.steps.push('approval');
|
|
176
|
-
requirements.dependencies.push('sys_user_group');
|
|
177
|
-
}
|
|
178
|
-
if (/notify|notification|email|send\s+message/i.test(instruction)) {
|
|
179
|
-
requirements.needsNotification = true;
|
|
180
|
-
requirements.steps.push('notification');
|
|
181
|
-
}
|
|
182
|
-
if (/integrate|api|external|rest/i.test(instruction)) {
|
|
183
|
-
requirements.needsIntegration = true;
|
|
184
|
-
requirements.steps.push('integration');
|
|
185
|
-
requirements.dependencies.push('sys_rest_message');
|
|
186
|
-
}
|
|
187
|
-
// Extract conditions
|
|
188
|
-
const conditionMatches = instruction.match(/(?:if|when|condition)\s+([^,\.]+)/gi);
|
|
189
|
-
if (conditionMatches) {
|
|
190
|
-
requirements.conditions = conditionMatches.map(match => match.replace(/^(if|when|condition)\s+/i, '').trim());
|
|
191
|
-
}
|
|
192
|
-
return requirements;
|
|
193
|
-
}
|
|
194
|
-
async checkExistingFlows(requirements) {
|
|
195
|
-
// Would use snow_discover_existing_flows MCP tool
|
|
196
|
-
// For now, return empty array
|
|
197
|
-
return [];
|
|
198
|
-
}
|
|
199
|
-
async designFlowStructure(requirements) {
|
|
200
|
-
const structure = {
|
|
201
|
-
stages: [],
|
|
202
|
-
decisionPoints: [],
|
|
203
|
-
parallelPaths: false,
|
|
204
|
-
errorHandling: true
|
|
205
|
-
};
|
|
206
|
-
// Start stage
|
|
207
|
-
structure.stages.push({
|
|
208
|
-
name: 'Start',
|
|
209
|
-
type: 'trigger',
|
|
210
|
-
position: { x: 100, y: 100 }
|
|
211
|
-
});
|
|
212
|
-
let currentX = 300;
|
|
213
|
-
const currentY = 100;
|
|
214
|
-
const stepSpacing = 200;
|
|
215
|
-
// Add validation stage if complex flow
|
|
216
|
-
if (requirements.conditions.length > 0) {
|
|
217
|
-
structure.stages.push({
|
|
218
|
-
name: 'Validate Input',
|
|
219
|
-
type: 'action',
|
|
220
|
-
actionType: 'script',
|
|
221
|
-
position: { x: currentX, y: currentY }
|
|
222
|
-
});
|
|
223
|
-
currentX += stepSpacing;
|
|
224
|
-
}
|
|
225
|
-
// Add approval stage if needed
|
|
226
|
-
if (requirements.needsApproval) {
|
|
227
|
-
structure.stages.push({
|
|
228
|
-
name: 'Request Approval',
|
|
229
|
-
type: 'approval',
|
|
230
|
-
position: { x: currentX, y: currentY }
|
|
231
|
-
});
|
|
232
|
-
currentX += stepSpacing;
|
|
233
|
-
// Add decision point for approval result
|
|
234
|
-
structure.decisionPoints.push({
|
|
235
|
-
name: 'Approval Decision',
|
|
236
|
-
condition: 'approval.result == "approved"',
|
|
237
|
-
position: { x: currentX, y: currentY },
|
|
238
|
-
truePath: 'Continue',
|
|
239
|
-
falsePath: 'Rejection Handler'
|
|
240
|
-
});
|
|
241
|
-
currentX += stepSpacing;
|
|
242
|
-
}
|
|
243
|
-
// Add main action stage
|
|
244
|
-
structure.stages.push({
|
|
245
|
-
name: 'Execute Main Action',
|
|
246
|
-
type: 'action',
|
|
247
|
-
actionType: requirements.needsIntegration ? 'integration' : 'script',
|
|
248
|
-
position: { x: currentX, y: currentY }
|
|
249
|
-
});
|
|
250
|
-
currentX += stepSpacing;
|
|
251
|
-
// Add notification stage if needed
|
|
252
|
-
if (requirements.needsNotification) {
|
|
253
|
-
structure.stages.push({
|
|
254
|
-
name: 'Send Notification',
|
|
255
|
-
type: 'notification',
|
|
256
|
-
position: { x: currentX, y: currentY }
|
|
257
|
-
});
|
|
258
|
-
currentX += stepSpacing;
|
|
259
|
-
}
|
|
260
|
-
// End stage
|
|
261
|
-
structure.stages.push({
|
|
262
|
-
name: 'End',
|
|
263
|
-
type: 'end',
|
|
264
|
-
position: { x: currentX, y: currentY }
|
|
265
|
-
});
|
|
266
|
-
// Add error handling path
|
|
267
|
-
if (structure.errorHandling) {
|
|
268
|
-
structure.stages.push({
|
|
269
|
-
name: 'Error Handler',
|
|
270
|
-
type: 'error_handler',
|
|
271
|
-
position: { x: 300, y: 250 }
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
return structure;
|
|
275
|
-
}
|
|
276
|
-
async createFlowDefinition(requirements, structure) {
|
|
277
|
-
const definition = {
|
|
278
|
-
name: requirements.name,
|
|
279
|
-
description: requirements.description,
|
|
280
|
-
type: requirements.flowType,
|
|
281
|
-
category: requirements.category,
|
|
282
|
-
active: true,
|
|
283
|
-
stages: structure.stages,
|
|
284
|
-
connections: [],
|
|
285
|
-
variables: [],
|
|
286
|
-
settings: {
|
|
287
|
-
run_as: 'system',
|
|
288
|
-
error_handling: 'stop_on_error',
|
|
289
|
-
logging_level: 'info'
|
|
290
|
-
}
|
|
291
|
-
};
|
|
292
|
-
// Create connections between stages
|
|
293
|
-
for (let i = 0; i < structure.stages.length - 1; i++) {
|
|
294
|
-
const fromStage = structure.stages[i];
|
|
295
|
-
const toStage = structure.stages[i + 1];
|
|
296
|
-
// Skip if this is a decision point
|
|
297
|
-
if (structure.decisionPoints.some(dp => dp.name === fromStage.name)) {
|
|
298
|
-
continue;
|
|
299
|
-
}
|
|
300
|
-
definition.connections.push({
|
|
301
|
-
from: fromStage.name,
|
|
302
|
-
to: toStage.name,
|
|
303
|
-
condition: 'always'
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
// Add decision point connections
|
|
307
|
-
for (const decisionPoint of structure.decisionPoints) {
|
|
308
|
-
definition.connections.push({
|
|
309
|
-
from: decisionPoint.name,
|
|
310
|
-
to: decisionPoint.truePath,
|
|
311
|
-
condition: decisionPoint.condition
|
|
312
|
-
});
|
|
313
|
-
definition.connections.push({
|
|
314
|
-
from: decisionPoint.name,
|
|
315
|
-
to: decisionPoint.falsePath,
|
|
316
|
-
condition: `!(${decisionPoint.condition})`
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
|
-
// Define flow variables
|
|
320
|
-
if (requirements.targetTable) {
|
|
321
|
-
definition.variables.push({
|
|
322
|
-
name: 'current_record',
|
|
323
|
-
type: 'reference',
|
|
324
|
-
reference_table: requirements.targetTable,
|
|
325
|
-
description: 'The record that triggered this flow'
|
|
326
|
-
});
|
|
327
|
-
}
|
|
328
|
-
if (requirements.needsApproval) {
|
|
329
|
-
definition.variables.push({
|
|
330
|
-
name: 'approval_result',
|
|
331
|
-
type: 'string',
|
|
332
|
-
description: 'Result of the approval request'
|
|
333
|
-
});
|
|
334
|
-
definition.variables.push({
|
|
335
|
-
name: 'approver',
|
|
336
|
-
type: 'reference',
|
|
337
|
-
reference_table: 'sys_user',
|
|
338
|
-
description: 'User who approved/rejected the request'
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
return definition;
|
|
342
|
-
}
|
|
343
|
-
async configureTriggers(requirements) {
|
|
344
|
-
const triggers = [];
|
|
345
|
-
switch (requirements.triggerType) {
|
|
346
|
-
case 'record_created':
|
|
347
|
-
triggers.push({
|
|
348
|
-
type: 'record_created',
|
|
349
|
-
table: requirements.targetTable,
|
|
350
|
-
conditions: requirements.conditions,
|
|
351
|
-
active: true,
|
|
352
|
-
order: 100
|
|
353
|
-
});
|
|
354
|
-
break;
|
|
355
|
-
case 'record_updated':
|
|
356
|
-
triggers.push({
|
|
357
|
-
type: 'record_updated',
|
|
358
|
-
table: requirements.targetTable,
|
|
359
|
-
conditions: requirements.conditions,
|
|
360
|
-
fields_to_watch: ['state', 'priority', 'assignment_group'],
|
|
361
|
-
active: true,
|
|
362
|
-
order: 100
|
|
363
|
-
});
|
|
364
|
-
break;
|
|
365
|
-
case 'scheduled':
|
|
366
|
-
triggers.push({
|
|
367
|
-
type: 'scheduled',
|
|
368
|
-
schedule: {
|
|
369
|
-
type: 'daily',
|
|
370
|
-
time: '00:00',
|
|
371
|
-
timezone: 'UTC'
|
|
372
|
-
},
|
|
373
|
-
active: true,
|
|
374
|
-
order: 100
|
|
375
|
-
});
|
|
376
|
-
break;
|
|
377
|
-
case 'manual':
|
|
378
|
-
triggers.push({
|
|
379
|
-
type: 'manual',
|
|
380
|
-
roles: ['admin', 'itil'],
|
|
381
|
-
ui_action: true,
|
|
382
|
-
active: true,
|
|
383
|
-
order: 100
|
|
384
|
-
});
|
|
385
|
-
break;
|
|
386
|
-
default:
|
|
387
|
-
// Default to record created trigger
|
|
388
|
-
triggers.push({
|
|
389
|
-
type: 'record_created',
|
|
390
|
-
table: requirements.targetTable || 'task',
|
|
391
|
-
active: true,
|
|
392
|
-
order: 100
|
|
393
|
-
});
|
|
394
|
-
}
|
|
395
|
-
return triggers;
|
|
396
|
-
}
|
|
397
|
-
async setupActions(requirements, structure) {
|
|
398
|
-
const actions = [];
|
|
399
|
-
for (const stage of structure.stages) {
|
|
400
|
-
if (stage.type === 'action' || stage.type === 'approval' || stage.type === 'notification') {
|
|
401
|
-
const action = await this.createAction(stage, requirements);
|
|
402
|
-
if (action) {
|
|
403
|
-
actions.push(action);
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
return actions;
|
|
408
|
-
}
|
|
409
|
-
async createAction(stage, requirements) {
|
|
410
|
-
const action = {
|
|
411
|
-
name: stage.name,
|
|
412
|
-
type: stage.type,
|
|
413
|
-
order: 100,
|
|
414
|
-
active: true
|
|
415
|
-
};
|
|
416
|
-
switch (stage.type) {
|
|
417
|
-
case 'approval':
|
|
418
|
-
action.config = {
|
|
419
|
-
approval_type: 'user',
|
|
420
|
-
approvers: 'current_record.assignment_group.manager',
|
|
421
|
-
approval_message: `Please approve ${requirements.targetTable} ${requirements.name}`,
|
|
422
|
-
due_date: '3 business days',
|
|
423
|
-
reminders: true,
|
|
424
|
-
escalation: {
|
|
425
|
-
enabled: true,
|
|
426
|
-
after: '2 business days',
|
|
427
|
-
escalate_to: 'current_record.assignment_group.manager.manager'
|
|
428
|
-
}
|
|
429
|
-
};
|
|
430
|
-
break;
|
|
431
|
-
case 'notification':
|
|
432
|
-
action.config = {
|
|
433
|
-
recipients: ['current_record.requested_for', 'current_record.assigned_to'],
|
|
434
|
-
template: 'flow_notification',
|
|
435
|
-
subject: `${requirements.name} - Action Completed`,
|
|
436
|
-
message: 'The flow has completed processing your request.',
|
|
437
|
-
include_record_link: true
|
|
438
|
-
};
|
|
439
|
-
break;
|
|
440
|
-
case 'action':
|
|
441
|
-
if (stage.actionType === 'integration') {
|
|
442
|
-
action.config = {
|
|
443
|
-
rest_message: 'External System Integration',
|
|
444
|
-
endpoint: '/api/process',
|
|
445
|
-
method: 'POST',
|
|
446
|
-
headers: {
|
|
447
|
-
'Content-Type': 'application/json'
|
|
448
|
-
},
|
|
449
|
-
body: {
|
|
450
|
-
record_number: '${current_record.number}',
|
|
451
|
-
record_type: requirements.targetTable,
|
|
452
|
-
action: 'process'
|
|
453
|
-
}
|
|
454
|
-
};
|
|
455
|
-
}
|
|
456
|
-
else {
|
|
457
|
-
action.config = {
|
|
458
|
-
script: `
|
|
459
|
-
// ${stage.name} Script
|
|
460
|
-
(function execute(inputs, outputs) {
|
|
461
|
-
// Get the current record
|
|
462
|
-
var current = inputs.current_record;
|
|
463
|
-
|
|
464
|
-
// Perform the main action
|
|
465
|
-
gs.info('Executing ${stage.name} for ' + current.getDisplayValue());
|
|
466
|
-
|
|
467
|
-
// Add your business logic here
|
|
468
|
-
current.work_notes = 'Processed by ${requirements.name} flow';
|
|
469
|
-
current.update();
|
|
470
|
-
|
|
471
|
-
// Set outputs
|
|
472
|
-
outputs.success = true;
|
|
473
|
-
outputs.message = 'Action completed successfully';
|
|
474
|
-
|
|
475
|
-
})(inputs, outputs);`
|
|
476
|
-
};
|
|
477
|
-
}
|
|
478
|
-
break;
|
|
479
|
-
case 'error_handler':
|
|
480
|
-
action.config = {
|
|
481
|
-
script: `
|
|
482
|
-
// Error Handler Script
|
|
483
|
-
(function handleError(inputs, outputs) {
|
|
484
|
-
var errorMessage = inputs.error_message || 'Unknown error';
|
|
485
|
-
var current = inputs.current_record;
|
|
486
|
-
|
|
487
|
-
// Log the error
|
|
488
|
-
gs.error('Flow error in ${requirements.name}: ' + errorMessage);
|
|
489
|
-
|
|
490
|
-
// Update the record with error information
|
|
491
|
-
if (current) {
|
|
492
|
-
current.work_notes = 'Flow error: ' + errorMessage;
|
|
493
|
-
current.update();
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
// Send error notification if configured
|
|
497
|
-
if (${requirements.needsNotification}) {
|
|
498
|
-
// Send error notification logic
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
})(inputs, outputs);`
|
|
502
|
-
};
|
|
503
|
-
break;
|
|
504
|
-
}
|
|
505
|
-
return action;
|
|
506
|
-
}
|
|
507
|
-
prepareDeploymentInstructions(requirements, artifact) {
|
|
508
|
-
return {
|
|
509
|
-
primaryTool: 'snow_create_flow',
|
|
510
|
-
instruction: `Create ${requirements.flowType} for ${requirements.targetTable || 'general'} with ${requirements.needsApproval ? 'approval' : 'automated'} processing`,
|
|
511
|
-
testingTools: [
|
|
512
|
-
{
|
|
513
|
-
tool: 'snow_test_flow_with_mock',
|
|
514
|
-
purpose: 'Test flow with mock data before deployment'
|
|
515
|
-
},
|
|
516
|
-
{
|
|
517
|
-
tool: 'snow_comprehensive_flow_test',
|
|
518
|
-
purpose: 'Run comprehensive tests including edge cases'
|
|
519
|
-
}
|
|
520
|
-
],
|
|
521
|
-
validationSteps: [
|
|
522
|
-
'Verify trigger configuration',
|
|
523
|
-
'Test all decision branches',
|
|
524
|
-
'Validate approval routing if applicable',
|
|
525
|
-
'Check error handling paths',
|
|
526
|
-
'Verify notifications are sent correctly'
|
|
527
|
-
],
|
|
528
|
-
catalogLinking: requirements.needsCatalogLink ? {
|
|
529
|
-
tool: 'snow_link_catalog_to_flow',
|
|
530
|
-
instruction: 'Link this flow to relevant catalog items'
|
|
531
|
-
} : null
|
|
532
|
-
};
|
|
533
|
-
}
|
|
534
196
|
}
|
|
535
197
|
exports.FlowBuilderAgent = FlowBuilderAgent;
|