# Copyright (c) 2025 Patrick Motsch # All rights reserved. # progressTracker.py # Progress tracking for adaptive Dynamic mode import logging from typing import Dict, Any, List from datetime import datetime, timezone logger = logging.getLogger(__name__) class ProgressTracker: """Tracks what has been accomplished and what's still needed""" def __init__(self): self.completedObjectives = [] self.partialAchievements = [] self.failedAttempts = [] self.learningInsights = [] self.currentPhase = "plan" def updateOperation(self, result: Any, validation: Dict[str, Any], taskIntent: Dict[str, Any]): """Updates progress tracking based on action result - tracks per TASK, not workflow""" try: schemaCompliant = validation.get('schemaCompliant', True) overallSuccess = validation.get('overallSuccess', None) qualityScore = validation.get('qualityScore', None) improvementSuggestions = validation.get('improvementSuggestions', []) # Get task objective from taskIntent (task-level, not workflow-level) taskObjective = taskIntent.get('taskObjective', taskIntent.get('primaryGoal', 'Unknown')) # If validation is not schema compliant, treat as indeterminate (do not count as failure) if not schemaCompliant or overallSuccess is None or qualityScore is None: self.partialAchievements.append({ "objective": taskObjective, "partialAchievement": "Validation indeterminate (schema non-compliant or missing fields)", "missingFields": validation.get('missingFields', []), "timestamp": datetime.now(timezone.utc).timestamp() }) self.currentPhase = "partial" logger.info(f"Indeterminate validation (no penalty): {taskObjective}") elif overallSuccess and qualityScore > 0.7: # Successful completion self.completedObjectives.append({ "objective": taskObjective, "achievement": f"Quality score: {qualityScore:.2f}", "qualityScore": qualityScore, "timestamp": datetime.now(timezone.utc).timestamp() }) self.currentPhase = "completed" logger.info(f"Task objective completed: {taskObjective}") elif qualityScore > 0.3: # Partial achievement self.partialAchievements.append({ "objective": taskObjective, "partialAchievement": f"Quality score: {qualityScore:.2f}", "missingParts": improvementSuggestions, "timestamp": datetime.now(timezone.utc).timestamp() }) self.currentPhase = "partial" logger.info(f"Partial achievement: {taskObjective}") else: # Failed attempt self.failedAttempts.append({ "objective": taskObjective, "failureReason": f"Quality score: {qualityScore:.2f}", "learningOpportunity": improvementSuggestions, "timestamp": datetime.now(timezone.utc).timestamp() }) self.currentPhase = "failed" logger.info(f"Failed attempt: {taskObjective}") # Extract learning insights if improvementSuggestions: for suggestion in improvementSuggestions: if suggestion not in self.learningInsights: self.learningInsights.append(suggestion) except Exception as e: logger.error(f"Error updating progress: {str(e)}") def getCurrentProgress(self) -> Dict[str, Any]: """Gets current progress state""" return { "completedObjectives": self.completedObjectives, "partialAchievements": self.partialAchievements, "failedAttempts": self.failedAttempts, "learningInsights": self.learningInsights, "currentPhase": self.currentPhase, "nextActionsSuggested": self._getNextActionSuggestions() } def shouldContinue(self, progress: Dict[str, Any], validation: Dict[str, Any]) -> bool: """Determines if the task should continue""" try: # If we have completed objectives, don't continue if progress.get('completedObjectives'): return False # If we have too many failed attempts, don't continue if len(progress.get('failedAttempts', [])) >= 3: return False # If validation shows success, don't continue if validation.get('schemaCompliant', True) and validation.get('overallSuccess', False): return False # If validation is not schema compliant, allow one refinement pass without counting as failure if not validation.get('schemaCompliant', True): return True # Otherwise, continue return True except Exception as e: logger.error(f"Error checking if should continue: {str(e)}") return True # Default to continue on error def _getNextActionSuggestions(self) -> List[str]: """Suggests next actions based on progress""" suggestions = [] # If we have failed attempts, suggest avoiding those actions if self.failedAttempts: suggestions.append("Avoid actions that have failed before") # If we have partial achievements, suggest building on them if self.partialAchievements: suggestions.append("Build on partial achievements") # If we have learning insights, suggest applying them if self.learningInsights: suggestions.extend(self.learningInsights[:3]) # Top 3 insights # Default suggestions if not suggestions: suggestions.append("Try a different approach") suggestions.append("Focus on user intent") return suggestions def getProgressSummary(self) -> Dict[str, Any]: """Gets a summary of progress""" return { "totalCompleted": len(self.completedObjectives), "totalPartial": len(self.partialAchievements), "totalFailed": len(self.failedAttempts), "totalInsights": len(self.learningInsights), "currentPhase": self.currentPhase, "successRate": len(self.completedObjectives) / max(len(self.completedObjectives) + len(self.failedAttempts), 1) } def reset(self): """Resets progress tracking""" self.completedObjectives = [] self.partialAchievements = [] self.failedAttempts = [] self.learningInsights = [] self.currentPhase = "plan"