feat(briefing): project continuity — yesterday's activity and stale project warnings
This commit is contained in:
@@ -259,6 +259,45 @@ async def _gather_internal(user_id: int) -> dict:
|
|||||||
except Exception:
|
except Exception:
|
||||||
logger.debug("Weather cross-reference failed", exc_info=True)
|
logger.debug("Weather cross-reference failed", exc_info=True)
|
||||||
|
|
||||||
|
# Recent activity — what was the user working on yesterday?
|
||||||
|
recent_activity: list[str] = []
|
||||||
|
stale_projects: list[str] = []
|
||||||
|
try:
|
||||||
|
from sqlalchemy import select as _sel, func as _func
|
||||||
|
from fabledassistant.models.note import Note
|
||||||
|
from fabledassistant.models.project import Project
|
||||||
|
|
||||||
|
yesterday = datetime.now(user_tz) - __import__('datetime').timedelta(days=1)
|
||||||
|
async with async_session() as session:
|
||||||
|
# Notes/tasks updated in last 24h, grouped by project
|
||||||
|
result = await session.execute(
|
||||||
|
_sel(Project.title, _func.count(Note.id))
|
||||||
|
.join(Note, Note.project_id == Project.id)
|
||||||
|
.where(Note.user_id == user_id)
|
||||||
|
.where(Note.updated_at >= yesterday)
|
||||||
|
.group_by(Project.title)
|
||||||
|
.order_by(_func.count(Note.id).desc())
|
||||||
|
.limit(3)
|
||||||
|
)
|
||||||
|
for proj_title, count in result.all():
|
||||||
|
recent_activity.append(f"{proj_title}: {count} item{'s' if count != 1 else ''} updated")
|
||||||
|
|
||||||
|
# Stale projects — active projects with no note/task activity in 7+ days
|
||||||
|
week_ago = datetime.now(user_tz) - __import__('datetime').timedelta(days=7)
|
||||||
|
active_projects_q = await session.execute(
|
||||||
|
_sel(Project).where(Project.user_id == user_id, Project.status == "active")
|
||||||
|
)
|
||||||
|
for p in active_projects_q.scalars().all():
|
||||||
|
latest = await session.execute(
|
||||||
|
_sel(_func.max(Note.updated_at))
|
||||||
|
.where(Note.project_id == p.id, Note.user_id == user_id)
|
||||||
|
)
|
||||||
|
last_activity = latest.scalar()
|
||||||
|
if last_activity is None or last_activity < week_ago:
|
||||||
|
stale_projects.append(p.title or "Untitled")
|
||||||
|
except Exception:
|
||||||
|
logger.debug("Failed to gather recent activity for briefing", exc_info=True)
|
||||||
|
|
||||||
# Projects: active projects
|
# Projects: active projects
|
||||||
projects_summary = []
|
projects_summary = []
|
||||||
try:
|
try:
|
||||||
@@ -324,6 +363,8 @@ async def _gather_internal(user_id: int) -> dict:
|
|||||||
"focus_tasks": focus_tasks,
|
"focus_tasks": focus_tasks,
|
||||||
"event_time_blocks": event_time_blocks,
|
"event_time_blocks": event_time_blocks,
|
||||||
"weather_warnings": weather_warnings,
|
"weather_warnings": weather_warnings,
|
||||||
|
"recent_activity": recent_activity,
|
||||||
|
"stale_projects": stale_projects,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -600,6 +641,17 @@ def _unified_user_prompt(internal_data: dict, external_data: dict, slot: str, te
|
|||||||
lines.append(" (Identify free blocks between events for focused work.)")
|
lines.append(" (Identify free blocks between events for focused work.)")
|
||||||
lines.append("")
|
lines.append("")
|
||||||
|
|
||||||
|
# Project continuity — what was the user working on?
|
||||||
|
if internal_data.get("recent_activity") and slot == "compilation":
|
||||||
|
lines.append("YESTERDAY'S ACTIVITY (mention what the user was working on to help them pick up):")
|
||||||
|
lines.extend(f" - {a}" for a in internal_data["recent_activity"])
|
||||||
|
lines.append("")
|
||||||
|
|
||||||
|
if internal_data.get("stale_projects") and slot == "compilation":
|
||||||
|
lines.append("STALE PROJECTS (no activity in 7+ days — gently flag):")
|
||||||
|
lines.extend(f" - {p}" for p in internal_data["stale_projects"])
|
||||||
|
lines.append("")
|
||||||
|
|
||||||
# News — clustered by topic for thematic synthesis
|
# News — clustered by topic for thematic synthesis
|
||||||
rss = external_data.get("rss_items") or []
|
rss = external_data.get("rss_items") or []
|
||||||
if rss:
|
if rss:
|
||||||
|
|||||||
Reference in New Issue
Block a user