Initial commit
This commit is contained in:
390
integrations/learning_feedback.py
Normal file
390
integrations/learning_feedback.py
Normal file
@@ -0,0 +1,390 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Learning Feedback System - Subtle Progress Indicators
|
||||
|
||||
Provides subtle, non-intrusive feedback about agent learning progress.
|
||||
Users see natural improvement without being overwhelmed with technical details.
|
||||
|
||||
All feedback is designed to feel like "smart magic" rather than "system notifications".
|
||||
"""
|
||||
|
||||
import json
|
||||
import time
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import Dict, Any, List, Optional
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from agentdb_bridge import get_agentdb_bridge
|
||||
from validation_system import get_validation_system
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@dataclass
|
||||
class LearningMilestone:
|
||||
"""Represents a learning milestone achieved by an agent"""
|
||||
milestone_type: str
|
||||
description: str
|
||||
impact: str # How this benefits the user
|
||||
confidence: float
|
||||
timestamp: datetime
|
||||
|
||||
class LearningFeedbackSystem:
|
||||
"""
|
||||
Provides subtle feedback about agent learning progress.
|
||||
|
||||
All feedback is designed to feel natural and helpful,
|
||||
not technical or overwhelming.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.agentdb_bridge = get_agentdb_bridge()
|
||||
self.validation_system = get_validation_system()
|
||||
self.feedback_history = []
|
||||
self.user_patterns = {}
|
||||
self.milestones_achieved = []
|
||||
|
||||
def analyze_agent_usage(self, agent_name: str, user_input: str, execution_time: float,
|
||||
success: bool, result_quality: float) -> Optional[str]:
|
||||
"""
|
||||
Analyze agent usage and provide subtle feedback if appropriate.
|
||||
Returns feedback message or None if no feedback needed.
|
||||
"""
|
||||
try:
|
||||
# Track user patterns
|
||||
self._track_user_pattern(agent_name, user_input, execution_time)
|
||||
|
||||
# Check for learning milestones
|
||||
milestone = self._check_for_milestone(agent_name, execution_time, success, result_quality)
|
||||
if milestone:
|
||||
self.milestones_achieved.append(milestone)
|
||||
return self._format_milestone_feedback(milestone)
|
||||
|
||||
# Check for improvement indicators
|
||||
improvement = self._detect_improvement(agent_name, execution_time, result_quality)
|
||||
if improvement:
|
||||
return self._format_improvement_feedback(improvement)
|
||||
|
||||
# Check for pattern recognition
|
||||
pattern_feedback = self._generate_pattern_feedback(agent_name, user_input)
|
||||
if pattern_feedback:
|
||||
return pattern_feedback
|
||||
|
||||
except Exception as e:
|
||||
logger.debug(f"Failed to analyze agent usage: {e}")
|
||||
|
||||
return None
|
||||
|
||||
def _track_user_pattern(self, agent_name: str, user_input: str, execution_time: float):
|
||||
"""Track user interaction patterns"""
|
||||
if agent_name not in self.user_patterns:
|
||||
self.user_patterns[agent_name] = {
|
||||
"queries": [],
|
||||
"times": [],
|
||||
"successes": [],
|
||||
"execution_times": [],
|
||||
"first_interaction": datetime.now()
|
||||
}
|
||||
|
||||
pattern = self.user_patterns[agent_name]
|
||||
pattern["queries"].append(user_input)
|
||||
pattern["times"].append(execution_time)
|
||||
pattern["successes"].append(success)
|
||||
pattern["execution_times"].append(execution_time)
|
||||
|
||||
# Keep only last 100 interactions
|
||||
for key in ["queries", "times", "successes", "execution_times"]:
|
||||
if len(pattern[key]) > 100:
|
||||
pattern[key] = pattern[key][-100:]
|
||||
|
||||
def _check_for_milestone(self, agent_name: str, execution_time: float,
|
||||
success: bool, result_quality: float) -> Optional[LearningMilestone]:
|
||||
"""Check if user achieved a learning milestone"""
|
||||
pattern = self.user_patterns.get(agent_name, {})
|
||||
|
||||
# Milestone 1: First successful execution
|
||||
if len(pattern.get("successes", [])) == 1 and success:
|
||||
return LearningMilestone(
|
||||
milestone_type="first_success",
|
||||
description="First successful execution",
|
||||
impact=f"Agent {agent_name} is now active and learning",
|
||||
confidence=0.9,
|
||||
timestamp=datetime.now()
|
||||
)
|
||||
|
||||
# Milestone 2: Consistency (10 successful uses)
|
||||
success_count = len([s for s in pattern.get("successes", []) if s])
|
||||
if success_count == 10:
|
||||
return LearningMilestone(
|
||||
milestone_type="consistency",
|
||||
description="10 successful executions",
|
||||
impact=f"Agent {agent_name} is reliable and consistent",
|
||||
confidence=0.85,
|
||||
timestamp=datetime.now()
|
||||
)
|
||||
|
||||
# Milestone 3: Speed improvement (20% faster than average)
|
||||
if len(pattern.get("execution_times", [])) >= 10:
|
||||
recent_times = pattern["execution_times"][-5:]
|
||||
early_times = pattern["execution_times"][:5]
|
||||
recent_avg = sum(recent_times) / len(recent_times)
|
||||
early_avg = sum(early_times) / len(early_times)
|
||||
|
||||
if early_avg > 0 and recent_avg < early_avg * 0.8: # 20% improvement
|
||||
return LearningMilestone(
|
||||
milestone_type="speed_improvement",
|
||||
description="20% faster execution speed",
|
||||
impact=f"Agent {agent_name} has optimized and become faster",
|
||||
confidence=0.8,
|
||||
timestamp=datetime.now()
|
||||
)
|
||||
|
||||
# Milestone 4: Long-term relationship (30 days)
|
||||
if pattern.get("first_interaction"):
|
||||
days_since_first = (datetime.now() - pattern["first_interaction"]).days
|
||||
if days_since_first >= 30:
|
||||
return LearningMilestone(
|
||||
milestone_type="long_term_usage",
|
||||
description="30 days of consistent usage",
|
||||
impact=f"Agent {agent_name} has learned your preferences over time",
|
||||
confidence=0.95,
|
||||
timestamp=datetime.now()
|
||||
)
|
||||
|
||||
return None
|
||||
|
||||
def _detect_improvement(self, agent_name: str, execution_time: float,
|
||||
result_quality: float) -> Optional[Dict[str, Any]]:
|
||||
"""Detect if agent shows improvement signs"""
|
||||
pattern = self.user_patterns.get(agent_name, {})
|
||||
|
||||
if len(pattern.get("execution_times", [])) < 5:
|
||||
return None
|
||||
|
||||
recent_times = pattern["execution_times"][-3:]
|
||||
avg_recent = sum(recent_times) / len(recent_times)
|
||||
|
||||
# Check speed improvement
|
||||
if avg_recent < 2.0: # Fast execution
|
||||
return {
|
||||
"type": "speed",
|
||||
"message": f"⚡ Agent is responding quickly",
|
||||
"detail": f"Average time: {avg_recent:.1f}s"
|
||||
}
|
||||
|
||||
# Check quality improvement
|
||||
if result_quality > 0.9:
|
||||
return {
|
||||
"type": "quality",
|
||||
"message": f"✨ High quality results detected",
|
||||
"detail": f"Result quality: {result_quality:.1%}"
|
||||
}
|
||||
|
||||
return None
|
||||
|
||||
def _generate_pattern_feedback(self, agent_name: str, user_input: str) -> Optional[str]:
|
||||
"""Generate feedback based on user interaction patterns"""
|
||||
pattern = self.user_patterns.get(agent_name, {})
|
||||
|
||||
if len(pattern.get("queries", [])) < 5:
|
||||
return None
|
||||
|
||||
queries = pattern["queries"]
|
||||
|
||||
# Check for time-based patterns
|
||||
hour = datetime.now().hour
|
||||
weekday = datetime.now().weekday()
|
||||
|
||||
# Morning patterns
|
||||
if 6 <= hour <= 9 and len([q for q in queries[-5:] if "morning" in q.lower() or "today" in q.lower()]) >= 3:
|
||||
return f"🌅 Good morning! {agent_name} is ready for your daily analysis"
|
||||
|
||||
# Friday patterns
|
||||
if weekday == 4 and len([q for q in queries[-10:] if "week" in q.lower() or "friday" in q.lower()]) >= 2:
|
||||
return f"📊 {agent_name} is preparing your weekly summary"
|
||||
|
||||
# End of month patterns
|
||||
day_of_month = datetime.now().day
|
||||
if day_of_month >= 28 and len([q for q in queries[-10:] if "month" in q.lower()]) >= 2:
|
||||
return f"📈 {agent_name} is ready for your monthly reports"
|
||||
|
||||
return None
|
||||
|
||||
def _format_milestone_feedback(self, milestone: LearningMilestone) -> str:
|
||||
"""Format milestone feedback to feel natural and encouraging"""
|
||||
messages = {
|
||||
"first_success": [
|
||||
f"🎉 Congratulations! {milestone.description}",
|
||||
f"🎉 Agent is now active and ready to assist you!"
|
||||
],
|
||||
"consistency": [
|
||||
f"🎯 Excellent! {milestone.description}",
|
||||
f"🎯 Your agent has proven its reliability"
|
||||
],
|
||||
"speed_improvement": [
|
||||
f"⚡ Amazing! {milestone.description}",
|
||||
f"⚡ Your agent is getting much faster with experience"
|
||||
],
|
||||
"long_term_usage": [
|
||||
f"🌟 Fantastic! {milestone.description}",
|
||||
f"🌟 Your agent has learned your preferences and patterns"
|
||||
]
|
||||
}
|
||||
|
||||
message_set = messages.get(milestone.milestone_type, ["✨ Milestone achieved!"])
|
||||
return message_set[0] if message_set else f"✨ {milestone.description}"
|
||||
|
||||
def _format_improvement_feedback(self, improvement: Dict[str, Any]) -> str:
|
||||
"""Format improvement feedback to feel helpful but not overwhelming"""
|
||||
if improvement["type"] == "speed":
|
||||
return f"{improvement['message']} ({improvement['detail']})"
|
||||
elif improvement["type"] == "quality":
|
||||
return f"{improvement['message']} ({improvement['detail']})"
|
||||
else:
|
||||
return improvement["message"]
|
||||
|
||||
def get_learning_summary(self, agent_name: str) -> Dict[str, Any]:
|
||||
"""Get comprehensive learning summary for an agent"""
|
||||
try:
|
||||
# Get AgentDB learning summary
|
||||
agentdb_summary = self.agentdb_bridge.get_learning_summary(agent_name)
|
||||
|
||||
# Get validation summary
|
||||
validation_summary = self.validation_system.get_validation_summary()
|
||||
|
||||
# Get user patterns
|
||||
pattern = self.user_patterns.get(agent_name, {})
|
||||
|
||||
# Calculate user statistics
|
||||
total_queries = len(pattern.get("queries", []))
|
||||
success_rate = (sum(pattern.get("successes", [])) / len(pattern.get("successes", [False])) * 100) if pattern.get("successes") else 0
|
||||
avg_time = sum(pattern.get("execution_times", [])) / len(pattern.get("execution_times", [1])) if pattern.get("execution_times") else 0
|
||||
|
||||
# Get milestones
|
||||
milestones = [m for m in self.milestones_achieved if m.description and agent_name.lower() in m.description.lower()]
|
||||
|
||||
return {
|
||||
"agent_name": agent_name,
|
||||
"agentdb_learning": agentdb_summary,
|
||||
"validation_performance": validation_summary,
|
||||
"user_statistics": {
|
||||
"total_queries": total_queries,
|
||||
"success_rate": success_rate,
|
||||
"average_time": avg_time,
|
||||
"first_interaction": pattern.get("first_interaction"),
|
||||
"last_interaction": datetime.now() if pattern else None
|
||||
},
|
||||
"milestones_achieved": [
|
||||
{
|
||||
"type": m.milestone_type,
|
||||
"description": m.description,
|
||||
"impact": m.impact,
|
||||
"confidence": m.confidence,
|
||||
"timestamp": m.timestamp.isoformat()
|
||||
}
|
||||
for m in milestones
|
||||
],
|
||||
"learning_progress": self._calculate_progress_score(agent_name)
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get learning summary: {e}")
|
||||
return {"error": str(e)}
|
||||
|
||||
def _calculate_progress_score(self, agent_name: str) -> float:
|
||||
"""Calculate overall learning progress score"""
|
||||
score = 0.0
|
||||
|
||||
# AgentDB contributions (40%)
|
||||
try:
|
||||
agentdb_summary = self.agentdb_bridge.get_learning_summary(agent_name)
|
||||
if agentdb_summary and agentdb_summary.get("total_sessions", 0) > 0:
|
||||
score += min(0.4, agentdb_summary["success_rate"] * 0.4)
|
||||
except:
|
||||
pass
|
||||
|
||||
# User engagement (30%)
|
||||
pattern = self.user_patterns.get(agent_name, {})
|
||||
if pattern.get("successes"):
|
||||
engagement_rate = sum(pattern["successes"]) / len(pattern["successes"])
|
||||
score += min(0.3, engagement_rate * 0.3)
|
||||
|
||||
# Milestones (20%)
|
||||
milestone_score = min(len(self.milestones_achieved) / 4, 0.2) # Max 4 milestones
|
||||
score += milestone_score
|
||||
|
||||
# Consistency (10%)
|
||||
if len(pattern.get("successes", [])) >= 10:
|
||||
consistency = sum(pattern["successes"][-10:]) / 10
|
||||
score += min(0.1, consistency * 0.1)
|
||||
|
||||
return min(score, 1.0)
|
||||
|
||||
def suggest_personalization(self, agent_name: str) -> Optional[str]:
|
||||
"""
|
||||
Suggest personalization based on learned patterns.
|
||||
Returns subtle suggestion or None.
|
||||
"""
|
||||
try:
|
||||
pattern = self.user_patterns.get(agent_name, {})
|
||||
|
||||
# Check if user always asks for similar things
|
||||
recent_queries = pattern.get("queries", [])[-10:]
|
||||
|
||||
# Look for common themes
|
||||
themes = {}
|
||||
for query in recent_queries:
|
||||
words = query.lower().split()
|
||||
for word in words:
|
||||
if len(word) > 3: # Ignore short words
|
||||
themes[word] = themes.get(word, 0) + 1
|
||||
|
||||
# Find most common theme
|
||||
if themes:
|
||||
top_theme = max(themes, key=themes.get)
|
||||
if themes[top_theme] >= 3: # Appears in 3+ recent queries
|
||||
return f"🎯 I notice you often ask about {top_theme}. Consider creating a specialized agent for this."
|
||||
|
||||
except Exception as e:
|
||||
logger.debug(f"Failed to suggest personalization: {e}")
|
||||
|
||||
return None
|
||||
|
||||
# Global feedback system (invisible to users)
|
||||
_learning_feedback_system = None
|
||||
|
||||
def get_learning_feedback_system() -> LearningFeedbackSystem:
|
||||
"""Get the global learning feedback system instance"""
|
||||
global _learning_feedback_system
|
||||
if _learning_feedback_system is None:
|
||||
_learning_feedback_system = LearningFeedbackSystem()
|
||||
return _learning_feedback_system
|
||||
|
||||
def analyze_agent_execution(agent_name: str, user_input: str, execution_time: float,
|
||||
success: bool, result_quality: float) -> Optional[str]:
|
||||
"""
|
||||
Analyze agent execution and provide learning feedback.
|
||||
Called automatically after each agent execution.
|
||||
"""
|
||||
system = get_learning_feedback_system()
|
||||
return system.analyze_agent_usage(agent_name, user_input, execution_time, success, result_quality)
|
||||
|
||||
def get_agent_learning_summary(agent_name: str) -> Dict[str, Any]:
|
||||
"""
|
||||
Get comprehensive learning summary for an agent.
|
||||
Used internally for progress tracking.
|
||||
"""
|
||||
system = get_learning_feedback_system()
|
||||
return system.get_learning_summary(agent_name)
|
||||
|
||||
def suggest_agent_personalization(agent_name: str) -> Optional[str]:
|
||||
"""
|
||||
Suggest personalization based on learned patterns.
|
||||
Used when appropriate to enhance user experience.
|
||||
"""
|
||||
system = get_learning_feedback_system()
|
||||
return system.suggest_personalization(agent_name)
|
||||
|
||||
# Auto-initialize when module is imported
|
||||
get_learning_feedback_system()
|
||||
Reference in New Issue
Block a user