From 3e33cf64399977d714c3883ac20ce8f50f07b81a Mon Sep 17 00:00:00 2001 From: Afonso Coutinho Date: Wed, 3 Jun 2026 06:23:10 +0100 Subject: [PATCH] Anchor shell-verb intent patterns to imperative or can-you position (#1664) --- src/action_intents.py | 7 ++++- tests/test_action_intents_shell_verbs.py | 35 ++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 tests/test_action_intents_shell_verbs.py diff --git a/src/action_intents.py b/src/action_intents.py index fa78abd..7054801 100644 --- a/src/action_intents.py +++ b/src/action_intents.py @@ -63,7 +63,12 @@ _TOOL_INTENT_PATTERNS: tuple[Pattern[str], ...] = tuple( r"\bssh\s+\w+", r"\b(run|execute)\s+.{1,40}\bon\s+\w+", r"\b(can|could|please|would)\s+you\s+(run|execute|exec)\b", - r"\b(deploy|build|install|restart|reboot|kill|tail|grep|cat|ls|cd|cp|mv|rm)\b\s+\S+", + # 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"). + rf"{_PLEASE}(deploy|build|install|restart|reboot|kill|tail|grep|cat|ls|cd|cp|mv|rm)\b\s+\S+", + rf"{_ACTION_QUESTION}(deploy|build|install|restart|reboot|kill|tail|grep|cat|ls|cd|cp|mv|rm)\b\s+\S+", r"\b(check|see)\s+(if|whether|what)\s+.{1,40}\b(running|process|service|port|file|exists?)\b", ) ) diff --git a/tests/test_action_intents_shell_verbs.py b/tests/test_action_intents_shell_verbs.py new file mode 100644 index 0000000..b524d82 --- /dev/null +++ b/tests/test_action_intents_shell_verbs.py @@ -0,0 +1,35 @@ +"""Regression: shell verbs must not promote informational chat to agent mode. + +The shell-verb pattern used to be a bare word match +(`\\b(deploy|build|...|rm)\\b\\s+\\S+`), so any sentence merely containing one +of these common English words escalated a plain chat turn to agent mode via +routes/chat_routes.py. That broke the module's stated contract ("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"). The pattern is now anchored to +imperative position (start of message, optionally after "please") or to a +"can/could/would/will you ..." request. +""" +from src.action_intents import message_needs_tools + + +def test_informational_shell_questions_stay_plain_chat(): + assert not message_needs_tools("What does the grep command do?") + assert not message_needs_tools("How do I tail a log file in production?") + assert not message_needs_tools("Is it safe to kill a process with kill -9?") + + +def test_incidental_shell_words_stay_plain_chat(): + assert not message_needs_tools("My cat ate my homework") + assert not message_needs_tools("The movie was a real kill joy for everyone") + + +def test_imperative_shell_commands_still_promote_to_agent(): + assert message_needs_tools("tail the nginx error log") + assert message_needs_tools("restart the media server") + assert message_needs_tools("please install docker on the host") + assert message_needs_tools("cat /etc/hosts") + + +def test_can_you_shell_requests_still_promote_to_agent(): + assert message_needs_tools("can you grep the logs for 500 errors") + assert message_needs_tools("could you tail the access log")