diff --git a/gateway/run.py b/gateway/run.py index 1164717391bbf..5e2fe4f8a197a 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -69,6 +69,14 @@ _ADAPTER_DISCONNECT_TIMEOUT_SECS_DEFAULT = 5.0 _TELEGRAM_COMMAND_MENTION_RE = re.compile(r"(? str: redacted = _redact_gateway_user_facing_secrets(str(text)) if _looks_like_gateway_provider_error(redacted): return _gateway_provider_error_reply(redacted) + # Strip internal tool-trace banner lines (e.g. ⚠️ 🛠️ `tool (agent)` failed) + redacted = _TOOL_TRACE_BANNER_RE.sub("", redacted).strip() return redacted diff --git a/tests/gateway/test_telegram_noise_filter.py b/tests/gateway/test_telegram_noise_filter.py index 5ba7c04e359b8..5bf9494ac0869 100644 --- a/tests/gateway/test_telegram_noise_filter.py +++ b/tests/gateway/test_telegram_noise_filter.py @@ -232,3 +232,20 @@ def test_chat_gateways_redact_all_issue_23810_credential_shapes(platform, shape_ # Prose around the secret is preserved — redaction is surgical. assert "here is the token you asked me to echo" in sanitized assert sanitized.endswith("done.") + + +def test_tool_trace_banner_stripped_from_chat(): + """Internal tool-trace lines like ⚠️ 🛠️ `tool (agent)` failed must be + stripped from chat delivery. Regression test for #54957. + """ + raw = "Done.\n⚠️ 🛠️ `search repos (agent)` failed" + sanitized = _sanitize_gateway_final_response(Platform.TELEGRAM, raw) + assert sanitized == "Done." + assert "failed" not in sanitized + + +def test_tool_trace_banner_kept_on_raw_surface(): + """Programmatic surfaces (local, api_server) should keep raw trace text.""" + raw = "Done.\n⚠️ 🛠️ `search repos (agent)` failed" + result = _sanitize_gateway_final_response("local", raw) + assert "failed" in result