fix(agent): gate Telegram rich-Markdown hint on rich_messages config
The platform hint in PLATFORM_HINTS['telegram'] always encouraged rich Markdown constructs (tables, task lists, math, collapsible details) even when rich_messages: false (the default). This caused the agent to produce formatting that MarkdownV2 cannot render, especially broken on Telegram Web. Split the hint into a base hint (MarkdownV2-compatible) and a TELEGRAM_RICH_MESSAGES_HINT extension. The extension is conditionally appended in system_prompt.py only when platforms.telegram.extra.rich_messages is true. Fixes #57122
This commit is contained in:
parent
34d07732dd
commit
b45a217e0a
4 changed files with 94 additions and 20 deletions
|
|
@ -659,19 +659,7 @@ PLATFORM_HINTS = {
|
|||
"Standard Markdown is automatically converted to Telegram formatting. "
|
||||
"Supported: **bold**, *italic*, ~~strikethrough~~, ||spoiler||, "
|
||||
"`inline code`, ```code blocks```, [links](url), and ## headers. "
|
||||
"Telegram now supports rich Markdown, so lean into it: whenever it "
|
||||
"makes the answer clearer or easier to scan, actively reach for real "
|
||||
"Markdown tables (pipe `| col | col |` syntax), bullet and numbered "
|
||||
"lists, task lists (`- [ ]` / `- [x]`), headings, nested blockquotes, "
|
||||
"collapsible details, footnotes/references, math/formulas (`$...$`, "
|
||||
"`$$...$$`), underline, subscript/superscript, marked (highlighted) "
|
||||
"text, and anchors. Default to structured formatting over dense "
|
||||
"paragraphs for any comparison, set of steps, key/value summary, or "
|
||||
"tabular data. Prefer real Markdown tables and task lists over "
|
||||
"hand-built bullet substitutes when presenting structured data; these "
|
||||
"degrade gracefully (tables become readable bullet groups) when rich "
|
||||
"rendering is unavailable, but advanced constructs like math and "
|
||||
"collapsible details may render as plain source text in that case. "
|
||||
"Prefer bullet lists and labeled key:value pairs for structured data. "
|
||||
"You can send media files natively: to deliver a file to the user, "
|
||||
"include MEDIA:/absolute/path/to/file in your response. Images "
|
||||
"(.png, .jpg, .webp) appear as photos, audio (.ogg) sends as voice "
|
||||
|
|
@ -865,6 +853,27 @@ PLATFORM_HINTS = {
|
|||
),
|
||||
}
|
||||
|
||||
# Telegram rich-messages extension — only injected when the user has opted in
|
||||
# to ``platforms.telegram.extra.rich_messages: true``. The base
|
||||
# PLATFORM_HINTS["telegram"] covers MarkdownV2-compatible constructs; this
|
||||
# extension adds the Bot API 10.1 rich-Markdown guidance (tables, task lists,
|
||||
# collapsible details, math, etc.).
|
||||
TELEGRAM_RICH_MESSAGES_HINT = (
|
||||
"Telegram now supports rich Markdown, so lean into it: whenever it "
|
||||
"makes the answer clearer or easier to scan, actively reach for real "
|
||||
"Markdown tables (pipe `| col | col |` syntax), bullet and numbered "
|
||||
"lists, task lists (`- [ ]` / `- [x]`), headings, nested blockquotes, "
|
||||
"collapsible details, footnotes/references, math/formulas (`$...$`, "
|
||||
"`$$...$$`), underline, subscript/superscript, marked (highlighted) "
|
||||
"text, and anchors. Default to structured formatting over dense "
|
||||
"paragraphs for any comparison, set of steps, key/value summary, or "
|
||||
"tabular data. Prefer real Markdown tables and task lists over "
|
||||
"hand-built bullet substitutes when presenting structured data; these "
|
||||
"degrade gracefully (tables become readable bullet groups) when rich "
|
||||
"rendering is unavailable, but advanced constructs like math and "
|
||||
"collapsible details may render as plain source text in that case. "
|
||||
)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Environment hints — execution-environment awareness for the agent.
|
||||
# Unlike PLATFORM_HINTS (which describe the messaging channel), these describe
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ from agent.prompt_builder import (
|
|||
SKILLS_GUIDANCE,
|
||||
STEER_CHANNEL_NOTE,
|
||||
TASK_COMPLETION_GUIDANCE,
|
||||
TELEGRAM_RICH_MESSAGES_HINT,
|
||||
TOOL_USE_ENFORCEMENT_GUIDANCE,
|
||||
TOOL_USE_ENFORCEMENT_MODELS,
|
||||
drain_truncation_warnings,
|
||||
|
|
@ -429,6 +430,20 @@ def build_system_prompt_parts(agent: Any, system_message: Optional[str] = None)
|
|||
except Exception:
|
||||
pass
|
||||
|
||||
# For Telegram: append the rich-messages extension only when the user has
|
||||
# opted in to ``platforms.telegram.extra.rich_messages: true``. The base
|
||||
# hint covers MarkdownV2-compatible constructs; the extension adds Bot API
|
||||
# 10.1 guidance (tables, task lists, math, collapsible details, etc.).
|
||||
if platform_key == "telegram" and _default_hint:
|
||||
try:
|
||||
from hermes_cli.config import load_config_readonly
|
||||
_cfg = load_config_readonly()
|
||||
_tg_extra = ((_cfg.get("platforms") or {}).get("telegram") or {}).get("extra") or {}
|
||||
if _tg_extra.get("rich_messages"):
|
||||
_default_hint = _default_hint.rstrip() + " " + TELEGRAM_RICH_MESSAGES_HINT
|
||||
except Exception:
|
||||
pass # Config read failure — fall back to base hint only
|
||||
|
||||
_effective_hint = _resolve_platform_hint(agent, platform_key, _default_hint)
|
||||
if platform_key == "tui" and _effective_hint:
|
||||
_effective_hint = _tui_embedded_pane_clarifier(_effective_hint)
|
||||
|
|
|
|||
|
|
@ -1092,15 +1092,22 @@ class TestPromptBuilderConstants:
|
|||
hint = PLATFORM_HINTS["telegram"]
|
||||
lowered = hint.lower()
|
||||
assert "Telegram has NO table syntax" not in hint
|
||||
assert "rich markdown" in lowered
|
||||
assert "table" in lowered
|
||||
assert "task list" in lowered
|
||||
assert "math" in lowered
|
||||
# Base hint covers MarkdownV2-compatible constructs.
|
||||
assert "MEDIA:" in hint
|
||||
# Rich-messages extension (TELEGRAM_RICH_MESSAGES_HINT) covers the
|
||||
# Bot API 10.1 guidance; it is injected conditionally in
|
||||
# system_prompt.py when rich_messages: true.
|
||||
from agent.prompt_builder import TELEGRAM_RICH_MESSAGES_HINT
|
||||
rich_lowered = TELEGRAM_RICH_MESSAGES_HINT.lower()
|
||||
assert "rich markdown" in rich_lowered
|
||||
assert "table" in rich_lowered
|
||||
assert "task list" in rich_lowered
|
||||
assert "math" in rich_lowered
|
||||
# Hint should proactively steer toward structured formatting, not just
|
||||
# permit it: bullet + numbered lists for scannable, structured output.
|
||||
assert "bullet" in lowered
|
||||
assert "numbered" in lowered
|
||||
# Local media delivery guidance must remain intact.
|
||||
assert "bullet" in rich_lowered
|
||||
assert "numbered" in rich_lowered
|
||||
# Local media delivery guidance must remain intact in the base hint.
|
||||
assert "include MEDIA:" in hint
|
||||
|
||||
def test_platform_hints_mattermost(self):
|
||||
|
|
|
|||
|
|
@ -99,3 +99,46 @@ class TestCodingContextBlock:
|
|||
monkeypatch.setenv("TERMINAL_CWD", str(tmp_path))
|
||||
agent = _make_agent(valid_tool_names=[], platform="cli")
|
||||
assert "coding agent" not in _stable_prompt(agent)
|
||||
|
||||
|
||||
class TestTelegramRichMessagesHint:
|
||||
"""Verify that TELEGRAM_RICH_MESSAGES_HINT is conditionally included."""
|
||||
|
||||
def test_base_hint_without_rich_messages(self, monkeypatch):
|
||||
"""When rich_messages is False (default), only the base hint is used."""
|
||||
agent = _make_agent(platform="telegram")
|
||||
# Mock config to return rich_messages: false (default)
|
||||
with patch("hermes_cli.config.load_config_readonly") as mock_cfg:
|
||||
mock_cfg.return_value = {
|
||||
"platforms": {"telegram": {"extra": {"rich_messages": False}}}
|
||||
}
|
||||
stable = _stable_prompt(agent)
|
||||
# Base hint should be present
|
||||
assert "Standard Markdown is automatically converted" in stable
|
||||
# Rich-messages extension should NOT be present
|
||||
assert "lean into it" not in stable
|
||||
assert "task lists" not in stable
|
||||
|
||||
def test_rich_hint_with_rich_messages_enabled(self, monkeypatch):
|
||||
"""When rich_messages is True, the rich-messages extension is appended."""
|
||||
agent = _make_agent(platform="telegram")
|
||||
with patch("hermes_cli.config.load_config_readonly") as mock_cfg:
|
||||
mock_cfg.return_value = {
|
||||
"platforms": {"telegram": {"extra": {"rich_messages": True}}}
|
||||
}
|
||||
stable = _stable_prompt(agent)
|
||||
# Base hint should be present
|
||||
assert "Standard Markdown is automatically converted" in stable
|
||||
# Rich-messages extension should be present
|
||||
assert "lean into it" in stable
|
||||
assert "task lists" in stable
|
||||
assert "math/formulas" in stable
|
||||
|
||||
def test_base_hint_without_config(self, monkeypatch):
|
||||
"""When config has no telegram section, only base hint is used."""
|
||||
agent = _make_agent(platform="telegram")
|
||||
with patch("hermes_cli.config.load_config_readonly") as mock_cfg:
|
||||
mock_cfg.return_value = {}
|
||||
stable = _stable_prompt(agent)
|
||||
assert "Standard Markdown is automatically converted" in stable
|
||||
assert "lean into it" not in stable
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue