Skip to content

feat(buzz): configure active thread mentions - #75049

Closed
cmyk wants to merge 5 commits into
NousResearch:mainfrom
Peakhunter:feat/buzz-thread-mentions
Closed

cmyk wants to merge 5 commits into
NousResearch:mainfrom
Peakhunter:feat/buzz-thread-mentions

Conversation

@cmyk

@cmyk cmyk commented Jul 30, 2026

Copy link
Copy Markdown

What does this PR do?

Adds configurable Buzz mention policy with strict backward-compatible defaults. Shared-channel messages can continue requiring an initial mention while follow-ups are allowed only in threads where Hermes has successfully participated.

The adapter preserves explicit environment-variable precedence, hot-reloads Dashboard-saved YAML policy, resolves nested replies to the thread root, reconstructs participation after restart, and handles self-echo ordering without permanently dropping follow-ups. DMs and allowlists are unchanged.

Related Issue

N/A — this is separate from dynamic joined-channel discovery in #74823 and from the top-level reply behavior proposed in #74985.

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • Add strict buzz.extra.require_mention and buzz.extra.thread_require_mention defaults in hermes_cli/config_defaults.py and cli-config.yaml.example.
  • Expose a standalone Buzz Dashboard category and add a BuzzIcon component for the config page, using the supplied canonical 24×24 Buzz asset.
  • Give schema-generated boolean switches accessible names in web/src/components/AutoField.tsx.
  • Hot-reload YAML-owned mention settings in plugins/platforms/buzz/adapter.py while preserving explicit environment precedence and last-known-good policy.
  • Resolve nested replies to a flat root, reconstruct active participation, retry bounded out-of-order follow-ups, and track only accepted text/image sends.
  • Preserve existing free-listening behavior: when require_mention is false, unmentioned top-level and threaded messages both continue to dispatch regardless of the thread-policy default.
  • Add focused backend, schema, icon, and accessibility regression coverage.

How to Test

  1. Run scripts/run_tests.sh tests/gateway/test_buzz_adapter.py -q (40 passed).
  2. Run scripts/run_tests.sh tests/hermes_cli/test_web_server.py -q (146 passed).
  3. In web/, run npm run typecheck, npm test, npm run lint, and npm run build (199 tests passed; typecheck/build passed; ESLint reported no errors).

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: Linux

Focused backend and complete frontend suites were run; the repository-wide Python suite was not run, so that checkbox is intentionally left unchecked.

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

CONTRIBUTING.md/AGENTS.md and tool descriptions are N/A. Configuration documentation is included in cli-config.yaml.example; runtime behavior is documented in adapter comments/docstrings.

Screenshots / Logs

N/A. Dashboard schema, icon layout, and accessible switch output are covered by frontend tests.

@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/plugins Plugin system and bundled plugins comp/cli CLI entry point, hermes_cli/, setup wizard comp/dashboard Web dashboard / control panel UI (dashboard/, landing) area/config Config system, migrations, profiles labels Jul 30, 2026

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for the focused Buzz threading work. The current-main premise is valid: plugins/platforms/buzz/adapter.py:1012 still gates every unmentioned non-DM message, while this PR adds the requested active-thread exception.

Problems

  • The public configuration documentation is incomplete. website/docs/user-guide/messaging/buzz.md:47-57 lists the Buzz environment-variable interface, and website/docs/user-guide/messaging/buzz.md:82,98-102 describes only the existing strict mention behavior. This PR adds thread_require_mention / BUZZ_THREAD_REQUIRE_MENTION, but does not update either the canonical Buzz guide or website/docs/reference/environment-variables.md.

Suggested changes

  • Document the YAML and environment forms, precedence, strict defaults, and the rule that only threads with a successful Hermes reply permit unmentioned follow-ups.

This is an automated hermes-sweeper review.

Comment thread cli-config.yaml.example
# buzz:
# extra:
# require_mention: true # Require @mention in shared channels (default: true)
# thread_require_mention: true # Require @mention in active threads (default: true)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please also update the canonical Buzz guide and environment-variable reference. website/docs/user-guide/messaging/buzz.md:47-57 currently enumerates the supported Buzz variables, and its mention-policy text at lines 82 and 98-102 does not describe active-thread follow-ups or this new override.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Addressed in c9ac06279; the canonical Buzz guide and environment-variable reference are now updated.

@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 30, 2026
Codename-11 added a commit to Codename-11/hermes-agent that referenced this pull request Aug 1, 2026
@cmyk

cmyk commented Aug 10, 2026

Copy link
Copy Markdown
Author

Added a follow-up for the Dashboard integration boundary: live mention-policy refresh now reads canonical gateway.platforms.buzz.extra.* values while retaining legacy buzz.extra.* precedence until a
canonical save removes the shadow. The complete Buzz adapter suite passes 39 tests. This pairs with the legacy-shadow cleanup in #80287.

@gering

gering commented Aug 11, 2026

Copy link
Copy Markdown

Heads-up: regression on require_mention: false installs

I independently needed this feature and landed on the same setting name (thread_require_mention). While comparing, I found a behavior change that looks unintended.

Reproduction

Same test on both bases — require_mention: false (the documented free-listening install), a top-level message, then a NIP-10 threaded reply, neither mentioning the agent:

Base Top-level Threaded reply
main dispatches dispatches
this PR dispatches dropped

The failing assertion is:

# adapter with require_mention: false, thread_require_mention left at default
assert [d["message_id"] for d in adapter._dispatched] == ["root1", "reply1"]
# this PR: AssertionError: assert ['root1'] == ['root1', 'reply1']

Cause

The gate returns early on any un-mentioned reply when thread_require_mention is true (the default), before consulting require_mention:

if not is_dm and not self._is_mentioned(content):
    if reply_target and self.thread_require_mention:
        return   # ← fires even when require_mention is False
    if self.require_mention and not in_agent_thread:
        ...

So the new setting at its default tightens behavior for existing free-listening installs — every threaded reply that used to dispatch is now silently dropped. The PR body claims strict backward-compatible defaults; this breaks that for the require_mention: false path.

Suggested fix

Keep require_mention as the outer condition (the Discord shape): only evaluate thread_require_mention / in_agent_thread when the top-level gate is actually on. That way require_mention: false still means free-listening everywhere, and the new setting can only ever relax the gate.

I opened a smaller alternative that does this: #TBD (will edit with the number once live). Happy to close mine in favor of this PR once the regression is fixed — the Dashboard surface here is valuable either way.

@gering

gering commented Aug 11, 2026

Copy link
Copy Markdown

Follow-up: the alternative PR is now up at #83775.

@reinhold-ph
reinhold-ph force-pushed the feat/buzz-thread-mentions branch from 7ced04b to 19c69ea Compare August 11, 2026 09:00
@cmyk

cmyk commented Aug 11, 2026

Copy link
Copy Markdown
Author

Thanks @gering — confirmed. The report exposed a real backward-compatibility regression in the require_mention: false path.

I added a focused RED test on the previous head: an unmentioned top-level message dispatched, but its unmentioned threaded reply failed with ['root'] != ['root', 'reply']. The gate now keeps require_mention as the outer condition, so thread_require_mention can relax an enabled mention gate but cannot tighten a free-listening install. I also corrected the two existing tests that had encoded the rejected independent-gate behavior.

The PR has been rebased onto current main (c0106e50e7ecedb3ce34e785d949725dc4e0e457) and is now at 19c69eadfae70b7a36d7dfcea0a33f78166c18fe.

Verification on the rebased head:

  • Buzz adapter: 40 passed
  • Web-server config/schema: 146 passed
  • Dashboard: typecheck passed, 199 tests passed, lint reported 0 errors, production build passed
  • Ruff and git diff --check: passed

Thanks for providing the exact matrix case and for cross-linking #83775. This PR keeps its broader Dashboard and hot-reload scope while adopting the backward-compatible outer-gate semantics.

@cmyk

cmyk commented Aug 20, 2026

Copy link
Copy Markdown
Author

Superseded by #91020, which carries this behavior forward as part of the profile-scoped Buzz policy and Config integration on current main. Closing this earlier proposal so maintainers have one implementation to review.

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

Labels

area/config Config system, migrations, profiles comp/cli CLI entry point, hermes_cli/, setup wizard comp/dashboard Web dashboard / control panel UI (dashboard/, landing) comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have 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.

5 participants