2026-06-01 15:32:41 +10:00
""" Lightweight routing hints for chat requests that need tools.
These patterns are intentionally conservative . They only promote plain chat
to agent mode when the user asks the assistant to take an action , not when the
user asks how a feature works .
"""
from __future__ import annotations
import re
2026-06-04 22:20:04 +10:00
from dataclasses import dataclass
2026-06-01 15:32:41 +10:00
from typing import Iterable , Pattern
2026-06-04 22:20:04 +10:00
@dataclass ( frozen = True )
class ToolIntent :
""" A cheap, deterministic chat-to-agent routing decision. """
needs_tools : bool
category : str = " "
reason : str = " "
2026-06-01 15:32:41 +10:00
_ACTION_QUESTION = r " \ b(?:can|could|would|will) \ s+you \ s+ "
2026-06-04 22:20:04 +10:00
_ACTION_FOLLOWUP = (
r " \ b(?:you \ s+should \ s+be \ s+able \ s+to| "
r " (?:can|could|would|will|should) \ s+you| "
r " you \ s+(?:can|could|would|will|should|need \ s+to|have \ s+to)) \ s+ "
)
_PLEASE = r " ^ \ s*(?:(?:please|ok(?:ay)?|alright|right|sure|cool|great|thanks)[ \ s,.!-]+)* "
2026-06-01 15:32:41 +10:00
2026-06-04 22:20:04 +10:00
_CALENDAR_ACTION = (
r " (?:add|adding|create|creating|recreate|recreating|schedule|scheduling| "
r " reschedule|rescheduling|book|booking|put|set \ s+up|make|making| "
r " delete|deleting|remove|removing|cancel|cancelling|canceling) "
)
2026-06-01 15:32:41 +10:00
_CALENDAR_THING = r " (?:calendar|calendar \ s+(?:entry|item)|event|meeting|appointment|entry|call) "
2026-06-05 08:24:04 +00:00
_CALENDAR_READ_THING = r " (?:calendar|schedule|events?|meetings?|appointments?|classes?) "
2026-06-04 22:20:04 +10:00
_EXPLANATORY_PREFIX = re . compile (
r " ^ \ s*(?:how \ s+(?:do|can) \ s+i|can \ s+you \ s+explain|what \ s+about|tell \ s+me \ s+how|show \ s+me \ s+how) \ b " ,
re . I ,
)
2026-06-01 15:32:41 +10:00
_PANEL = (
r " (?:calendar|notes?|inbox|email|mail|documents?|docs|library|gallery| "
r " settings|cookbook|sessions?|chats?|skills|memories|memory|brain) "
)
2026-06-04 22:20:04 +10:00
_ROUTING_PATTERNS : tuple [ tuple [ str , str , Pattern [ str ] ] , . . . ] = tuple (
( category , reason , re . compile ( pattern , re . I ) )
for category , reason , pattern in (
2026-06-01 15:32:41 +10:00
# Calendar/event creation. Covers "Can you add an entry to my
2026-06-04 22:20:04 +10:00
# calendar?", imperatives like "add lunch to my calendar", and
# follow-ups such as "you should be able to create that event now".
( " calendar " , " assistant calendar action request " , rf " { _ACTION_QUESTION } { _CALENDAR_ACTION } \ b. {{ 0,120 }} \ b { _CALENDAR_THING } \ b " ) ,
( " calendar " , " calendar follow-up action request " , rf " { _ACTION_FOLLOWUP } { _CALENDAR_ACTION } \ b. {{ 0,120 }} \ b { _CALENDAR_THING } \ b " ) ,
( " calendar " , " calendar imperative action request " , rf " { _PLEASE } { _CALENDAR_ACTION } \ b. {{ 0,120 }} \ b { _CALENDAR_THING } \ b " ) ,
( " calendar " , " calendar target action request " , rf " { _PLEASE } { _CALENDAR_ACTION } \ b. {{ 0,120 }} \ b(?:to|on|in|into|for) \ s+(?:my \ s+|the \ s+|this \ s+)?calendar \ b " ) ,
( " calendar " , " calendar item action request " , rf " { _PLEASE } { _CALENDAR_ACTION } \ s+(?:it \ s+)?(?:a \ s+|an \ s+)?(?:calendar \ s+)?(?:event|meeting|appointment|entry|item|call) \ b " ) ,
( " calendar " , " calendar target action request " , rf " \ b { _CALENDAR_ACTION } \ b. {{ 0,120 }} \ b(?:to|on|in|into|for) \ s+(?:my \ s+|the \ s+|this \ s+)?calendar \ b " ) ,
( " calendar " , " put item on calendar request " , r " \ bput \ s+.+ \ bon \ s+(?:my \ s+)?calendar \ b " ) ,
2026-06-01 15:32:41 +10:00
2026-06-05 08:24:04 +00:00
# Calendar/event lookup. A question such as "Do I have Taekwondo
# classes this week?" needs the calendar tool; plain chat cannot know.
( " calendar " , " calendar lookup request " , rf " \ b(?:list|show|check|find) \ b. {{ 0,120 }} \ b(?:my \ s+|the \ s+)?(?:upcoming|next|today ' ?s?|tomorrow ' ?s?|this \ s+week ' ?s?) \ b. {{ 0,120 }} \ b { _CALENDAR_READ_THING } \ b " ) ,
( " calendar " , " calendar lookup question " , rf " \ b(?:what|which) \ b. {{ 0,120 }} \ b(?:upcoming|next|today ' ?s?|tomorrow ' ?s?|this \ s+week ' ?s?) \ b. {{ 0,120 }} \ b { _CALENDAR_READ_THING } \ b " ) ,
( " calendar " , " calendar availability question " , rf " \ bdo \ s+i \ s+have \ b. {{ 0,120 }} \ b(?:upcoming|next|today|tomorrow|this \ s+week) \ b. {{ 0,120 }} \ b { _CALENDAR_READ_THING } \ b " ) ,
( " calendar " , " calendar agenda question " , r " \ bwhat(?: ' s| is) \ s+on \ s+(?:my \ s+)?calendar \ b " ) ,
( " calendar " , " next calendar item question " , r " \ bwhen \ s+(?:is|are) \ s+(?:my \ s+)?next \ s+(?:event|meeting|appointment|class) \ b " ) ,
2026-06-01 15:32:41 +10:00
# Notes, todos, checklists, and reminders.
2026-06-04 22:20:04 +10:00
( " notes " , " reminder request " , r " \ bremind \ s+me \ b " ) ,
( " notes " , " assistant note/todo action request " , rf " { _ACTION_QUESTION } (?:add|create|make|take|jot|write \ s+down|set) \ b. {{ 0,120 }} \ b(?:note|todo|task|checklist|reminder) \ b " ) ,
( " notes " , " note/todo imperative request " , rf " { _PLEASE } (?:add|create|make) \ s+(?:a \ s+|an \ s+)?(?:todo|task|reminder|note|checklist) \ b " ) ,
( " notes " , " take note request " , rf " { _PLEASE } (?:take|jot|write \ s+down) \ s+(?:a \ s+|an \ s+)?note \ b " ) ,
( " notes " , " add item to notes/todo request " , rf " { _PLEASE } (?:add|jot|write \ s+down) \ b. {{ 0,120 }} \ b(?:to|in|into) \ s+(?:my \ s+|the \ s+)?(?:todo(?: \ s+list)?|task \ s+list|notes?|checklist) \ b " ) ,
( " notes " , " set reminder request " , rf " { _PLEASE } set \ s+(?:a \ s+)?reminder \ b " ) ,
( " notes " , " assistant reminder request " , rf " { _ACTION_QUESTION } set \ s+(?:a \ s+)?reminder \ b " ) ,
2026-06-01 15:32:41 +10:00
# Email actions.
2026-06-04 22:20:04 +10:00
( " email " , " assistant email action request " , rf " { _ACTION_QUESTION } (?:send|write|reply|email|message|archive|delete|mark) \ b. {{ 0,120 }} \ b(?:emails?|mail|messages?|inbox|unread|read) \ b " ) ,
( " email " , " send/write/reply email request " , rf " { _PLEASE } (?:send|write|reply) \ b. {{ 0,120 }} \ b(?:emails?|mail|messages?) \ b " ) ,
( " email " , " archive/delete/mark email request " , rf " { _PLEASE } (?:archive|delete|mark) \ b. {{ 0,120 }} \ b(?:emails?|mail|messages?|inbox) \ b " ) ,
( " email " , " email composition request " , r " \ b(?:send|write|reply) \ s+(?:an? \ s+)?(?:email|message|mail) \ b " ) ,
( " email " , " email contact request " , r " \ bemail \ s+ \ w+ \ b " ) ,
( " email " , " check inbox request " , r " \ bcheck \ s+(?:my \ s+)?(?:email|inbox|mail) \ b " ) ,
( " email " , " unread email request " , r " \ bunread \ s+(?:email|mail)s? \ b " ) ,
2026-06-01 15:32:41 +10:00
# UI/control-plane actions that should open panels or flip toggles.
2026-06-04 22:20:04 +10:00
( " ui " , " open/show panel request " , rf " { _PLEASE } (?:open|show|bring \ s+up) \ s+(?:me \ s+)?(?:my \ s+|the \ s+)? { _PANEL } \ b " ) ,
( " ui " , " tool or feature toggle request " , r " \ b(?:disable|enable|turn \ s+(?:on|off)) \ s+(?:the \ s+)?(?:shell|search|web|browser|documents?|memory|skills|images?|calendar|email|mail|research|incognito) \ b " ) ,
2026-06-01 15:32:41 +10:00
# Deep research jobs, not quick conceptual mentions of research.
2026-06-04 22:20:04 +10:00
( " research " , " deep research imperative request " , rf " { _PLEASE } (?:research|deep \ s+dive|look \ s+into|investigate) \ s+.+ " ) ,
( " research " , " assistant deep research request " , rf " { _ACTION_QUESTION } (?:research|do \ s+research|deep \ s+dive|look \ s+into|investigate) \ s+.+ " ) ,
2026-06-01 15:32:41 +10:00
# Shell / remote-host intent.
2026-06-04 22:20:04 +10:00
( " shell " , " ssh request " , r " \ bssh \ s+(?:in)?to \ b " ) ,
( " shell " , " ssh target request " , r " \ bssh \ s+ \ w+ " ) ,
( " shell " , " remote command request " , r " \ b(run|execute) \ s+. { 1,40} \ bon \ s+ \ w+ " ) ,
( " shell " , " assistant command execution request " , r " \ b(can|could|please|would) \ s+you \ s+(run|execute|exec) \ b " ) ,
2026-06-03 06:23:10 +01:00
# Shell verbs only count in imperative position (start of message,
# optionally after "please") or as a "can you ..." request. A bare
# word match promoted informational questions ("What does the grep
# command do?") and incidental uses ("My cat ate my homework").
2026-06-04 22:20:04 +10:00
( " shell " , " imperative shell command request " , rf " { _PLEASE } (deploy|build|install|restart|reboot|kill|tail|grep|cat|ls|cd|cp|mv|rm) \ b \ s+ \ S+ " ) ,
( " shell " , " assistant shell command request " , rf " { _ACTION_QUESTION } (deploy|build|install|restart|reboot|kill|tail|grep|cat|ls|cd|cp|mv|rm) \ b \ s+ \ S+ " ) ,
( " shell " , " system/file check request " , r " \ b(check|see) \ s+(if|whether|what) \ s+. { 1,40} \ b(running|process|service|port|file|exists?) \ b " ) ,
2026-06-01 15:32:41 +10:00
)
)
2026-06-04 22:20:04 +10:00
_TOOL_INTENT_PATTERNS : tuple [ Pattern [ str ] , . . . ] = tuple (
pattern for _ , _ , pattern in _ROUTING_PATTERNS
)
def classify_tool_intent ( text : str ) - > ToolIntent :
""" Classify whether a chat message should be promoted to agent mode. """
if not text :
return ToolIntent ( False , reason = " empty message " )
if _EXPLANATORY_PREFIX . search ( text ) :
return ToolIntent ( False , reason = " explanatory feature question " )
for category , reason , pattern in _ROUTING_PATTERNS :
if pattern . search ( text ) :
return ToolIntent ( True , category = category , reason = reason )
return ToolIntent ( False , reason = " no tool-action pattern matched " )
2026-06-01 15:32:41 +10:00
def message_needs_tools ( text : str , patterns : Iterable [ Pattern [ str ] ] = _TOOL_INTENT_PATTERNS ) - > bool :
""" Return True when a plain chat message should be promoted to agent mode. """
if not text :
return False
2026-06-04 22:20:04 +10:00
if _EXPLANATORY_PREFIX . search ( text ) :
return False
if patterns is _TOOL_INTENT_PATTERNS :
return classify_tool_intent ( text ) . needs_tools
2026-06-01 15:32:41 +10:00
return any ( pattern . search ( text ) for pattern in patterns )