Files
hope-voice-api/agent/task_router.py
T
snowspeeder 321421e37f
Rebuild & Deploy / rebuild (push) Successful in 47s
fix: reliably dispatch and return background tasks
2026-08-29 07:29:38 -04:00

59 lines
2.2 KiB
Python

"""Deterministic routing hints for background voice tasks."""
from __future__ import annotations
import re
# Gemma is a small model and will sometimes promise to do work without actually
# calling dispatch_task. Force that tool for high-confidence background intents;
# the main prompt remains responsible for less obvious cases.
_BACKGROUND_TASK_RE = re.compile(
r"\b(?:"
r"latest|news|current events?|headlines?|prices?|scores?|"
r"research|look\s+up|search(?:\s+for)?|find\s+out|investigate|"
r"compare|comparison|pros\s+and\s+cons|"
r"plan|itinerary|schedule|"
r"write|draft|compose|rewrite|"
r"summari[sz]e|summary|analy[sz]e|analysis|review|report|"
r"recommend|recommendation|options?|developments?"
r")\b",
re.IGNORECASE,
)
_MEMORY_INTENT_RE = re.compile(
r"\b(?:remember|memory|memories|forget|write down|my name|"
r"what do you know about me|preference|preferences)\b",
re.IGNORECASE,
)
_DIRECT_WEATHER_TIME_RE = re.compile(
r"\b(?:weather|temperature|forecast|what time|current time|what day|today's date)\b",
re.IGNORECASE,
)
def should_force_background_task(text: str) -> bool:
"""Return whether a fresh user turn should be forced through dispatch_task.
This deliberately favors precise intent signals over trying to classify every
possible request. Memory stays on its authenticated MCP and straightforward
weather/time requests stay on their purpose-built tools.
"""
normalized = " ".join((text or "").split())
if not normalized or _MEMORY_INTENT_RE.search(normalized):
return False
if re.search(r"\b(?:my|saved)\s+notes?\b", normalized, re.IGNORECASE):
return False
match = _BACKGROUND_TASK_RE.search(normalized)
if not match:
return bool(re.search(r"\b(?:tell me about|give me an overview of)\b", normalized, re.I))
# Straightforward weather/time requests stay on the fast dedicated MCP.
# Comparisons, research, plans, and written reports still go background.
if _DIRECT_WEATHER_TIME_RE.search(normalized) and not re.search(
r"\b(?:compare|comparison|research|investigate|plan|write|draft|"
r"summari[sz]e|analy[sz]e|review|report)\b",
normalized,
re.IGNORECASE,
):
return False
return True