fix(discord): resolve outbound @Name mentions to real <@id> (opt-in) - #69206
fix(discord): resolve outbound @Name mentions to real <@id> (opt-in)#69206tieubao wants to merge 2 commits into
Conversation
|
Reviewed against #69203 — the runtime change is clean and does what the issue asks. Behavior. Opt-in via One thing worth changing — the test reads source. Otherwise this is a solid parity fix. |
|
Addressed in cc0fdb86. The test now imports |
An LLM writes @name rather than the raw <@id> Discord needs, so an agent's attempt to tag a user or hand off to another bot is inert plain text. The Feishu adapter already resolves mentions on outbound; this adds the same to Discord, reusing the guild-member name->id matching the adapter already has (_resolve_allowed_usernames). Opt-in via DISCORD_RESOLVE_MENTIONS (unset/false = byte-identical behavior). @everyone/roles stay governed by the existing allowed_mentions safe defaults. Fixes #69203 Signed-off-by: Han Ngo <nntruonghan@gmail.com>
cc0fdb8 to
b8103fb
Compare
|
Thank you for the focused Discord parity work and for addressing the earlier test-import feedback. This automated hermes-sweeper review is closing the PR under the standing configuration policy:
A focused re-scope using a documented Closed as not-planned per standing maintainer policy ( |
… edit + forum paths Re-scope of NousResearch#69206 (closed under the env-var-for-config policy) to the shape the sweeper asked for: the opt-in is the documented ``discord.resolve_outbound_mentions`` setting in config.yaml, bridged to the internal ``DISCORD_RESOLVE_MENTIONS`` var by ``_apply_yaml_config``, exactly as the neighbouring ``discord.approval_mentions`` works. The bridge is kept private -- the default-config comment documents only the config key, and no test pins the env override. Three delivery paths, not one. The original resolved mentions in send() only: * the forum branch returned before the resolver ran, so a forum thread's starter post kept the inert @name; * edit_message() -- which is how every streamed reply is delivered -- never resolved at all, and neither did its _edit_overflow_split() continuation chunks, which re-format the same content. The resolver now runs above the forum branch in send(), and once in edit_message() on the FINAL edit. Mid-stream is deliberately skipped: the text is still partial there, so a member named "Al" matches while "@alice" is only half-written, and an edit can deliver that ping. Resolving once at finalize means the message the user keeps is the correct one, and it also covers the overflow-split path. guild.members is empty unless the privileged Server Members intent is requested, which startup asked for only for named allowlist entries or role authorization -- so turning the setting on resolved nothing and gave no clue why. The condition moves to a module-level _needs_members_intent() helper that includes this opt-in and is testable without a live client. The "*" open-mode wildcard still does not pull the intent in, so the migrate-from-OpenClaw path is unchanged. The Developer Portal prerequisite is documented where someone setting this up actually reads: the intent table and its explanation in the Discord setup guide, the discord: config block next to the other settings, and voice-mode.md, whose "only needed if your allowlist uses usernames" claim was now incomplete. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
What
Adds opt-in outbound mention resolution to the Discord adapter. When
DISCORD_RESOLVE_MENTIONSis enabled, a bot's readable@Display Namein an outgoing message is rewritten to a real<@id>mention so it actually pings.Fixes #ISSUE.
Why
An LLM reliably writes
@Namerather than the raw<@123...>Discord requires, so an agent's attempt to tag a user, or hand off to another bot, currently comes out as inert plain text. The Feishu adapter already resolves mentions on outbound; this brings Discord to parity, reusing the guild-member name→ID matching the Discord adapter already has in_resolve_allowed_usernames.How
_resolve_outbound_mentions(content, channel): matches guild members byname/display_name/global_name(case-insensitive, longest name first so@Support Botwins over a member namedSupport) and rewrites@Name→<@id>.send(), beforeformat_message().DISCORD_RESOLVE_MENTIONSunset/false the method returns the content unchanged, so behavior is byte-identical for every existing deployment.@everyone/roles remain governed by the existingallowed_mentionssafe defaults. Already-formed<@id>, emails (me@host), and unknown names are left untouched.Tests
Unit tests cover: name→mention, case-insensitivity, multiple names in one message, flag-off no-op, already-real mention untouched, and email / unknown-name left alone.