Schedule reminders by mentioning the Discord bot

メンション本文にリマインド系のキーワードが含まれていたとき、LLM に
create_reminder / list_reminders / cancel_reminder の3ツールを渡し、
自然言語から日時と用件を取り出して reminders テーブルに保存する。
system メッセージに現在時刻を入れてあるので『明日』『30分後』のような
相対表現はモデル側が絶対日時に直す。扱うのは一回きりの通知のみ。

配信は APScheduler の discord_reminders ジョブ(既定30秒間隔)が担い、
Webhook ではなく Bot クライアントから登録元チャンネルへ依頼者を
メンションして送るため、専用の Webhook URL 設定は要らない。

- 日時は他テーブルと同じく UTC で保存し、ユーザー・LLM とのやり取りは
  ローカル時刻で行って reminders.py の境界で変換する
- 過去・REMINDER_MAX_AHEAD_DAYS より先・解釈不能な日時はツール結果として
  エラー文をモデルに返し、聞き直させる
- 一覧・取り消しは依頼者の user_id で絞るため他人のリマインドには触れない
- 配信に5回失敗したら notified_at を立てて諦める(チャンネル削除などで
  ポーリングのたびにエラーログを出し続けるのを防ぐ)。カウンタは
  プロセス内のみなので、再起動すればまた試す

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-23 23:29:55 +09:00
co-authored by Claude Opus 5
parent 3b30dab650
commit c1aba42cf8
8 changed files with 499 additions and 0 deletions
+10
View File
@@ -10,6 +10,7 @@ from apscheduler.triggers.interval import IntervalTrigger
from app.core.config import (
DISCORD_WEBHOOK_URL,
DISCORD_WEBHOOK_URL_TIPS,
REMINDER_CHECK_INTERVAL_SECONDS,
USELESS_TIPS_ENABLED,
USELESS_TIPS_INTERVAL_HOURS,
USELESS_TIPS_MODEL,
@@ -21,6 +22,7 @@ from app.core.config import (
)
from app.core.llm import complete
from app.core.discord.notify import send_discord_message
from app.core.discord.reminders import deliver_due_reminders
from app.core.weather.weather import fetch_tomorrow_weather, judge_laundry
from app.core.weather.weather_cache import set_latest
from app.core.memory_kb.word_memory import pick_random_word
@@ -144,4 +146,12 @@ def start_scheduler() -> None:
)
logger.info("Useless tips job started: every %d hour(s)", USELESS_TIPS_INTERVAL_HOURS)
scheduler.add_job(
deliver_due_reminders,
trigger=IntervalTrigger(seconds=REMINDER_CHECK_INTERVAL_SECONDS),
id="discord_reminders",
replace_existing=True,
)
logger.info("Reminder delivery job started: every %d second(s)", REMINDER_CHECK_INTERVAL_SECONDS)
scheduler.start()