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

This commit is contained in:
ooiuuii 2026-06-29 23:08:03 +08:00 committed by Teknium
parent b8ce583e05
commit 87be36c240
3 changed files with 98 additions and 9 deletions

View file

@ -52,6 +52,9 @@ _DISCORD_COMMAND_SYNC_MAX_RATE_LIMIT_SLEEP_SECONDS = 30.0
# every slash command — not just the overflow ones. We keep the desired set
# at or below this limit at registration time.
_DISCORD_MAX_APP_COMMANDS = 100
_DISCORD_SELECT_FIELD_LIMIT = 100
_DISCORD_BUTTON_LABEL_LIMIT = 80
_DISCORD_ELLIPSIS = "\u2026"
_DISCORD_NONCONVERSATIONAL_METADATA_KEYS = frozenset({
"non_conversational",
"non_conversational_history",
@ -117,11 +120,18 @@ from gateway.platforms.base import (
cache_document_from_bytes,
SUPPORTED_DOCUMENT_TYPES,
_TEXT_INJECT_EXTENSIONS,
_prefix_within_utf16_limit,
utf16_len,
validate_inbound_media_size,
)
from tools.url_safety import is_safe_url
def _truncate_discord_component_text(text: str, limit: int) -> str:
"""Return text within Discord's UTF-16 component field budget."""
return _prefix_within_utf16_limit(str(text or ""), max(0, limit))
async def _wait_for_ready_or_bot_exit(
ready_event: asyncio.Event,
bot_task: asyncio.Task,
@ -6888,7 +6898,10 @@ def _define_discord_view_classes() -> None:
desc = "current" if p.get("is_current") else None
options.append(
discord.SelectOption(
label=label[:100],
label=_truncate_discord_component_text(
label,
_DISCORD_SELECT_FIELD_LIMIT,
),
value=p["slug"],
description=desc,
)
@ -6925,8 +6938,14 @@ def _define_discord_view_classes() -> None:
short = model_id.split("/")[-1] if "/" in model_id else model_id
options.append(
discord.SelectOption(
label=short[:100],
value=model_id[:100],
label=_truncate_discord_component_text(
short,
_DISCORD_SELECT_FIELD_LIMIT,
),
value=_truncate_discord_component_text(
model_id,
_DISCORD_SELECT_FIELD_LIMIT,
),
)
)
if not options:
@ -7205,15 +7224,18 @@ def _define_discord_view_classes() -> None:
# budget (hyphen, comma, period, paren)
# 3. Hard cut at the budget limit (last resort)
prefix = f"{index + 1}. "
budget = 80 - len(prefix)
if len(choice) <= budget:
budget = _DISCORD_BUTTON_LABEL_LIMIT - utf16_len(prefix)
if utf16_len(choice) <= budget:
label_body = choice
else:
truncated = choice[: budget - 1].rstrip()
truncated = _prefix_within_utf16_limit(
choice,
max(0, budget - utf16_len(_DISCORD_ELLIPSIS)),
).rstrip()
cut_at = -1
# 1. Last space in the trailing half of the budget.
space = truncated.rfind(" ")
if space >= budget // 2:
if space >= len(truncated) // 2:
cut_at = space
# 2. Soft boundary — only if no word boundary found.
# Find the latest soft boundary in the trailing half
@ -7226,11 +7248,11 @@ def _define_discord_view_classes() -> None:
(truncated.rfind(s) for s in ("-", ",", ".", ")")),
default=-1,
)
if latest_soft >= budget // 2:
if latest_soft >= len(truncated) // 2:
cut_at = latest_soft + 1
if cut_at > 0:
truncated = truncated[:cut_at]
label_body = truncated.rstrip() + ""
label_body = truncated.rstrip() + _DISCORD_ELLIPSIS
button = discord.ui.Button(
label=f"{prefix}{label_body}",
style=discord.ButtonStyle.primary,