fix(buzz): require an @ in the mention gate, keep DM classification loose (#78798) - #78869
Closed
thelonewander3r wants to merge 1 commit into
Closed
thelonewander3r wants to merge 1 commit into
thelonewander3r wants to merge 1 commit into
Conversation
…oose Fixes NousResearch#78798. Rebased onto current main; applies unchanged. `require_mention` matched the bare display name, so any use of the agent's name in prose woke it — "the Chip migration is done" dispatched a turn. Buzz was the outlier among the connectors: Discord matches `<@id>`, Slack `<@uid>`, Chatto `@login`/`@displayName`. The single `_is_mentioned` helper was doing two jobs with one predicate. They need opposite strictness: - The mention gate must require a literal `@`. Picker-inserted mentions carry `@Name`, so UI-driven channel mentions still match. - DM classification must stay loose. A p-tagged message whose text visibly addresses us — bare name or `@name` — is a channel reply, not structural DM addressing, so only a p-tag with no visible address latches. `_matches_self(content, *, require_at)` carries both, with `_is_mentioned` (strict) and `_content_references_self` (loose) reading off it. `_has_dm_shaped_meta` additionally keeps relay-materialized DMs (name "DM", empty description, NousResearch#68871) on the mention-free path. Verified against current main: the 8 new assertions fail on unpatched `origin/main` (cf64ca2) and pass with this diff; the diff is the only variable. tests/gateway/test_buzz_adapter.py 38/38. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
thelonewander3r
force-pushed
the
fix/buzz-mention-gate-requires-at-sign
branch
from
August 17, 2026 13:19
543de2c to
2d8735c
Compare
Collaborator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Fixes #78798 — with
require_mentionenabled, the Buzz adapter wakes the agent for a full turn whenever its display name appears as a bare word. Talking about an agent in a shared channel is enough to summon it.Root cause
BuzzAdapter._is_mentioned()built the display-name pattern with an optional@:Driving the real predicate, 6 of 7 unaddressed messages wake the agent:
In an active shared channel, agents get discussed in the third person constantly — status updates, handoffs, retrospectives. Every one of those is an uninvited full turn: model calls, tool calls, context. The reporter measured a single passing mention consuming 21+ API calls and ~148k tokens before it was interrupted.
It is also the opposite of what the setting promises.
require_mention: truereads as "only respond when addressed"; the implementation was closer to "respond when named".Why this isn't the one-character fix the issue suggests
The issue proposes making
@required — a one-character change. That is not safe on its own, because_is_mentioned()has two callers that want opposite things:_poll_channel)_is_direct_message_event()ptag explained by something visible in the text?"The DM discriminator returns
p_tagged_to_self and not self._is_mentioned(content). Tighten the shared predicate and a p-tagged bare-name channel post starts reading as structural DM addressing —_maybe_latch_dm()then latches the whole conversation tochat_type="dm"permanently, and from that point every message in it dispatches with no mention gate at all.That is strictly worse than the reported bug: wakes-on-name becomes wakes-on-everything. Measured on a metadata-less conversation, with the naive shared-predicate change applied:
In fairness to the reported scope:
_may_reclassify_as_dm()already protects conversations whosechannels listmetadata looks like a real channel, and #77987 reports that Buzz Desktop only p-tags typed mentions (which carry a literal@Name). So the window is metadata-less conversations reached by a client that p-tags on a bare-name mention. #77987 is itself an open report that the p-tag assumption doesn't hold uniformly across clients, which is exactly when this would bite — cheap to close off rather than rely on.The fix
Split the predicate.
_matches_self(content, require_at=...)holds the shared body; the two callers each get the rule they need:_is_mentioned()→require_at=True— the wake gate._content_references_self()→require_at=False— DM classification, behaviour unchanged.npub and hex branches stay loose in both: those are explicit identity strings that never appear in incidental prose.
_strip_mention()is deliberately untouched — it still strips a leading bare name, so a DM that opens with "Chip /whoami" keeps working.How to test
14 new tests pin the behaviour, and they distinguish all three states:
maintest_ptagged_bare_name_post_does_not_latch_channel_as_dmThe middle row is the point: the suite catches not just the original bug but the regression the obvious fix would introduce.
Coverage:
bob@Chip,@Chipmunk).@Chip,@chip, mid-sentence, markdown-wrapped, raw hex pubkey, npub).Test results
tests/gateway/test_buzz_adapter.py+test_buzz_websocket.py— 41 passed.tests/gateway/sweep (-k "buzz or mention or dm") — 466 passed, 2 failed:test_feishu.py::TestGroupMentionAtAll::test_at_all_still_requires_policy_gateandtest_slash_access_dispatch.py::test_admin_runs_quick_command_when_gating_enabled. Both fail identically on unmodifiedmain— pre-existing, unrelated._is_mentionedexist outside this adapter.Platform tested: Windows 11, Python 3.11.15, pytest 9.1.1 / pytest-asyncio 1.3.0. The change is pure string matching with no platform-specific behaviour.
Related
Same class as #70748 (Slack mention gating fails open), which is still open — a fix there would want the same "does this predicate have more than one caller?" check.
🤖 Generated with Claude Code