From 3687fbeeb91a9af948f3e5de151488de06564b3f Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Wed, 8 Apr 2026 22:09:18 -0400 Subject: [PATCH] =?UTF-8?q?feat(briefing):=20differentiated=20check-in=20s?= =?UTF-8?q?lots=20=E2=80=94=20midday=20progress=20nudge,=20afternoon=20wra?= =?UTF-8?q?p-up?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../services/briefing_pipeline.py | 75 ++++++++++++++++--- 1 file changed, 63 insertions(+), 12 deletions(-) diff --git a/src/fabledassistant/services/briefing_pipeline.py b/src/fabledassistant/services/briefing_pipeline.py index b5900fa..fc5a2f0 100644 --- a/src/fabledassistant/services/briefing_pipeline.py +++ b/src/fabledassistant/services/briefing_pipeline.py @@ -369,26 +369,77 @@ async def _llm_synthesise(system_prompt: str, user_prompt: str, model: str, num_ return "" -def _unified_system_prompt(profile_body: str) -> str: - return ( - "You are a personal assistant delivering a daily briefing. " +def _unified_system_prompt(profile_body: str, slot: str = "compilation") -> str: + base = ( + "You are a personal assistant. " "Speak naturally and conversationally — as if talking to the user, not writing a report. " "Use no markdown: no headers, no bullet points, no bold, no lists. Write in flowing prose. " - "Weave together what matters today: mention the weather in a sentence, note any calendar " - "events or tasks due today, and briefly reference one or two noteworthy news stories. " - "Only mention projects if a task from one is specifically due today. " - "Be warm, concise, and human — aim for 4 to 8 sentences.\n\n" - "IMPORTANT: Be actionable, not just informational. For overdue or due-today tasks, " - "suggest a concrete next step — offer to reschedule, mark in progress, or break it down. " - "For upcoming events, mention if preparation might help. " + "Be warm, concise, and human. " "The user can reply to act on your suggestions via tool calls.\n\n" - + (f"User profile:\n{profile_body}\n" if profile_body else "") ) + if slot == "compilation": + base += ( + "This is the MORNING BRIEFING — the full daily overview. " + "Weave together what matters today: mention the weather, note calendar events and tasks, " + "briefly reference one or two noteworthy news themes, and suggest a daily focus. " + "Be actionable: for overdue or due-today tasks, suggest a concrete next step. " + "Aim for 4 to 8 sentences.\n\n" + ) + elif slot in ("morning", "midday"): + base += ( + "This is a MIDDAY CHECK-IN — brief progress nudge, not a full briefing. " + "Focus on what's been done and what hasn't been touched yet today. " + "If weather conditions have changed, mention it briefly. " + "Keep it to 2-3 sentences. Don't repeat news or the full task list.\n\n" + ) + elif slot == "afternoon": + base += ( + "This is the AFTERNOON WRAP-UP — help the user close out the day. " + "Summarize what was accomplished today. Flag anything still overdue. " + "Ask if there's anything to capture before tomorrow — notes, thoughts, follow-ups. " + "Keep it to 2-4 sentences. Reflective and encouraging tone.\n\n" + ) + + if profile_body: + base += f"User profile:\n{profile_body}\n" + return base + def _unified_user_prompt(internal_data: dict, external_data: dict, slot: str, temp_unit: str = "C") -> str: lines = [f"Date: {internal_data['date']}", f"Slot: {slot}", ""] + # For check-in slots, build a slimmer prompt + if slot in ("morning", "midday"): + # Just tasks status + any weather changes + if internal_data.get("due_today"): + lines.append("TASKS DUE TODAY (note which are still untouched):") + lines.extend(f" - {t}" for t in internal_data["due_today"]) + lines.append("") + if internal_data.get("overdue_tasks"): + lines.append(f"STILL OVERDUE: {len(internal_data['overdue_tasks'])} task(s)") + lines.append("") + if internal_data.get("calendar_events"): + lines.append("REMAINING EVENTS TODAY:") + lines.extend(f" - {e}" for e in internal_data["calendar_events"]) + lines.append("") + return "\n".join(lines) + + if slot == "afternoon": + if internal_data.get("due_today"): + lines.append("TASKS THAT WERE DUE TODAY:") + lines.extend(f" - {t}" for t in internal_data["due_today"]) + lines.append("") + if internal_data.get("overdue_tasks"): + overdue = internal_data["overdue_tasks"] + lines.append(f"OVERDUE ({len(overdue)} remaining):") + lines.extend(f" - {t}" for t in overdue[:3]) + lines.append("") + lines.append("Ask the user if there's anything to capture before tomorrow — a note, a thought, a follow-up task.") + return "\n".join(lines) + + # ── Full compilation prompt below ────────────────────────────────────────── + # Weather (brief — card handles detail) weather = external_data.get("weather") or [] if weather: @@ -590,7 +641,7 @@ async def run_compilation( } briefing_text = await _llm_synthesise( - _unified_system_prompt(profile_context), + _unified_system_prompt(profile_context, slot), _unified_user_prompt(internal_data_filtered, external_data_filtered, slot, temp_unit), model, num_ctx=8192,