Skip to content

fix(send_message): use markdown for DingTalk standalone webhook delivery#34400

Closed
WenhuaXia wants to merge 2 commits into
NousResearch:mainfrom
WenhuaXia:fix/dingtalk-markdown-webhook
Closed

fix(send_message): use markdown for DingTalk standalone webhook delivery#34400
WenhuaXia wants to merge 2 commits into
NousResearch:mainfrom
WenhuaXia:fix/dingtalk-markdown-webhook

Conversation

@WenhuaXia

Copy link
Copy Markdown

Summary

  • Standalone cron delivery sends msgtype: "text" for DingTalk, which doesn't render markdown tables — pipes show as literal characters
  • The live DingTalk adapter sends msgtype: "markdown" which renders tables correctly
  • Align the two paths so all DingTalk deliveries render markdown consistently
  • Adds 20K character truncation (matching live adapter's MAX_MESSAGE_LENGTH)
  • Falls back to plain text if the API rejects the markdown payload

Test plan

  • Configure DINGTALK_WEBHOOK_URL and verify cron job delivery renders markdown tables
  • Verify fallback to text works when markdown is rejected
  • Verify existing Telegram/Discord/Slack standalone delivery is unaffected

🤖 Generated with Claude Code

WenhuaXia and others added 2 commits May 26, 2026 15:04
…er concurrent writes

Root cause: multiple kanban worker processes (hermes -p <profile>) open
independent sqlite3 connections to the same kanban.db. SQLite WAL + BEGIN
_IMMEDIATE only protects within-process threads — concurrent writers from
different processes can still corrupt the WAL under heavy write pressure
(task_events + task_runs + status transitions within the same tick).

Fix: acquire an fcntl.LOCK_EX on a per-DB .db.lock file around every
write_txn().  The lock fd is stored in a module-level dict keyed by
id(conn) (sqlite3.Connection is a C-extension type that rejects both
attribute assignment and weakref).  On platforms without fcntl (Windows)
or when the lock file can't be opened, the lock is a graceful no-op.

This preserves the existing WAL + BEGIN IMMEDIATE strategy while
serialising cross-process writes, which is the common pattern for
SQLite-based multi-process workloads.
Standalone fallback sends msgtype: "text" which doesn't render markdown
tables. The live DingTalk adapter sends msgtype: "markdown" which works.
Align the two paths so cron job delivery renders tables correctly.

Also adds 20K character truncation (matching live adapter limit) and
fallback to plain text if the API rejects the markdown payload.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have platform/dingtalk DingTalk adapter comp/cron Cron scheduler and job management labels May 29, 2026
@WenhuaXia

Copy link
Copy Markdown
Author

Closing — will be reopened as a bilingual PR on a clean branch.

@WenhuaXia WenhuaXia closed this Jun 2, 2026
WenhuaXia added a commit to WenhuaXia/hermes-agent that referenced this pull request Jun 2, 2026
…+ DingTalk markdown webhook

看板 SQLite 跨进程写锁(inter-process flock):
Kanban SQLite cross-process write lock (inter-process flock):

问题:多个 kanban worker 进程并发写入同一 SQLite 数据库导致
WAL 损坏。SQLite WAL + busy_timeout 只能保护同一进程内的
并发线程,跨进程仍会竞争 BEGIN IMMEDIATE 导致页面损坏。

Problem: Multiple kanban worker processes writing concurrently to the
same SQLite database caused frequent WAL corruption. SQLite WAL +
busy_timeout only protects concurrent threads within the same process;
cross-process races through BEGIN IMMEDIATE can corrupt WAL pages.

修复:
Fix:
1. connect() 后打开 .db.lock 文件,write_txn() 用 fcntl.flock(LOCK_EX)
   包裹整个事务,确保同一时间只有一个进程在写。
2. schema init 也获取 .db.lock(不只是 .init.lock),防止 DDL/DML 竞争。
3. Windows 或 fcntl 不可用时优雅降级为 no-op。

1. After connect(), open a .db.lock file. Every write_txn() acquires
   fcntl.flock(LOCK_EX) around the entire transaction, ensuring only one
   process writes at a time.
2. Schema init also acquires .db.lock (not just .init.lock) to prevent
   DDL/DML races.
3. Graceful fallback on Windows or when fcntl is unavailable.

钉钉 webhook Markdown 渲染:
DingTalk webhook Markdown rendering:

问题:standalone cron delivery 用 msgtype:"text" 发钉钉消息,markdown
表格中的管道符显示为文字。live adapter 用 msgtype:"markdown" 正确渲染。

Problem: Standalone cron delivery sent msgtype:"text" for DingTalk, which
does not render markdown tables — pipes show as literal characters. The
live DingTalk adapter sends msgtype:"markdown" which renders tables correctly.

修复:统一使用 msgtype:"markdown",被拒绝时 fallback 到纯文本。
Fix: Use msgtype:"markdown" consistently with fallback to plain text
if the API rejects the markdown payload.

Changes:
- hermes_cli/kanban_db.py: fcntl flock for inter-process write safety
- tools/send_message_tool.py: markdown msgtype for DingTalk standalone delivery

Related: NousResearch#35787 (closed), NousResearch#34400 (closed)
WenhuaXia added a commit to WenhuaXia/hermes-agent that referenced this pull request Jun 6, 2026
…alk standalone webhook

问题 / Problem: standalone cron delivery 用 msgtype:"text" 发钉钉消息,markdown
表格中的管道符显示为文字。live adapter 用 msgtype:"markdown" 正确渲染。

Problem: Standalone cron delivery sent msgtype:"text" for DingTalk, which does
not render markdown tables — pipes show as literal characters. The live
DingTalk adapter sends msgtype:"markdown" which renders tables correctly.

修复 / Fix: 统一使用 msgtype:"markdown",被拒绝时 fallback 到纯文本。
Fix: Use msgtype:"markdown" consistently with fallback to plain text if the
API rejects the markdown payload.

Changes:
- tools/send_message_tool.py: markdown msgtype for DingTalk standalone delivery

Related: NousResearch#34400 (closed), NousResearch#37292 (closed, split)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cron Cron scheduler and job management P3 Low — cosmetic, nice to have platform/dingtalk DingTalk adapter type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants