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:
@@ -11,17 +11,16 @@ from quart import Blueprint, jsonify, request
|
||||
|
||||
from fabledassistant.auth import get_current_user_id, login_required
|
||||
from fabledassistant.config import Config
|
||||
from fabledassistant.services.intent import classify_intent
|
||||
from fabledassistant.services.intent import classify_capture_intent
|
||||
from fabledassistant.services.tools import execute_tool, get_tools_for_user
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
quick_capture_bp = Blueprint("quick_capture", __name__, url_prefix="/api/quick-capture")
|
||||
|
||||
# Only creation tools are offered to the intent classifier here — no delete,
|
||||
# update, search, or research. This keeps the fallback safe (worst case we
|
||||
# create a plain note) and avoids accidental destructive actions.
|
||||
_CAPTURE_TOOL_NAMES = {"create_note", "create_task", "create_event", "create_todo"}
|
||||
# Tools offered to the quick-capture classifier. Excludes destructive ops
|
||||
# (delete_*) and read-only queries — worst-case fallback is a plain note.
|
||||
_CAPTURE_TOOL_NAMES = {"create_note", "create_task", "create_event", "update_note", "research_topic"}
|
||||
|
||||
|
||||
@quick_capture_bp.route("", methods=["POST"])
|
||||
@@ -42,21 +41,43 @@ async def quick_capture_route():
|
||||
t for t in all_tools if t.get("function", {}).get("name") in _CAPTURE_TOOL_NAMES
|
||||
]
|
||||
|
||||
intent = await classify_intent(text, capture_tools, intent_model)
|
||||
intent = await classify_capture_intent(text, capture_tools, intent_model)
|
||||
|
||||
if intent.should_execute:
|
||||
# research_topic bypasses execute_tool — run the pipeline directly
|
||||
if intent.tool_name == "research_topic" and Config.searxng_enabled():
|
||||
from fabledassistant.services.research import run_research_pipeline
|
||||
|
||||
topic = intent.arguments.get("topic", text)
|
||||
model = Config.OLLAMA_MODEL
|
||||
try:
|
||||
note = await run_research_pipeline(topic, uid, model, intent_model)
|
||||
logger.info(
|
||||
"Quick-capture uid=%d: research note id=%d '%s'",
|
||||
uid, note.id, note.title,
|
||||
)
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"type": "note",
|
||||
"message": f"Research note created: {note.title}",
|
||||
"data": {"id": note.id, "title": note.title},
|
||||
})
|
||||
except Exception as exc:
|
||||
logger.exception("Quick-capture research failed for topic: %s", topic)
|
||||
return jsonify({"error": f"Research failed: {exc}"}), 500
|
||||
|
||||
result = await execute_tool(uid, intent.tool_name, intent.arguments)
|
||||
if result.get("success"):
|
||||
item_type = result.get("type", "note")
|
||||
title = (result.get("data") or {}).get("title", "")
|
||||
logger.info(
|
||||
"Quick-capture uid=%d: created %s '%s' via intent '%s'",
|
||||
"Quick-capture uid=%d: %s '%s' via intent '%s'",
|
||||
uid, item_type, title, intent.tool_name,
|
||||
)
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"type": item_type,
|
||||
"message": f"{item_type.capitalize()} created: {title}",
|
||||
"message": f"{item_type.capitalize()}: {title}",
|
||||
"data": result.get("data"),
|
||||
})
|
||||
logger.warning(
|
||||
@@ -66,13 +87,9 @@ async def quick_capture_route():
|
||||
# Fall through to plain-note fallback
|
||||
|
||||
# Fallback: create a plain note with the raw text as the body.
|
||||
# Use the first 80 chars as the title so short snippets look clean.
|
||||
if len(text) <= 80:
|
||||
fallback_title = text
|
||||
fallback_body = ""
|
||||
else:
|
||||
fallback_title = text[:77] + "..."
|
||||
fallback_body = text
|
||||
# Always preserve the full text as the body; derive a short title.
|
||||
fallback_title = text if len(text) <= 80 else text[:77] + "..."
|
||||
fallback_body = text
|
||||
|
||||
result = await execute_tool(
|
||||
uid, "create_note", {"title": fallback_title, "body": fallback_body}
|
||||
|
||||
Reference in New Issue
Block a user