feat(journal): conversational LLM-generated daily prep (replaces card)

The structured prep card was data-rich but voiceless. Replaced with an
LLM-generated conversational opener — same shape the briefing's compilation
slot had — that renders as a normal assistant chat bubble at the top of
the day's conversation.

Backend (services/journal_prep.py):
- Renamed generate_daily_prep -> gather_daily_sections (still pure data
  fetching, no LLM); kept the old name as a backwards-compat alias.
- New _generate_prep_prose: hands the gathered sections to generate_completion
  with a warm-conversational system prompt; returns prose. Falls back to a
  plain greeting if the LLM call fails or no model is configured.
- ensure_daily_prep_message now persists the prep as role='assistant' with
  the prose as content. Structured sections stay on msg_metadata for
  provenance. Auto-upgrades legacy system-role preps in place on next call.

Frontend:
- Drop the <article class="daily-prep"> structured block from JournalView.
  The prep is now just the first chat bubble — picks up the existing
  Illuminated Transcript styling automatically.
- Drop dayMessages / prepMessage / prepSections / asArray helpers — no
  longer needed.
- ChatMessage hideMessage filter: comment refined to clarify it only
  catches LEGACY system-role prep rows. Current preps are assistant-role
  and render normally.

Net effect: open /journal -> first thing you see is a warm assistant bubble
that talks about your day -> input bar below to reply.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-04-26 15:42:30 -04:00
parent dda62265c9
commit c9f2134ad4
3 changed files with 212 additions and 116 deletions
+4 -3
View File
@@ -43,9 +43,10 @@ function formatMs(ms: number | null | undefined): string {
const metadata = computed(() => (props.message.metadata ?? {}) as Record<string, unknown>);
// Hide daily-prep system messages — they're rendered separately as a structured
// card in JournalView. Without this filter they render as a flat unstyled block
// inside the chat (no .role-system bubble styling exists).
// Hide LEGACY system-role daily_prep messages from earlier versions. The
// current journal prep is a normal assistant message (renders with proper
// bubble styling). Old system-role rows lurking in existing conversations
// would render as a flat unstyled block — filter them.
const hideMessage = computed(() =>
props.message.role === "system" && metadata.value.kind === "daily_prep"
);