feat: filter chat conversations by type; add get_weather and get_rss_items LLM tools

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-11 19:46:08 -04:00
parent ae3dff0952
commit 42b0d8c4ac
3 changed files with 67 additions and 4 deletions
+2 -1
View File
@@ -40,6 +40,7 @@ async def list_conversations_route():
uid = get_current_user_id()
limit = min(request.args.get("limit", 50, type=int), 500)
offset = request.args.get("offset", 0, type=int)
conv_type = request.args.get("type", "chat")
# Apply retention policy before returning list
retention_str = await get_setting(uid, "chat_retention_days", "90")
try:
@@ -48,7 +49,7 @@ async def list_conversations_route():
retention_days = 90
if retention_days > 0:
await cleanup_old_conversations(uid, retention_days)
conversations, total = await list_conversations(uid, limit=limit, offset=offset)
conversations, total = await list_conversations(uid, limit=limit, offset=offset, conv_type=conv_type)
return jsonify({
"conversations": conversations,
"total": total,
+6 -3
View File
@@ -46,12 +46,13 @@ async def get_conversation(
async def list_conversations(
user_id: int, limit: int = 50, offset: int = 0
user_id: int, limit: int = 50, offset: int = 0, conv_type: str = "chat"
) -> tuple[list[dict], int]:
async with async_session() as session:
total = await session.scalar(
select(func.count(Conversation.id)).where(
Conversation.user_id == user_id
Conversation.user_id == user_id,
Conversation.conversation_type == conv_type,
)
) or 0
@@ -65,7 +66,7 @@ async def list_conversations(
result = await session.execute(
select(Conversation, msg_count.label("message_count"))
.where(Conversation.user_id == user_id)
.where(Conversation.user_id == user_id, Conversation.conversation_type == conv_type)
.order_by(Conversation.updated_at.desc())
.limit(limit)
.offset(offset)
@@ -78,6 +79,8 @@ async def list_conversations(
"id": conv.id,
"title": conv.title,
"model": conv.model,
"conversation_type": conv.conversation_type,
"briefing_date": conv.briefing_date.isoformat() if conv.briefing_date else None,
"message_count": row[1],
"created_at": conv.created_at.isoformat(),
"updated_at": conv.updated_at.isoformat(),
+59
View File
@@ -478,6 +478,51 @@ _CORE_TOOLS = [
},
},
},
{
"type": "function",
"function": {
"name": "get_weather",
"description": (
"Get the current 7-day weather forecast for the user's configured locations. "
"Returns temperature, precipitation, and conditions for each day. "
"Also reports any changes since the last forecast was fetched."
),
"parameters": {
"type": "object",
"properties": {
"location_key": {
"type": "string",
"description": "Which location to focus on: 'home', 'work', or 'all'. Defaults to 'all'.",
}
},
"required": [],
},
},
},
{
"type": "function",
"function": {
"name": "get_rss_items",
"description": (
"Get recent items from the user's RSS feeds (news, blogs, Reddit, podcasts). "
"Returns titles, URLs, and summaries of recent posts."
),
"parameters": {
"type": "object",
"properties": {
"limit": {
"type": "integer",
"description": "Number of items to return (default 15, max 50)",
},
"category": {
"type": "string",
"description": "Filter by feed category (e.g. 'news', 'tech'). Omit for all.",
},
},
"required": [],
},
},
},
]
# CalDAV tools — only included when user has CalDAV configured
@@ -1568,6 +1613,20 @@ async def execute_tool(user_id: int, tool_name: str, arguments: dict) -> dict:
return {"success": False, "error": str(e)}
return {"success": True, "log": log.to_dict(), "task": note.title}
elif tool_name == "get_weather":
from fabledassistant.services.weather import get_cached_weather
location_key = arguments.get("location_key", "all")
locations = await get_cached_weather(user_id)
if location_key != "all":
locations = [loc for loc in locations if loc["location_key"] == location_key]
return {"data": {"locations": locations}}
elif tool_name == "get_rss_items":
from fabledassistant.services.rss import get_recent_items
limit = min(int(arguments.get("limit", 15)), 50)
items = await get_recent_items(user_id, limit=limit)
return {"data": {"items": items, "count": len(items)}}
else:
return {"success": False, "error": f"Unknown tool: {tool_name}"}