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:
@@ -84,15 +84,9 @@ Rules:
|
||||
- "what are my overdue tasks", "show overdue", "tasks due today", "high priority tasks", "in progress tasks", "what's due this week" → use list_tasks with appropriate status/priority/due_before/due_after filters. For overdue, set due_before to today's date.
|
||||
- If a note was created earlier in the conversation and the user provides more content for it, use update_note (not create_note).
|
||||
- Use create_note ONLY when the user explicitly wants a brand new note that doesn't already exist.
|
||||
- "update", "change", "rename", "set due date on" a CalDAV todo → use update_todo.
|
||||
- "update", "change", "move", "reschedule" an event → use update_event.
|
||||
- "delete", "cancel", "remove" an event → use delete_event.
|
||||
- "which calendars", "list calendars", "my calendars" → use list_calendars.
|
||||
- "create a calendar todo", "add a CalDAV todo" → use create_todo. Default to create_task for general tasks unless the user explicitly mentions CalDAV or calendar todo.
|
||||
- "show calendar todos", "list calendar todos" → use list_todos.
|
||||
- "find calendar todo", "search calendar todos", "find todo named X" → use search_todos with query=<keyword>.
|
||||
- "completed/finished calendar todo" → use complete_todo.
|
||||
- "delete/remove calendar todo" → use delete_todo.
|
||||
- "remind me X minutes/hours before" an event → convert to reminder_minutes parameter on create_event.
|
||||
- When the user asks about events in a time period (e.g. "events in September", "what's on next week", "my schedule for March"), use list_events with date_from/date_to covering that period. Do NOT use search_events for time-based queries — search_events is only for keyword matching against event titles.
|
||||
- "delete", "remove", "trash", "get rid of" a note (not a task) → use delete_note with query=<note name/keyword>. NEVER use this for tasks.
|
||||
@@ -279,3 +273,74 @@ def _try_json(text: str) -> dict | list | None:
|
||||
return json.loads(text)
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
return None
|
||||
|
||||
|
||||
# ── Quick-capture classifier ──────────────────────────────────────────────────
|
||||
# A stripped-down prompt designed for the /api/quick-capture endpoint.
|
||||
# Unlike the general intent prompt, this ALWAYS routes to a create tool —
|
||||
# null is not a valid response.
|
||||
|
||||
_CAPTURE_SYSTEM_PROMPT = """\
|
||||
You are a quick-capture classifier. The user has sent a short snippet of text \
|
||||
from a mobile app or external client. Classify it as a note, task, or calendar \
|
||||
event, then extract the relevant fields.
|
||||
|
||||
Today's date is {today}.
|
||||
|
||||
Available tools:
|
||||
{tool_summary}
|
||||
|
||||
Rules:
|
||||
- You MUST choose one of the available tools. Never return null.
|
||||
- create_task: action items, todos, reminders, things to do ("buy milk", "call John", "fix the bug", "remind me to…")
|
||||
- create_event: appointments, meetings, scheduled occurrences with a date/time ("dentist Friday 2pm", "team meeting next Tuesday")
|
||||
- update_note: updating, editing, appending to an existing note or task ("add to my shopping list: eggs", "mark buy milk done", "append to my meeting notes", "update my project note")
|
||||
- research_topic: user wants a comprehensive research note from web sources ("research X", "look up X and make a note", "find everything about X", "compile a note on X")
|
||||
- create_note: everything else — ideas, observations, links, excerpts, longer text
|
||||
- For create_task / create_event: extract a concise title; put any extra detail in "body"
|
||||
- For create_note: use a short descriptive title (≤60 chars); put the FULL original text as "body"
|
||||
- For update_note: set "query" to the note or task title to find; set other fields as needed
|
||||
- For research_topic: set "topic" to the subject being researched
|
||||
- For dates use YYYY-MM-DD; for datetime use ISO 8601
|
||||
- confidence: "high" if the type is clear; "medium" if you're guessing
|
||||
|
||||
Respond with ONLY a JSON object:
|
||||
{{"tool": "tool_name", "arguments": {{...}}, "confidence": "high"|"medium"}}
|
||||
|
||||
Do NOT wrap in markdown code fences."""
|
||||
|
||||
|
||||
async def classify_capture_intent(
|
||||
text: str,
|
||||
tools: list[dict],
|
||||
model: str,
|
||||
) -> IntentResult:
|
||||
"""Classify quick-capture text and extract arguments.
|
||||
|
||||
Uses a simplified prompt that always routes to a create tool — never null.
|
||||
Returns IntentResult with tool_name set. Falls back to IntentResult() only
|
||||
on LLM/parse failure (caller should handle that case).
|
||||
"""
|
||||
if not tools:
|
||||
return IntentResult()
|
||||
|
||||
tool_summary = _build_tool_summary(tools)
|
||||
today = date_type.today().isoformat()
|
||||
|
||||
messages = [
|
||||
{
|
||||
"role": "system",
|
||||
"content": _CAPTURE_SYSTEM_PROMPT.format(
|
||||
today=today, tool_summary=tool_summary
|
||||
),
|
||||
},
|
||||
{"role": "user", "content": text},
|
||||
]
|
||||
|
||||
try:
|
||||
raw = await generate_completion(messages, model, max_tokens=300, num_ctx=2048)
|
||||
except Exception:
|
||||
logger.warning("Quick-capture intent LLM call failed", exc_info=True)
|
||||
return IntentResult()
|
||||
|
||||
return _parse_intent(raw, tools)
|
||||
|
||||
Reference in New Issue
Block a user