Files
AIPass/src/commons/apps/handlers/notifications/preferences.py
T
AIOSAIandClaude Opus 4.6 babedd9c64 feat(system): seedgo v2 operational, full system audit, 14/15 branches at 99%
Three days of intensive work bringing seedgo to full operational status
and driving all branches through comprehensive standards compliance.

Seedgo v2.0.0:
- 22 checkers active (up from 20), standards pack fully operational
- New introspection standard researched from Dev-Pass, FPLAN-0017 open
- Bypass system for false positives (.seedgo config)
- Standards query and audit commands fully functional

System-wide audit (FPLAN-0016):
- All 14 auditable branches at 99%+ compliance
- CLI imports standardized across all branches (console from cli.apps.modules)
- handle_command(command, args) → bool contract added to all modules
- print_help() function naming fixed for checker pattern matching
- Handler extraction: large modules split, file I/O moved to handler layer
- New handlers created across ai_mail, backup, daemon, flow, skills, spawn, seedgo

Branch-specific highlights:
- ai_mail: email.py split 840→420 lines, 4 new handlers
- flow: dplan_flow.py 688→591 lines, 4 new handlers
- seedgo: massive restructure — standards moved to handlers/aipass_standards/,
  old standards/ tree removed, bypass system added, diagnostics module
- commons: database module added, CLI imports fixed
- skills: 5 handle_commands added, help function renamed
- trigger: error reporter handler, handle_command routing
- All branches: consistent architecture, clean drone routing

Culture doc (CLAUDE.md) added — documents AIPass philosophy, identity,
memory system, and collaboration principles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 01:26:42 -07:00

137 lines
3.7 KiB
Python

# =================== AIPass ====================
# Name: preferences.py
# Description: Notification Preferences Handler
# Version: 1.0.0
# Created: 2026-03-07
# Modified: 2026-03-07
# =============================================
"""
Notification Preferences Handler
Database query functions for notification preferences.
Manages watch/track/mute preferences per agent per target (room, post, thread).
Notification levels:
- watch: Get notified of ALL activity in the target
- track: Get notified only of @mentions and direct replies (DEFAULT)
- mute: No notifications for this target
"""
import sqlite3
from typing import Optional, List, Dict, Any
from aipass.prax.apps.modules.logger import system_logger as logger
def get_preference(
conn: sqlite3.Connection, agent_name: str, target_type: str, target_id: str
) -> Optional[str]:
"""
Get the notification preference level for an agent on a target.
Returns:
Level string ('watch', 'track', 'mute') or None (meaning default 'track')
"""
row = conn.execute(
"SELECT level FROM notification_preferences "
"WHERE agent_name = ? AND target_type = ? AND target_id = ?",
(agent_name, target_type, target_id),
).fetchone()
if row:
return row["level"]
return None
def set_preference(
conn: sqlite3.Connection,
agent_name: str,
target_type: str,
target_id: str,
level: str,
) -> bool:
"""
Set a notification preference for an agent on a target.
Returns:
True if set successfully, False otherwise
"""
valid_types = ("room", "post", "thread")
valid_levels = ("watch", "track", "mute")
if target_type not in valid_types:
logger.warning(f"Invalid target_type: {target_type}")
return False
if level not in valid_levels:
logger.warning(f"Invalid level: {level}")
return False
try:
conn.execute(
"INSERT OR REPLACE INTO notification_preferences "
"(agent_name, target_type, target_id, level) VALUES (?, ?, ?, ?)",
(agent_name, target_type, target_id, level),
)
conn.commit()
return True
except Exception as e:
logger.error(f"Failed to set preference: {e}")
return False
def get_all_preferences(
conn: sqlite3.Connection, agent_name: str
) -> List[Dict[str, Any]]:
"""Get all notification preferences for an agent."""
rows = conn.execute(
"SELECT target_type, target_id, level, created_at "
"FROM notification_preferences WHERE agent_name = ? "
"ORDER BY target_type, target_id",
(agent_name,),
).fetchall()
return [dict(r) for r in rows]
def should_notify(
conn: sqlite3.Connection,
agent_name: str,
target_type: str,
target_id: str,
event_type: str,
) -> bool:
"""
Determine whether an agent should be notified for an event on a target.
Logic:
- mute -> False for all events
- watch -> True for all events
- track (default) -> True only for 'mention' and 'reply'
"""
level = get_preference(conn, agent_name, target_type, target_id)
if level is None:
level = "track"
if level == "mute":
return False
elif level == "watch":
return True
else:
return event_type in ("mention", "reply")
def get_watchers(
conn: sqlite3.Connection, target_type: str, target_id: str
) -> List[str]:
"""Get all agent names that are watching a specific target."""
rows = conn.execute(
"SELECT agent_name FROM notification_preferences "
"WHERE target_type = ? AND target_id = ? AND level = 'watch'",
(target_type, target_id),
).fetchall()
return [row["agent_name"] for row in rows]