feat(journal): backend services (moments, search, prep, scheduler, pipeline)

- services/moments.py — CRUD with embedding sync + entity-link helpers
- services/journal_search.py — three-mode search (temporal / entity / semantic)
  with notes-RAG isolation; cosine-similarity helper unit-tested
- services/journal_prep.py — gathers tasks/events/weather/news/projects/
  recent-moments/open-threads into a structured prep block
- services/journal_scheduler.py — per-user APScheduler cron for daily prep,
  follows the BackgroundScheduler + threadsafe-async pattern from event_scheduler
- services/journal_pipeline.py — system prompt (persona + calibration rules)
  with last-48h ambient moments injection
- app.py: wire journal scheduler start/stop hooks
- routes/settings.py: re-add live-reschedule on timezone change (now via
  journal_scheduler.update_user_schedule)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-04-25 22:37:39 -04:00
parent 7602bf2293
commit d9ab538ef4
7 changed files with 863 additions and 3 deletions
+4 -2
View File
@@ -94,8 +94,10 @@ async def update_settings_route():
if to_save:
await set_settings_batch(uid, to_save)
# Journal scheduler live-reschedule on timezone change is wired up in
# services/journal_scheduler.update_user_schedule (Stage C).
# Live-reschedule the journal daily-prep job when the timezone changes.
if "user_timezone" in to_save:
from fabledassistant.services.journal_scheduler import update_user_schedule as _update_journal_schedule
await _update_journal_schedule(uid)
if "default_model" in to_save and to_save["default_model"]:
asyncio.create_task(_prime_kv_cache_bg(uid, to_save["default_model"]))