Skip to content

fix(slack): honor disable_dms, ignored channels, threading defaults + small correctness batch - #70196

Merged
teknium1 merged 12 commits into
mainfrom
slack/c18-settings
Jul 23, 2026
Merged

fix(slack): honor disable_dms, ignored channels, threading defaults + small correctness batch#70196
teknium1 merged 12 commits into
mainfrom
slack/c18-settings

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

Slack settings that were silently ignored are now honored — disable_dms, ignored channels (gated at both runner and adapter, across send/edit/typing/uploads), surface-specific reply-threading defaults — plus a batch of small correctness fixes, each verified live against main first.

Changes (per-item verdicts in the report)

Credits

Salvaged with authorship preserved: #51899 (@byshubham — placeholder commit identity re-stamped to their noreply, flagged), #53030 (@vexclawx31), #32580 (@jackberger03), #58421 (@DavidMetcalfe), #17693, #34695 (@annguyenNous), #43734 (@mwbrooks), #65256 (@2001Y). #46925 (@bhanusharma) folded with credit.

Validation

Check Result
tests/gateway/ -q -k slack 786 passed, 0 failed (re-verified post-rebase)
Per-fix regression tests + setup wizard suites green

Infographic

slack-settings-honored

@teknium1 teknium1 added the platform/slack Slack app adapter label Jul 23, 2026
@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

૮ >ﻌ< ა ci review

ran on 411d298

all good!

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/acp Agent Communication Protocol adapter comp/gateway Gateway runner, session dispatch, delivery comp/cli CLI entry point, hermes_cli/, setup wizard comp/plugins Plugin system and bundled plugins comp/tui Terminal UI (ui-tui/ + tui_gateway/) platform/discord Discord bot adapter platform/feishu Feishu / Lark adapter platform/matrix Matrix adapter (E2EE) platform/qqbot QQ Bot adapter platform/wecom WeCom / WeChat Work adapter platform/whatsapp WhatsApp Business adapter sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages needs-decision Awaiting maintainer decision before any implementation labels Jul 23, 2026
@teknium1
teknium1 force-pushed the slack/c18-settings branch 2 times, most recently from ac805fe to aa76bcc Compare July 23, 2026 18:43
byshubham and others added 11 commits July 23, 2026 11:51
Blank (or whitespace-only) answers to the home-channel prompt in the
interactive setup wizards previously left any previously saved
*_HOME_CHANNEL / *_HOME_ROOM env value in place, so operators could not
clear a stale home channel by re-running setup. Strip the prompt input
and call remove_env_value() on blank answers across the Discord, Slack,
Feishu, Matrix, Mattermost, WeCom and WhatsApp plugin setup wizards,
with per-adapter wizard tests covering set/clear/whitespace flows.

Squash of the three commits from PR #58421 (setup-wizard fix, matrix/
wecom extension, and 6-adapter test coverage) — one commit per
contributor on this salvage branch.

Fixes #12423
Salvaged from #58421
.get("key", {}) only applies the default when the key is ABSENT.
When the key exists with value None (null in JSON), .get() returns
None and the subsequent .get() raises AttributeError.

Fix: replace .get("key", {}).get(...) with (.get("key") or {}).get(...)
which handles both missing keys AND None values.

8 instances across 6 files:
- gateway/run.py: tool_call function name check
- acp_adapter/server.py: tool name/description extraction
- gateway/platforms/qqbot/onboard.py: API response task_id
- gateway/platforms/yuanbao.py: message content parsing (x2)
- gateway/platforms/slack.py: block text extraction (x2)
- tui_gateway/server.py: error message extraction
Hermes already identifies itself on outbound calls to model providers
and monitoring endpoints — see hermes_cli/models.py and
plugins/model-providers/gmi/__init__.py
("Attribution so GMI can identify traffic from Hermes Agent"). The
Slack adapter is the one outbound surface that doesn't carry the
same identifier, so HermesAgent-driven Slack traffic is
indistinguishable from any other Bolt-Python app at the Slack
platform layer.

This sets `user_agent_prefix=f"HermesAgent/{_HERMES_VERSION}"` on the
AsyncWebClient instances constructed in gateway/platforms/slack.py
and threads them through AsyncApp via its `client` kwarg. Both
kwargs are first-class in slack-sdk and slack-bolt; no new
dependencies. Resulting header looks like:

    HermesAgent/<version> Python/3.x slackclient/3.x ...

No behavioral change for users — the Slack API ignores User-Agent
semantically; it lands in logs and analytics. Reversible.

Tests in tests/gateway/test_slack.py:
- TestSlackUserAgent pins the prefix shape and runs connect()
  end-to-end (multi-token config) to assert every AsyncWebClient
  carries the prefix and AsyncApp receives the pre-built client.
- TestSlackProxyBehavior fakes updated to tolerate the new kwargs
  via **_kwargs so they don't break on future passthroughs.
PR #37303 added per-platform streaming defaults and the commit message
explicitly called out "Discord/Slack/etc. only have edit-based streaming
(repeated editMessage), which flickers and is noticeably jankier" — but
only discord.streaming=false was shipped. Slack uses the same edit-based
streaming mechanism and has the same flicker problem, yet it was left to
follow the global switch (default true when streaming is enabled).

Add "slack": {"streaming": False} to DEFAULT_CONFIG["display"]["platforms"]
alongside the Discord default. The same deep-merge semantics apply: a user
who explicitly sets display.platforms.slack.streaming: true keeps their
value unchanged. The dashboard schema gains a slack.streaming toggle
automatically since it is generated from DEFAULT_CONFIG.

Update test_per_platform_streaming_defaults.py to cover slack in all
existing assertions and rename the resolver test to reflect both platforms.
Add --long-description / --long-description-file to `hermes slack
manifest` so the generated app manifest can carry Slack's
display_information.long_description (175–4,000 characters), with
validation of the length bounds, mutual-exclusion with --slashes-only,
and UTF-8 file input. Also propagate the manifest command's exit status
through cmd_slack so validation failures reach the shell.

Squash of the two commits from PR #65256 — one commit per contributor
on this salvage branch.

Salvaged from #65256
…g path

Follow-up to the #51899 pick, folding in the config-bridge half of the
competing PR #46925 (@bhanusharma, earliest submitter for the
ignored-channel gate):

- _apply_yaml_config: translate config.yaml slack.ignored_channels into
  SLACK_IGNORED_CHANNELS (list or CSV), env-var-wins like every other
  bridged Slack key.
- SlackAdapter._slack_ignored_channels / gateway.run's
  _slack_ignored_channels_from_gateway_config: fall back to the
  SLACK_IGNORED_CHANNELS env var when PlatformConfig.extra carries no
  value, so top-level slack: blocks (which flow through the env bridge,
  not extra) are honored at both the adapter and runner gates.
- conftest: force-clear SLACK_ALLOWED_CHANNELS / SLACK_IGNORED_CHANNELS /
  SLACK_DISABLE_DMS between tests (config-loader side-effect leak class).
- Tests: env-bridge translation + precedence in test_config.py, env
  fallback + extra-wins in test_slack_runner_ignored_channels.py.

Credit: #46925 by @bhanusharma proposed the same gate with the YAML→env
bridge; #51899 (picked as the base) carries the wider outbound/runner
coverage. Closes #46925 as consolidated here with first-submitter credit.
Previously, Slack sessions and the channel directory stored raw channel
IDs (e.g. C0ATFHY907L) as chat_name, making it impossible for operators
to identify channels in send_message listings or session data.

Changes:
- Add _channel_name_cache and _resolve_channel_name() to SlackAdapter
  that calls conversations.info (channels) or users.info (DMs) with
  in-memory caching to avoid repeated API calls
- Use resolved names in _handle_slack_message() build_source() calls
- Use cached names in _seed_assistant_thread_session()
- Enrich session-sourced entries in channel_directory._build_slack()
  by cross-referencing API results and falling back to conversations.info
  + users.info for DMs and private channels not in the bot's scope

Fixes: channel directory and session origins now show readable names
like 'general' or 'John Doe' instead of 'C0xxx' / 'D0xxx'.
…ndividually

Two related Slack delivery fixes for send_message text sends:

- Route Slack text delivery through _send_via_adapter so the live
  in-process gateway adapter (multi-workspace aware, channel→client
  mapping, adapter-side gates) is preferred, with the plugin's
  _standalone_send as the out-of-process fallback — matching how the
  media path already behaves.
- _standalone_send: SLACK_BOT_TOKEN can be a comma-separated list in
  multi-workspace installs and slack_tokens.json carries OAuth
  per-workspace tokens; the standalone Web-API path used to send the
  literal comma-joined string, which Slack rejects as invalid_auth.
  Try each token individually, retrying on token-scoped errors
  (invalid_auth / not_in_channel / channel_not_found …) and stopping on
  terminal ones. User-DM resolution (U…/W… targets) also tries each
  token.

Adapted from #47547 by @replygirl — the original patched the legacy
tools/send_message_tool.py::_send_slack helper, which moved to the
Slack plugin's _standalone_send in #41112.

Salvaged from #47547
Note: #51899's commit was authored as a placeholder identity
(hermes-agent@example.invalid); it was re-stamped to @byshubham's
numeric noreply on this branch, so no mapping file is needed. Other
salvaged commits use GitHub noreply addresses.
…annel guard

Gateway tests construct GatewayRunner via object.__new__ without __init__;
the new #51899 guard accessed self.config directly and crashed those
runners (AttributeError). Use getattr with None default — the guard
no-ops without config, matching the documented object.__new__ pitfall.
@teknium1
teknium1 force-pushed the slack/c18-settings branch from aa76bcc to 411d298 Compare July 23, 2026 18:52
@teknium1
teknium1 merged commit c4f5a45 into main Jul 23, 2026
37 checks passed
@teknium1
teknium1 deleted the slack/c18-settings branch July 23, 2026 19:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/acp Agent Communication Protocol adapter comp/cli CLI entry point, hermes_cli/, setup wizard comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins comp/tui Terminal UI (ui-tui/ + tui_gateway/) needs-decision Awaiting maintainer decision before any implementation P2 Medium — degraded but workaround exists platform/discord Discord bot adapter platform/feishu Feishu / Lark adapter platform/matrix Matrix adapter (E2EE) platform/qqbot QQ Bot adapter platform/slack Slack app adapter platform/wecom WeCom / WeChat Work adapter platform/whatsapp WhatsApp Business adapter sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Feishu setup cannot clear an existing FEISHU_HOME_CHANNEL