NousResearch/hermes-agent

Suppress noisy gateway status messages, config flags

Cluster 39293 · gateway. Data as of

Nothing open on GitHub. Fix merged in #53316 on 26 Jun 2026. Check it covers your case.

The short answer

0open issues
0open PRs
3items grouped
Known?
Yes. 3 related items grouped here, 1 issue 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
Nothing open on GitHub.

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 issues0

No open issues.

Open PRs0

No open pull requests.

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():

1 PR closed without merging

From the close comments: done elsewhere 1

  • #39323 fix(gateway): suppress operational status/error noise on all chat gateways, not just Telegram (#39293) · done elsewhere → 57864d0, c377e95, #53316
Closed issues · 1
  • Closed#39293[Bug]: Gateway status/error sanitization is Telegram-only — WhatsApp/Discord/Slack/Signal leak internal noise to users
How this cluster was grouped
  • Link evidence (structural links throughout): every member is connected by structural evidence: shared changed files, or a closing/superseded reference.
  • Pairwise link density 0.67: 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
gateway
Merged PRs
#53316
Closed issues
1
Attempts
1 PR closed without merging
Fix link checked
26 Jun 2026

For your agent

The same facts, typed.