fix(tui): suppress Bot Mode silence markers

This commit is contained in:
KoNit-K
2026-09-14 19:12:26 +08:00
committed by Teknium
parent 182ec5c28d
commit 50a834fa2a
4 changed files with 116 additions and 1 deletions
@@ -0,0 +1,56 @@
"""Regression coverage for Bot Mode's shared completed-reply delivery boundary."""
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,
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"
assert payload["text"] == "NO_REPLY"
@@ -108,6 +108,40 @@ 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."""
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"] == ""
@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
def test_deliver_lands_in_live_bot_chat_instead_of_subprocess(home, monkeypatch):
"""#100523: a Desktop-owned Bot Chat receives the DM as a normal user turn.
+6 -1
View File
@@ -147,7 +147,12 @@ def _(rid, params: dict, _root=_relay_root, _run=_run_delivery) -> dict:
detail = _detail(proc)
return _err(rid, 5092, f"delivery turn failed: {detail or proc.returncode}",
data={"reason": classify_agent_error(detail)})
return _ok(rid, {"reply": (proc.stdout or "").strip()})
# Use the same canonical whole-response predicate as live Bot Chat
# completion. A marker remains a successful turn, but is never sent
# back to the relay caller as visible prose.
from tui_gateway.prompt_turn import _bot_mode_delivery_text
reply = _bot_mode_delivery_text((proc.stdout or "").strip(), successful=True)
return _ok(rid, {"reply": reply})
except subprocess.TimeoutExpired:
return _err(rid, 5093, "delivery turn timed out")
except Exception as e:
+20
View File
@@ -16,6 +16,24 @@ from .method_ctx import HandlerRegistry, bind_module
_registry = HandlerRegistry()
def _bot_mode_delivery_text(response: Any, *, successful: bool) -> Any:
"""Return the text Bot Mode may render or relay after a completed turn.
The gateway owns the canonical marker set. Keep the row and completion
event intact, but make a successful bare marker invisible at every Bot
Mode delivery boundary. Failed turns intentionally fail open so their
diagnostic text is never swallowed.
"""
from gateway.response_filters import is_intentional_silence_response
return "" if successful and is_intentional_silence_response(response) else response
def _is_bot_mode_session(session: dict) -> bool:
"""Whether this completion belongs to the canonical Bot Chat surface."""
from tools.bot_mode_probe import BOT_CHAT_TITLE
return any(session.get(field) == BOT_CHAT_TITLE for field in ("pending_title", "title"))
def _hook_failure(what: str, exc: BaseException) -> None:
print(f"[tui_gateway] {what} failed: {type(exc).__name__}: {exc}", file=sys.stderr)
@@ -638,6 +656,8 @@ def _complete_turn_payload(session: dict, st: _TurnRun, status_note: str | None,
except Exception:
_error_surface = None
raw, status, last_reasoning = _turn_outcome(result, _error_surface)
if _is_bot_mode_session(session):
raw = _bot_mode_delivery_text(raw, successful=status == "complete")
payload = {"text": raw, "usage": _get_usage(agent), "status": status}
if last_reasoning:
payload["reasoning"] = last_reasoning