Skip to content

fix(telegram): send_clarify budgets the HTML-escaped rendering - #115533

Open
EloquentBrush0x wants to merge 1 commit into
NousResearch:mainfrom
EloquentBrush0x:fix/2-telegram-clarify-length-budget
Open

EloquentBrush0x wants to merge 1 commit into
NousResearch:mainfrom
EloquentBrush0x:fix/2-telegram-clarify-length-budget

Conversation

@EloquentBrush0x

Copy link
Copy Markdown
Contributor

What does this PR do?

send_clarify escapes the question and each choice individually with no total length budget on the rendered card. Earlier today two sibling prompt cards were fixed for the exact same failure mode: _send_exec_approval_prompt (b502504) and send_slash_confirm (edd9fd6) both now budget their HTML/MarkdownV2-escaped rendering against Telegram's 4096-char cap using the shared _ea_fit bisection — because escaping expands text (&&amp;, <&lt;), a raw-length cut (or no cut at all) can still overflow the cap after escaping, and Telegram answers "Message is too long" instead of delivering the prompt.

send_clarify never got the same treatment. A long, model-controlled clarify question or many/long choices (tools/clarify_tool.py places no upstream length limit on either) can overflow the cap the same way, silently failing to deliver the clarify prompt.

Related Issue

None found. Related but non-overlapping: open PR #111093 explicitly scopes itself to "Slack, Discord, Google Chat and the relay" for a different readability concern (long choices becoming unreadable, not exceeding a hard length cap) and its file list confirms it never touches plugins/platforms/telegram/adapter.py.

Scope note: open PR #104081 touches the same send_clarify.build() function (replacing str(c) with a choice_label(c) helper to support {label, description} choice objects) — same lines, unrelated concern, no semantic conflict. Applying its choice_label() extraction on top of this PR's body-based restructuring is a one-line change (swap c for choice_label(c) in the choice-joining comprehension); this PR does not depend on or block that one.

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)

Changes Made

  • plugins/platforms/telegram/adapter.pysend_clarify: question + choices are now assembled as one raw body, fit through the shared _ea_fit bisection (same helper send_slash_confirm uses) measured after HTML-escaping, then escaped once. Budget reserves room for both the "❓ " header and _ea_fit's own "..." truncation suffix (which rides outside the budget it's given, per its docstring) — this reservation was missing from my first pass and caught by the new tests before commit.
  • tests/gateway/test_telegram_clarify_buttons.py — new: an oversized escaped choice-set test and an emoji-dense (UTF-16 unit) test, mirroring the sibling tests in test_telegram_approval_buttons.py.

How to Test

  1. pytest tests/gateway/test_telegram_clarify_buttons.py -v → 7 passed
  2. Sibling regression: pytest tests/gateway/test_telegram_approval_buttons.py tests/gateway/test_telegram_error_redaction.py -q → 21 passed
  3. Mutation-verify: reverting the fix makes both new tests fail (6009 <= 4096 assertion, i.e. the unbudgeted card is ~1.5x the cap), confirming they exercise the real defect.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits
  • 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 the relevant test slice and all tests pass
  • I've added tests for my changes
  • I've tested on my platform: macOS (Darwin 25.5.0)

Documentation & Housekeeping

  • I've updated relevant documentation (inline comment explaining the suffix-margin reservation)
  • I've updated cli-config.yaml.example — N/A
  • I've updated CONTRIBUTING.md/AGENTS.md — N/A
  • I've considered cross-platform impact — pure Python string handling, no platform surface
  • I've updated tool descriptions/schemas — N/A

🤖 Generated with Claude Code

send_clarify escaped the question and each choice individually with no total
length budget, unlike the exec-approval and slash-confirm cards fixed earlier
today (b502504, edd9fd6). A long, model-controlled question or many/long
choices can expand past Telegram's 4096-char cap once HTML-escaped, and
Telegram answers "Message is too long" instead of sending the prompt at all —
the same failure mode those two cards were just fixed for.

Reuses the shared _ea_fit bisection (gateway/platforms/base.py) the same way
send_slash_confirm does, including reserving budget for both the header and
_ea_fit's own "..." truncation suffix (which rides outside the budget it's
given, per its docstring) — an oversight caught by the new tests before this
was accounted for.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@whyyagswhy

Copy link
Copy Markdown
Contributor

Independent verification on the PR head (c8684b2): clarify-buttons suite 7/7 green on Linux. Budgeting the escaped rendering (not the raw text) is the correct measuring point: escaping only expands, so raw budgeting undercounts exactly when it matters, and matching the exec-approval cards keeps one policy. No findings.

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

This branch has not been deployed

No deployments
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/telegram Telegram 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.

3 participants