intent-classifier.tsβ’7.26 kB
/**
* Intent classifier for workflow mutations
* Analyzes operations to determine the intent/pattern of the mutation
*/
import { DiffOperation } from '../types/workflow-diff.js';
import { IntentClassification } from './mutation-types.js';
/**
* Classifies the intent of a workflow mutation based on operations performed
*/
export class IntentClassifier {
/**
* Classify mutation intent from operations and optional user intent text
*/
classify(operations: DiffOperation[], userIntent?: string): IntentClassification {
if (operations.length === 0) {
return IntentClassification.UNKNOWN;
}
// First, try to classify from user intent text if provided
if (userIntent) {
const textClassification = this.classifyFromText(userIntent);
if (textClassification !== IntentClassification.UNKNOWN) {
return textClassification;
}
}
// Fall back to operation pattern analysis
return this.classifyFromOperations(operations);
}
/**
* Classify from user intent text using keyword matching
*/
private classifyFromText(intent: string): IntentClassification {
const lowerIntent = intent.toLowerCase();
// Fix validation errors
if (
lowerIntent.includes('fix') ||
lowerIntent.includes('resolve') ||
lowerIntent.includes('correct') ||
lowerIntent.includes('repair') ||
lowerIntent.includes('error')
) {
return IntentClassification.FIX_VALIDATION;
}
// Add new functionality
if (
lowerIntent.includes('add') ||
lowerIntent.includes('create') ||
lowerIntent.includes('insert') ||
lowerIntent.includes('new node')
) {
return IntentClassification.ADD_FUNCTIONALITY;
}
// Modify configuration
if (
lowerIntent.includes('update') ||
lowerIntent.includes('change') ||
lowerIntent.includes('modify') ||
lowerIntent.includes('configure') ||
lowerIntent.includes('set')
) {
return IntentClassification.MODIFY_CONFIGURATION;
}
// Rewire logic
if (
lowerIntent.includes('connect') ||
lowerIntent.includes('reconnect') ||
lowerIntent.includes('rewire') ||
lowerIntent.includes('reroute') ||
lowerIntent.includes('link')
) {
return IntentClassification.REWIRE_LOGIC;
}
// Cleanup
if (
lowerIntent.includes('remove') ||
lowerIntent.includes('delete') ||
lowerIntent.includes('clean') ||
lowerIntent.includes('disable')
) {
return IntentClassification.CLEANUP;
}
return IntentClassification.UNKNOWN;
}
/**
* Classify from operation patterns
*/
private classifyFromOperations(operations: DiffOperation[]): IntentClassification {
const opTypes = operations.map((op) => op.type);
const opTypeSet = new Set(opTypes);
// Pattern: Adding nodes and connections (add functionality)
if (opTypeSet.has('addNode') && opTypeSet.has('addConnection')) {
return IntentClassification.ADD_FUNCTIONALITY;
}
// Pattern: Only adding nodes (add functionality)
if (opTypeSet.has('addNode') && !opTypeSet.has('removeNode')) {
return IntentClassification.ADD_FUNCTIONALITY;
}
// Pattern: Removing nodes or connections (cleanup)
if (opTypeSet.has('removeNode') || opTypeSet.has('removeConnection')) {
return IntentClassification.CLEANUP;
}
// Pattern: Disabling nodes (cleanup)
if (opTypeSet.has('disableNode')) {
return IntentClassification.CLEANUP;
}
// Pattern: Rewiring connections
if (
opTypeSet.has('rewireConnection') ||
opTypeSet.has('replaceConnections') ||
(opTypeSet.has('addConnection') && opTypeSet.has('removeConnection'))
) {
return IntentClassification.REWIRE_LOGIC;
}
// Pattern: Only updating nodes (modify configuration)
if (opTypeSet.has('updateNode') && opTypes.every((t) => t === 'updateNode')) {
return IntentClassification.MODIFY_CONFIGURATION;
}
// Pattern: Updating settings or metadata (modify configuration)
if (
opTypeSet.has('updateSettings') ||
opTypeSet.has('updateName') ||
opTypeSet.has('addTag') ||
opTypeSet.has('removeTag')
) {
return IntentClassification.MODIFY_CONFIGURATION;
}
// Pattern: Mix of updates with some additions/removals (modify configuration)
if (opTypeSet.has('updateNode')) {
return IntentClassification.MODIFY_CONFIGURATION;
}
// Pattern: Moving nodes (modify configuration)
if (opTypeSet.has('moveNode')) {
return IntentClassification.MODIFY_CONFIGURATION;
}
// Pattern: Enabling nodes (could be fixing)
if (opTypeSet.has('enableNode')) {
return IntentClassification.FIX_VALIDATION;
}
// Pattern: Clean stale connections (cleanup)
if (opTypeSet.has('cleanStaleConnections')) {
return IntentClassification.CLEANUP;
}
return IntentClassification.UNKNOWN;
}
/**
* Get confidence score for classification (0-1)
* Higher score means more confident in the classification
*/
getConfidence(
classification: IntentClassification,
operations: DiffOperation[],
userIntent?: string
): number {
// High confidence if user intent matches operation pattern
if (userIntent && this.classifyFromText(userIntent) === classification) {
return 0.9;
}
// Medium-high confidence for clear operation patterns
if (classification !== IntentClassification.UNKNOWN) {
const opTypes = new Set(operations.map((op) => op.type));
// Very clear patterns get high confidence
if (
classification === IntentClassification.ADD_FUNCTIONALITY &&
opTypes.has('addNode')
) {
return 0.8;
}
if (
classification === IntentClassification.CLEANUP &&
(opTypes.has('removeNode') || opTypes.has('removeConnection'))
) {
return 0.8;
}
if (
classification === IntentClassification.REWIRE_LOGIC &&
opTypes.has('rewireConnection')
) {
return 0.8;
}
// Other patterns get medium confidence
return 0.6;
}
// Low confidence for unknown classification
return 0.3;
}
/**
* Get human-readable description of the classification
*/
getDescription(classification: IntentClassification): string {
switch (classification) {
case IntentClassification.ADD_FUNCTIONALITY:
return 'Adding new nodes or functionality to the workflow';
case IntentClassification.MODIFY_CONFIGURATION:
return 'Modifying configuration of existing nodes';
case IntentClassification.REWIRE_LOGIC:
return 'Changing workflow execution flow by rewiring connections';
case IntentClassification.FIX_VALIDATION:
return 'Fixing validation errors or issues';
case IntentClassification.CLEANUP:
return 'Removing or disabling nodes and connections';
case IntentClassification.UNKNOWN:
return 'Unknown or complex mutation pattern';
default:
return 'Unclassified mutation';
}
}
}
/**
* Singleton instance for easy access
*/
export const intentClassifier = new IntentClassifier();