servicenow-mcp-server 2.1.0
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/.claude/settings.local.json +70 -0
- package/CLAUDE.md +777 -0
- package/LICENSE +21 -0
- package/README.md +562 -0
- package/assets/logo.svg +385 -0
- package/config/servicenow-instances.json.example +28 -0
- package/docs/403_TROUBLESHOOTING.md +329 -0
- package/docs/API_REFERENCE.md +1142 -0
- package/docs/APPLICATION_SCOPE_VALIDATION.md +681 -0
- package/docs/CLAUDE_DESKTOP_SETUP.md +373 -0
- package/docs/CONVENIENCE_TOOLS.md +601 -0
- package/docs/CONVENIENCE_TOOLS_SUMMARY.md +371 -0
- package/docs/FLOW_DESIGNER_GUIDE.md +1021 -0
- package/docs/IMPLEMENTATION_COMPLETE.md +165 -0
- package/docs/INSTANCE_SWITCHING_GUIDE.md +219 -0
- package/docs/MULTI_INSTANCE_CONFIGURATION.md +185 -0
- package/docs/NATURAL_LANGUAGE_SEARCH_IMPLEMENTATION.md +221 -0
- package/docs/PUPPETEER_INTEGRATION_PROPOSAL.md +1322 -0
- package/docs/QUICK_REFERENCE.md +395 -0
- package/docs/README.md +75 -0
- package/docs/RESOURCES_ARCHITECTURE.md +392 -0
- package/docs/RESOURCES_IMPLEMENTATION.md +276 -0
- package/docs/RESOURCES_SUMMARY.md +104 -0
- package/docs/SETUP_GUIDE.md +104 -0
- package/docs/UI_OPERATIONS_ARCHITECTURE.md +1219 -0
- package/docs/UI_OPERATIONS_DECISION_MATRIX.md +542 -0
- package/docs/UI_OPERATIONS_SUMMARY.md +507 -0
- package/docs/UPDATE_SET_VALIDATION.md +598 -0
- package/docs/UPDATE_SET_VALIDATION_SUMMARY.md +209 -0
- package/docs/VALIDATION_SUMMARY.md +479 -0
- package/jest.config.js +24 -0
- package/package.json +61 -0
- package/scripts/background_script_2025-09-29T20-19-35-101Z.js +23 -0
- package/scripts/link_ui_policy_actions_2025-09-29T20-17-15-218Z.js +90 -0
- package/scripts/set_update_set_Integration_Governance_Framework_2025-09-29T19-47-06-790Z.js +30 -0
- package/scripts/set_update_set_Integration_Governance_Framework_2025-09-29T19-59-33-152Z.js +30 -0
- package/scripts/set_update_set_current_2025-09-29T20-16-59-675Z.js +24 -0
- package/scripts/test_sys_dictionary_403.js +85 -0
- package/setup/setup-report.json +5313 -0
- package/src/config/comprehensive-table-definitions.json +2575 -0
- package/src/config/instance-config.json +4693 -0
- package/src/config/prompts.md +59 -0
- package/src/config/table-definitions.json +4681 -0
- package/src/config-manager.js +146 -0
- package/src/mcp-server-consolidated.js +2894 -0
- package/src/natural-language.js +472 -0
- package/src/resources.js +326 -0
- package/src/script-sync.js +428 -0
- package/src/server.js +125 -0
- package/src/servicenow-client.js +1625 -0
- package/src/stdio-server.js +52 -0
- package/start-mcp.sh +7 -0
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ServiceNow MCP Server - Natural Language Query Processing
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2025 Happy Technologies LLC
|
|
5
|
+
* Licensed under the MIT License - see LICENSE file for details
|
|
6
|
+
*
|
|
7
|
+
* Natural Language to ServiceNow Encoded Query Parser
|
|
8
|
+
* Converts human-readable queries into ServiceNow encoded query strings.
|
|
9
|
+
* Uses pattern matching for reliability and speed.
|
|
10
|
+
*
|
|
11
|
+
* @module natural-language
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Table-specific state mappings
|
|
16
|
+
*/
|
|
17
|
+
const STATE_MAPPINGS = {
|
|
18
|
+
incident: {
|
|
19
|
+
'new': '1',
|
|
20
|
+
'in progress': '2',
|
|
21
|
+
'on hold': '3',
|
|
22
|
+
'resolved': '6',
|
|
23
|
+
'closed': '7',
|
|
24
|
+
'canceled': '8',
|
|
25
|
+
'open': '1^ORstate=2^ORstate=3', // New, In Progress, or On Hold
|
|
26
|
+
'active': 'active=true'
|
|
27
|
+
},
|
|
28
|
+
change_request: {
|
|
29
|
+
'new': '-5',
|
|
30
|
+
'assess': '-4',
|
|
31
|
+
'authorize': '-3',
|
|
32
|
+
'scheduled': '-2',
|
|
33
|
+
'implement': '-1',
|
|
34
|
+
'review': '0',
|
|
35
|
+
'closed': '3',
|
|
36
|
+
'canceled': '4',
|
|
37
|
+
'open': 'state<0', // Negative states are open
|
|
38
|
+
'active': 'active=true'
|
|
39
|
+
},
|
|
40
|
+
problem: {
|
|
41
|
+
'new': '1',
|
|
42
|
+
'assessed': '2',
|
|
43
|
+
'root cause analysis': '3',
|
|
44
|
+
'fix in progress': '4',
|
|
45
|
+
'resolved': '6',
|
|
46
|
+
'closed': '7',
|
|
47
|
+
'open': '1^ORstate=2^ORstate=3^ORstate=4',
|
|
48
|
+
'active': 'active=true'
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Priority mappings (consistent across tables)
|
|
54
|
+
*/
|
|
55
|
+
const PRIORITY_MAPPINGS = {
|
|
56
|
+
'critical': '1',
|
|
57
|
+
'high': '2',
|
|
58
|
+
'moderate': '3',
|
|
59
|
+
'low': '4',
|
|
60
|
+
'planning': '5',
|
|
61
|
+
'p1': '1',
|
|
62
|
+
'p2': '2',
|
|
63
|
+
'p3': '3',
|
|
64
|
+
'p4': '4',
|
|
65
|
+
'p5': '5'
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Impact mappings
|
|
70
|
+
*/
|
|
71
|
+
const IMPACT_MAPPINGS = {
|
|
72
|
+
'high': '1',
|
|
73
|
+
'medium': '2',
|
|
74
|
+
'low': '3'
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Urgency mappings
|
|
79
|
+
*/
|
|
80
|
+
const URGENCY_MAPPINGS = {
|
|
81
|
+
'high': '1',
|
|
82
|
+
'medium': '2',
|
|
83
|
+
'low': '3'
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Pattern definitions for natural language parsing
|
|
88
|
+
* Each pattern has: regex, parser function, priority (higher = check first)
|
|
89
|
+
*/
|
|
90
|
+
const PATTERNS = [
|
|
91
|
+
// Priority patterns
|
|
92
|
+
{
|
|
93
|
+
regex: /\b(critical|high|moderate|low|planning)\s+priority\b/i,
|
|
94
|
+
priority: 10,
|
|
95
|
+
parser: (match) => {
|
|
96
|
+
const level = match[1].toLowerCase();
|
|
97
|
+
return `priority=${PRIORITY_MAPPINGS[level]}`;
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
regex: /\bp([1-5])\b/i,
|
|
102
|
+
priority: 10,
|
|
103
|
+
parser: (match) => {
|
|
104
|
+
return `priority=${match[1]}`;
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
regex: /\bpriority\s+(critical|high|moderate|low|planning|[1-5])\b/i,
|
|
109
|
+
priority: 10,
|
|
110
|
+
parser: (match) => {
|
|
111
|
+
const level = match[1].toLowerCase();
|
|
112
|
+
return `priority=${PRIORITY_MAPPINGS[level] || match[1]}`;
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
// Impact patterns
|
|
117
|
+
{
|
|
118
|
+
regex: /\b(high|medium|low)\s+impact\b/i,
|
|
119
|
+
priority: 9,
|
|
120
|
+
parser: (match) => {
|
|
121
|
+
const level = match[1].toLowerCase();
|
|
122
|
+
return `impact=${IMPACT_MAPPINGS[level]}`;
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
// Urgency patterns
|
|
127
|
+
{
|
|
128
|
+
regex: /\b(high|medium|low)\s+urgency\b/i,
|
|
129
|
+
priority: 9,
|
|
130
|
+
parser: (match) => {
|
|
131
|
+
const level = match[1].toLowerCase();
|
|
132
|
+
return `urgency=${URGENCY_MAPPINGS[level]}`;
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
// Assignment patterns
|
|
137
|
+
{
|
|
138
|
+
regex: /\b(assigned\s+to\s+me|my\s+(incidents|problems|changes|tickets))\b/i,
|
|
139
|
+
priority: 15,
|
|
140
|
+
parser: () => 'assigned_to=javascript:gs.getUserID()'
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
regex: /\bunassigned\b/i,
|
|
144
|
+
priority: 15,
|
|
145
|
+
parser: () => 'assigned_toISEMPTY'
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
regex: /\bassigned\s+to\s+([a-zA-Z\s]+?)(?:\s+(?:and|or|with|created|opened|updated)|\s*$)/i,
|
|
149
|
+
priority: 14,
|
|
150
|
+
parser: (match) => {
|
|
151
|
+
const userName = match[1].trim();
|
|
152
|
+
// Note: This creates a LIKE query - could be enhanced with user lookup
|
|
153
|
+
return `assigned_to.nameLIKE${userName}`;
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
|
|
157
|
+
// Date patterns - relative
|
|
158
|
+
{
|
|
159
|
+
regex: /\b(created|opened|updated|modified|closed)\s+(today|yesterday)\b/i,
|
|
160
|
+
priority: 12,
|
|
161
|
+
parser: (match) => {
|
|
162
|
+
const field = match[1].toLowerCase() === 'opened' ? 'sys_created_on' : `${match[1].toLowerCase()}_on`;
|
|
163
|
+
const days = match[2].toLowerCase() === 'today' ? 0 : 1;
|
|
164
|
+
return `${field}>javascript:gs.daysAgoStart(${days})`;
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
regex: /\b(created|opened|updated|modified|closed)\s+(?:in\s+)?(?:the\s+)?last\s+(\d+)\s+(days?|weeks?|months?)\b/i,
|
|
169
|
+
priority: 12,
|
|
170
|
+
parser: (match) => {
|
|
171
|
+
const field = match[1].toLowerCase() === 'opened' ? 'sys_created_on' : `${match[1].toLowerCase()}_on`;
|
|
172
|
+
const amount = parseInt(match[2]);
|
|
173
|
+
const unit = match[3].toLowerCase();
|
|
174
|
+
|
|
175
|
+
let days = amount;
|
|
176
|
+
if (unit.startsWith('week')) days = amount * 7;
|
|
177
|
+
if (unit.startsWith('month')) days = amount * 30;
|
|
178
|
+
|
|
179
|
+
return `${field}>javascript:gs.daysAgo(${days})`;
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
regex: /\b(recent|recently\s+created|new)\b/i,
|
|
184
|
+
priority: 8,
|
|
185
|
+
parser: () => 'sys_created_on>javascript:gs.daysAgo(7)'
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
regex: /\b(created|opened|updated|modified|closed)\s+before\s+([a-zA-Z]+\s+\d{1,2}(?:,?\s+\d{4})?)\b/i,
|
|
189
|
+
priority: 11,
|
|
190
|
+
parser: (match) => {
|
|
191
|
+
const field = match[1].toLowerCase() === 'opened' ? 'sys_created_on' : `${match[1].toLowerCase()}_on`;
|
|
192
|
+
// Simple date parsing - could be enhanced
|
|
193
|
+
return `${field}<${match[2]}`;
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
regex: /\b(created|opened|updated|modified|closed)\s+after\s+([a-zA-Z]+\s+\d{1,2}(?:,?\s+\d{4})?)\b/i,
|
|
198
|
+
priority: 11,
|
|
199
|
+
parser: (match) => {
|
|
200
|
+
const field = match[1].toLowerCase() === 'opened' ? 'sys_created_on' : `${match[1].toLowerCase()}_on`;
|
|
201
|
+
return `${field}>${match[2]}`;
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
|
|
205
|
+
// State patterns (table-dependent)
|
|
206
|
+
{
|
|
207
|
+
regex: /\b(new|open|active|in\s+progress|on\s+hold|resolved|closed|canceled)\b/i,
|
|
208
|
+
priority: 7,
|
|
209
|
+
parser: (match, table) => {
|
|
210
|
+
const state = match[1].toLowerCase().trim();
|
|
211
|
+
const mapping = STATE_MAPPINGS[table] || STATE_MAPPINGS.incident;
|
|
212
|
+
return mapping[state] || `state=${state}`;
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
|
|
216
|
+
// Content search patterns
|
|
217
|
+
{
|
|
218
|
+
regex: /\b(?:about|containing|with|includes?)\s+["']?([a-zA-Z0-9\s]+?)["']?(?:\s+(?:and|or|in|with|created|opened|assigned)|\s*$)/i,
|
|
219
|
+
priority: 5,
|
|
220
|
+
parser: (match) => {
|
|
221
|
+
const searchTerm = match[1].trim();
|
|
222
|
+
return `short_descriptionLIKE${searchTerm}^ORdescriptionLIKE${searchTerm}`;
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
regex: /\bdescription\s+(?:contains|includes)\s+["']?([^"']+?)["']?(?:\s+(?:and|or)|\s*$)/i,
|
|
227
|
+
priority: 6,
|
|
228
|
+
parser: (match) => {
|
|
229
|
+
const searchTerm = match[1].trim();
|
|
230
|
+
return `descriptionLIKE${searchTerm}`;
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
|
|
234
|
+
// Number patterns
|
|
235
|
+
{
|
|
236
|
+
regex: /\bnumber\s+(?:is|=|equals?)\s+([A-Z]{3}\d{7})\b/i,
|
|
237
|
+
priority: 20,
|
|
238
|
+
parser: (match) => `number=${match[1]}`
|
|
239
|
+
},
|
|
240
|
+
|
|
241
|
+
// Caller patterns
|
|
242
|
+
{
|
|
243
|
+
regex: /\bcaller\s+(?:is|=)\s+([a-zA-Z\s]+?)(?:\s+(?:and|or|with)|\s*$)/i,
|
|
244
|
+
priority: 10,
|
|
245
|
+
parser: (match) => {
|
|
246
|
+
const callerName = match[1].trim();
|
|
247
|
+
return `caller_id.nameLIKE${callerName}`;
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
|
|
251
|
+
// Category patterns
|
|
252
|
+
{
|
|
253
|
+
regex: /\bcategory\s+(?:is|=)\s+([a-zA-Z\s]+?)(?:\s+(?:and|or|with)|\s*$)/i,
|
|
254
|
+
priority: 10,
|
|
255
|
+
parser: (match) => {
|
|
256
|
+
const category = match[1].trim();
|
|
257
|
+
return `categoryLIKE${category}`;
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
|
|
261
|
+
// Assignment group patterns
|
|
262
|
+
{
|
|
263
|
+
regex: /\bassignment\s+group\s+(?:is|=)\s+([a-zA-Z\s]+?)(?:\s+(?:and|or|with)|\s*$)/i,
|
|
264
|
+
priority: 10,
|
|
265
|
+
parser: (match) => {
|
|
266
|
+
const group = match[1].trim();
|
|
267
|
+
return `assignment_group.nameLIKE${group}`;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
];
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Parse natural language query into ServiceNow encoded query
|
|
274
|
+
*
|
|
275
|
+
* @param {string} query - Natural language query
|
|
276
|
+
* @param {string} table - Target ServiceNow table (default: 'incident')
|
|
277
|
+
* @returns {object} - { encodedQuery, matchedPatterns, unmatchedText, suggestions }
|
|
278
|
+
*/
|
|
279
|
+
export function parseNaturalLanguage(query, table = 'incident') {
|
|
280
|
+
if (!query || typeof query !== 'string') {
|
|
281
|
+
return {
|
|
282
|
+
encodedQuery: '',
|
|
283
|
+
matchedPatterns: [],
|
|
284
|
+
unmatchedText: query,
|
|
285
|
+
suggestions: ['Please provide a valid query string']
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const originalQuery = query;
|
|
290
|
+
let remainingQuery = query;
|
|
291
|
+
const conditions = [];
|
|
292
|
+
const matchedPatterns = [];
|
|
293
|
+
const suggestions = [];
|
|
294
|
+
|
|
295
|
+
// Sort patterns by priority (highest first)
|
|
296
|
+
const sortedPatterns = [...PATTERNS].sort((a, b) => b.priority - a.priority);
|
|
297
|
+
|
|
298
|
+
// Process each pattern
|
|
299
|
+
for (const pattern of sortedPatterns) {
|
|
300
|
+
const match = remainingQuery.match(pattern.regex);
|
|
301
|
+
if (match) {
|
|
302
|
+
try {
|
|
303
|
+
const condition = pattern.parser(match, table);
|
|
304
|
+
conditions.push(condition);
|
|
305
|
+
matchedPatterns.push({
|
|
306
|
+
pattern: pattern.regex.toString(),
|
|
307
|
+
matched: match[0],
|
|
308
|
+
condition
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
// Remove matched text from remaining query
|
|
312
|
+
remainingQuery = remainingQuery.replace(match[0], ' ').trim();
|
|
313
|
+
} catch (error) {
|
|
314
|
+
console.error(`Pattern parsing error:`, error);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Check for logical operators in remaining text
|
|
320
|
+
const hasAnd = /\band\b/i.test(remainingQuery);
|
|
321
|
+
const hasOr = /\bor\b/i.test(remainingQuery);
|
|
322
|
+
|
|
323
|
+
// Build encoded query
|
|
324
|
+
let encodedQuery = '';
|
|
325
|
+
if (conditions.length > 0) {
|
|
326
|
+
// Use OR if query contains "or", otherwise use AND (default)
|
|
327
|
+
const operator = hasOr ? '^OR' : '^';
|
|
328
|
+
encodedQuery = conditions.join(operator);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Clean up remaining query
|
|
332
|
+
remainingQuery = remainingQuery
|
|
333
|
+
.replace(/\b(and|or|with|in|the|a|an)\b/gi, ' ')
|
|
334
|
+
.replace(/\s+/g, ' ')
|
|
335
|
+
.trim();
|
|
336
|
+
|
|
337
|
+
// Generate suggestions for unmatched text
|
|
338
|
+
if (remainingQuery.length > 3) {
|
|
339
|
+
suggestions.push(`Unrecognized: "${remainingQuery}"`);
|
|
340
|
+
suggestions.push('Try using encoded query format: field=value^field2=value2');
|
|
341
|
+
suggestions.push('Supported patterns: priority (P1-P5), state (new/open/closed), assigned to me/unassigned, recent, dates');
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// If no patterns matched, return original query (might be encoded query already)
|
|
345
|
+
if (conditions.length === 0) {
|
|
346
|
+
// Check if it looks like an encoded query already
|
|
347
|
+
if (/[=^]/.test(originalQuery)) {
|
|
348
|
+
return {
|
|
349
|
+
encodedQuery: originalQuery,
|
|
350
|
+
matchedPatterns: [],
|
|
351
|
+
unmatchedText: '',
|
|
352
|
+
suggestions: ['Using query as-is (appears to be encoded query format)']
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
return {
|
|
357
|
+
encodedQuery: '',
|
|
358
|
+
matchedPatterns: [],
|
|
359
|
+
unmatchedText: originalQuery,
|
|
360
|
+
suggestions: [
|
|
361
|
+
'No patterns matched. Supported patterns:',
|
|
362
|
+
'- Priority: "high priority", "P1", "priority 2"',
|
|
363
|
+
'- Assignment: "assigned to me", "unassigned", "assigned to John"',
|
|
364
|
+
'- State: "new", "open", "closed", "in progress"',
|
|
365
|
+
'- Dates: "created today", "last 7 days", "recent"',
|
|
366
|
+
'- Content: "about SAP", "containing error"',
|
|
367
|
+
'Or use ServiceNow encoded query format: field=value^field2=value2'
|
|
368
|
+
]
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
return {
|
|
373
|
+
encodedQuery,
|
|
374
|
+
matchedPatterns,
|
|
375
|
+
unmatchedText: remainingQuery,
|
|
376
|
+
suggestions: suggestions.length > 0 ? suggestions : ['Query parsed successfully']
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Test the natural language parser with example queries
|
|
382
|
+
*
|
|
383
|
+
* @param {string} table - Table name to test against
|
|
384
|
+
* @returns {Array} - Array of test results
|
|
385
|
+
*/
|
|
386
|
+
export function testParser(table = 'incident') {
|
|
387
|
+
const testQueries = [
|
|
388
|
+
'find all P1 incidents',
|
|
389
|
+
'show recent problems assigned to me',
|
|
390
|
+
'high priority changes created last week',
|
|
391
|
+
'open incidents about SAP',
|
|
392
|
+
'unassigned P2 incidents',
|
|
393
|
+
'incidents created today with high priority',
|
|
394
|
+
'closed problems assigned to John Smith',
|
|
395
|
+
'critical incidents opened in the last 30 days',
|
|
396
|
+
'show me my active tickets',
|
|
397
|
+
'new incidents with high impact and high urgency',
|
|
398
|
+
'incidents containing database error',
|
|
399
|
+
'P1 incidents assigned to Network Team',
|
|
400
|
+
'incidents created after January 1',
|
|
401
|
+
'resolved incidents about authentication'
|
|
402
|
+
];
|
|
403
|
+
|
|
404
|
+
return testQueries.map(query => ({
|
|
405
|
+
query,
|
|
406
|
+
result: parseNaturalLanguage(query, table)
|
|
407
|
+
}));
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Get supported patterns documentation
|
|
412
|
+
*
|
|
413
|
+
* @returns {object} - Documentation of supported patterns
|
|
414
|
+
*/
|
|
415
|
+
export function getSupportedPatterns() {
|
|
416
|
+
return {
|
|
417
|
+
priority: {
|
|
418
|
+
examples: ['high priority', 'P1', 'priority 2', 'critical priority'],
|
|
419
|
+
encodedQuery: 'priority=1'
|
|
420
|
+
},
|
|
421
|
+
assignment: {
|
|
422
|
+
examples: ['assigned to me', 'unassigned', 'assigned to John Smith', 'my incidents'],
|
|
423
|
+
encodedQuery: 'assigned_to=javascript:gs.getUserID() or assigned_toISEMPTY'
|
|
424
|
+
},
|
|
425
|
+
state: {
|
|
426
|
+
examples: ['new', 'open', 'active', 'in progress', 'closed', 'resolved'],
|
|
427
|
+
encodedQuery: 'state=1 (varies by table)'
|
|
428
|
+
},
|
|
429
|
+
dates: {
|
|
430
|
+
examples: ['created today', 'last 7 days', 'recent', 'opened yesterday', 'updated last week'],
|
|
431
|
+
encodedQuery: 'sys_created_on>javascript:gs.daysAgo(7)'
|
|
432
|
+
},
|
|
433
|
+
content: {
|
|
434
|
+
examples: ['about SAP', 'containing error', 'description contains authentication'],
|
|
435
|
+
encodedQuery: 'short_descriptionLIKESAP'
|
|
436
|
+
},
|
|
437
|
+
impact: {
|
|
438
|
+
examples: ['high impact', 'medium impact', 'low impact'],
|
|
439
|
+
encodedQuery: 'impact=1'
|
|
440
|
+
},
|
|
441
|
+
urgency: {
|
|
442
|
+
examples: ['high urgency', 'medium urgency', 'low urgency'],
|
|
443
|
+
encodedQuery: 'urgency=1'
|
|
444
|
+
},
|
|
445
|
+
number: {
|
|
446
|
+
examples: ['number is INC0012345'],
|
|
447
|
+
encodedQuery: 'number=INC0012345'
|
|
448
|
+
},
|
|
449
|
+
caller: {
|
|
450
|
+
examples: ['caller is John Smith'],
|
|
451
|
+
encodedQuery: 'caller_id.nameLIKEJohn Smith'
|
|
452
|
+
},
|
|
453
|
+
category: {
|
|
454
|
+
examples: ['category is Software'],
|
|
455
|
+
encodedQuery: 'categoryLIKESoftware'
|
|
456
|
+
},
|
|
457
|
+
assignmentGroup: {
|
|
458
|
+
examples: ['assignment group is Network Team'],
|
|
459
|
+
encodedQuery: 'assignment_group.nameLIKENetwork Team'
|
|
460
|
+
},
|
|
461
|
+
combining: {
|
|
462
|
+
examples: ['high priority and assigned to me', 'P1 or P2 incidents', 'recent and unassigned'],
|
|
463
|
+
encodedQuery: 'Use "and" for ^ operator, "or" for ^OR operator'
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
export default {
|
|
469
|
+
parseNaturalLanguage,
|
|
470
|
+
testParser,
|
|
471
|
+
getSupportedPatterns
|
|
472
|
+
};
|