Skip to content

feat(telegram): send rich messages as rich html#93286

Merged
obviyus merged 16 commits into
mainfrom
codex/telegram-rich-message
Jun 15, 2026
Merged

feat(telegram): send rich messages as rich html#93286
obviyus merged 16 commits into
mainfrom
codex/telegram-rich-message

Conversation

@obviyus

@obviyus obviyus commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Render Telegram Markdown through OpenClaw Markdown IR into Bot API 10.1 rich HTML before sendRichMessage.
  • Preserve supported rich tags for tables, details, pull quotes, checklists, anchors, math, rich media, and split the final rendered rich HTML against Telegram limits.
  • Teach Telegram agents about the new rich formatting surface.

Proof

  • node scripts/run-vitest.mjs extensions/telegram/src/bot-message-dispatch.test.ts extensions/telegram/src/format.test.ts packages/markdown-core/src/ir.raw-html.test.ts extensions/telegram/src/send.test.ts extensions/telegram/src/draft-stream.test.ts extensions/telegram/src/telegram-outbound.test.ts src/agents/system-prompt.test.ts src/agents/cli-runner/helpers.system-prompt.test.ts
  • node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.extensions.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/extensions-test.tsbuildinfo
  • node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.test.packages.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/test-packages.tsbuildinfo
  • node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.test.src.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/test-src.tsbuildinfo

@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation channel: telegram Channel integration: telegram agents Agent runtime and tooling size: L maintainer Maintainer-authored PR labels Jun 15, 2026
@clawsweeper

clawsweeper Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed June 15, 2026, 8:44 AM ET / 12:44 UTC.

Summary
The PR changes Telegram outbound rich-message rendering from raw rich Markdown to OpenClaw Markdown IR rendered as Telegram Bot API rich HTML, with related chunking, sanitization, docs, prompts, and tests.

PR surface: Source +136, Tests +126, Docs 0. Total +262 across 16 files.

Reproducibility: yes. for the review finding from source inspection and the Telegram Bot API rich-message contract; no live Telegram repro was run. The current-main Markdown path preserves Telegram parsing, while the PR turns table cells into escaped string-only HTML cells.

Review metrics: 1 noteworthy metric.

  • Telegram payload mode: 1 outbound text path changed from markdown to html. Changing the Bot API rich_message payload shape is the core compatibility surface maintainers need to review beyond green tests.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🧂 unranked krab
Patch quality: 🦐 gold shrimp
Result: blocked until real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Preserve Markdown table-cell inline formatting or keep those tables on a rich Markdown path.
  • [P1] Add redacted real Telegram Desktop or live bot proof showing representative rich HTML output after the patch.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The PR body lists tests and type checks only; it needs redacted real Telegram proof such as a screenshot, recording, terminal/live output, linked artifact, or logs showing the changed rendering after the patch. After adding proof, update the PR body so ClawSweeper can re-review automatically, or ask a maintainer to comment @clawsweeper re-review if it does not.

Mantis proof suggestion
Native Telegram Desktop proof would materially help verify that Telegram accepts and renders the generated rich HTML after this patch. A maintainer can ask Mantis to capture proof by posting a new PR comment that starts with the OpenClaw Mantis account mention, followed by:

telegram desktop proof: verify rich Telegram HTML rendering for headings, tables with inline formatting, details, links, media blocks, and currency text after this patch.

Risk before merge

  • [P1] The PR changes the outbound Telegram payload mode from rich_message.markdown to rich_message.html for Markdown text, and real Bot API/client rendering for representative generated HTML is not proven by the PR body.
  • [P1] Markdown tables that currently rely on Telegram rich Markdown for inline cell formatting can render differently because the PR serializes table metadata as escaped plain text before building rich HTML.

Maintainer options:

  1. Fix And Prove Rich HTML Before Merge (recommended)
    Preserve Markdown table-cell inline formatting in the generated rich HTML and add redacted real Telegram proof for representative headings, tables, details, links, media blocks, and currency text.
  2. Accept A Narrower Table Scope
    Maintainers could intentionally accept plain table cells, but the docs and prompt should stop claiming preserved table spans or supported rich table behavior beyond what the conversion actually keeps.
  3. Pause Until Live Proof Exists
    If no real Telegram artifact can be provided, pause this visible transport feature because CI does not prove Telegram accepts and renders the generated rich HTML as intended.

Next step before merge

  • [P1] Human maintainer review is needed because the PR has a protected maintainer label, lacks contributor real-behavior proof, and the remaining correctness issue is tied to Telegram rendering semantics.

Security
Cleared: No concrete repo-side security or supply-chain regression was found; the diff does not change dependencies, workflows, lockfiles, secrets handling, package scripts, or downloaded code paths.

Review findings

  • [P2] Preserve table-cell inline formatting — extensions/telegram/src/format.ts:725-726
Review details

Best possible solution:

Preserve table-cell inline formatting through the IR-to-rich-HTML conversion or keep those tables on a rich Markdown path, then attach redacted Telegram Desktop or live bot proof before maintainer merge.

Do we have a high-confidence way to reproduce the issue?

Yes for the review finding from source inspection and the Telegram Bot API rich-message contract; no live Telegram repro was run. The current-main Markdown path preserves Telegram parsing, while the PR turns table cells into escaped string-only HTML cells.

Is this the best way to solve the issue?

No: the IR-to-rich-HTML direction is plausible for avoiding Rich Markdown sigil ambiguity, but this patch is not yet the best fix because it drops supported table-cell inline formatting and lacks real Telegram proof. The safer path is to preserve the full rich-table contract first, then prove the live output.

Full review comments:

  • [P2] Preserve table-cell inline formatting — extensions/telegram/src/format.ts:725-726
    This renders Markdown tables from string-only metadata and escapes each cell, so a cell like **42** <sup>ms</sup> loses the inline formatting that current main leaves for Telegram rich Markdown to parse and that the Bot API rich-message docs support. Carry cell spans/links/supported tags through the table metadata, or keep Markdown tables on a rich Markdown path that preserves those semantics.
    Confidence: 0.86

Overall correctness: patch is incorrect
Overall confidence: 0.86

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against a09f6b1b2787.

Label changes

Label changes:

  • add P2: This is a normal-priority user-visible Telegram channel feature with bounded but real rendering impact.
  • add merge-risk: 🚨 compatibility: The PR changes how existing Telegram Markdown table replies are rendered during upgrade, which can alter supported inline formatting in table cells.
  • add merge-risk: 🚨 message-delivery: The PR changes the final Telegram Bot API rich_message payload shape, so unsupported or malformed generated HTML can render incorrectly or be rejected by Telegram.

Label justifications:

  • P2: This is a normal-priority user-visible Telegram channel feature with bounded but real rendering impact.
  • merge-risk: 🚨 compatibility: The PR changes how existing Telegram Markdown table replies are rendered during upgrade, which can alter supported inline formatting in table cells.
  • merge-risk: 🚨 message-delivery: The PR changes the final Telegram Bot API rich_message payload shape, so unsupported or malformed generated HTML can render incorrectly or be rejected by Telegram.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🦐 gold shrimp.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body lists tests and type checks only; it needs redacted real Telegram proof such as a screenshot, recording, terminal/live output, linked artifact, or logs showing the changed rendering after the patch. After adding proof, update the PR body so ClawSweeper can re-review automatically, or ask a maintainer to comment @clawsweeper re-review if it does not.
  • mantis: telegram-visible-proof: Mantis should capture Telegram visible proof. The PR changes user-visible Telegram chat formatting, including rich HTML rendering, tables, details, links, media blocks, and currency text.
Evidence reviewed

PR surface:

Source +136, Tests +126, Docs 0. Total +262 across 16 files.

View PR surface stats
Area Files Added Removed Net
Source 8 382 246 +136
Tests 7 224 98 +126
Docs 1 3 3 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 16 609 347 +262

What I checked:

  • Repository policy applied: Read the root policy plus scoped extension, docs, and agents policies; the Telegram maintainer note requires real Telegram proof for transport-visible Telegram behavior PRs. (.agents/maintainer-notes/telegram.md:37, a09f6b1b2787)
  • PR proof is synthetic only: The live PR body lists focused Vitest and tsgo commands, but no redacted Telegram screenshot, recording, live output, terminal proof, logs, or linked artifact showing the changed rendering after the patch. (a03fa890866d)
  • PR changes Markdown sends to rich HTML: The PR makes buildTelegramRichMarkdown render Markdown into Telegram rich HTML, then send an html rich_message payload instead of the current markdown payload. (extensions/telegram/src/rich-message.ts:158, a03fa890866d)
  • Current main preserves raw rich Markdown: Current main's buildTelegramRichMarkdown sends sanitized normalized Markdown as rich_message.markdown, which leaves Telegram's rich Markdown table-cell parsing to Telegram. (extensions/telegram/src/rich-message.ts:146, a09f6b1b2787)
  • Table metadata drops cell spans before rich HTML rendering: MarkdownTableMeta stores only string headers and rows, and the PR renders each table cell by escaping that string, so inline spans and supported raw tags in Markdown table cells are not carried into the generated rich HTML table. (extensions/telegram/src/format.ts:725, a03fa890866d)
  • Telegram contract supports inline formatting inside table cells: Official Telegram Bot API rich-message docs state that table cells can contain inline formatting and include an example table cell with bold Markdown plus a supported sup tag, so dropping those spans changes supported rich table behavior.

Likely related people:

  • obviyus: Authored the merged Telegram rich-message work and current PR, with prior merged commits adding rich text sends and table-limit coverage on the same path. (role: implemented current behavior and recent area contributor; confidence: high; commits: 547cc0f10903, 93318050e12b, 80d2b40fac67; files: extensions/telegram/src/send.ts, extensions/telegram/src/rich-message.ts, extensions/telegram/src/send.test.ts)
  • vincentkoc: Recent current-main history includes a rich-message typecheck repair and broad adjacent agent/channel work in the touched surface. (role: recent adjacent contributor; confidence: medium; commits: 42759a1b799b; files: extensions/telegram/src/rich-message.ts, src/agents/system-prompt.ts)
  • steipete: Prior current-main history includes Telegram outbound table-mode propagation and the sampled shortlog shows heavy ownership across the touched Telegram, markdown, and agent prompt files. (role: adjacent table-path contributor; confidence: medium; commits: 7fc691a426cb; files: extensions/telegram/src/telegram-outbound.ts, extensions/telegram/src/telegram-outbound.test.ts, extensions/telegram/src/send.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@obviyus obviyus self-assigned this Jun 15, 2026
@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. mantis: telegram-visible-proof Mantis should capture Telegram visible proof. labels Jun 15, 2026
@clawsweeper
clawsweeper Bot temporarily deployed to qa-live-shared June 15, 2026 12:35 Inactive
@clawsweeper clawsweeper Bot added P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. labels Jun 15, 2026
@obviyus
obviyus deleted the codex/telegram-rich-message branch June 15, 2026 15:08
@obviyus

obviyus commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

Landed via squash onto main.

  • Scoped tests: node scripts/run-vitest.mjs src/config/markdown-tables.test.ts packages/markdown-core/src/ir.table-block.test.ts extensions/telegram/src/bot-message-dispatch.test.ts extensions/telegram/src/format.test.ts packages/markdown-core/src/ir.raw-html.test.ts extensions/telegram/src/send.test.ts extensions/telegram/src/draft-stream.test.ts extensions/telegram/src/telegram-outbound.test.ts src/agents/system-prompt.test.ts src/agents/cli-runner/helpers.system-prompt.test.ts (passed: unit-fast 91, runtime-config 8, agents 6, extension-telegram 347)
  • Typecheck: node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.extensions.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/extensions-test.tsbuildinfo && node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.test.packages.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/test-packages.tsbuildinfo && node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.test.src.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/test-src.tsbuildinfo (passed)
  • Autoreview: .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main --thinking medium --no-web-search (clean)
  • Changelog: not updated; release generation owns CHANGELOG.md.
  • PR head: eb2d91079ace69e7a7509d13c54474008985a089
  • Squash commit: da92615816b66e56bc46f92f16da144d5510ec48

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jun 16, 2026
* feat(telegram): render rich messages through rich html

* docs(telegram): teach agents rich formatting

* fix(telegram): bound rich draft payloads (openclaw#93286)

* fix(telegram): narrow rich draft payload type (openclaw#93286)

* fix(telegram): preserve rich table cell formatting (openclaw#93286)

* fix(telegram): honor rich table mode config (openclaw#93286)

* fix(telegram): default rich markdown tables (openclaw#93286)

* fix(telegram): gate rich table block mode (openclaw#93286)

* fix(telegram): normalize raw rich html limits (openclaw#93286)

* fix(telegram): preserve link preview suppression (openclaw#93286)

* fix(telegram): preserve rich markdown headings (openclaw#93286)

* fix(telegram): reject unsupported rich media sources (openclaw#93286)

* fix(telegram): honor link preview off in rich chunks (openclaw#93286)

* fix(telegram): avoid double escaping markdown media (openclaw#93286)

* fix(telegram): render markdown media via placeholders (openclaw#93286)

* fix(telegram): preserve table text in prompt context (openclaw#93286)
crh-code pushed a commit to crh-code/openclaw that referenced this pull request Jun 18, 2026
* feat(telegram): render rich messages through rich html

* docs(telegram): teach agents rich formatting

* fix(telegram): bound rich draft payloads (openclaw#93286)

* fix(telegram): narrow rich draft payload type (openclaw#93286)

* fix(telegram): preserve rich table cell formatting (openclaw#93286)

* fix(telegram): honor rich table mode config (openclaw#93286)

* fix(telegram): default rich markdown tables (openclaw#93286)

* fix(telegram): gate rich table block mode (openclaw#93286)

* fix(telegram): normalize raw rich html limits (openclaw#93286)

* fix(telegram): preserve link preview suppression (openclaw#93286)

* fix(telegram): preserve rich markdown headings (openclaw#93286)

* fix(telegram): reject unsupported rich media sources (openclaw#93286)

* fix(telegram): honor link preview off in rich chunks (openclaw#93286)

* fix(telegram): avoid double escaping markdown media (openclaw#93286)

* fix(telegram): render markdown media via placeholders (openclaw#93286)

* fix(telegram): preserve table text in prompt context (openclaw#93286)
badgerbees pushed a commit to badgerbees/openclaw that referenced this pull request Jul 8, 2026
* feat(telegram): render rich messages through rich html

* docs(telegram): teach agents rich formatting

* fix(telegram): bound rich draft payloads (openclaw#93286)

* fix(telegram): narrow rich draft payload type (openclaw#93286)

* fix(telegram): preserve rich table cell formatting (openclaw#93286)

* fix(telegram): honor rich table mode config (openclaw#93286)

* fix(telegram): default rich markdown tables (openclaw#93286)

* fix(telegram): gate rich table block mode (openclaw#93286)

* fix(telegram): normalize raw rich html limits (openclaw#93286)

* fix(telegram): preserve link preview suppression (openclaw#93286)

* fix(telegram): preserve rich markdown headings (openclaw#93286)

* fix(telegram): reject unsupported rich media sources (openclaw#93286)

* fix(telegram): honor link preview off in rich chunks (openclaw#93286)

* fix(telegram): avoid double escaping markdown media (openclaw#93286)

* fix(telegram): render markdown media via placeholders (openclaw#93286)

* fix(telegram): preserve table text in prompt context (openclaw#93286)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling channel: telegram Channel integration: telegram docs Improvements or additions to documentation maintainer Maintainer-authored PR mantis: telegram-visible-proof Mantis should capture Telegram visible proof. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. P2 Normal backlog priority with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: XL status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant