Skip to content

fix(weixin): stop line wrapping from breaking markdown links - #51235

Open
KANIKIG wants to merge 1 commit into
NousResearch:mainfrom
KANIKIG:fix/weixin-preserve-markdown-link-wrapping
Open

fix(weixin): stop line wrapping from breaking markdown links#51235
KANIKIG wants to merge 1 commit into
NousResearch:mainfrom
KANIKIG:fix/weixin-preserve-markdown-link-wrapping

Conversation

@KANIKIG

@KANIKIG KANIKIG commented Jun 23, 2026

Copy link
Copy Markdown

What does this PR do?

Fixes a Weixin delivery-formatting regression where the copy-friendly long-line wrapper can split valid Markdown links in the middle of the [text](url) syntax. When that happens, WeChat receives broken Markdown and shows what should have been a clickable link as plain text.

This is most visible in cron/report/article-summary messages: the source Markdown is valid, but the Weixin adapter rewrites a long single-line link before delivery.

Root cause

Follow-up to #21258 / #19161. _wrap_copy_friendly_lines_for_weixin() intentionally wraps long non-code, non-table lines at WEIXIN_COPY_LINE_WIDTH so WeChat users can copy long prose more reliably.

That is still useful for plain text, but textwrap.wrap() does not understand Markdown inline syntax. A valid link such as:

[Designcenter NX中的分析载荷](https://...)

can be delivered as:

[Designcenter
NX中的分析载荷](https://...)

At that point WeChat no longer sees a valid Markdown link. The content is correct before formatting; it is corrupted during Weixin delivery formatting.

Related Issue

Follow-up to #21258 and #19161. I did not find an existing duplicate PR/issue for the interaction between Weixin copy-friendly wrapping and long Markdown links.

Related historical context, but not duplicates:

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✅ Tests (adding or improving test coverage)

Changes Made

  • gateway/platforms/weixin.py: skip copy-friendly wrapping for lines that contain Markdown links, reusing the existing _MARKDOWN_LINK_RE.
  • tests/gateway/test_weixin.py: add a regression test for long Markdown links that exceed WEIXIN_COPY_LINE_WIDTH.

This keeps #21258's wrapping behavior for long plain text, issue-template/log-style prose, and other copy-unfriendly lines, while treating Markdown links as atomic inline content.

How to Test

  1. Format a Weixin message containing a long Markdown link that exceeds WEIXIN_COPY_LINE_WIDTH.
  2. Before this change, the wrapper can insert a newline inside [text](url) and break the link.
  3. After this change, the Markdown link remains intact, while long plain text still wraps.

Tests run on Windows:

.\.venv\Scripts\python.exe -m pytest -p no:timeout -o "addopts=" tests/gateway/test_weixin.py::TestWeixinFormatting::test_format_message_wraps_long_plain_lines_for_copying tests/gateway/test_weixin.py::TestWeixinFormatting::test_format_message_does_not_wrap_long_markdown_links tests/gateway/test_weixin.py::TestWeixinFormatting::test_format_message_does_not_wrap_long_code_block_lines -q
# 3 passed

.\.venv\Scripts\python.exe scripts/run_tests_parallel.py tests/gateway/test_weixin.py -- -q -p no:timeout -o "addopts="
# 70 passed

.\.venv\Scripts\python.exe scripts/check-windows-footguns.py gateway/platforms/weixin.py tests/gateway/test_weixin.py
# No Windows footguns found

uv tool run --offline ruff@0.15.10 check gateway/platforms/weixin.py tests/gateway/test_weixin.py
# All checks passed

git diff --check
# passed

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix
  • I've run the relevant pytest suite and all targeted tests pass
  • I've added tests for my changes
  • I've tested on Windows

Documentation & Housekeeping

  • Documentation update N/A — this preserves existing Weixin formatting semantics
  • cli-config.yaml.example N/A — no config changes
  • CONTRIBUTING.md / AGENTS.md N/A — no workflow or architecture changes
  • Cross-platform impact considered — change is pure string formatting logic
  • Tool descriptions/schemas N/A — no tool schema changes

Copilot AI review requested due to automatic review settings June 23, 2026 06:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a Weixin delivery formatting regression where the “copy-friendly” long-line wrapper could insert newlines inside valid Markdown link syntax ([text](url)), causing WeChat to render links as plain text.

Changes:

  • Update Weixin’s copy-friendly wrapper to skip wrapping any line that contains an inline Markdown link (detected via existing _MARKDOWN_LINK_RE).
  • Add a regression test ensuring long Markdown links are not modified/wrapped even when exceeding WEIXIN_COPY_LINE_WIDTH.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
gateway/platforms/weixin.py Prevents the copy-friendly line wrapper from splitting lines containing Markdown links.
tests/gateway/test_weixin.py Adds regression coverage for long inline Markdown links so they remain intact after formatting.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@alt-glitch alt-glitch added type/bug Something isn't working comp/gateway Gateway runner, session dispatch, delivery platform/wecom WeCom / WeChat Work adapter P3 Low — cosmetic, nice to have sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages labels Jun 23, 2026

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for tracing this to the copy-friendly wrapper; the current-main path does pass long lines through textwrap.wrap() at gateway/platforms/weixin.py:726, so protecting inline link syntax is needed.

Problems

  • gateway/platforms/weixin.py:722 skips wrapping the entire line when it contains any Markdown link. That removes the intended copy-friendly behavior for a long prose/report line containing even a short link; the wrapper was added for long copy-unfriendly lines in 7244a1f0d3c17631661fbf103440a3790ab0bab9.
  • The new test only covers a nearly all-link line. It does not preserve the wrapper's behavior for prose surrounding an inline link.

Suggested changes

  • Protect matched [label](url) spans as atomic tokens, but continue wrapping surrounding prose.
  • Add a test with a space-containing link label embedded in long prose, asserting both that the link stays contiguous and that non-link prose is still wrapped.

Automated hermes-sweeper review.

or not stripped
or stripped.startswith("|")
or _TABLE_RULE_RE.match(stripped)
or _MARKDOWN_LINK_RE.search(stripped)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This bypasses the copy-friendly wrapper for the entire line, including arbitrary surrounding prose. Please protect only the matched Markdown-link span(s) and keep wrapping text before/after them; add coverage for a long prose line containing a short inline link.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P3 Low — cosmetic, nice to have platform/wecom WeCom / WeChat Work adapter sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants