feat(briefing): differentiated check-in slots — midday progress nudge, afternoon wrap-up
This commit is contained in:
@@ -369,26 +369,77 @@ async def _llm_synthesise(system_prompt: str, user_prompt: str, model: str, num_
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
def _unified_system_prompt(profile_body: str) -> str:
|
def _unified_system_prompt(profile_body: str, slot: str = "compilation") -> str:
|
||||||
return (
|
base = (
|
||||||
"You are a personal assistant delivering a daily briefing. "
|
"You are a personal assistant. "
|
||||||
"Speak naturally and conversationally — as if talking to the user, not writing a report. "
|
"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. "
|
"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 "
|
"Be warm, concise, and human. "
|
||||||
"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. "
|
|
||||||
"The user can reply to act on your suggestions via tool calls.\n\n"
|
"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:
|
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}", ""]
|
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 (brief — card handles detail)
|
||||||
weather = external_data.get("weather") or []
|
weather = external_data.get("weather") or []
|
||||||
if weather:
|
if weather:
|
||||||
@@ -590,7 +641,7 @@ async def run_compilation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
briefing_text = await _llm_synthesise(
|
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),
|
_unified_user_prompt(internal_data_filtered, external_data_filtered, slot, temp_unit),
|
||||||
model,
|
model,
|
||||||
num_ctx=8192,
|
num_ctx=8192,
|
||||||
|
|||||||
Reference in New Issue
Block a user