Switch default model to qwen3 and add intent routing for reliable tool calling

Mistral didn't reliably use Ollama's structured tool calling API — it wrote
tool calls as JSON text instead of invoking them. This adds an intent routing
layer that classifies user intent via a fast non-streaming LLM call before
streaming, executing detected tools directly and bypassing native tool calling.

- Change default OLLAMA_MODEL from mistral to qwen3
- Add intent.py: classify_intent() with JSON parsing and fallback regex
- Integrate intent routing into generation_task.py round 0
- Add all-day event support (iCalendar DATE values) to CalDAV service
- Add recurring event support (RRULE) to CalDAV service and tool definition
- Improve create_event tool description for descriptive titles
- Enhance system prompt with structured tool usage guidance

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-16 16:24:01 -05:00
parent d7bc3f3222
commit 75560dee4e
7 changed files with 272 additions and 31 deletions
+14 -4
View File
@@ -98,19 +98,19 @@ _CALDAV_TOOLS = [
"properties": {
"title": {
"type": "string",
"description": "The event title",
"description": "A descriptive event title (e.g. 'John's Birthday' not just 'Birthday')",
},
"start": {
"type": "string",
"description": "Start date/time in ISO 8601 format (e.g. 2025-01-15T14:00:00)",
"description": "Start date (YYYY-MM-DD for all-day) or datetime (ISO 8601, e.g. 2025-01-15T14:00:00)",
},
"end": {
"type": "string",
"description": "Optional end date/time in ISO 8601 format",
"description": "Optional end date or datetime in same format as start",
},
"duration": {
"type": "integer",
"description": "Optional duration in minutes (default 60, ignored if end is set)",
"description": "Optional duration in minutes (default 60, ignored if end is set or all_day is true)",
},
"description": {
"type": "string",
@@ -120,6 +120,14 @@ _CALDAV_TOOLS = [
"type": "string",
"description": "Optional event location",
},
"all_day": {
"type": "boolean",
"description": "Set to true for all-day events like birthdays, holidays, deadlines (default false)",
},
"recurrence": {
"type": "string",
"description": "Optional iCalendar RRULE (e.g. 'FREQ=YEARLY' for annual, 'FREQ=WEEKLY' for weekly, 'FREQ=MONTHLY' for monthly)",
},
},
"required": ["title", "start"],
},
@@ -264,6 +272,8 @@ async def execute_tool(user_id: int, tool_name: str, arguments: dict) -> dict:
duration=arguments.get("duration"),
description=arguments.get("description"),
location=arguments.get("location"),
all_day=arguments.get("all_day", False),
recurrence=arguments.get("recurrence"),
)
return {
"success": True,