feat: proactive notifications — web_push channel + daily reminder check
Routes web_push through notification.py alongside NCT/email/Google Chat, and fires daily reminder summaries via the scheduler. - notification.py: _notify_web_push() + "web_push" case in notify(); all four channels (web_push/email/nextcloud/google_chat) now routable - scheduler.py: _run_reminder_check() daily at 09:00 — reads due reminders per persona via set_context(), formats up to 3 entries, calls notify() - routers/settings.py: "web_push" added to valid notification_channel values - static/settings.html: "Browser Push Notification" option in channel selector - TODO__Agents.md: proactive notifications section marked complete Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -114,6 +114,18 @@ async def _notify_google_chat(webhook_url: str, message: str, username: str) ->
|
||||
logger.error("notify Google Chat error for %s: %s", username, e)
|
||||
|
||||
|
||||
async def _notify_web_push(username: str, message: str) -> None:
|
||||
"""Send a browser push notification."""
|
||||
import push_utils
|
||||
result = await push_utils.send_push(username, "Cortex", message, "")
|
||||
if "error" in result:
|
||||
logger.warning("notify web_push error for %s: %s", username, result["error"])
|
||||
elif result.get("sent", 0) == 0:
|
||||
logger.debug("notify web_push: no subscriptions for %s", username)
|
||||
else:
|
||||
logger.info("notify web_push → %s (%d device(s))", username, result["sent"])
|
||||
|
||||
|
||||
async def notify(username: str, message: str, channel: str | None = None) -> None:
|
||||
"""Send a notification to the user's preferred outbound channel.
|
||||
|
||||
@@ -123,6 +135,7 @@ async def notify(username: str, message: str, channel: str | None = None) -> Non
|
||||
3. "nextcloud" if notification_room is configured
|
||||
4. Silent no-op
|
||||
|
||||
Supported channels: "web_push", "email", "nextcloud", "google_chat"
|
||||
Configure via home/{user}/channels.json — see module docstring.
|
||||
"""
|
||||
from auth_utils import get_user_channels
|
||||
@@ -137,7 +150,10 @@ async def notify(username: str, message: str, channel: str | None = None) -> Non
|
||||
else:
|
||||
return
|
||||
|
||||
if target == "email":
|
||||
if target == "web_push":
|
||||
await _notify_web_push(username, message)
|
||||
|
||||
elif target == "email":
|
||||
email_override = channels.get("notification_email", "").strip() or None
|
||||
await _notify_email(username, message, email_override=email_override)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user