feat(briefing): surface news items in compilation via get_rss_items
The compilation prompt mentioned "news themes" but didn't name the tool, and the model was never calling get_rss_items. Result: today's briefing had zero news coverage despite the tool being wired up and in the allowlist. - Explicitly list the tools to call in the compilation prompt so get_rss_items gets invoked alongside list_tasks/list_events/get_weather. - When the model calls get_rss_items during a compilation run, intercept and return the already-scored/filtered items (topic prefs + reaction-weighted) instead of the raw feed dump execute_tool would return. Aligns the model's view of news with the sidebar's rss_item_ids metadata.
This commit is contained in:
@@ -73,13 +73,18 @@ def _agentic_system_prompt(
|
|||||||
if slot == "compilation":
|
if slot == "compilation":
|
||||||
base = (
|
base = (
|
||||||
"You are the user's personal assistant giving their full morning briefing. "
|
"You are the user's personal assistant giving their full morning briefing. "
|
||||||
"Use the tools available to see what's actually relevant today — tasks due, "
|
"Weave real data from tool calls into a warm, natural-sounding summary.\n\n"
|
||||||
"overdue items, events on the calendar, weather, news themes, project state — "
|
"Tools to call every compilation (skip only if you already know a category is empty):\n"
|
||||||
"and weave it into a warm, natural-sounding summary.\n\n"
|
"- list_tasks — what's due today, overdue, or in progress\n"
|
||||||
|
"- list_events — what's on the calendar today\n"
|
||||||
|
"- get_weather — today's forecast\n"
|
||||||
|
"- get_rss_items — recent news/blog items from the user's feeds\n"
|
||||||
|
"- list_projects (optional) — active project context for narrative continuity\n\n"
|
||||||
"Rules:\n"
|
"Rules:\n"
|
||||||
"- Call tools to see the data. Never assert facts you didn't learn from a tool.\n"
|
"- Call tools to see the data. Never assert facts you didn't learn from a tool.\n"
|
||||||
"- If a tool returns nothing (no events today, no overdue tasks), say so honestly. "
|
"- If a tool returns nothing (no events today, no overdue tasks, no news items), "
|
||||||
"Don't fabricate items to fill space.\n"
|
"say so honestly. Don't fabricate items to fill space.\n"
|
||||||
|
"- For news, pick one or two items worth mentioning — surface the theme, not a laundry list.\n"
|
||||||
"- Write flowing prose. No markdown, no headers, no bullet points.\n"
|
"- Write flowing prose. No markdown, no headers, no bullet points.\n"
|
||||||
"- Aim for 6 to 10 sentences. Skip topics that have nothing interesting.\n"
|
"- Aim for 6 to 10 sentences. Skip topics that have nothing interesting.\n"
|
||||||
"- Close on one or two concrete, actionable suggestions.\n\n"
|
"- Close on one or two concrete, actionable suggestions.\n\n"
|
||||||
@@ -131,6 +136,7 @@ async def run_agentic_briefing(
|
|||||||
slot: str,
|
slot: str,
|
||||||
model: str,
|
model: str,
|
||||||
conv_id: int | None = None,
|
conv_id: int | None = None,
|
||||||
|
rss_override: list[dict] | None = None,
|
||||||
) -> tuple[str, list[dict]]:
|
) -> tuple[str, list[dict]]:
|
||||||
"""
|
"""
|
||||||
Run the agentic briefing loop for a user and slot.
|
Run the agentic briefing loop for a user and slot.
|
||||||
@@ -234,7 +240,27 @@ async def run_agentic_briefing(
|
|||||||
arguments = {}
|
arguments = {}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = await execute_tool(user_id, tool_name, arguments, conv_id=conv_id)
|
if tool_name == "get_rss_items" and rss_override is not None:
|
||||||
|
# Use topic-scored/filtered items already computed by
|
||||||
|
# the briefing pipeline rather than the raw feed dump
|
||||||
|
# that execute_tool would return. Keeps the model's
|
||||||
|
# view of news aligned with the user's topic prefs
|
||||||
|
# and the sidebar's rss_item_ids metadata.
|
||||||
|
slim = [
|
||||||
|
{
|
||||||
|
"id": item.get("id"),
|
||||||
|
"title": item.get("title", ""),
|
||||||
|
"url": item.get("url", ""),
|
||||||
|
"source": item.get("feed_title", ""),
|
||||||
|
"summary": (item.get("content") or "")[:400],
|
||||||
|
"published_at": item.get("published_at"),
|
||||||
|
"topics": item.get("topics") or [],
|
||||||
|
}
|
||||||
|
for item in rss_override
|
||||||
|
]
|
||||||
|
result = {"success": True, "data": {"items": slim, "count": len(slim)}}
|
||||||
|
else:
|
||||||
|
result = await execute_tool(user_id, tool_name, arguments, conv_id=conv_id)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Tool %s failed during agentic briefing: %s", tool_name, exc,
|
"Tool %s failed during agentic briefing: %s", tool_name, exc,
|
||||||
@@ -338,7 +364,7 @@ async def run_compilation(
|
|||||||
weather_card = parse_weather_card_data(weather_rows[0], temp_unit) if weather_rows else None
|
weather_card = parse_weather_card_data(weather_rows[0], temp_unit) if weather_rows else None
|
||||||
|
|
||||||
briefing_text, agentic_messages = await run_agentic_briefing(
|
briefing_text, agentic_messages = await run_agentic_briefing(
|
||||||
user_id, slot, model, conv_id=None,
|
user_id, slot, model, conv_id=None, rss_override=filtered_rss,
|
||||||
)
|
)
|
||||||
|
|
||||||
metadata: dict = {
|
metadata: dict = {
|
||||||
|
|||||||
Reference in New Issue
Block a user