From 623eb48f2f85f3d27ab31201368a42e08cb5df01 Mon Sep 17 00:00:00 2001 From: Todd Dailey <251794714+twidtwid@users.noreply.github.com> Date: Mon, 14 Sep 2026 07:41:35 -0700 Subject: [PATCH] fix(gateway): a translated intentional-silence sentinel is still silence A model lane that does not think in English answers the cron instruction ("respond with exactly [SILENT]") by translating the sentinel rather than dropping it. LIVE_GATEWAY_SILENT_MARKERS is English-only, so the whole control token is delivered to the user as content. Carry the zh-Hans forms (the only non-English locale this project documents) and derive the autonomous lane's bracketed-prefix rule from the set so the two rules cannot drift. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_011oAAQ4T859Y8fWNXRoiNEB --- gateway/response_filters.py | 20 +++++++++++++++++--- tests/gateway/test_response_filters.py | 23 +++++++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/gateway/response_filters.py b/gateway/response_filters.py index 5d495e9f7c..49473a7f92 100644 --- a/gateway/response_filters.py +++ b/gateway/response_filters.py @@ -11,8 +11,22 @@ from typing import Any # Exact whole-response markers meaning "the agent intentionally chose not to # reply". Keep small and explicit; arbitrary empty output remains an -# error/empty-response path, not silence. -LIVE_GATEWAY_SILENT_MARKERS = frozenset({"[SILENT]", "SILENT", "NO_REPLY", "NO REPLY"}) +# error/empty-response path, not silence. A lane that does not think in English +# translates the sentinel rather than dropping it, and the whole control token +# then reaches the user as content, so the translated forms are carried here +# too. zh-Hans is the only non-English locale this project ships documentation +# for, which is where the list stops. +LIVE_GATEWAY_SILENT_MARKERS = frozenset({ + "[SILENT]", "SILENT", "NO_REPLY", "NO REPLY", + "[静默]", "静默", "[沉默]", "沉默", +}) + +# Bracketed markers drive the autonomous lane's prefix rule ("[SILENT] nothing +# new this tick"). Derived from the set above so a new marker cannot be added to +# one rule and forgotten in the other. +_BRACKETED_SILENCE_MARKERS = tuple( + sorted(m for m in LIVE_GATEWAY_SILENT_MARKERS if m.startswith("[")) +) # The persisted user-row kind of a self-injected MessageEvent(internal=True) turn — the only # machinery kind the gateway produces; only these may vanish on a bare silence marker. @@ -75,7 +89,7 @@ def is_autonomous_silence_response(response: Any) -> bool: return False lines = [ln for ln in stripped.splitlines() if ln.strip()] # Bracketed form only for the prefix rule, so a bare "Silent retry succeeded" is NOT swallowed. - return stripped.upper().startswith("[SILENT]") or any( + return stripped.upper().startswith(_BRACKETED_SILENCE_MARKERS) or any( _canonical_silence_candidate(c) in LIVE_GATEWAY_SILENT_MARKERS for c in (stripped, lines[0], lines[-1]) ) diff --git a/tests/gateway/test_response_filters.py b/tests/gateway/test_response_filters.py index d54916ab28..d79a180772 100644 --- a/tests/gateway/test_response_filters.py +++ b/tests/gateway/test_response_filters.py @@ -19,3 +19,26 @@ def test_autonomous_silence_accepts_marker_with_own_line_note(): assert is_autonomous_silence_response("[SILENT] No changes detected") +def test_translated_sentinel_suppresses_delivery(): + """Regression: a non-English lane answers the silence instruction in its own language. + + 2026-09-14 — a deepseek cron lane had nothing to report and answered the cron + instruction ("respond with exactly [SILENT]") with "[静默]". The control token + was not a known marker, so the whole token was delivered to the user's DM as + content. + """ + assert is_intentional_silence_response("[静默]") + assert is_autonomous_silence_response("[静默]") + + +def test_translated_sentinel_takes_the_same_forms_as_the_english_one(): + """Same loose rule: own-line note, reordered lines, bracketless; the exact rule strips punctuation.""" + assert is_autonomous_silence_response("[静默]\n\nNothing new this tick.") + assert is_autonomous_silence_response("2 deals filtered\n\n[沉默]") + assert is_autonomous_silence_response("静默") + assert is_intentional_silence_response("**沉默**") + + +def test_prose_mentioning_the_translated_sentinel_is_delivered(): + assert not is_intentional_silence_response("status: 静默 means the lane is quiet") + assert not is_autonomous_silence_response("the lane said 静默 mid-sentence and kept talking")