Remove CalDAV todo tools; overhaul quick-capture

- Remove all 6 CalDAV todo tools (create/list/update/complete/delete/search_todos)
  from tools.py definitions, imports, execute_tool branches, intent routing rules,
  generation_task labels/actions, and llm.py system prompt hints. CalDAV event
  tools remain. Todo functions still exist in caldav.py but are no longer exposed.

- Quick-capture now uses a dedicated classify_capture_intent() with a focused
  _CAPTURE_SYSTEM_PROMPT that always routes to a tool (never null). Tool set
  expanded: create_note/task/event + update_note + research_topic.

- research_topic in quick-capture calls run_research_pipeline() directly (no SSE
  buffer). run_research_pipeline() now accepts buf=None; all buf.append_event
  calls are guarded so status events are skipped when no buffer is provided.

- Fallback note now always sets body=text (was empty for texts ≤80 chars).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-01 19:13:07 -05:00
parent 4c77eab84b
commit 6f5170854b
7 changed files with 122 additions and 318 deletions
-267
View File
@@ -5,19 +5,13 @@ import logging
from datetime import date, datetime
from fabledassistant.services.caldav import (
complete_todo,
create_event,
create_todo,
delete_event,
delete_todo,
is_caldav_configured,
list_calendars,
list_events,
list_todos,
search_events,
search_todos,
update_event,
update_todo,
)
from fabledassistant.config import Config
from fabledassistant.services.notes import create_note, delete_note, get_note_by_title, list_notes, update_note
@@ -489,178 +483,6 @@ _CALDAV_TOOLS = [
},
},
},
{
"type": "function",
"function": {
"name": "create_todo",
"description": "Create a CalDAV todo item on the calendar server. Use this when the user explicitly asks to create a calendar todo or CalDAV todo (NOT for regular app tasks).",
"parameters": {
"type": "object",
"properties": {
"summary": {
"type": "string",
"description": "The todo summary/title",
},
"due": {
"type": "string",
"description": "Optional due date/datetime in ISO 8601 format",
},
"description": {
"type": "string",
"description": "Optional description",
},
"priority": {
"type": "integer",
"description": "Optional priority (1=highest, 9=lowest)",
},
"reminder_minutes": {
"type": "integer",
"description": "Optional reminder N minutes before due date",
},
"timezone": {
"type": "string",
"description": "Optional IANA timezone (e.g. 'America/New_York')",
},
"calendar_name": {
"type": "string",
"description": "Optional calendar name",
},
},
"required": ["summary"],
},
},
},
{
"type": "function",
"function": {
"name": "list_todos",
"description": "List CalDAV todos from the calendar server. Use this when the user asks to see their calendar todos.",
"parameters": {
"type": "object",
"properties": {
"include_completed": {
"type": "boolean",
"description": "Whether to include completed todos (default false)",
},
"calendar_name": {
"type": "string",
"description": "Optional calendar name",
},
},
},
},
},
{
"type": "function",
"function": {
"name": "update_todo",
"description": "Update a CalDAV todo's summary, due date, description, or priority.",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Search term to find the todo to update (matches against summary)",
},
"summary": {
"type": "string",
"description": "New summary/title for the todo",
},
"due": {
"type": "string",
"description": "New due date or datetime in ISO 8601 format",
},
"description": {
"type": "string",
"description": "New description",
},
"priority": {
"type": "integer",
"description": "New priority (1=highest, 9=lowest)",
},
"timezone": {
"type": "string",
"description": "Optional IANA timezone for due datetime",
},
"calendar_name": {
"type": "string",
"description": "Optional calendar name to search in",
},
},
"required": ["query"],
},
},
},
{
"type": "function",
"function": {
"name": "complete_todo",
"description": "Mark a CalDAV todo as completed. Use this when the user says they finished or completed a calendar todo.",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Search term to find the todo to complete (matches against summary)",
},
"calendar_name": {
"type": "string",
"description": "Optional calendar name",
},
},
"required": ["query"],
},
},
},
{
"type": "function",
"function": {
"name": "delete_todo",
"description": "Delete a CalDAV todo. Use this when the user asks to remove or delete a calendar todo.",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Search term to find the todo to delete (matches against summary)",
},
"calendar_name": {
"type": "string",
"description": "Optional calendar name",
},
},
"required": ["query"],
},
},
},
{
"type": "function",
"function": {
"name": "search_todos",
"description": (
"Search CalDAV todos by keyword. Use this when the user asks to find a specific calendar todo "
"by name or content, rather than listing all todos."
),
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Keyword to search for in todo summary or description",
},
"include_completed": {
"type": "boolean",
"description": "Include completed todos in search (default false)",
},
"calendar_name": {
"type": "string",
"description": "Optional calendar name to restrict search",
},
},
"required": ["query"],
},
},
},
]
@@ -1040,95 +862,6 @@ async def execute_tool(user_id: int, tool_name: str, arguments: dict) -> dict:
},
}
elif tool_name == "create_todo":
result = await create_todo(
user_id=user_id,
summary=arguments.get("summary", "Untitled Todo"),
due=arguments.get("due"),
description=arguments.get("description"),
priority=arguments.get("priority"),
reminder_minutes=arguments.get("reminder_minutes"),
timezone=arguments.get("timezone"),
calendar_name=arguments.get("calendar_name"),
)
return {
"success": True,
"type": "todo",
"data": result,
}
elif tool_name == "list_todos":
todos = await list_todos(
user_id=user_id,
include_completed=arguments.get("include_completed", False),
calendar_name=arguments.get("calendar_name"),
)
return {
"success": True,
"type": "todos",
"data": {
"count": len(todos),
"todos": todos,
},
}
elif tool_name == "update_todo":
result = await update_todo(
user_id=user_id,
query=arguments["query"],
summary=arguments.get("summary"),
due=arguments.get("due"),
description=arguments.get("description"),
priority=arguments.get("priority"),
timezone=arguments.get("timezone"),
calendar_name=arguments.get("calendar_name"),
)
return {
"success": True,
"type": "todo_updated",
"data": result,
}
elif tool_name == "complete_todo":
result = await complete_todo(
user_id=user_id,
query=arguments["query"],
calendar_name=arguments.get("calendar_name"),
)
return {
"success": True,
"type": "todo_completed",
"data": result,
}
elif tool_name == "delete_todo":
result = await delete_todo(
user_id=user_id,
query=arguments["query"],
calendar_name=arguments.get("calendar_name"),
)
return {
"success": True,
"type": "todo_deleted",
"data": result,
}
elif tool_name == "search_todos":
results = await search_todos(
user_id=user_id,
query=arguments.get("query", ""),
include_completed=bool(arguments.get("include_completed", False)),
calendar_name=arguments.get("calendar_name"),
)
return {
"success": True,
"type": "todos",
"data": {
"count": len(results),
"todos": results,
},
}
elif tool_name == "get_note":
query = arguments.get("query", "")
note = await get_note_by_title(user_id, query)