/** * Classify Step — keyword-based classification using classification_rules table. * Config: { * rule_type: 'branch_routing' | 'ticket_type' | 'issue_classification' | 'priority' | 'queue_routing', * result_field: 'branch' | 'ticket_type' | 'issue_type' | 'priority' | 'queue_id', * result_field_2?: 'sub_issue_type', // for issue_classification only * default_value?: any // fallback if no rules match * } */ import { registerWorkflowStepExecutor } from '../ticket-workflow-engine'; import { roboticClassifier } from '../robotic-classifier'; import { TicketWorkflowStep, WorkflowStepContext, WorkflowStepResult } from '../../types/ticket-workflow'; async function executeClassify( step: TicketWorkflowStep, context: WorkflowStepContext, _executionId: number ): Promise { const ruleType = step.config.rule_type; const resultField = step.config.result_field; const resultField2 = step.config.result_field_2; const defaultValue = step.config.default_value; if (!ruleType || !resultField) { return { success: false, error: 'Missing required config: rule_type and result_field' }; } // Ensure rules are loaded await roboticClassifier.loadRules(); // Build ticket context (may have values from previous steps) const ticket = { ...context.ticket, ...(context.field_changes || {}) }; // Run classification for this rule type const result = await (roboticClassifier as any).classifyByType(ruleType, ticket); if (!result && defaultValue !== undefined) { // No match, use default const output: any = { [resultField]: defaultValue, matched_rule: null, confidence: 'default', method: 'default' }; // Track field change if (!context.field_changes) { context.field_changes = {}; } context.field_changes[resultField] = { before: (ticket as any)[resultField] || null, after: defaultValue }; return { success: true, output }; } if (!result) { // No match and no default return { success: true, output: { [resultField]: null, matched_rule: null, confidence: 'none', method: 'no_match' } }; } // Matched a rule const output: any = { [resultField]: result.value, matched_rule: result.matched_rule_name, confidence: result.confidence, method: 'robotic' }; // Track field change for primary result if (!context.field_changes) { context.field_changes = {}; } context.field_changes[resultField] = { before: (ticket as any)[resultField] || null, after: result.value }; // Handle secondary result (e.g., sub_issue_type) if (resultField2 && result.value_2 !== undefined) { output[resultField2] = result.value_2; context.field_changes[resultField2] = { before: (ticket as any)[resultField2] || null, after: result.value_2 }; } // Store full classification result in context for later steps if (!context.classification) { context.classification = {}; } context.classification[ruleType] = result; return { success: true, output }; } registerWorkflowStepExecutor('classify', executeClassify);