diff --git a/agent/turn_context.py b/agent/turn_context.py index e080d6a5d9..a341698cd4 100644 --- a/agent/turn_context.py +++ b/agent/turn_context.py @@ -25,6 +25,7 @@ move-and-name refactor with no semantic change. from __future__ import annotations import logging +import re import threading import time import uuid @@ -49,6 +50,37 @@ from agent.model_metadata import ( logger = logging.getLogger(__name__) +# Trivial user-input pattern — used to gate the per-turn memory-provider +# prefetch on short, semantically-empty queries. Covers greetings, +# acknowledgements, and trailing-punctuation variants (e.g. "hi!", "hey.", +# "thanks :)"). +_RE_TRIVIAL_USER_QUERY = re.compile( + r'^(yes|no|ok|okay|sure|thanks|thank you|y|n|yep|nope|yeah|nah|' + r'hi|hey|hello|yo|sup|' + r'continue|go ahead|do it|proceed|got it|cool|nice|great|done|next|lgtm|k)' + r'[\s!?.:;,"' + "'" + r'~\u2018\u2019\u201c\u201d\u2014\u2013\u2026()\[\]{}<>*&^%$#@!+=`\u00a0]*$', + re.IGNORECASE, +) + + +def _is_trivial_user_query(query: str) -> bool: + """Return True if the query is a greeting or too trivial to warrant prefetch. + + Strips leading/trailing whitespace first, then checks against + _RE_TRIVIAL_USER_QUERY which permits common trailing punctuation + (exclamation, question mark, emoji, etc.) so variants like "hi!", + "hey.", and "thanks :)" register as trivial. + """ + if not query: + return True + stripped = query.strip() + if not stripped: + return True + if stripped.startswith("/"): + return True + return bool(_RE_TRIVIAL_USER_QUERY.match(stripped)) + + def compose_user_api_content( content: Any, ext_prefetch_cache: str, @@ -1152,11 +1184,15 @@ def build_turn_context( pass # External memory provider: prefetch once before the tool loop. + # + # Skip prefetch on trivial prompts (greetings, acknowledgements) to + # prevent memory-context injection on turns that carry no semantic signal. ext_prefetch_cache = "" if agent._memory_manager: try: _query = original_user_message if isinstance(original_user_message, str) else "" - ext_prefetch_cache = agent._memory_manager.prefetch_all(_query) or "" + if not _is_trivial_user_query(_query): + ext_prefetch_cache = agent._memory_manager.prefetch_all(_query) or "" except Exception: pass diff --git a/plugins/memory/honcho/__init__.py b/plugins/memory/honcho/__init__.py index c90734ad8a..ffbf657cdb 100644 --- a/plugins/memory/honcho/__init__.py +++ b/plugins/memory/honcho/__init__.py @@ -1196,12 +1196,14 @@ class HonchoMemoryProvider(MemoryProvider): return r return "" - # Prompts that carry no semantic signal — trivial acknowledgements, slash - # commands, empty input. Skipping injection here saves tokens and prevents + # Prompts that carry no semantic signal — trivial acknowledgements, greetings, + # slash commands, empty input. Skipping injection here saves tokens and prevents # stale user-model context from derailing one-word replies. _TRIVIAL_PROMPT_RE = re.compile( r'^(yes|no|ok|okay|sure|thanks|thank you|y|n|yep|nope|yeah|nah|' - r'continue|go ahead|do it|proceed|got it|cool|nice|great|done|next|lgtm|k)$', + r'hi|hey|hello|yo|sup|' + r'continue|go ahead|do it|proceed|got it|cool|nice|great|done|next|lgtm|k)' + r'[\s!?.:;,~]*$', re.IGNORECASE, ) diff --git a/tests/honcho_plugin/test_session.py b/tests/honcho_plugin/test_session.py index 201979a13a..cd8e1bb51a 100644 --- a/tests/honcho_plugin/test_session.py +++ b/tests/honcho_plugin/test_session.py @@ -791,6 +791,10 @@ class TestTrivialPromptHeuristic: for t in ("ok", "OK", " ok ", "y", "yes", "sure", "thanks", "lgtm", "/help", "", " "): assert HonchoMemoryProvider._is_trivial_prompt(t), f"expected trivial: {t!r}" + def test_classifier_catches_greetings(self): + """Greeting words must register as trivial so context injection is skipped.""" + for t in ("hi", "HI", "hey", "hello", "yo", "sup", " hi ", "hey!", "hello."): + assert HonchoMemoryProvider._is_trivial_prompt(t), f"expected trivial: {t!r}" def test_prefetch_skips_on_trivial_prompt(self): provider = self._make_provider()