Skip to content

fix(discord): bound component labels by UTF-16 units - #54969

Closed
ooiuuii wants to merge 1 commit into
NousResearch:mainfrom
ooiuuii:fix/discord-component-utf16-labels
Closed

fix(discord): bound component labels by UTF-16 units#54969
ooiuuii wants to merge 1 commit into
NousResearch:mainfrom
ooiuuii:fix/discord-component-utf16-labels

Conversation

@ooiuuii

@ooiuuii ooiuuii commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Summary

  • truncate Discord model picker select labels/values with Hermes' existing UTF-16 helper instead of Python code-point slices
  • apply the same UTF-16 budget to clarify choice button labels while preserving the existing word/soft-boundary truncation
  • add emoji-heavy regression coverage for model picker options and clarify buttons

Context

This follows the same Discord component boundary fixed in OpenClaw:

Closes #54968.

Duplicate Audit

Live search found adjacent model-picker and UTF-16 work, but not this specific Discord component field budget issue. #49325 is Telegram entity offset UTF-16 handling, not Discord select/button label limits. The model-picker PRs in search results change picker contents/providers, not component string-budget enforcement.

Tests

  • uv run --extra dev python -m pytest tests\gateway\test_discord_model_picker.py tests\gateway\test_discord_clarify_buttons.py -q --basetemp .pytest-tmp-discord-component-utf16-labels
  • uv run --extra dev python -m ruff check plugins\platforms\discord\adapter.py tests\gateway\test_discord_model_picker.py tests\gateway\test_discord_clarify_buttons.py
  • git diff --check

@alt-glitch alt-glitch added type/bug Something isn't working comp/plugins Plugin system and bundled plugins platform/discord Discord bot adapter sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages P3 Low — cosmetic, nice to have labels Jun 29, 2026
@teknium1

teknium1 commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Merged via #60113 - your commit was cherry-picked onto current main with your authorship preserved in git log (87be36c). Thanks!

@teknium1 teknium1 closed this Jul 7, 2026
trevornk pushed a commit to trevornk/hermes-agent that referenced this pull request Jul 11, 2026
Discord clarify buttons put the (truncated) choice text directly on
the button label, relying on Discord's 80-char label cap plus a
word-boundary truncation algorithm. In practice this is still
unreadable: Discord mobile clients wrap/cut button text well before
80 chars (often <40 visible), so any truncation strategy on the
label itself still garbles longer choices regardless of how the cut
point is chosen.

PR NousResearch#54969 (merged as 87be36c) already fixed a related but
different bug in this same truncation path -- code-point slicing
instead of UTF-16 unit slicing, which could corrupt emoji-heavy
choice text at the cut boundary. That fix made the truncation
correct; this one removes the need for truncation at all.

Telegram and WhatsApp adapters already avoid this class of bug
entirely: button labels are just a short index, and the full choice
text is mirrored in the message body where there's no meaningful
length cap. This brings Discord's send_clarify() in line with that
same pattern:

- ClarifyChoiceView button labels are now just the option number
  ("1", "2", ...) instead of "1. <truncated text>". Removed the
  now-dead word/soft-boundary truncation logic for this path.
- send_clarify() renders the full, untruncated choice text as a
  numbered list in the embed's "Choices" field (1024-char cap,
  truncated only if genuinely absurd) and mirrors it again in the
  plain-text message content, matching the existing embeds-may-be-
  invisible-on-some-clients precaution already used elsewhere in
  this adapter.

Related: NousResearch#36186 (different bug in the same file -- clarify text
disappearing when Discord hides embed bodies entirely, not button
label truncation).

Review fixes (per hermes-sweeper automated review on PR NousResearch#62291):
- The embed field truncation only capped the option-list portion at
  1024 chars, then appended a ~65-char instruction suffix afterward --
  the combined value could reach ~1089 chars, over Discord's real
  1024-char embed-field limit, causing send_clarify() to fail on
  exactly the long-choice-list case this fix exists to handle. Now
  reserves suffix length before truncating so the combined field
  value never exceeds the cap. Added a boundary regression test with
  24 long choices asserting the rendered field stays <= 1024 chars
  and the suffix is never dropped.
- The plain-text message-content mirror now explicitly uses the
  *untruncated* option list (Discord's 2000-char content cap is much
  larger than the embed field's 1024), rather than reusing whatever
  the embed truncated to.
- Rebased onto a clean upstream main and dropped four unrelated
  fork-local commits (three explicitly tagged [carried], one
  untagged plugin symlink fix) that had accumulated on the source
  branch before this PR was cut -- this PR is Discord-only again.

Tests: tests/gateway/test_discord_clarify_buttons.py -- 5
truncation-behavior tests replaced with simpler "label is always
short" tests, 5 dict-unwrap tests updated to assert the full text
lands in the embed field rather than the button label, plus 1 new
boundary regression test for the field-cap fix. 21/21 pass. ruff
clean. git diff --check clean.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have platform/discord Discord bot 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.

Discord component labels use code-point slicing instead of UTF-16 limits

3 participants