Skip to content

Desktop and webhook notifications for price drop alerts #487

@kovtcharov

Description

@kovtcharov

Summary

Implement a notification system for the DealAgent that sends alerts when tracked product prices drop below configured thresholds. Support Windows desktop toast notifications (primary) and webhooks (for Slack/Discord/Teams integration).

Motivation

Notifications are the core value proposition of price tracking. Without them, users must manually check prices. CamelCamelCamel's #1 feature is email alerts on price drops — our equivalent uses desktop toasts (private, local-first) with optional webhook integration.

Design

Notification Architecture

# src/gaia/agents/deals/notifications.py
from abc import ABC, abstractmethod

class NotificationChannel(ABC):
    @abstractmethod
    def send(self, title: str, message: str, url: str = "", image: str = "") -> bool:
        """Send a notification. Returns True if delivered."""

class DesktopNotification(NotificationChannel):
    """Windows toast notification via win10toast or plyer."""
    def send(self, title, message, url="", image=""):
        # Windows: win10toast-persist or plyer
        # Linux: plyer (uses libnotify)
        pass

class WebhookNotification(NotificationChannel):
    """Send notification to a webhook URL (Slack, Discord, Teams, custom)."""
    def __init__(self, webhook_url: str, format: str = "auto"):
        self.webhook_url = webhook_url
        self.format = format  # 'slack', 'discord', 'teams', 'generic'

    def send(self, title, message, url="", image=""):
        # Auto-detect format from URL or use explicit format
        pass

class NotificationManager:
    """Manages notification channels and alert delivery."""
    def __init__(self, channels: List[NotificationChannel]):
        self.channels = channels

    def notify_price_drop(self, product_name: str, old_price: float,
                          new_price: float, target_price: float, url: str = ""):
        title = f"Price Drop: {product_name}"
        pct = ((old_price - new_price) / old_price) * 100
        message = f"${new_price:.2f} (was ${old_price:.2f}, -{pct:.0f}%)"
        if new_price <= target_price:
            message += f" — Below your target of ${target_price:.2f}!"
        for channel in self.channels:
            channel.send(title, message, url)

Configuration

# In DealAgentConfig
notification_channels: List[str] = ["desktop"]  # 'desktop', 'webhook'
webhook_url: str = ""  # For Slack/Discord integration
alert_cooldown_hours: int = 24  # Don't re-alert for same product within this window

Environment Variables

Variable Required Description
GAIA_DEALS_WEBHOOK_URL No Webhook URL for Slack/Discord notifications
GAIA_DEALS_ALERT_COOLDOWN No Hours between alerts for same product (default: 24)

Alert Flow

Price check detects drop → Check watchlist threshold → Check cooldown timer
  → If threshold met AND cooldown expired:
      1. Send to all configured channels
      2. Update last_alerted_at in watchlist table
      3. Log alert in notification_history table

Notification History Table

CREATE TABLE notification_history (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    product_id INTEGER NOT NULL,
    channel TEXT NOT NULL,
    old_price REAL,
    new_price REAL,
    delivered BOOLEAN DEFAULT 1,
    sent_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (product_id) REFERENCES products(id)
);

Acceptance Criteria

  • Windows desktop toast notifications work (via plyer or win10toast)
  • Webhook notifications work for Slack, Discord, and generic endpoints
  • Alert cooldown prevents duplicate notifications
  • Notification history stored in SQLite
  • Graceful fallback: if desktop notification fails, log warning (don't crash)
  • gaia deals can show recent alerts: list_alerts tool
  • Unit tests with mocked notification channels
  • Integration test sending to a test webhook endpoint

Phase

Phase 2 — Tracking & Alerts

Dependencies

  • Watchlist management (Phase 2)
  • Scheduled price checking (Phase 2)

New Dependencies

Package Version License Purpose
plyer >=2.1 MIT Cross-platform desktop notifications

Metadata

Metadata

Assignees

No one assigned

    Labels

    agentdealsDealAgent: price tracking and deal discoveryenhancementNew feature or requestp1medium priority

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions