Files
ws-sanctum-chronicler/app/agent/policies.py

106 lines
3.5 KiB
Python

"""Agent behavior policies and rules."""
import logging
from datetime import datetime, timedelta
logger = logging.getLogger(__name__)
class ChatActivityPolicy:
"""Policy for detecting chat activity and inactivity periods."""
def __init__(self, inactivity_threshold_minutes: int = 15):
"""
Initialize policy.
Args:
inactivity_threshold_minutes: Minutes of no chat before Hearthkeeper activates
"""
self.inactivity_threshold = timedelta(minutes=inactivity_threshold_minutes)
self.last_message_time: dict[str, datetime] = {}
def record_activity(self, session_id: str) -> None:
"""Record that chat activity occurred."""
self.last_message_time[session_id] = datetime.utcnow()
def minutes_since_activity(self, session_id: str) -> int:
"""Get minutes since last chat message."""
if session_id not in self.last_message_time:
return 0
elapsed = datetime.utcnow() - self.last_message_time[session_id]
return int(elapsed.total_seconds() / 60)
def should_hearthkeeper_prompt(self, session_id: str) -> bool:
"""Determine if Hearthkeeper should send a prompt."""
minutes = self.minutes_since_activity(session_id)
should = minutes >= self.inactivity_threshold.total_seconds() / 60
if should:
logger.info(f"Chat inactive for {minutes} minutes. Hearthkeeper may prompt.")
return should
class ResponseSuppression:
"""Policy for when the agent should NOT respond."""
# Suppress responses when chat is very active (humans are talking)
ACTIVE_CHAT_THRESHOLD = 5 # 5+ messages per minute = suppress
@staticmethod
def should_suppress_response(recent_message_count: int, time_window_minutes: int = 1) -> bool:
"""
Determine if agent should stay silent due to active chat.
Args:
recent_message_count: Number of messages in the time window
time_window_minutes: Time window in minutes
Returns:
True if agent should suppress response
"""
messages_per_minute = recent_message_count / time_window_minutes
suppress = messages_per_minute >= ResponseSuppression.ACTIVE_CHAT_THRESHOLD
if suppress:
logger.debug(f"Response suppressed due to active chat ({messages_per_minute:.1f} msg/min)")
return suppress
class SuspiciousContentPolicy:
"""Policy for detecting suspicious content."""
# Patterns that raise Warden alerts
SUSPICIOUS_KEYWORDS = [
"join our discord",
"discord.gg",
"grow your channel",
"easy money",
"limited offer",
]
@staticmethod
def is_suspicious(message: str) -> bool:
"""
Check if a message matches suspicious patterns.
Args:
message: Message content
Returns:
True if message is suspicious
"""
message_lower = message.lower()
for keyword in SuspiciousContentPolicy.SUSPICIOUS_KEYWORDS:
if keyword in message_lower:
logger.warning(f"Suspicious content detected: {keyword}")
return True
# Check for multiple links
link_count = message.count("http") + message.count("www")
if link_count > 1:
logger.warning("Suspicious content detected: multiple links")
return True
return False