From 2984bd80e431c0f0d610992c09f1dfec1ee72434 Mon Sep 17 00:00:00 2001 From: engineer Date: Sat, 26 Sep 2026 06:56:39 -0700 Subject: [PATCH] fix(gateway): first-turn intro note must not swallow a real task The zero-session first-contact sidecar note (PLAIN_INTRO_NOTE / _hmwa_first_contact_notes) unconditionally told the model to just introduce itself, with no carve-out for the case where the user's first-ever message IS a real task. On a fresh tenant whose voice task was the very first message, the model followed the note verbatim and replied with a static 'I'm Hermes. /help shows the available commands.' - no tool call, no attempt at the task at all. This is a third shape of the first-turn-onboarding-hijack class (turn replaced outright, not just augmented with the known profile-build pitch). Fix: PLAIN_INTRO_NOTE now instructs the model to do the task first (call whatever tools it needs) and fold the one-line intro into the close of that same reply; only a message with no real request gets the old bare intro behavior. Also de-duplicated the literal note text in gateway/run_turn.py, which had drifted into an inline copy instead of importing agent.onboarding.PLAIN_INTRO_NOTE. (cherry picked from commit fc7c3839b0b6774133d4fe8df59a9e98d23bdd8b) --- agent/onboarding.py | 9 +++++++-- gateway/run_turn.py | 7 ++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/agent/onboarding.py b/agent/onboarding.py index 34cb16a1bd..7781df108d 100644 --- a/agent/onboarding.py +++ b/agent/onboarding.py @@ -121,8 +121,13 @@ def profile_build_mode(config: Mapping[str, Any]) -> str: PLAIN_INTRO_NOTE = ( "[System note: This is the user's very first message ever. " - "Briefly introduce yourself and mention that /help shows available commands. " - "Keep the introduction concise -- one or two sentences max.]" + "If this message is itself a real request or task, DO THE TASK FIRST -- call " + "whatever tools it needs -- and only then, in the same reply, add one brief " + "closing sentence introducing yourself and mentioning that /help shows available " + "commands. Never let this note replace or skip work the user actually asked for. " + "If the message truly carries no request (e.g. just a greeting), briefly " + "introduce yourself and mention that /help shows available commands, in one or " + "two sentences.]" ) diff --git a/gateway/run_turn.py b/gateway/run_turn.py index da34ab6b7a..015d37cda2 100644 --- a/gateway/run_turn.py +++ b/gateway/run_turn.py @@ -1424,11 +1424,8 @@ class GatewayTurnMixin: if history: return if not await self.async_session_store.has_any_sessions(): - _intro_note = ( - "[System note: This is the user's very first message ever. " - "Briefly introduce yourself and mention that /help shows available commands. " - "Keep the introduction concise -- one or two sentences max.]" - ) + from agent.onboarding import PLAIN_INTRO_NOTE + _intro_note = PLAIN_INTRO_NOTE # onboarding.profile_build == "ask" (default) and not yet offered: swap the plain intro for # a consent-gated profile-build directive. Fires at most once. try: