Skip to content

Add Slack native progress cards - #29496

Closed
simonvanlaak wants to merge 4 commits into
NousResearch:mainfrom
simonvanlaak:feat/slack-native-progress-cards
Closed

Add Slack native progress cards#29496
simonvanlaak wants to merge 4 commits into
NousResearch:mainfrom
simonvanlaak:feat/slack-native-progress-cards

Conversation

@simonvanlaak

Copy link
Copy Markdown
Contributor

Summary

Closes #29483.

This adds an opt-in Slack gateway progress path that renders tool progress through Slack native streaming task cards. When platforms.slack.extra.native_task_cards: true is set, Hermes starts a Slack stream with task_display_mode: plan, appends plan_update / task_update chunks as tools start and finish, and stops the stream once the run is finalized.

Final assistant replies still use the normal Hermes Slack send path. The native stream is progress-only and remains Slack-specific.

Behavior

  • Defaults remain unchanged. Native task cards are off unless explicitly enabled for Slack.
  • Slack thread routing is preserved through existing thread metadata.
  • Slack team/user recipient metadata is forwarded when available for stream startup.
  • Repeated same-name tool calls get distinct task IDs.
  • Tool completion maps to complete; tool errors map to error.
  • If the native stream cannot start or update, Hermes falls back to an in-thread text progress message and still allows the final reply path to continue.

Docs

  • Added the new Slack config key to the Slack messaging guide.
  • Added a short note to cli-config.yaml.example near the existing tool progress setting.

Checks

  • python3 -m py_compile gateway/platforms/slack.py gateway/run.py tests/gateway/test_slack.py tests/gateway/test_run_progress_topics.py
  • git diff --check
  • UV_CACHE_DIR=/tmp/uv-cache uv run --with pytest --with pytest-xdist --with pytest-timeout --with pytest-asyncio pytest tests/gateway/test_slack.py::TestNativeTaskCardProgress tests/gateway/test_run_progress_topics.py -q - 39 passed
  • UV_CACHE_DIR=/tmp/uv-cache uv run --with pytest --with pytest-xdist --with pytest-timeout --with pytest-asyncio pytest tests/gateway/test_slack.py -q - 192 passed, 33 existing AsyncMock warnings

Notes

I did not perform live Slack runtime validation in this draft. The PR has focused unit coverage for the adapter payloads, gateway progress routing, fallback behavior, and final-response separation.

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the focused, opt-in Slack progress implementation. The native-card behavior is not present on current main, so the feature remains relevant.

Problems

  • After the first native-stream failure, native_failed is set at gateway/run.py:15755; _send_native_update() then returns immediately at gateway/run.py:15744. Later tool events therefore do not refresh the in-thread text fallback. Please keep updating the fallback after a native failure and add a multi-tool regression test.
  • The adapter target has moved: this PR edits gateway/platforms/slack.py, while current main uses plugins/platforms/slack/adapter.py:405 after 5600105478ffde29d7566b45421b100eaa29c4ef. The adapter and its tests need to be transplanted to the active plugin surface.

Suggested changes

  • Preserve a live textual fallback for all later tool updates once native streaming fails.
  • Port the adapter and tests to plugins/platforms/slack/adapter.py and reconcile the gateway wiring with current gateway/run.py:17246-17458.

Automated hermes-sweeper review.

Comment thread gateway/run.py Outdated
@teknium1 teknium1 added sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 13, 2026
menhguin added a commit to menhguin/hermes-agent that referenced this pull request Jul 16, 2026
…ress (opt-in)

Renders tool progress on Slack as native collapsible task cards
(chat.startStream/appendStream/stopStream with task_update chunks — the
UI Slack's own AI features use) instead of markdown progress bubbles.
Opt-in via display.platforms.slack.tool_progress_native (default false):
flag off is byte-identical to current behavior on every platform.

Card features: one grouped plan-mode card per turn; per-tool entries
with friendly labels, descriptive completion titles and short output
previews; source-link chips on web tools; live numbered cards for
delegate_task children; interleaved 💭 cards carrying the model's full
reasoning (first-sentence TLDR title, complete text in the collapsible
body). Failed calls render 'complete + ✗' rather than Slack's error
status (red triangle reserved for genuine stream breakage); MCP
text-form errors are sniffed so a 403 doesn't render a checkmark.

Empirically measured Slack API behavior this encodes (docs are wrong or
silent on each): recipient_team_id AND recipient_user_id are required
for bot-token streams despite being documented optional;
task_update.title/status REPLACE per update while details APPENDS
across updates (all details sends are therefore deltas); a streamed
message has an absolute ~306s lifetime regardless of append activity —
handled by proactive rollover onto a fresh streamed message with open
tasks replayed ('⤵ continued below'); msg_too_long is per-chunk, not
cumulative (62k cumulative verified clean); leading whitespace can be
stripped at chunk joins while trailing survives.

Delivery correctness: all sends serialized through a FIFO asyncio.Lock;
tool.started drains the reasoning throttle buffer before the tool card
is scheduled (the model completes reasoning before emitting a tool
call, so the buffered tail belongs before the tool entry); reasoning
flushes cut at sentence boundaries with sub-40-char fragments carried
forward; any API failure self-disables and falls back silently to the
markdown path for the rest of the turn.

Files: gateway/slack_task_stream.py (new, self-contained);
gateway/run.py (flag-gated wiring only); gateway/display_config.py
(toggle + 5 tuning knobs via standard display-setting resolution).

Related: NousResearch#17321 NousResearch#29496 (earlier takes on this surface), NousResearch#54522 (same
feature via GatewayEventDispatcher — happy to migrate onto that seam as
a follow-up once it lands and grows reasoning/subagent event types),
NousResearch#48066 (final-answer draft streaming; complementary, different
transport). Depends on the reasoning-delivery fixes in the sibling
fix/gateway-reasoning-delivery PR.

Co-authored-by: Minh Nguyen <menhguin@users.noreply.github.com>
@simonvanlaak
simonvanlaak requested a review from teknium1 July 21, 2026 19:57
teknium1 pushed a commit that referenced this pull request Aug 13, 2026
Adds platforms.slack.extra.native_task_cards: when enabled, live tool
calls render as Slack-native plan/task cards via chat.startStream /
chat.appendStream (task_display_mode: plan, task_update chunks) instead
of text/edit progress bubbles. ID-bearing tool_start/tool_complete
callbacks correlate concurrent same-name tool calls correctly; any
native API failure falls back to one continuously edited text update.
The stream is stopped exactly once when the turn finalizes.

Salvaged from PR #29496 onto current main (TurnRunner/TurnContext seam);
closes #29483.
teknium1 pushed a commit that referenced this pull request Aug 13, 2026
…ace scoping, fallback

Ports the test coverage from PR #29496 onto the salvaged implementation:
adapter-level serialization/workspace isolation/disconnect sealing, and
gateway-level ID-correlated concurrent duplicate tools plus the editable
text fallback when the native stream fails.
@teknium1

Copy link
Copy Markdown
Contributor

Merged via PR #85476 — your implementation was reapplied onto the current TurnRunner/TurnContext seam (gateway/run.py was decomposed since your branch) with your authorship preserved on both the feature and test commits. This closes your issue #29483 too. Thanks for the ID-correlated design and the workspace-scoped stream isolation — both survived intact.

@teknium1 teknium1 closed this Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P3 Low — cosmetic, nice to have platform/slack Slack app adapter sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Render Slack progress drafts as plan cards

3 participants