fix(bot-mode): Bot Chat identity + one-shot DM transport apply the silence rule; trim tests

Follow-up to the salvaged #110786 commit:

- `_is_bot_mode_session` mirrors the system-prompt gate (`agent._session_title_hint`
  first, then the live DB title) instead of reading `pending_title`/`title` off the
  session dict: `pending_title` is cleared after turn 1 and the record never carries
  `title`, so the contributor's gate matched only the very first Bot Chat turn.
- `tools/bot_mode_dm.py::_run_local_turn` (the `hermes -p X chat -c "Bot Chat" -Q`
  transport behind `message_agent` when no live owner holds the target) re-emits ""
  for a successful bare marker — the third delivery path of the same class.
- Tests trimmed to one invariant per surface (live completion, relay RPC, one-shot
  transport), each proven red on origin/main sources.
- Bot Mode docs gain a "Staying silent" line pointing at the shared token list.
This commit is contained in:
teknium1
2026-09-14 18:47:51 -07:00
committed by Teknium
parent 50a834fa2a
commit 4eb69cbce5
6 changed files with 76 additions and 76 deletions
@@ -1,56 +1,44 @@
"""Regression coverage for Bot Mode's shared completed-reply delivery boundary."""
"""Bot Mode never renders or relays a bare intentional-silence marker (#110782).
Silence is a delivery decision shared with the gateway (``gateway/response_filters``):
the assistant row stays persisted, only the outbound text is emptied; failed turns and
prose that merely mentions a marker are delivered unchanged.
"""
import contextlib
from types import SimpleNamespace
import pytest
import tui_gateway.server as srv
from tui_gateway.prompt_turn import _bot_mode_delivery_text, _is_bot_mode_session
@pytest.mark.parametrize("response", [
"NO_REPLY", " [silent] ", "silent", "no reply", "*NO_REPLY*",
])
def test_bot_mode_delivery_hides_successful_canonical_silence_markers(response):
assert _bot_mode_delivery_text(response, successful=True) == ""
@pytest.mark.parametrize("response", [
"The NO_REPLY marker means do not answer.",
"[SILENT] is mentioned here, but this is a real answer.",
])
def test_bot_mode_delivery_keeps_substantive_marker_mentions(response):
assert _bot_mode_delivery_text(response, successful=True) == response
def test_bot_mode_delivery_keeps_failed_marker_response_visible():
assert _bot_mode_delivery_text("NO_REPLY", successful=False) == "NO_REPLY"
def test_only_canonical_bot_chat_sessions_use_the_live_delivery_boundary():
assert _is_bot_mode_session({"pending_title": "Bot Chat"})
assert _is_bot_mode_session({"title": "Bot Chat"})
assert not _is_bot_mode_session({"pending_title": "Scratch"})
def test_live_bot_chat_completion_suppresses_markers_but_failed_turns_fail_open(monkeypatch):
"""The prompt.submit completion path applies the shared delivery boundary."""
monkeypatch.setattr(srv, "_get_usage", lambda _agent: {})
monkeypatch.setattr(srv, "render_message", lambda _text, _cols: None)
monkeypatch.setattr(srv, "_clear_inflight_turn", lambda _session: None)
session = {"pending_title": "Bot Chat", "history_lock": contextlib.nullcontext()}
turn = SimpleNamespace(
result={"final_response": "NO_REPLY"}, agent=object(), terminal_callback=None,
def _turn(result):
return SimpleNamespace(
result=result, agent=SimpleNamespace(_session_title_hint="Bot Chat"), terminal_callback=None,
receipt_committed=True, receipt_attempted=False, marker_key="", error_retained=False,
error_detail="", prompt_text="ping",
)
payload, _, status = srv._complete_turn_payload(session, turn, None, 80)
assert status == "complete"
assert payload["text"] == ""
turn.result = {"final_response": "NO_REPLY", "error": "provider failed", "failed": True}
payload, _, status = srv._complete_turn_payload(session, turn, None, 80)
assert status == "error"
def test_live_bot_chat_completion_empties_marker_only_for_successful_turns(monkeypatch):
monkeypatch.setattr(srv, "_get_usage", lambda _agent: {})
monkeypatch.setattr(srv, "render_message", lambda _text, _cols: None)
monkeypatch.setattr(srv, "_clear_inflight_turn", lambda _session: None)
session = {"pending_title": None, "session_key": "k", "history_lock": contextlib.nullcontext(),
"agent": SimpleNamespace(_session_title_hint="Bot Chat")}
payload, _, status = srv._complete_turn_payload(session, _turn({"final_response": " *NO_REPLY* "}), None, 80)
assert (status, payload["text"]) == ("complete", "")
prose = "[SILENT] is mentioned here, but this is a real answer."
payload, _, _ = srv._complete_turn_payload(session, _turn({"final_response": prose}), None, 80)
assert payload["text"] == prose
failed = {"final_response": "NO_REPLY", "error": "provider failed", "failed": True}
payload, _, status = srv._complete_turn_payload(session, _turn(failed), None, 80)
assert (status, payload["text"]) == ("error", "NO_REPLY")
# A plain (non-Bot-Chat) desktop session keeps the marker: the gate is the canonical title.
session["agent"] = SimpleNamespace(_session_title_hint="Scratch")
monkeypatch.setattr(srv, "_session_live_title", lambda _s, _k: "Scratch")
payload, _, _ = srv._complete_turn_payload(session, _turn({"final_response": "NO_REPLY"}), None, 80)
assert payload["text"] == "NO_REPLY"
+9 -28
View File
@@ -108,38 +108,19 @@ def test_deliver_requires_params(home):
assert "error" in err
@pytest.mark.parametrize("reply", [
"NO_REPLY", " [silent] ", "silent", "no reply", "*NO_REPLY*",
])
def test_deliver_suppresses_successful_silence_markers(home, monkeypatch, reply):
"""A successful subprocess relay never returns a bare silence marker to Bot Mode."""
def test_deliver_relays_empty_reply_for_a_bare_silence_marker(home, monkeypatch):
"""#110782: the subprocess transport applies the gateway's silence rule — a bare marker
relays as "", prose that merely mentions one is relayed verbatim."""
class _Proc:
returncode = 0
stdout = reply
stderr = ""
returncode, stderr = 0, ""
stdout = " *NO_REPLY* "
monkeypatch.setattr("subprocess.run", lambda *_args, **_kwargs: _Proc())
monkeypatch.setattr("subprocess.run", lambda *_a, **_k: _Proc())
assert _result(srv._methods["bot_relay.deliver"](1, {"profile": "ops", "message": "ping"}))["reply"] == ""
_Proc.stdout = "The NO_REPLY marker means do not answer."
out = _result(srv._methods["bot_relay.deliver"](1, {"profile": "ops", "message": "ping"}))
assert out["reply"] == ""
@pytest.mark.parametrize("reply", [
"The NO_REPLY marker means do not answer.",
"[SILENT] is mentioned here, but this is a real answer.",
])
def test_deliver_keeps_substantive_marker_mentions(home, monkeypatch, reply):
class _Proc:
returncode = 0
stdout = reply
stderr = ""
monkeypatch.setattr("subprocess.run", lambda *_args, **_kwargs: _Proc())
out = _result(srv._methods["bot_relay.deliver"](1, {"profile": "ops", "message": "ping"}))
assert out["reply"] == reply
assert out["reply"] == _Proc.stdout.strip()
def test_deliver_lands_in_live_bot_chat_instead_of_subprocess(home, monkeypatch):