diff --git a/nanobot/channels/feishu.py b/nanobot/channels/feishu.py index f657359..bbe5281 100644 --- a/nanobot/channels/feishu.py +++ b/nanobot/channels/feishu.py @@ -437,16 +437,36 @@ class FeishuChannel(BaseChannel): _CODE_BLOCK_RE = re.compile(r"(```[\s\S]*?```)", re.MULTILINE) - @staticmethod - def _parse_md_table(table_text: str) -> dict | None: + # Markdown bold/italic patterns that need to be stripped for table cells + _MD_BOLD_RE = re.compile(r"\*\*(.+?)\*\*") + _MD_ITALIC_RE = re.compile(r"(? str: + """Strip markdown formatting markers from text for plain display. + + Feishu table cells do not support markdown rendering, so we remove + the formatting markers to keep the text readable. + """ + # Remove bold markers + text = cls._MD_BOLD_RE.sub(r"\1", text) + # Remove italic markers + text = cls._MD_ITALIC_RE.sub(r"\1", text) + # Remove strikethrough markers + text = cls._MD_STRIKE_RE.sub(r"\1", text) + return text + + @classmethod + def _parse_md_table(cls, table_text: str) -> dict | None: """Parse a markdown table into a Feishu table element.""" lines = [_line.strip() for _line in table_text.strip().split("\n") if _line.strip()] if len(lines) < 3: return None def split(_line: str) -> list[str]: return [c.strip() for c in _line.strip("|").split("|")] - headers = split(lines[0]) - rows = [split(_line) for _line in lines[2:]] + headers = [cls._strip_md_formatting(h) for h in split(lines[0])] + rows = [[cls._strip_md_formatting(c) for c in split(_line)] for _line in lines[2:]] columns = [{"tag": "column", "name": f"c{i}", "display_name": h, "width": "auto"} for i, h in enumerate(headers)] return { @@ -513,11 +533,16 @@ class FeishuChannel(BaseChannel): if before: elements.append({"tag": "markdown", "content": before}) text = m.group(2).strip() + # Avoid double bold markers if text already contains them + if text.startswith("**") and text.endswith("**"): + display_text = text + else: + display_text = f"**{text}**" elements.append({ "tag": "div", "text": { "tag": "lark_md", - "content": f"**{text}**", + "content": display_text, }, }) last_end = m.end()