mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-21 10:22:18 +00:00
Two bugs surfaced from production usage in #37134: 1. Dict choices rendered as Python repr. LLMs sometimes emit [{"description": "..."}] instead of bare strings; the old str(c).strip() coercion turned the whole dict into "{'description': '...'}" on the button label. Fix: add a _flatten_choice helper that unwraps dicts against the canonical LLM tool-call user-facing keys (label, description, text, title) in that order. Dicts with none of those keys are dropped. The "name" and "value" keys are deliberately NOT in the priority list — they're Discord-component-shaped fields that could appear in dicts that aren't meant to be choices (a developer-error wiring that passes a Button-shaped object); picking them would leak raw enum values or 4-char model identifiers onto user-facing buttons. 2. Mid-word truncation on long button labels. The old choice[:72] + "..." cut at position 72, mid-word. Worse, the three-char ellipsis ate into the 80-char Discord label cap, leaving only 75 chars of body. Fix: budget-aware cut strategy with three tiers: a. Last space in the trailing half of the budget (word boundary). b. Last soft boundary (- , . )) in the trailing half — used only when no word boundary exists. c. Hard cut at the budget limit (last resort). Use single U+2026 (…) to fit the cap. Cut AT soft boundaries (inclusive) so the label ends on the boundary char rather than on the alpha char that followed it. Tests: - test_unwraps_dict_choices_to_description: reproduces the screenshot in #37134, asserts the Python repr is gone. - test_unwrap_prefers_description_over_name_in_multi_key_dict: regression guard for the name-key order in the unwrap list. - test_unwrap_prefers_label_over_description: regression guard for label winning over description. - test_unwrap_does_not_pick_value_or_name_alone: regression guard for the "name"/"value" fields being absent. - test_truncates_long_choice_label: 200-char input, asserts total <= 80 and U+2026. - test_truncates_long_choice_label_breaks_on_word_boundary: asserts the cut is on a space, not mid-word. - test_truncates_long_no_space_choice_on_soft_boundary: adversarial input where position 76 is mid-word alpha, asserts the renderer falls back to a soft boundary. Parity: telegram clarify suite (12 tests) still passes; the helper is a Discord adapter local, not shared with the gateway. Follow-up: gateway/platforms/telegram.py has the same str(c).strip() pattern in its own send_clarify and will need a similar fix (separate PR to keep this diff reviewable). Fixes #37134 |
||
|---|---|---|
| .. | ||
| discord | ||
| google_chat | ||
| homeassistant | ||
| irc | ||
| line | ||
| mattermost | ||
| ntfy | ||
| photon | ||
| simplex | ||
| teams | ||