"""Smart proactive trigger system for the DRIFT companion.""" import random from datetime import datetime from typing import Dict, Optional class ProactiveState: def __init__(self): self.last_user_time: Optional[datetime] = None self.last_stress_level: float = 0.0 self.last_dissonance_score: float = 0.0 self.proactive_count: int = 0 def record_interaction(self, user_input: str, emotion: Dict, dissonance: Dict): self.last_user_time = datetime.now() self.last_stress_level = emotion.get("intensity", 0.0) * ( 1.0 if emotion.get("label") in ("anxious", "angry", "sad", "overwhelmed") else 0.5 ) self.last_dissonance_score = dissonance.get("score", 0.0) def should_trigger(self, goals_db=None) -> Optional[str]: """Returns a proactive prompt if a trigger fires, else None.""" now = datetime.now() # Trigger 1: User has been away for a while (15-45 min) and last interaction was stressful if self.last_user_time is not None: minutes_away = (now - self.last_user_time).total_seconds() / 60.0 if minutes_away > 20 and self.last_stress_level > 0.6: return ( "user stepped away after a stressful moment. " "Share one gentle, grounding observation or question. " "Do not ask for a status update; just leave a small light on." ) # Trigger 2: Upcoming deadlines (within 4 hours) if goals_db is not None: try: reminders = goals_db.pending_reminders(within_minutes=240) if reminders: r = random.choice(reminders) return ( f"There is an upcoming reminder: '{r['message']}' at {r['remind_at']}. " f"Offer a brief, helpful nudge. Keep it under two sentences." ) except Exception: pass # Trigger 3: Unresolved cognitive dissonance (score > 0.5) if self.last_dissonance_score > 0.5: return ( "Earlier user showed signs of inner conflict. " "Drop one small, non-intrusive question that might help them name one side of the tension. " "Do not solve it; just reopen the door gently." ) # Trigger 4: Random philosophical prompt (low probability, only if nothing else fires) if random.random() < 0.08: prompts = [ "What is one thing you are quietly proud of but rarely mention?", "If your current project could speak, what would it ask for?", "What pattern in your own behavior have you noticed but not named?", "What is the smallest step that would make tomorrow easier?", "What question are you avoiding because the answer might change something?", ] return f"Share this brief reflective question with user: {random.choice(prompts)}" return None def next_wait_seconds(self) -> int: """Dynamic wait based on recent activity. STRONG CONTINUOUS MODE: background cycles fire every 15–30 seconds so the bot maintains an ongoing inner life even when idle. """ if self.last_stress_level > 0.7: return random.randint(15, 25) # faster when stressed if self.last_dissonance_score > 0.5: return random.randint(20, 30) # faster when dissonant return random.randint(15, 30) # 15-30 s default — continuous thought