openclaw - 💡(How to fix) Fix [Bug] markdown.tables config is ignored during Telegram outbound message chunking / streaming

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Fix Action

Fix / Workaround

Here is a hotfix that resolves this issue by propagating the configuration context and resolving the table mode in chunkTelegramOutboundText.

Code Example

"channels": {
     "telegram": {
       "markdown": {
         "tables": "bullets"
       }
     }
   }

---

function markdownToTelegramHtmlChunks(markdown, limit, options = {}) {
	return markdownToTelegramChunks(markdown, limit, options).map((chunk) => chunk.html);
}

---

import { t as resolveMarkdownTableMode } from "./markdown-tables-D2-aDWLS.js";

function chunkTelegramOutboundText(text, limit, ctx) {
	const tableMode = resolveMarkdownTableMode({
		cfg: ctx?.cfg,
		channel: "telegram",
		accountId: ctx?.accountId
	});
	return ctx?.formatting?.parseMode === "HTML" ? splitTelegramHtmlChunks(text, limit) : markdownToTelegramHtmlChunks(text, limit, { tableMode });
}

---

function chunkTextForPlan(params) {
      return params.formatting 
          ? params.chunker(params.text, params.limit, { formatting: params.formatting, cfg: params.cfg, accountId: params.accountId }) 
          : params.chunker(params.text, params.limit, { cfg: params.cfg, accountId: params.accountId });
  }

---

const chunks = limit && params.adapter.chunker ? params.adapter.chunker(text, limit, {
      formatting: params.ctx.formatting,
      cfg: params.ctx.cfg,
      accountId: params.ctx.accountId
  }) : [text];
RAW_BUFFERClick to expand / collapse

Describe the Bug

When sending messages through the Telegram outbound adapter, if the parse mode is not explicitly HTML (such as during streaming assistant updates or chunked progress text), the message text is split using markdownToTelegramHtmlChunks(text, limit).

However, in the compiled output (specifically format-CqcuR36z.js / src/extensions/telegram/src/format.ts), the markdownToTelegramHtmlChunks function does not accept or propagate an options parameter to markdownToTelegramChunks. Consequently, the configured tableMode (e.g., "markdown.tables": "bullets") is completely ignored, and markdown tables are delivered to Telegram in their raw format (| --- |), which looks unrendered and messy.

Additionally, the delivery orchestrator (deliver.ts) and the reply payload sender (reply-payload.ts) do not supply the configuration context (cfg and accountId) to the chunker function, preventing it from resolving tableMode configuration for the channel.

Steps to Reproduce

  1. Set the following in openclaw.json:
    "channels": {
      "telegram": {
        "markdown": {
          "tables": "bullets"
        }
      }
    }
  2. Initiate a streaming response from an assistant that generates a Markdown table.
  3. Observe that the intermediate or final streaming message chunks delivered to Telegram render the raw markdown tables instead of converting them to lists/bullets.

Proposed Solution

Here is a hotfix that resolves this issue by propagating the configuration context and resolving the table mode in chunkTelegramOutboundText.

1. Accept options in markdownToTelegramHtmlChunks

Modify format-CqcuR36z.js to accept options and forward them:

function markdownToTelegramHtmlChunks(markdown, limit, options = {}) {
	return markdownToTelegramChunks(markdown, limit, options).map((chunk) => chunk.html);
}

2. Resolve tableMode in chunkTelegramOutboundText

Modify channel-RqV6hPGF.js (or the Telegram outbound adapter file) to import resolveMarkdownTableMode and resolve tableMode from the context:

import { t as resolveMarkdownTableMode } from "./markdown-tables-D2-aDWLS.js";

function chunkTelegramOutboundText(text, limit, ctx) {
	const tableMode = resolveMarkdownTableMode({
		cfg: ctx?.cfg,
		channel: "telegram",
		accountId: ctx?.accountId
	});
	return ctx?.formatting?.parseMode === "HTML" ? splitTelegramHtmlChunks(text, limit) : markdownToTelegramHtmlChunks(text, limit, { tableMode });
}

3. Propagate context down to chunkers

  • In deliver-Cp6bjPd4.js (outbound message plan): Update chunkTextForPlan and planOutboundTextMessageUnits to accept and pass cfg and accountId to the chunker call:
    function chunkTextForPlan(params) {
        return params.formatting 
            ? params.chunker(params.text, params.limit, { formatting: params.formatting, cfg: params.cfg, accountId: params.accountId }) 
            : params.chunker(params.text, params.limit, { cfg: params.cfg, accountId: params.accountId });
    }
  • In reply-payload-DP0q6t5P.js: Forward cfg and accountId when calling the chunker function in sendTextMediaPayload:
    const chunks = limit && params.adapter.chunker ? params.adapter.chunker(text, limit, {
        formatting: params.ctx.formatting,
        cfg: params.ctx.cfg,
        accountId: params.ctx.accountId
    }) : [text];

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING