@simonecoelhosfo/optimizely-mcp-server
Version:
Optimizely MCP Server for AI assistants with integrated CLI tools
403 lines • 19.7 kB
JavaScript
/**
* Modification-Aware Error Enhancement System
* @description Specialized error enhancement for entity modification workflows
*
* Addresses critical gap: Current system only handles entity creation errors.
* This enhancer specifically handles modification operations like:
* - Adding variations to existing flags
* - Updating rulesets and rules
* - Modifying traffic allocations
* - Complex entity update workflows
*
* @author Optimizely MCP Server
* @version 1.0.0
*/
import { AutomatedPrescriptiveErrorEnhancer } from './AutomatedPrescriptiveErrorEnhancer.js';
import { getLogger } from '../logging/Logger.js';
/**
* Specialized error enhancer for modification workflows
*/
export class ModificationAwareErrorEnhancer extends AutomatedPrescriptiveErrorEnhancer {
constructor() {
super();
// Add modification-specific patterns to the beginning of the pattern list
// This ensures they're checked before generic patterns
this.addModificationPatterns();
}
/**
* Enhanced error processing with modification workflow detection
*/
enhanceError(originalError, context = {}) {
getLogger().debug({
originalError,
context,
isModification: context.isModificationWorkflow
}, 'ModificationAwareErrorEnhancer: Processing error');
// Check if this is a modification workflow error first
if (this.isModificationError(originalError, context)) {
context.isModificationWorkflow = true;
// Try modification-specific patterns
const modificationResponse = this.processModificationError(originalError, context);
if (modificationResponse) {
return modificationResponse;
}
}
// Fall back to base class for standard patterns
return super.enhanceError(originalError, context);
}
/**
* Add modification-specific error patterns
*/
addModificationPatterns() {
// Access the protected patterns array via reflection
const patterns = this.patterns;
// Insert modification patterns at the beginning
const modificationPatterns = [
{
name: 'RulesetUpdateFailure',
detect: (error, context) => this.detectRulesetError(error, context),
enhance: (error, context) => this.enhanceRulesetError(error, context)
},
{
name: 'VariationAdditionWorkflow',
detect: (error, context) => this.detectVariationWorkflowError(error, context),
enhance: (error, context) => this.enhanceVariationWorkflowError(error, context)
},
{
name: 'EntityModificationConfusion',
detect: (error, context) => this.detectModificationConfusion(error, context),
enhance: (error, context) => this.enhanceModificationGuidance(error, context)
},
{
name: 'TrafficAllocationError',
detect: (error, context) => this.detectTrafficError(error, context),
enhance: (error, context) => this.enhanceTrafficError(error, context)
}
];
// Insert at the beginning of patterns array
patterns.unshift(...modificationPatterns);
}
/**
* Detect if this is a modification workflow error
*/
isModificationError(error, context) {
// Operation-based detection
if (context.operation === 'update' || context.operation === 'delete') {
return true;
}
// Entity-specific modification indicators
const modificationIndicators = [
'ruleset', 'rule', 'variation', 'traffic', 'allocation',
'HTTP 400', 'HTTP 405', 'HTTP 409', 'Method Not Allowed',
'already exists', 'cannot be modified', 'invalid state'
];
return modificationIndicators.some(indicator => error.toLowerCase().includes(indicator.toLowerCase()));
}
/**
* Process modification-specific errors
*/
processModificationError(error, context) {
// Detect workflow context if not provided
if (!context.workflowContext) {
context.workflowContext = this.detectWorkflowContext(error, context);
}
// Check each modification pattern explicitly
if (this.detectRulesetError(error, context)) {
return this.enhanceRulesetError(error, context);
}
if (this.detectVariationWorkflowError(error, context)) {
return this.enhanceVariationWorkflowError(error, context);
}
if (this.detectModificationConfusion(error, context)) {
return this.enhanceModificationGuidance(error, context);
}
if (this.detectTrafficError(error, context)) {
return this.enhanceTrafficError(error, context);
}
return null;
}
/**
* Detect workflow context from error patterns
*/
detectWorkflowContext(error, context) {
// Pattern: Variation creation followed by ruleset errors
if (context.entityType === 'variation' || error.includes('variation')) {
return {
detectedWorkflow: 'add_variation_to_existing_flag',
relatedEntities: ['flag', 'variation', 'ruleset'],
modificationTarget: 'variation_addition'
};
}
// Pattern: Ruleset/rule update errors
if (context.entityType === 'ruleset' || context.entityType === 'rule') {
return {
detectedWorkflow: 'update_targeting_rules',
relatedEntities: ['flag', 'ruleset', 'rule'],
modificationTarget: 'traffic_allocation'
};
}
// Pattern: Traffic allocation errors
if (error.includes('traffic') || error.includes('allocation')) {
return {
detectedWorkflow: 'redistribute_traffic',
relatedEntities: ['ruleset', 'variation'],
modificationTarget: 'traffic_distribution'
};
}
return {
detectedWorkflow: 'generic_modification',
relatedEntities: [context.entityType || 'unknown'],
modificationTarget: 'unknown'
};
}
// Pattern Detection Methods
detectRulesetError(error, context) {
const rulesetIndicators = [
// Direct ruleset/rule mentions
context.entityType === 'ruleset' || context.entityType === 'rule',
error.toLowerCase().includes('ruleset'),
error.toLowerCase().includes('rule'),
// REMOVED: Overly broad HTTP error detection that was catching ALL update errors
// Only check for ruleset-specific API patterns
error.includes('/rulesets') || error.includes('/rules'),
error.includes('/environments/') && error.includes('/ruleset'),
// More specific targeting errors that mention rules
error.includes('targeting') && (error.includes('rule') || error.includes('ruleset')),
error.includes('allocation') && (error.includes('rule') || error.includes('variation'))
];
return rulesetIndicators.some(indicator => indicator);
}
detectVariationWorkflowError(error, context) {
const variationIndicators = [
// Creating variation on existing flag - key indicator is flag_key in metadata/options
context.operation === 'create' && context.entityType === 'variation' &&
(context.metadata?.flag_key || context.metadata?.existing_flag),
// Creating variation with flag context (most common pattern)
context.operation === 'create' && context.entityType === 'variation' &&
context.metadata && Object.keys(context.metadata).some(key => key.includes('flag') || key.includes('environment')),
// Errors mentioning variations in context of existing entities
error.includes('variation') && (error.includes('already') || error.includes('existing')),
// Traffic allocation errors during variation operations
error.includes('variation') && error.includes('traffic'),
// API errors when trying to create variations on existing flags
error.includes('variations') && (error.includes('400') || error.includes('Bad Request')),
// Workflow sequence indicators
context.workflowContext?.detectedWorkflow === 'add_variation_to_existing_flag'
];
return variationIndicators.some(indicator => indicator);
}
detectModificationConfusion(error, context) {
// CRITICAL: Don't enhance already well-formatted error messages
// Check if error message is already properly structured with REASON and SUGGESTED ACTIONS
if (error.includes('REASON:') && error.includes('SUGGESTED ACTIONS:')) {
getLogger().info({
errorPattern: 'Well-formatted error detected',
entityType: context.entityType,
operation: context.operation
}, 'ModificationAwareErrorEnhancer: Skipping enhancement for well-formatted error');
return false;
}
const confusionIndicators = [
// Update operations that are failing due to workflow misunderstanding
context.operation === 'update' && (error.includes('not found') ||
error.includes('invalid') ||
error.includes('cannot')),
// Complex entity modifications without proper workflow
this.isComplexModificationWorkflow(context),
// Multiple entity references in error (indicates complex workflow)
this.countEntityMentions(error) > 1
];
return confusionIndicators.some(indicator => indicator);
}
detectTrafficError(error, context) {
const trafficIndicators = [
error.includes('traffic'),
error.includes('allocation'),
error.includes('percentage'),
error.includes('basis points'),
error.includes('weight'),
error.includes('100%') || error.includes('10000'),
error.includes('sum') && error.includes('allocation')
];
return trafficIndicators.some(indicator => indicator);
}
// Enhancement Methods
enhanceRulesetError(error, context) {
return {
status: 'WORKFLOW_GUIDANCE_REQUIRED',
error: {
code: 'RULESET_MODIFICATION_ERROR',
message: 'Ruleset/rule operations require understanding of targeting hierarchy and proper workflow'
},
required_action: {
tool: 'get_entity_templates',
parameters: {
entity_type: 'ruleset_concepts',
project_id: context.projectId,
flag_key: context.metadata?.flag_key,
environment_key: context.metadata?.environment_key
}
},
immediate_guidance: {
critical_rule: 'ANY error with rules/rulesets MUST use get_entity_templates for workflow guidance',
why_templates_required: 'Rules and rulesets have complex hierarchy and API patterns that require step-by-step guidance',
next_step: 'Call get_entity_templates(entity_type="ruleset_concepts") immediately'
},
workflow_hints: [
'Rulesets contain rules - update the ruleset, not individual rules',
'Each flag+environment has exactly one ruleset',
'Use PATCH method for ruleset updates, not POST or PUT',
'Always provide flag_key and environment_key for ruleset operations'
],
api_guidance: {
correct_pattern: 'GET ruleset → modify rules array → PATCH entire ruleset',
common_mistakes: [
'Trying to POST individual rules',
'Using wrong HTTP method',
'Missing flag_key or environment_key context',
'Modifying rules without updating parent ruleset'
]
},
documentation_link: 'Call get_entity_templates(entity_type="ruleset_concepts") for complete guidance'
};
}
enhanceVariationWorkflowError(error, context) {
return {
status: 'WORKFLOW_GUIDANCE_REQUIRED',
error: {
code: 'VARIATION_ADDITION_WORKFLOW_ERROR',
message: 'Adding variation to existing A/B test requires specific multi-step workflow'
},
required_action: {
tool: 'get_entity_templates',
parameters: {
entity_type: 'flag_variation_addition',
project_id: context.projectId,
flag_key: context.metadata?.flag_key || context.metadata?.existing_flag
}
},
immediate_guidance: {
critical_rule: 'Adding variations requires BOTH variation creation AND ruleset updates',
why_templates_required: 'Variation addition involves coordination between multiple entities with specific sequencing',
next_step: 'Call get_entity_templates(entity_type="flag_variation_addition") for complete workflow'
},
workflow_explanation: {
title: 'Adding Variation to Existing A/B Test',
required_steps: [
'1. Create the new variation definition',
'2. Update the ruleset to include new variation',
'3. Redistribute traffic allocation across all variations',
'4. Validate total allocation equals 100%'
],
critical_concepts: {
'variations_vs_rulesets': 'Variations define options; rulesets control traffic allocation',
'sequencing': 'Create variation first, then update ruleset - never the reverse',
'traffic_math': 'Total allocation must equal 10000 basis points (100%)'
}
},
common_errors: {
'variation_without_ruleset': 'Created variation but forgot to update ruleset',
'wrong_sequence': 'Tried to update ruleset before creating variation',
'traffic_mismatch': 'Traffic allocation doesn\'t sum to 100%'
},
documentation_link: 'Call get_entity_templates(entity_type="flag_variation_addition") for step-by-step guide'
};
}
enhanceModificationGuidance(error, context) {
const workflowType = context.workflowContext?.detectedWorkflow || 'entity_modification';
return {
status: 'WORKFLOW_GUIDANCE_REQUIRED',
error: {
code: 'COMPLEX_MODIFICATION_WORKFLOW',
message: `Complex entity modification workflow detected - requires guided approach`
},
required_action: {
tool: 'get_entity_templates',
parameters: {
entity_type: workflowType,
project_id: context.projectId
}
},
immediate_guidance: {
critical_rule: 'Complex entity modifications require workflow templates for success',
detected_workflow: workflowType,
next_step: `Call get_entity_templates(entity_type="${workflowType}") for guidance`
},
modification_context: {
target_entity: context.entityType || 'unknown',
modification_type: context.modificationDetails?.modificationTarget || 'unknown',
related_entities: context.workflowContext?.relatedEntities || [],
complexity_reason: 'Multi-entity workflow with dependencies and sequencing requirements'
},
workflow_hints: [
'Entity modifications often require updating multiple related entities',
'Order of operations matters for complex modifications',
'Use templates to understand complete workflow before starting',
'Template mode can handle complex modifications automatically'
],
documentation_link: `Call get_entity_templates(entity_type="${workflowType}") for workflow guidance`
};
}
enhanceTrafficError(error, context) {
return {
status: 'WORKFLOW_GUIDANCE_REQUIRED',
error: {
code: 'TRAFFIC_ALLOCATION_ERROR',
message: 'Traffic allocation errors require understanding of distribution rules and calculations'
},
required_action: {
tool: 'get_entity_templates',
parameters: {
entity_type: 'traffic_allocation_concepts',
project_id: context.projectId
}
},
immediate_guidance: {
critical_rule: 'Traffic allocation must always sum to exactly 100% (10000 basis points)',
common_mistake: 'Modifying one variation without adjusting others',
next_step: 'Call get_entity_templates(entity_type="traffic_allocation_concepts") for calculation guide'
},
traffic_rules: {
basis_points: '10000 basis points = 100% traffic',
equal_split_2: '5000, 5000 (50%, 50%)',
equal_split_3: '3333, 3333, 3334 (33.33%, 33.33%, 33.34%)',
validation: 'Sum must equal exactly 10000 - no more, no less'
},
calculation_help: [
'For N equal variations: Math.floor(10000/N) for N-1 variations, remainder for last',
'For custom splits: Convert percentages to basis points (multiply by 100)',
'Always validate sum equals 10000 before submitting',
'Remainder goes to last variation to handle rounding'
],
documentation_link: 'Call get_entity_templates(entity_type="traffic_allocation_concepts") for examples'
};
}
// Helper Methods
isComplexModificationWorkflow(context) {
const complexIndicators = [
// Multiple entities involved
context.workflowContext?.relatedEntities?.length && context.workflowContext.relatedEntities.length > 1,
// Known complex modification types
['variation', 'ruleset', 'rule', 'campaign'].includes(context.entityType || ''),
// Modification involves dependencies
context.modificationDetails?.existingState !== undefined,
// Known complex workflow patterns
['add_variation_to_existing_flag', 'update_targeting_rules', 'redistribute_traffic'].includes(context.workflowContext?.detectedWorkflow || '')
];
return complexIndicators.some(indicator => indicator);
}
countEntityMentions(error) {
const entityTypes = [
'flag', 'variation', 'ruleset', 'rule', 'experiment', 'campaign',
'page', 'event', 'metric', 'audience', 'attribute'
];
return entityTypes.reduce((count, entity) => {
return count + (error.toLowerCase().includes(entity) ? 1 : 0);
}, 0);
}
}
/**
* Singleton instance for global use
*/
export const modificationAwareErrorEnhancer = new ModificationAwareErrorEnhancer();
//# sourceMappingURL=ModificationAwareErrorEnhancer.js.map