diff --git a/gateway/platforms/matrix.py b/gateway/platforms/matrix.py index cccb4d70e..a649bb91e 100644 --- a/gateway/platforms/matrix.py +++ b/gateway/platforms/matrix.py @@ -2799,11 +2799,11 @@ class MatrixAdapter(BasePlatformAdapter): def _markdown_to_html(self, text: str) -> str: """Convert Markdown to Matrix-compatible HTML (org.matrix.custom.html). - Uses the ``markdown`` library when available (installed with the - ``matrix`` extra). Falls back to a comprehensive regex converter - that handles fenced code blocks, inline code, headers, bold, - italic, strikethrough, links, blockquotes, lists, and horizontal - rules — everything the Matrix HTML spec allows. + Uses the ``markdown`` library (a core dependency) when available. + Falls back to a comprehensive regex converter that handles fenced + code blocks, inline code, headers, bold, italic, strikethrough, + links, blockquotes, lists, and horizontal rules — everything the + Matrix HTML spec allows. """ try: import markdown as _md diff --git a/pyproject.toml b/pyproject.toml index 0ce637528..2b12246e0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,6 +61,16 @@ dependencies = [ "prompt_toolkit==3.0.52", # Cron scheduler (built-in feature — scheduled cron/interval jobs use croniter). "croniter==6.0.0", + # Markdown -> HTML conversion for rich message delivery (Matrix + # `formatted_body`, and the `send_message` tool's HTML path). Now on the + # DEFAULT delivery path, not matrix-specific: without it both + # gateway/platforms/matrix.py and tools/send_message_tool.py silently fall + # back to plain text, so cron/agent deliveries render raw `##`/`**`/tables + # in clients like Element (see #32486). Pure-Python py3-none-any wheel + # (~108KB, no compiled extensions, no platform constraints), so unlike the + # matrix extra's `mautrix`/`python-olm` it's safe to ship everywhere — keeps + # it out of the lazy-install path that exists only for the heavy matrix deps. + "Markdown==3.10.2", # Skills Hub (GitHub App JWT auth — optional, only needed for bot identity) "PyJWT[crypto]==2.12.1", # CVE-2026-32597 # Windows has no IANA tzdata shipped with the OS, so Python's ``zoneinfo`` @@ -104,7 +114,7 @@ dev = ["debugpy==1.8.20", "pytest==9.0.2", "pytest-asyncio==1.3.0", "pytest-time messaging = ["python-telegram-bot[webhooks]==22.6", "discord.py[voice]==2.7.1", "aiohttp==3.13.3", "brotlicffi==1.2.0.1", "slack-bolt==1.27.0", "slack-sdk==3.40.1", "qrcode==7.4.2"] cron = [] # croniter is now a core dependency; this extra kept for back-compat slack = ["slack-bolt==1.27.0", "slack-sdk==3.40.1", "aiohttp==3.13.3"] -matrix = ["mautrix[encryption]==0.21.0", "Markdown==3.10.2", "aiosqlite==0.22.1", "asyncpg==0.31.0", "aiohttp-socks==0.11.0"] +matrix = ["mautrix[encryption]==0.21.0", "aiosqlite==0.22.1", "asyncpg==0.31.0", "aiohttp-socks==0.11.0"] # WeCom callback-mode adapter — parses untrusted XML POST bodies from # WeCom-controlled callback endpoints, so we use defusedxml (drop-in # replacement for stdlib xml.etree.ElementTree) to block billion-laughs diff --git a/tools/lazy_deps.py b/tools/lazy_deps.py index 0c0a2a6e9..5b5878eb4 100644 --- a/tools/lazy_deps.py +++ b/tools/lazy_deps.py @@ -135,7 +135,6 @@ LAZY_DEPS: dict[str, tuple[str, ...]] = { ), "platform.matrix": ( "mautrix[encryption]==0.21.0", - "Markdown==3.10.2", "aiosqlite==0.22.1", "asyncpg==0.31.0", "aiohttp-socks==0.11.0", diff --git a/uv.lock b/uv.lock index b10a215c9..c90be9add 100644 --- a/uv.lock +++ b/uv.lock @@ -1398,6 +1398,7 @@ dependencies = [ { name = "fire" }, { name = "httpx", extra = ["socks"] }, { name = "jinja2" }, + { name = "markdown" }, { name = "openai" }, { name = "pathspec" }, { name = "prompt-toolkit" }, @@ -1502,7 +1503,6 @@ matrix = [ { name = "aiohttp-socks" }, { name = "aiosqlite" }, { name = "asyncpg" }, - { name = "markdown" }, { name = "mautrix", extra = ["encryption"] }, ] mcp = [ @@ -1642,7 +1642,7 @@ requires-dist = [ { name = "httpx", extras = ["socks"], specifier = "==0.28.1" }, { name = "jinja2", specifier = "==3.1.6" }, { name = "lark-oapi", marker = "extra == 'feishu'", specifier = "==1.5.3" }, - { name = "markdown", marker = "extra == 'matrix'", specifier = "==3.10.2" }, + { name = "markdown", specifier = "==3.10.2" }, { name = "mautrix", extras = ["encryption"], marker = "extra == 'matrix'", specifier = "==0.21.0" }, { name = "mcp", marker = "extra == 'computer-use'", specifier = "==1.26.0" }, { name = "mcp", marker = "extra == 'dev'", specifier = "==1.26.0" },