Suppress noisy gateway status messages, config flags

NousResearch/hermes-agent · cluster 19572 · agent

Data as of

3 open items. Fix merged in #53316. Check it covers your case.

The short answer

2open issues
1open PR
11items grouped
Known?
Yes. 11 related items grouped here, 4 issues already closed.
Fix event
A fix was merged to main in PR #53316. Check it covers your case. No release data is tracked.
Tracker
The maintainers' tracker marks this unresolved. That is separate from the fix event.
Still open
2 issues and 1 PR.

These issues and PRs concern suppressing internal operational noise (status updates, retry messages, lifecycle events) from leaking to users across chat gateways (WhatsApp, Discord, Slack, Signal, Telegram), plus related config options and some compression/retry fixes.

Open issues2

  • Issue#19572Add config flag to suppress lifecycle status messages on messaging gateways
  • Issue#60604[Bug]: compact context fail

Open PRs1

  • PR#20040fix(gateway): gate lifecycle status messages

Fixes on record

Merged to main. A stamp counts the issues a fix is linked to.

  • #53316 fix(gateway): suppress operational status/error noise on all chat gateways (#39293)

    merged to main

    files: gateway/run.py, tests/gateway/test_telegram_noise_filter.py

    Show the diff
    • gateway/run.py
      @@ -87,6 +87,22 @@
           re.IGNORECASE | re.DOTALL,
       )
       
      +# Surfaces that consume gateway text programmatically (CLI/TUI "local"
      +# diagnostics, API JSON, webhook payloads) and therefore must keep RAW
      +# status/error text. EVERY other platform is a human-facing chat surface
      +# where operational lifecycle/provider-error noise (and any secrets in it)
      +# must be suppressed or sanitized. Widens #28533's Telegram-only filter to
      +# all chat gateways (#39293). Fail-closed: unknown/empty platform -> chat.
      +_GATEWAY_RAW_TEXT_PLATFORMS = frozenset(
      +    {"local", "api_server", "webhook", "msgraph_webhook"}
      +)
      +
      +
      +def _gateway_surface_passes_raw_text(platform: Any) -> bool:
      +    """True only for programmatic/local surfaces that must keep raw text."""
      +    return _gateway_platform_value(platform) in _GATEWAY_RAW_TEXT_PLATFORMS
      +
      +
       _GATEWAY_PROVIDER_ERROR_RE = re.compile(
           r"("  # infrastructure/provider error preambles, not ordinary assistant prose
           r"api\s+(?:call\s+)?failed"
      @@ -370,15 +386,18 @@ def _looks_like_gateway_provider_error(text: str) -> bool:
       
       
       def _sanitize_gateway_final_response(platform: Any, text: str) -> str:
      -    """Sanitize final gateway replies before sending them to high-noise chats.
      -
      -    Telegram is Bob's mobile inbox, so it should receive concise, safe provider
      -    failure categories instead of raw HTTP bodies, request IDs, or policy text.
      -    Other platforms keep the existing behaviour for now.
      +    """Sanitize final gateway replies before sending them to chat surfaces.
      +
      +    Every human-facing chat surface (Telegram, WhatsApp, Discord, Slack,
      +    Signal, Matrix, plugin platforms, etc.) should receive concise, safe
      +    provider failure categories with secrets redacted instead of raw HTTP
      +    bodies, request IDs, leaked credentials, or policy text. Only programmatic
      +    surfaces in ``_GATEWAY_RAW_TEXT_PLATFORMS`` (CLI/TUI ``local`` diagnostics,
      +    API JSON, webhook payloads) keep the raw text unchanged.
           """
           if not text:
               return text
      -    if _gateway_platform_value(platform) != "telegram":
      +    if _gateway_surface_passes_raw_text(platform):
               return text
       
           redacted = _redact_gateway_user_facing_secrets(str(text))
      @@ -392,7 +411,7 @@ def _prepare_gateway_status_message(platform: Any, event_type: str, message: str
           text = str(message or "").strip()
           if not text:
               return None
      -    if _gateway_platform_value(platform) != "telegram":
      +    if _gateway_surface_passes_raw_text(platform):
               return text
       
           text = _redact_gateway_user_facing_secrets(text)
    • tests/gateway/test_telegram_noise_filter.py
      @@ -1,4 +1,6 @@
      -"""Telegram-specific gateway filtering for noisy status/error output."""
      +"""Gateway noise/secret filtering across chat surfaces (Telegram + siblings)."""
      +
      +import pytest
       
       from gateway.config import Platform
       from gateway.run import (
      @@ -6,6 +8,34 @@
           _sanitize_gateway_final_response,
       )
       
      +# Every human-facing chat surface that must receive noise-filtered,
      +# secret-redacted, provider-error-sanitized output (not just Telegram).
      +CHAT_PLATFORMS = [
      +    "telegram",
      +    "whatsapp",
      +    "discord",
      +    "slack",
      +    "signal",
      +    "matrix",
      +    "mattermost",
      +    "dingtalk",
      +    "feishu",
      +    "wecom",
      +    "weixin",
      +    "bluebubbles",
      +    "qqbot",
      +    "homeassistant",
      +    "sms",
      +]
      +
      +NOISY_STATUS_MESSAGES = [
      +    "🗜️ Preflight compression check before sending...",
      +    "🗜️ Compacting context — summarizing earlier conversation so I can continue...",
      +    "⚠ Compression summary failed: upstream error. Inserted a fallback context marker.",
      +    "⏱️ Rate limited. Waiting 30.0s (attempt 2/3)...",
      +    "⏳ Retrying in 4.2s (attempt 1/3)...",
      +]
      +
       
       def test_telegram_status_suppresses_auxiliary_and_retry_noise():
           """Auxiliary failures and retry backoff chatter should not hit Telegram."""
      @@ -23,12 +53,91 @@ def test_telegram_status_suppresses_auxiliary_and_retry_noise():
               assert _prepare_gateway_status_message(Platform.TELEGRAM, "warn", message) is None
       
       
      -def test_non_telegram_status_is_unchanged():
      -    """The Telegram quieting policy must not hide CLI/Discord diagnostics."""
      +def test_programmatic_surfaces_keep_raw_status():
      +    """Programmatic surfaces (local/api/webhook) must keep raw diagnostics.
      +
      +    Negative case for the invariant: the chat-noise filter must not touch
      +    CLI/TUI diagnostics, API JSON, or webhook payloads.
      +    """
           message = "⏳ Retrying in 4.2s (attempt 1/3)..."
       
      -    assert _prepare_gateway_status_message(Platform.DISCORD, "lifecycle", message) == message
      -    assert _prepare_gateway_status_message("local", "lifecycle", message) == message
      +    for platform in ("local", "api_server", "webhook", "msgraph_webhook"):
      +        assert (
      +            _prepare_gateway_status_message(platform, "lifecycle", message) == message
      +        )
      +
      +
      [redacted:email]("platform", CHAT_PLATFORMS)
      [redacted:email]("message", NOISY_STATUS_MESSAGES)
      +def test_all_chat_gateways_suppress_noise(platform, message):
      +    """Operational lifecycle/retry noise must be suppressed on every chat surface."""
      +    assert _prepare_gateway_status_message(platform, "warn", message) is None
      +
      +
      [redacted:email]("platform", ["whatsapp", "slack", "signal", "matrix"])
      +def test_chat_gateways_redact_secret_in_provider_error(platform):
      +    """Provider-error bodies carrying secrets must never reach chat users.
      +
      +    THE security invariant being widened from Telegram (#28533) to all chat
      +    surfaces (#39293): a leaked bearer token in a provider error body must be
      +    redacted/replaced before delivery on any chat platform.
      +    """
      +    raw = (
      +        "API call failed after 3 retries: HTTP 401 Unauthorized — "
      +        "Authorization: Bearer [redacted:openai-key]"
      +    )
      +
      +    sanitized = _sanitize_gateway_final_response(platform, raw)
      +
      +    assert "[redacted:openai-key]" not in sanitized
      +    assert "sk-ABCDEF" not in sanitized
      +    assert "HTTP 401" not in sanitized
      +    # The user gets the safe provider-error category instead of the raw body.
      +    assert "provider" in sanitized.lower()
      +
      +
      [redacted:email]("platform", ["whatsapp", "slack", "signal", "matrix"])
      +def test_chat_gateways_redact_secret_in_non_error_body(platform):
      +    """Secrets must be redacted even when no provider-error rewrite fires.
      +
      +    The provider-error case above is rewritten wholesale to a generic
      +    category string, so it cannot, on its own, prove the secret-redaction
      +    layer works — the rewrite would strip the body regardless. This case
      +    feeds ordinary assistant prose that merely *echoes* a bearer token (not
      +    a provider-error envelope), so `_redact_gateway_user_facing_secrets` is
      +    the only thing standing between the token and the user. Removing the
      +    redaction patterns makes this fail (genuine regression guard); the
      +    surrounding prose must survive intact.
      +    """
      +    raw = (
      +        "Sure — here is the example request you asked for: "
      +        "curl -H 'Authorization: Bearer [redacted:openai-key]' "
      +        "https://api.example.com/v1/models"
      +    )
      +
      +    sanitized = _sanitize_gateway_final_response(platform, raw)
      +
      +    assert "[redacted:openai-key]" not in sanitized
      +    assert "sk-ABCDEF" not in sanitized
      +    assert "[REDACTED]" in sanitized
      +    # Non-secret prose is preserved — redaction is surgical, not a wholesale
      +    # rewrite, on bodies that are not provider-error envelopes.
      +    assert "here is the example request you asked for" in sanitized
      +
      +
      +def test_plugin_platform_string_suppresses_noise():
      +    """Unknown/plugin chat platforms fail closed to the chat-filter path."""
      +    message = "⏳ Retrying in 4.2s (attempt 1/3)..."
      +
      +    assert _prepare_gateway_status_message("irc", "warn", message) is None
      +
      +
      [redacted:email]("platform", CHAT_PLATFORMS)
      +def test_chat_gateways_keep_normal_answers(platform):
      +    """Normal assistant content must pass through unchanged on chat surfaces."""
      +    answer = "Here is the clean summary you asked for."
      +
      +    assert _sanitize_gateway_final_response(platform, answer) == answer
       
       
       def test_telegram_status_sanitizes_raw_provider_security_errors():

3 PRs closed without merging

From the close comments: done elsewhere 1 · stale or abandoned 1 · superseded by another PR 1

  • #27134 feat(logging): add config option to suppress fallback/rate-limit status messages · superseded by another PR → #4242
  • #39323 fix(gateway): suppress operational status/error noise on all chat gateways, not just Telegram (#39293) · done elsewhere → 57864d0, c377e95, #53316
  • #60744 fix(compression): raise timeout floor from 300s to 900s for slow local models (#60604) · stale or abandoned
Closed issues · 4
  • Closed#27131[Feature] Add config option to suppress fallback/rate-limit status messages from gateway channel
  • Closed#39293[Bug]: Gateway status/error sanitization is Telegram-only — WhatsApp/Discord/Slack/Signal leak internal noise to users
  • Closed#63554Add config flags to suppress '⏳ Working' and '💾 Self-improvement review' system messages on chat platforms
  • Closed#63555Add config flags to suppress 'Working' and 'Self-improvement review' system messages on chat platforms
How this cluster was grouped
  • Link evidence (partly structural links): some members are connected by structural evidence (shared changed files, or a closing/superseded reference); the rest are joined by an automated relevance judgement over their text.
  • Members outside that structural core may belong to a different underlying problem.
  • Pairwise link density 0.14: the share of item pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. 1.00 means every pair is linked.

Pick up a Lab task

Check whether a fix covers the open issues here, with your own agent. Bring back evidence for maintainers.

Open the Lab

At a glance

Subsystem
agent
Merged PRs
#53316
Closed issues
4
Attempts
3 PRs closed without merging
Fix link checked
26 Jun 2026

For your agent

The same facts, typed.