@simonecoelhosfo/optimizely-mcp-server
Version:
Optimizely MCP Server for AI assistants with integrated CLI tools
630 lines • 18.6 kB
JavaScript
/**
* Field Pattern Definitions for RobustIntentParser
*
* IMPLEMENTATION STATUS:
* COMPLETE: Common fields and entity-specific fields (50+ fields)
*
* Last Updated: July 3, 2025
*/
export const FIELD_PATTERNS = {
// Common fields across entities
id: {
canonical: 'id',
patterns: [
/\bid\b/i,
/identifier/i,
/unique\s+id/i
],
dataType: 'string'
},
key: {
canonical: 'key',
patterns: [
/\bkey\b/i,
/unique\s+key/i,
/identifier/i,
/slug/i
],
dataType: 'string'
},
name: {
canonical: 'name',
patterns: [
/\bname\b/i,
/title/i,
/label/i,
/display\s+name/i
],
dataType: 'string'
},
description: {
canonical: 'description',
patterns: [
/description/i,
/desc/i,
/details?/i,
/about/i,
/summary/i
],
dataType: 'string'
},
status: {
canonical: 'status',
patterns: [
/status/i,
/state/i,
/condition/i,
/active|inactive/i,
// REMOVED: /enabled|disabled/i - conflicts with specific enabled field
/disabled/i // Keep disabled but not enabled
],
dataType: 'string'
},
created_time: {
canonical: 'created_time',
patterns: [
/created(?:\s+time)?/i,
/creation(?:\s+date)?/i,
/created\s+at/i,
/date\s+created/i,
/when\s+created/i
],
dataType: 'date'
},
updated_time: {
canonical: 'updated_time',
patterns: [
/updated(?:\s+time)?/i,
/modified(?:\s+time)?/i,
/last\s+updated/i,
/updated\s+at/i,
/last\s+modified/i
],
dataType: 'date'
},
archived: {
canonical: 'archived',
patterns: [
/archived/i,
/deleted/i,
/removed/i,
/inactive/i,
/deactivated/i
],
dataType: 'boolean'
},
// Flag-specific fields
enabled: {
canonical: 'enabled',
patterns: [
/enabled/i,
/active/i,
/\bon\b/i,
/turned\s+on/i,
/activated/i
],
entity: 'flags',
jsonPath: 'environments.*.enabled',
dataType: 'boolean'
},
environment: {
canonical: 'environment_key',
patterns: [
/environment/i,
/env/i,
/stage/i,
/production|prod/i,
/development|dev/i,
/staging/i
],
entity: 'flags',
dataType: 'string'
},
percentage: {
canonical: 'percentage_included',
patterns: [
/percentage/i,
/percent/i,
/traffic(?:\s+allocation)?/i,
/rollout(?:\s+percentage)?/i,
/allocation/i,
/%/
],
entity: 'rules',
dataType: 'number'
},
// Experiment-specific fields
traffic_allocation: {
canonical: 'traffic_allocation',
patterns: [
/traffic\s+allocation/i,
/traffic\s+split/i,
/allocation/i,
/distribution/i
],
entity: 'experiments',
jsonPath: 'data_json.traffic_allocation',
dataType: 'json'
},
variations_count: {
canonical: 'variations_count',
patterns: [
/variations?\s+count/i,
/number\s+of\s+variations?/i,
/how\s+many\s+variations?/i,
/variant\s+count/i
],
entity: 'experiments',
dataType: 'number'
},
metrics: {
canonical: 'metrics',
patterns: [
/metrics?/i,
/goals?/i,
/conversions?/i,
/kpis?/i,
/measures?/i
],
entity: 'experiments',
jsonPath: 'data_json.metrics',
dataType: 'json'
},
// 🚨 PERFORMANCE METRICS - From experiment_results table
visitors: {
canonical: 'visitors',
patterns: [
/visitors?/i,
/users?/i,
/customers?/i,
/people/i,
/traffic/i,
/unique\s+visitors?/i,
/total\s+users?/i,
/site\s+visitors?/i,
/page\s+views?/i,
/sessions?/i
],
entity: 'experiment_results',
dataType: 'number'
},
conversion_rate: {
canonical: 'conversion_rate',
patterns: [
/conversion\s+rates?/i,
/cvr/i,
/conversion\s+%/i,
/conversion\s+percentage/i,
/success\s+rates?/i,
/conversion\s+ratio/i,
/goal\s+completion\s+rate/i,
/conversion\s+performance/i
],
entity: 'experiment_results',
dataType: 'number'
},
confidence: {
canonical: 'confidence',
patterns: [
/confidence/i,
/confidence\s+level/i,
/confidence\s+threshold/i,
/certainty/i,
/confidence\s+interval/i,
/confidence\s+score/i,
/statistical\s+confidence/i
],
entity: 'experiment_results',
dataType: 'number'
},
statistical_significance: {
canonical: 'statistical_significance',
patterns: [
/statistical\s+significance/i,
/stat\s+sig/i,
/significance/i,
/p[\s-]?value/i,
/significant/i,
/statistically\s+significant/i,
/sig\s+level/i
],
entity: 'experiment_results',
dataType: 'number'
},
lift: {
canonical: 'lift',
patterns: [
/lift/i,
/uplift/i,
/improvement/i,
/increase/i,
/gain/i,
/boost/i,
/performance\s+lift/i,
/relative\s+improvement/i,
/percentage\s+change/i
],
entity: 'experiment_results',
dataType: 'number'
},
conversions: {
canonical: 'conversions',
patterns: [
/conversions?/i,
/total\s+conversions?/i,
/conversion\s+count/i,
/goals?\s+achieved/i,
/successful\s+conversions?/i,
/completed\s+goals?/i
],
entity: 'experiment_results',
dataType: 'number'
},
unique_conversions: {
canonical: 'unique_conversions',
patterns: [
/unique\s+conversions?/i,
/unique\s+conversion\s+count/i,
/distinct\s+conversions?/i,
/unique\s+visitors?\s+converted/i,
/unique\s+users?\s+converted/i
],
entity: 'experiment_results',
dataType: 'number'
},
baseline_visitors: {
canonical: 'baseline_visitors',
patterns: [
/baseline\s+visitors?/i,
/control\s+visitors?/i,
/baseline\s+count/i,
/control\s+group\s+size/i,
/baseline\s+users?/i,
/original\s+visitors?/i
],
entity: 'experiment_results',
dataType: 'number'
},
treatment_visitors: {
canonical: 'treatment_visitors',
patterns: [
/treatment\s+visitors?/i,
/variation\s+visitors?/i,
/treatment\s+count/i,
/variant\s+users?/i,
/test\s+group\s+size/i,
/challenger\s+visitors?/i
],
entity: 'experiment_results',
dataType: 'number'
},
winner: {
canonical: 'winner',
patterns: [
/winner/i,
/winning\s+variation/i,
/best\s+performing/i,
/top\s+performer/i,
/winning\s+variant/i,
/champion/i
],
entity: 'experiment_results',
dataType: 'string'
},
error_rate: {
canonical: 'error_rate',
patterns: [
/error\s+rates?/i,
/javascript\s+errors?/i,
/js\s+errors?/i,
/page\s+errors?/i,
/error\s+percentage/i,
/failure\s+rates?/i
],
entity: 'experiment_results',
dataType: 'number'
},
// Conditions field (used by pages ONLY - URL targeting conditions)
conditions: {
canonical: 'conditions',
patterns: [
/url\s+conditions?/i,
/page\s+conditions?/i,
/url\s+targeting/i,
/page\s+targeting/i
],
entity: 'pages', // CONSTRAINT TO PAGES ONLY
dataType: 'json'
},
// Audience conditions field (used by rules and audiences)
audience_conditions: {
canonical: 'audience_conditions',
patterns: [
/audience\s+conditions?/i,
/audience\s+targeting/i,
/targeting/i, // MOVED HERE - targeting refers to audience targeting
/qualifications?/i,
/targeting\s+rules?/i,
/targeting\s+conditions?/i,
/who\s+qualifies/i,
/visitor\s+targeting/i
],
entity: 'rules', // CONSTRAINT TO RULES (primary usage in L3-1)
dataType: 'json'
},
// Additional audience conditions pattern for audiences table
conditions_audience: {
canonical: 'conditions',
patterns: [
/audience\s+conditions?/i,
/audience\s+targeting/i,
/who\s+qualifies/i,
/qualification\s+rules?/i
],
entity: 'audiences',
dataType: 'json'
},
// Variation-specific fields
weight: {
canonical: 'weight',
patterns: [
/weight/i,
/allocation/i,
/percentage/i,
/distribution/i
],
entity: 'variations',
dataType: 'number'
},
is_control: {
canonical: 'is_control',
patterns: [
/control/i,
/baseline/i,
/original/i,
/default/i
],
entity: 'variations',
dataType: 'boolean'
},
// Event-specific fields
event_type: {
canonical: 'event_type',
patterns: [
/event\s+type/i,
/type\s+of\s+event/i,
/click|page\s+view|custom/i,
/category/i
],
entity: 'events',
dataType: 'string'
},
selector: {
canonical: 'selector',
patterns: [
/selector/i,
/css\s+selector/i,
/element/i,
/target/i
],
entity: 'events',
dataType: 'string'
},
// Project-specific fields
platform: {
canonical: 'platform',
patterns: [
/platform/i,
/type/i,
/web|feature/i,
/experimentation\s+type/i
],
entity: 'projects',
dataType: 'string'
},
account_id: {
canonical: 'account_id',
patterns: [
/account(?:\s+id)?/i,
/organization/i,
/org(?:\s+id)?/i
],
entity: 'projects',
dataType: 'string'
},
// Page-specific fields
activation_type: {
canonical: 'activation_type',
patterns: [
/activation(?:\s+type)?/i,
/activation\s+mode/i,
/trigger(?:\s+type)?/i,
/page\s+activation/i,
/immediate|manual|polling|callback|dom_changed|url_changed/i
],
entity: 'pages',
dataType: 'string'
},
'url_targeting_pages': {
canonical: 'conditions',
patterns: [
/url\s+targeting(?:\s+activation)?/i,
/url\s+trigger/i,
/targeting\s+activation/i,
/pages?\s+(?:that\s+)?use\s+url\s+targeting/i,
/url\s+based\s+targeting/i,
/url\s+conditions?/i
],
entity: 'pages',
dataType: 'json',
jsonPath: '$[*].type'
},
edit_url: {
canonical: 'edit_url',
patterns: [
/edit\s+url/i,
/page\s+url/i,
/target\s+url/i,
/url/i
],
entity: 'pages',
dataType: 'string'
},
category: {
canonical: 'category',
patterns: [
/category/i,
/page\s+category/i,
/type/i,
/kind/i
],
entity: 'pages',
dataType: 'string'
},
// Complex JSON path fields
'environments.production.enabled': {
canonical: 'environments.production.enabled',
patterns: [
/production\s+enabled/i,
/enabled\s+in\s+production/i,
/prod\s+status/i
],
entity: 'flags',
jsonPath: '$.environments.production.enabled',
dataType: 'boolean'
},
'rules[0].percentage': {
canonical: 'rules[0].percentage_included',
patterns: [
/first\s+rule(?:'s)?\s+percentage/i,
/rule\s+1\s+percentage/i,
/initial\s+rule\s+traffic/i
],
entity: 'flags',
jsonPath: '$.rules[0].percentage_included',
dataType: 'number'
}
};
/**
* Common English stop words to ignore when extracting fields
*/
const STOP_WORDS = new Set([
'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for',
'of', 'with', 'by', 'from', 'as', 'is', 'was', 'are', 'been',
'their', 'them', 'they', 'this', 'that', 'these', 'those',
'my', 'your', 'his', 'her', 'its', 'our', 'their',
'what', 'which', 'who', 'whom', 'whose', 'where', 'when', 'why', 'how',
'all', 'each', 'every', 'some', 'few', 'more', 'most', 'other',
'such', 'only', 'own', 'same', 'so', 'than', 'too', 'very',
'just', 'being'
]);
/**
* Find matching fields in a query
*/
export function findFields(query, primaryEntity) {
const matches = [];
let normalizedQuery = query.toLowerCase();
// CRITICAL FIX: Handle compound phrases that refer to specific fields
const compoundPhraseMap = {
'enabled status': 'enabled',
'activation status': 'enabled',
'active status': 'enabled',
'flag status': 'enabled', // In flag context, status usually means enabled/disabled
'environment status': 'enabled',
'rollout status': 'enabled',
'feature status': 'enabled'
};
// Track which parts of the query we've already matched
const matchedRanges = [];
// First, check for compound phrases
for (const [phrase, fieldName] of Object.entries(compoundPhraseMap)) {
const phraseRegex = new RegExp(`\\b${phrase}\\b`, 'i');
const phraseMatch = normalizedQuery.match(phraseRegex);
if (phraseMatch && phraseMatch.index !== undefined) {
// Find the pattern for this field
const pattern = FIELD_PATTERNS[fieldName];
if (pattern) {
matches.push({
field: pattern.canonical,
confidence: 0.95, // High confidence for explicit compound phrases
match: phrase
});
// Track this range as matched
matchedRanges.push({
start: phraseMatch.index,
end: phraseMatch.index + phrase.length
});
}
}
}
for (const [fieldName, pattern] of Object.entries(FIELD_PATTERNS)) {
// Skip fields that are specific to other entities
if (pattern.entity && primaryEntity && pattern.entity !== primaryEntity) {
continue;
}
for (const regex of pattern.patterns) {
const match = normalizedQuery.match(regex);
if (match && match.index !== undefined) {
// CRITICAL: Skip if this match overlaps with a compound phrase we already handled
const matchStart = match.index;
const matchEnd = match.index + match[0].length;
let isOverlapping = false;
for (const range of matchedRanges) {
// Check if this match overlaps with any matched compound phrase
if ((matchStart >= range.start && matchStart < range.end) ||
(matchEnd > range.start && matchEnd <= range.end) ||
(matchStart <= range.start && matchEnd >= range.end)) {
isOverlapping = true;
break;
}
}
if (isOverlapping) {
continue;
}
// Check if the matched text is a stop word
const matchedText = match[0].trim();
const words = matchedText.split(/\s+/);
// Skip if ANY word in the match is a stop word (more aggressive filtering)
if (words.some(word => STOP_WORDS.has(word.toLowerCase()))) {
continue;
}
// Higher confidence if entity matches
const entityBonus = pattern.entity === primaryEntity ? 0.1 : 0;
const confidence = 0.8 + entityBonus;
matches.push({
field: pattern.canonical,
confidence,
match: match[0]
});
break; // Only match once per field
}
}
}
return matches.sort((a, b) => b.confidence - a.confidence);
}
/**
* Get canonical field name from various aliases
*/
export function getCanonicalFieldName(field, entity) {
const normalizedField = field.toLowerCase();
// Direct match on canonical names
for (const [_, pattern] of Object.entries(FIELD_PATTERNS)) {
if (pattern.canonical.toLowerCase() === normalizedField) {
return pattern.canonical;
}
}
// Pattern matching
for (const [_, pattern] of Object.entries(FIELD_PATTERNS)) {
if (pattern.entity && entity && pattern.entity !== entity) {
continue;
}
for (const regex of pattern.patterns) {
if (regex.test(normalizedField)) {
return pattern.canonical;
}
}
}
// Return as-is if no match
return field;
}
//# sourceMappingURL=FieldPatterns.js.map