UNPKG

@semantest/chrome-extension

Version:

Browser extension for ChatGPT-buddy - AI automation extension built on Web-Buddy framework

990 lines (898 loc) 30 kB
/** * Advanced Training Scenarios & Multi-Step Workflows * * Implements sophisticated training scenarios including conditional logic, * loops, data extraction, form handling, and complex multi-step workflows. */ import { globalPatternManager, AutomationPattern, PatternStep } from './pattern-manager'; import { globalMessageStore } from './message-store'; export interface TrainingScenario { id: string; name: string; description: string; category: ScenarioCategory; difficulty: 'beginner' | 'intermediate' | 'advanced' | 'expert'; estimatedTime: number; // in minutes prerequisites: string[]; objectives: LearningObjective[]; steps: ScenarioStep[]; variations: ScenarioVariation[]; assessment: ScenarioAssessment; metadata: ScenarioMetadata; } export type ScenarioCategory = | 'form-automation' | 'data-extraction' | 'navigation-flows' | 'e-commerce' | 'testing-scenarios' | 'workflow-automation' | 'api-integration' | 'multi-tab-workflows'; export interface LearningObjective { id: string; description: string; skills: string[]; verificationMethod: 'pattern-execution' | 'manual-verification' | 'automated-test'; } export interface ScenarioStep { id: string; name: string; description: string; instructionType: 'demonstration' | 'guided-practice' | 'independent-practice'; patterns: ScenarioPattern[]; hints: string[]; commonMistakes: string[]; successCriteria: string[]; timeLimit?: number; // in seconds } export interface ScenarioPattern { id: string; name: string; description: string; patternSteps: PatternStep[]; isOptional: boolean; alternativeApproaches: string[]; difficultyFactors: string[]; } export interface ScenarioVariation { id: string; name: string; description: string; changedElements: ElementChange[]; difficultyModifier: number; // -1 easier, 0 same, +1 harder } export interface ElementChange { selector: string; changeType: 'text' | 'position' | 'attribute' | 'visibility' | 'structure'; oldValue: string; newValue: string; adaptationStrategy: string; } export interface ScenarioAssessment { successMetrics: SuccessMetric[]; rubric: AssessmentRubric[]; feedback: FeedbackRules[]; } export interface SuccessMetric { name: string; type: 'completion-rate' | 'accuracy' | 'efficiency' | 'adaptability'; weight: number; thresholds: { excellent: number; good: number; acceptable: number; needsImprovement: number; }; } export interface AssessmentRubric { criteria: string; levels: { exemplary: { score: number; description: string }; proficient: { score: number; description: string }; developing: { score: number; description: string }; beginning: { score: number; description: string }; }; } export interface FeedbackRules { condition: string; feedbackType: 'encouragement' | 'correction' | 'guidance' | 'challenge'; message: string; suggestedActions: string[]; } export interface ScenarioMetadata { author: string; version: string; lastUpdated: string; tags: string[]; websiteTypes: string[]; browserCompatibility: string[]; language: string; translationSupport: boolean; } export interface WorkflowTemplate { id: string; name: string; description: string; category: string; complexity: 'simple' | 'moderate' | 'complex' | 'expert'; phases: WorkflowPhase[]; dataFlow: DataFlowDefinition[]; errorHandling: ErrorHandlingStrategy[]; parallelExecution: ParallelExecutionConfig; } export interface WorkflowPhase { id: string; name: string; description: string; order: number; patterns: string[]; // Pattern IDs dependencies: string[]; // Phase IDs that must complete first conditionalExecution: ConditionalLogic[]; outputData: DataOutputDefinition[]; rollbackStrategy?: RollbackStrategy; } export interface ConditionalLogic { id: string; condition: string; // JavaScript expression trueAction: 'continue' | 'skip' | 'jump-to' | 'repeat' | 'fail'; falseAction: 'continue' | 'skip' | 'jump-to' | 'repeat' | 'fail'; targetPhase?: string; maxRetries?: number; } export interface DataFlowDefinition { sourcePhase: string; targetPhase: string; dataMapping: { [key: string]: string }; transformations: DataTransformation[]; validations: DataValidation[]; } export interface DataTransformation { field: string; operation: 'format' | 'calculate' | 'lookup' | 'aggregate' | 'filter'; parameters: { [key: string]: any }; } export interface DataValidation { field: string; rule: 'required' | 'pattern' | 'range' | 'custom'; parameters: any; errorMessage: string; } export interface ErrorHandlingStrategy { errorType: string; severity: 'low' | 'medium' | 'high' | 'critical'; response: 'retry' | 'skip' | 'fallback' | 'abort' | 'manual-intervention'; maxRetries?: number; fallbackPattern?: string; notificationLevel: 'none' | 'log' | 'warn' | 'alert'; } export interface ParallelExecutionConfig { enabled: boolean; maxConcurrentPhases: number; syncPoints: string[]; // Phase IDs where all parallel execution must wait resourceSharing: ResourceSharingConfig[]; } export interface ResourceSharingConfig { resource: 'browser-tab' | 'data-storage' | 'network-session' | 'user-session'; policy: 'exclusive' | 'shared-read' | 'shared-write' | 'synchronized'; conflictResolution: 'queue' | 'merge' | 'override' | 'error'; } export interface RollbackStrategy { enabled: boolean; checkpoints: string[]; // Phase IDs rollbackMethod: 'state-restoration' | 'inverse-operations' | 'manual-cleanup'; dataBackup: boolean; } export class AdvancedTrainingManager { private scenarios: Map<string, TrainingScenario> = new Map(); private workflows: Map<string, WorkflowTemplate> = new Map(); private activeTrainingSessions: Map<string, TrainingSession> = new Map(); private readonly STORAGE_KEY = 'advanced-training-scenarios'; constructor() { this.loadScenarios(); this.initializePredefinedScenarios(); } /** * Create a comprehensive training scenario */ async createTrainingScenario( name: string, category: ScenarioCategory, difficulty: TrainingScenario['difficulty'], steps: ScenarioStep[], options: Partial<TrainingScenario> = {} ): Promise<TrainingScenario> { const scenario: TrainingScenario = { id: this.generateScenarioId(), name, description: options.description || '', category, difficulty, estimatedTime: options.estimatedTime || this.estimateScenarioTime(steps), prerequisites: options.prerequisites || [], objectives: options.objectives || [], steps, variations: options.variations || [], assessment: options.assessment || this.createDefaultAssessment(), metadata: { author: 'System', version: '1.0.0', lastUpdated: new Date().toISOString(), tags: [], websiteTypes: [], browserCompatibility: ['chrome', 'firefox', 'edge'], language: 'en', translationSupport: false, ...options.metadata } }; this.scenarios.set(scenario.id, scenario); await this.saveScenarios(); globalMessageStore.addInboundMessage( 'TRAINING_SCENARIO_CREATED', { scenarioId: scenario.id, name, category, difficulty }, `scenario-created-${Date.now()}`, { extensionId: chrome.runtime.id, userAgent: navigator.userAgent } ); console.log(`🎓 Created training scenario: ${name} (${scenario.id})`); return scenario; } /** * Start an advanced training session */ async startTrainingSession( scenarioId: string, userId: string = 'anonymous' ): Promise<TrainingSession> { const scenario = this.scenarios.get(scenarioId); if (!scenario) { throw new Error(`Training scenario not found: ${scenarioId}`); } const session = new TrainingSession(scenario, userId); this.activeTrainingSessions.set(session.id, session); globalMessageStore.addInboundMessage( 'TRAINING_SESSION_STARTED', { sessionId: session.id, scenarioId, userId }, `session-started-${Date.now()}`, { extensionId: chrome.runtime.id, userAgent: navigator.userAgent } ); console.log(`🎯 Started training session: ${session.id} for scenario: ${scenario.name}`); return session; } /** * Create a complex multi-step workflow */ async createWorkflowTemplate( name: string, phases: WorkflowPhase[], options: Partial<WorkflowTemplate> = {} ): Promise<WorkflowTemplate> { const workflow: WorkflowTemplate = { id: this.generateWorkflowId(), name, description: options.description || '', category: options.category || 'general', complexity: options.complexity || 'moderate', phases: phases.sort((a, b) => a.order - b.order), dataFlow: options.dataFlow || [], errorHandling: options.errorHandling || [], parallelExecution: options.parallelExecution || { enabled: false, maxConcurrentPhases: 1, syncPoints: [], resourceSharing: [] } }; // Validate workflow this.validateWorkflow(workflow); this.workflows.set(workflow.id, workflow); await this.saveWorkflows(); globalMessageStore.addInboundMessage( 'WORKFLOW_CREATED', { workflowId: workflow.id, name, complexity: workflow.complexity }, `workflow-created-${Date.now()}`, { extensionId: chrome.runtime.id, userAgent: navigator.userAgent } ); console.log(`⚙️ Created workflow template: ${name} (${workflow.id})`); return workflow; } /** * Execute a complex workflow */ async executeWorkflow( workflowId: string, context: WorkflowExecutionContext ): Promise<WorkflowExecutionResult> { const workflow = this.workflows.get(workflowId); if (!workflow) { throw new Error(`Workflow not found: ${workflowId}`); } const executor = new WorkflowExecutor(workflow, context); return await executor.execute(); } /** * Initialize predefined training scenarios */ private async initializePredefinedScenarios(): Promise<void> { // E-commerce Shopping Flow Scenario await this.createTrainingScenario( 'E-commerce Complete Purchase Flow', 'e-commerce', 'intermediate', [ { id: 'step-1', name: 'Product Search and Selection', description: 'Learn to search for products and navigate to product pages', instructionType: 'guided-practice', patterns: [{ id: 'search-pattern', name: 'Product Search', description: 'Search for specific products using search functionality', patternSteps: [ { id: 'search-input', type: 'type', selector: '[data-testid="search-input"], .search-input, #search', value: '${productName}', description: 'Enter product name in search field', timeout: 5000, retries: 2, errorHandling: 'retry' }, { id: 'search-submit', type: 'click', selector: '[data-testid="search-button"], .search-button, #search-btn', description: 'Click search button', timeout: 3000, retries: 2, errorHandling: 'retry' } ], isOptional: false, alternativeApproaches: ['voice-search', 'category-navigation', 'barcode-scan'], difficultyFactors: ['dynamic-search-suggestions', 'autocomplete-handling'] }], hints: [ 'Look for search boxes usually positioned at the top of the page', 'Some sites use magnifying glass icons for search buttons', 'Use data-testid attributes for more reliable element selection' ], commonMistakes: [ 'Not waiting for search suggestions to load', 'Clicking submit before typing is complete', 'Not handling autocomplete interference' ], successCriteria: [ 'Search results page loads successfully', 'Search term is correctly entered and submitted', 'Results are relevant to the search query' ], timeLimit: 60 }, { id: 'step-2', name: 'Add to Cart and Checkout', description: 'Complete the purchase process from product selection to payment', instructionType: 'independent-practice', patterns: [{ id: 'checkout-pattern', name: 'Complete Checkout Process', description: 'Navigate through the entire checkout flow', patternSteps: [ { id: 'add-to-cart', type: 'click', selector: '[data-testid="add-to-cart"], .add-to-cart, .btn-add-cart', description: 'Add product to shopping cart', timeout: 5000, retries: 3, errorHandling: 'retry' }, { id: 'proceed-checkout', type: 'click', selector: '[data-testid="checkout"], .checkout-btn, .proceed-checkout', description: 'Proceed to checkout', timeout: 5000, retries: 2, errorHandling: 'retry' }, { id: 'fill-shipping', type: 'type', selector: '#shipping-address, [name="address"]', value: '${shippingAddress}', description: 'Fill shipping address', timeout: 3000, retries: 2, errorHandling: 'retry' } ], isOptional: false, alternativeApproaches: ['guest-checkout', 'social-login', 'one-click-purchase'], difficultyFactors: ['multi-step-forms', 'payment-gateway-integration', 'address-validation'] }], hints: [ 'Cart buttons often change after adding items', 'Some sites require user registration before checkout', 'Look for security indicators during payment steps' ], commonMistakes: [ 'Not waiting for cart update animations', 'Missing required form fields', 'Not handling payment gateway redirects' ], successCriteria: [ 'Item successfully added to cart', 'Checkout process initiated', 'All required information entered correctly' ], timeLimit: 180 } ], { description: 'Comprehensive e-commerce automation training covering search, selection, and purchase flows', estimatedTime: 25, objectives: [ { id: 'obj-1', description: 'Master product search and navigation patterns', skills: ['element-identification', 'form-interaction', 'wait-handling'], verificationMethod: 'pattern-execution' }, { id: 'obj-2', description: 'Complete complex multi-step checkout processes', skills: ['multi-step-forms', 'conditional-logic', 'error-handling'], verificationMethod: 'automated-test' } ] } ); // Data Extraction Scenario await this.createTrainingScenario( 'Advanced Data Extraction and Processing', 'data-extraction', 'advanced', [ { id: 'step-1', name: 'Table Data Extraction', description: 'Extract structured data from tables with pagination', instructionType: 'demonstration', patterns: [{ id: 'table-extraction', name: 'Paginated Table Data Extraction', description: 'Extract all data from a paginated table', patternSteps: [ { id: 'identify-table', type: 'extract', selector: 'table, .data-table, [role="table"]', description: 'Identify the main data table', timeout: 5000, retries: 2, errorHandling: 'fail' }, { id: 'extract-headers', type: 'extract', selector: 'th, .table-header, [role="columnheader"]', description: 'Extract table headers', timeout: 3000, retries: 1, errorHandling: 'continue' }, { id: 'extract-rows', type: 'loop', selector: 'tr, .table-row, [role="row"]', description: 'Extract all table rows with pagination', timeout: 10000, retries: 3, errorHandling: 'retry' } ], isOptional: false, alternativeApproaches: ['api-extraction', 'csv-export', 'copy-paste'], difficultyFactors: ['infinite-scroll', 'lazy-loading', 'dynamic-content'] }], hints: [ 'Always identify table structure before extracting data', 'Handle pagination and infinite scroll scenarios', 'Consider using CSS selectors for better reliability' ], commonMistakes: [ 'Not waiting for table data to load completely', 'Missing pagination navigation', 'Extracting duplicate data across pages' ], successCriteria: [ 'All table headers correctly identified', 'Complete dataset extracted from all pages', 'Data structure maintained and validated' ], timeLimit: 300 } ], { description: 'Advanced data extraction techniques for complex tables and dynamic content', estimatedTime: 35, objectives: [ { id: 'obj-1', description: 'Master structured data extraction from complex tables', skills: ['data-extraction', 'pagination-handling', 'loop-patterns'], verificationMethod: 'automated-test' } ] } ); console.log(`🎓 Initialized ${this.scenarios.size} predefined training scenarios`); } /** * Get all available training scenarios */ getTrainingScenarios(filter?: { category?: ScenarioCategory; difficulty?: string; searchText?: string; }): TrainingScenario[] { let scenarios = Array.from(this.scenarios.values()); if (filter) { if (filter.category) { scenarios = scenarios.filter(s => s.category === filter.category); } if (filter.difficulty) { scenarios = scenarios.filter(s => s.difficulty === filter.difficulty); } if (filter.searchText) { const searchLower = filter.searchText.toLowerCase(); scenarios = scenarios.filter(s => s.name.toLowerCase().includes(searchLower) || s.description.toLowerCase().includes(searchLower) ); } } return scenarios.sort((a, b) => a.difficulty.localeCompare(b.difficulty)); } /** * Get workflow templates */ getWorkflowTemplates(filter?: { category?: string; complexity?: string; }): WorkflowTemplate[] { let workflows = Array.from(this.workflows.values()); if (filter) { if (filter.category) { workflows = workflows.filter(w => w.category === filter.category); } if (filter.complexity) { workflows = workflows.filter(w => w.complexity === filter.complexity); } } return workflows; } /** * Generate unique scenario ID */ private generateScenarioId(): string { return `scenario-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; } /** * Generate unique workflow ID */ private generateWorkflowId(): string { return `workflow-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; } /** * Estimate scenario completion time */ private estimateScenarioTime(steps: ScenarioStep[]): number { return steps.reduce((total, step) => { const stepTime = step.timeLimit || 120; // 2 minutes default return total + stepTime / 60; // Convert to minutes }, 0); } /** * Create default assessment criteria */ private createDefaultAssessment(): ScenarioAssessment { return { successMetrics: [ { name: 'Completion Rate', type: 'completion-rate', weight: 0.4, thresholds: { excellent: 100, good: 90, acceptable: 80, needsImprovement: 70 } }, { name: 'Accuracy', type: 'accuracy', weight: 0.3, thresholds: { excellent: 95, good: 85, acceptable: 75, needsImprovement: 65 } }, { name: 'Efficiency', type: 'efficiency', weight: 0.3, thresholds: { excellent: 90, good: 80, acceptable: 70, needsImprovement: 60 } } ], rubric: [], feedback: [] }; } /** * Validate workflow definition */ private validateWorkflow(workflow: WorkflowTemplate): void { // Check for circular dependencies const visited = new Set<string>(); const visiting = new Set<string>(); const hasCycle = (phaseId: string): boolean => { if (visiting.has(phaseId)) return true; if (visited.has(phaseId)) return false; visiting.add(phaseId); const phase = workflow.phases.find(p => p.id === phaseId); if (phase) { for (const dep of phase.dependencies) { if (hasCycle(dep)) return true; } } visiting.delete(phaseId); visited.add(phaseId); return false; }; for (const phase of workflow.phases) { if (hasCycle(phase.id)) { throw new Error(`Circular dependency detected in workflow: ${workflow.name}`); } } } /** * Load scenarios from storage */ private async loadScenarios(): Promise<void> { try { const result = await chrome.storage.local.get(this.STORAGE_KEY); const stored = result[this.STORAGE_KEY]; if (stored && stored.scenarios) { stored.scenarios.forEach((scenario: TrainingScenario) => { this.scenarios.set(scenario.id, scenario); }); console.log(`📚 Loaded ${this.scenarios.size} training scenarios from storage`); } } catch (error) { console.error('❌ Failed to load training scenarios:', error); } } /** * Save scenarios to storage */ private async saveScenarios(): Promise<void> { try { const scenarios = Array.from(this.scenarios.values()); await chrome.storage.local.set({ [this.STORAGE_KEY]: { scenarios, lastSaved: new Date().toISOString(), version: '1.0.0' } }); } catch (error) { console.error('❌ Failed to save training scenarios:', error); } } /** * Save workflows to storage */ private async saveWorkflows(): Promise<void> { try { const workflows = Array.from(this.workflows.values()); await chrome.storage.local.set({ 'advanced-training-workflows': { workflows, lastSaved: new Date().toISOString(), version: '1.0.0' } }); } catch (error) { console.error('❌ Failed to save workflows:', error); } } } /** * Training Session Management */ export class TrainingSession { public readonly id: string; public readonly scenario: TrainingScenario; public readonly userId: string; public readonly startTime: Date; public currentStep: number = 0; public progress: SessionProgress; public results: SessionResults; constructor(scenario: TrainingScenario, userId: string) { this.id = `session-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; this.scenario = scenario; this.userId = userId; this.startTime = new Date(); this.progress = { completedSteps: [], currentStepStartTime: new Date(), timeSpent: 0, hintsUsed: 0, mistakesMade: [] }; this.results = { score: 0, accuracy: 0, efficiency: 0, adaptability: 0, feedback: [], recommendations: [] }; } completeStep(stepId: string, success: boolean, timeSpent: number): void { this.progress.completedSteps.push({ stepId, success, timeSpent, completedAt: new Date() }); this.progress.timeSpent += timeSpent; this.currentStep++; // Update results this.calculateResults(); } private calculateResults(): void { const completedSteps = this.progress.completedSteps; const totalSteps = this.scenario.steps.length; // Calculate completion rate const completionRate = (completedSteps.length / totalSteps) * 100; // Calculate accuracy const successfulSteps = completedSteps.filter(s => s.success).length; this.results.accuracy = (successfulSteps / completedSteps.length) * 100; // Calculate efficiency (based on time vs estimated time) const estimatedTime = this.scenario.estimatedTime * 60; // Convert to seconds this.results.efficiency = Math.max(0, 100 - ((this.progress.timeSpent - estimatedTime) / estimatedTime * 100)); // Calculate overall score this.results.score = (completionRate * 0.4) + (this.results.accuracy * 0.3) + (this.results.efficiency * 0.3); } } export interface SessionProgress { completedSteps: StepCompletion[]; currentStepStartTime: Date; timeSpent: number; // in seconds hintsUsed: number; mistakesMade: string[]; } export interface StepCompletion { stepId: string; success: boolean; timeSpent: number; completedAt: Date; } export interface SessionResults { score: number; accuracy: number; efficiency: number; adaptability: number; feedback: string[]; recommendations: string[]; } /** * Workflow Execution Engine */ export class WorkflowExecutor { private workflow: WorkflowTemplate; private context: WorkflowExecutionContext; private executionState: WorkflowExecutionState; constructor(workflow: WorkflowTemplate, context: WorkflowExecutionContext) { this.workflow = workflow; this.context = context; this.executionState = { currentPhase: 0, completedPhases: [], data: new Map(), errors: [], startTime: new Date() }; } async execute(): Promise<WorkflowExecutionResult> { try { for (const phase of this.workflow.phases) { if (this.shouldExecutePhase(phase)) { await this.executePhase(phase); } } return { success: true, executionTime: Date.now() - this.executionState.startTime.getTime(), completedPhases: this.executionState.completedPhases, data: Object.fromEntries(this.executionState.data), errors: this.executionState.errors }; } catch (error) { return { success: false, executionTime: Date.now() - this.executionState.startTime.getTime(), completedPhases: this.executionState.completedPhases, data: Object.fromEntries(this.executionState.data), errors: [...this.executionState.errors, error.toString()] }; } } private shouldExecutePhase(phase: WorkflowPhase): boolean { // Check dependencies for (const depId of phase.dependencies) { if (!this.executionState.completedPhases.includes(depId)) { return false; } } // Check conditional execution for (const condition of phase.conditionalExecution) { if (!this.evaluateCondition(condition.condition)) { return condition.falseAction === 'continue'; } } return true; } private async executePhase(phase: WorkflowPhase): Promise<void> { console.log(`⚙️ Executing workflow phase: ${phase.name}`); // Execute patterns in this phase for (const patternId of phase.patterns) { const pattern = globalPatternManager.getPattern(patternId); if (pattern) { await this.executePattern(pattern); } } this.executionState.completedPhases.push(phase.id); } private async executePattern(pattern: AutomationPattern): Promise<void> { // This would integrate with the actual pattern execution engine console.log(`🎯 Executing pattern: ${pattern.name}`); // Implementation would depend on the pattern execution system } private evaluateCondition(condition: string): boolean { // Simple condition evaluation - in production, use a proper expression evaluator try { // Create a safe evaluation context const context = { data: Object.fromEntries(this.executionState.data), phase: this.executionState.currentPhase }; // This is a simplified implementation - in production, use a secure evaluator return new Function('context', `with(context) { return ${condition}; }`)(context); } catch (error) { console.error('Error evaluating condition:', error); return false; } } } export interface WorkflowExecutionContext { userId: string; sessionId: string; initialData: { [key: string]: any }; preferences: { [key: string]: any }; } export interface WorkflowExecutionState { currentPhase: number; completedPhases: string[]; data: Map<string, any>; errors: string[]; startTime: Date; } export interface WorkflowExecutionResult { success: boolean; executionTime: number; completedPhases: string[]; data: { [key: string]: any }; errors: string[]; } // Global advanced training manager instance export const globalAdvancedTrainingManager = new AdvancedTrainingManager();