@dingtalk-real-ai/dingtalk-connector 0.8.12 → 0.8.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.en.md +31 -6
  3. package/README.md +31 -6
  4. package/docs/RELEASE_NOTES_V0.7.10.md +40 -0
  5. package/docs/RELEASE_NOTES_V0.7.2.md +143 -0
  6. package/docs/RELEASE_NOTES_V0.7.3.md +149 -0
  7. package/docs/RELEASE_NOTES_V0.7.4.md +206 -0
  8. package/docs/RELEASE_NOTES_V0.7.5.md +267 -0
  9. package/docs/RELEASE_NOTES_V0.7.6.md +219 -0
  10. package/docs/RELEASE_NOTES_V0.7.7.md +122 -0
  11. package/docs/RELEASE_NOTES_V0.7.8.md +101 -0
  12. package/docs/RELEASE_NOTES_V0.7.9.md +65 -0
  13. package/docs/RELEASE_NOTES_V0.8.0.md +53 -0
  14. package/docs/RELEASE_NOTES_V0.8.1.md +47 -0
  15. package/docs/RELEASE_NOTES_V0.8.10.md +49 -0
  16. package/docs/RELEASE_NOTES_V0.8.11.md +51 -0
  17. package/docs/RELEASE_NOTES_V0.8.12.md +63 -0
  18. package/docs/RELEASE_NOTES_V0.8.13-beta.0.md +69 -0
  19. package/docs/RELEASE_NOTES_V0.8.13.md +62 -0
  20. package/docs/RELEASE_NOTES_V0.8.2.md +55 -0
  21. package/docs/RELEASE_NOTES_V0.8.3.md +63 -0
  22. package/docs/RELEASE_NOTES_V0.8.4.md +45 -0
  23. package/docs/RELEASE_NOTES_V0.8.7.md +49 -0
  24. package/docs/RELEASE_NOTES_V0.8.8.md +63 -0
  25. package/docs/RELEASE_NOTES_V0.8.9.md +81 -0
  26. package/docs/RELEASE_NOTES_v0.7.0.md +142 -0
  27. package/docs/RELEASE_NOTES_v0.7.1.md +74 -0
  28. package/openclaw.plugin.json +1 -1
  29. package/package.json +13 -2
  30. package/src/channel.ts +18 -6
  31. package/src/config/schema.ts +2 -2
  32. package/src/core/connection.ts +9 -6
  33. package/src/core/message-handler.ts +30 -10
  34. package/src/reply-dispatcher.ts +4 -3
  35. package/src/services/media/file.ts +7 -2
  36. package/src/services/media.ts +19 -12
  37. package/src/services/messaging/card.ts +1 -2
  38. package/src/services/messaging.ts +29 -16
  39. package/src/utils/http-client.ts +2 -1
  40. package/docs/images/dingtalk.svg +0 -1
  41. package/docs/images/image-1.png +0 -0
  42. package/docs/images/image-2.png +0 -0
  43. package/docs/images/image-3.png +0 -0
  44. package/docs/images/image-4.png +0 -0
  45. package/docs/images/image-5.png +0 -0
  46. package/docs/images/image-6.png +0 -0
  47. package/docs/images/image-7.png +0 -0
  48. package/install-beta.sh +0 -438
  49. package/install-npm.sh +0 -167
@@ -0,0 +1,81 @@
1
+ # Release Notes - v0.8.9
2
+
3
+ ## 🎉 新版本亮点 / Highlights
4
+
5
+ 本次更新带来**引用消息完整解析**、**macOS LaunchAgent 兼容性修复**和**多项稳定性改进**。消息处理层新增对引用消息(reply)的递归解析,支持提取引用中的文本、媒体附件和链接;修复了 macOS LaunchAgent 环境下因无效文件描述符导致 WebSocket 连接失败的问题;同时修复了 AI Card 流式关闭的竞争条件、FormData CJS 互操作问题,并锁定 axios 版本以提升依赖稳定性。
6
+
7
+ This release introduces **quoted message parsing**, **macOS LaunchAgent compatibility**, and **multiple stability improvements**. The message handler now recursively parses quoted (reply) messages, extracting text, media attachments, and URLs. A fix for invalid file descriptors (EBADF) on macOS LaunchAgent environments prevents WebSocket connection failures. Additionally, the AI Card streaming close race condition is fixed, FormData CJS interop issues are resolved, and axios is pinned to v1.6.0 for dependency stability.
8
+
9
+ ## ✨ 功能与体验改进 / Features & Improvements
10
+
11
+ - **引用消息完整解析 / Quoted message full parsing**
12
+ 新增 `extractQuotedMsgText` 递归解析引用消息(最多 3 层嵌套),支持 text、richText、picture、video、audio、file、markdown、interactiveCard 等消息类型。引用消息中的媒体附件(图片/视频/音频/文件)会被自动提取并传递给下游处理。引用了含链接的文本消息时,链接会被提取用于 URL 路由(如 alidocs 文档链接)。
13
+ Added `extractQuotedMsgText` for recursive quoted message parsing (up to 3 levels), supporting text, richText, picture, video, audio, file, markdown, and interactiveCard message types. Media attachments in quoted messages are automatically extracted and passed downstream. URLs from quoted text messages are extracted for URL routing (e.g., alidocs document links).
14
+
15
+ - **新增配置项 / New configuration options**
16
+ `configSchema` 新增 `asyncMode`、`ackText`、`endpoint`、`debug` 四个配置字段,为异步消息处理和自定义端点提供灵活配置能力。
17
+ Added `asyncMode`, `ackText`, `endpoint`, `debug` to `configSchema`, enabling flexible configuration for async message processing and custom endpoints.
18
+
19
+ - **普通消息本地图片后处理 / Local image post-processing for normal messages**
20
+ `sendNormalToUser` 和 `sendNormalToGroup` 新增本地图片上传后处理,发送普通消息时自动将 Markdown 中的本地图片路径上传到钉钉并替换为 media_id,与 AI Card 消息行为保持一致。
21
+ Added local image upload post-processing to `sendNormalToUser` and `sendNormalToGroup`, automatically uploading local image paths in Markdown to DingTalk and replacing them with media_id, consistent with AI Card message behavior.
22
+
23
+ ## 🐛 修复 / Fixes
24
+
25
+ - **macOS LaunchAgent 环境 WebSocket 连接失败 / WebSocket connection failure on macOS LaunchAgent**
26
+ 修复 macOS LaunchAgent/daemon 环境下,进程启动时 stdin/stdout/stderr(fd 0/1/2)无效(EBADF),导致 Node.js 创建 TCP 连接时出现 EBADF 错误。启动前检测并将无效 fd 重定向到 `/dev/null`。
27
+ Fixed EBADF errors when creating TCP connections on macOS LaunchAgent/daemon environments where stdin/stdout/stderr (fd 0/1/2) are invalid at process startup. Invalid file descriptors are now detected and redirected to `/dev/null`.
28
+
29
+ - **AI Card 流式关闭竞争条件 / AI Card streaming close race condition**
30
+ 修复 `closeStreaming` 可能被 `onIdle` 和 `onError` 同时触发时的竞争条件。现在在函数开头立即捕获并清空 `currentCardTarget`(snapshot 模式),防止并发调用导致 `finishAICard` 收到 null 参数而崩溃。
31
+ Fixed a race condition where `closeStreaming` could be triggered simultaneously by `onIdle` and `onError`. Now captures and clears `currentCardTarget` at function entry (snapshot pattern), preventing concurrent calls from passing null to `finishAICard`.
32
+
33
+ - **FormData CJS 互操作问题 / FormData CJS interop issue**
34
+ 将 `form-data` 从动态 `import()` 改为静态 `import`,修复 jiti/ESM 环境下动态导入 CJS 模块时 `.default` 偶发为 `undefined` 导致 `Cannot read properties of undefined (reading 'registry')` 错误的问题。
35
+ Changed `form-data` from dynamic `import()` to static `import`, fixing intermittent `Cannot read properties of undefined (reading 'registry')` errors caused by `.default` being `undefined` when dynamically importing CJS modules in jiti/ESM environments.
36
+
37
+ - **纯文本图片路径误转换 / Bare image path false conversion**
38
+ 禁用纯文本中本地图片路径的自动转换为图片语法的行为。此前纯文本中出现的本地路径(如 `/path/to/image.png`)会被自动包裹为 `![](mediaId)`,影响用户只想展示路径文本的场景。
39
+ Disabled automatic conversion of bare local image paths in plain text to image syntax. Previously, local paths like `/path/to/image.png` in plain text were automatically wrapped as `![](mediaId)`, which was undesirable when users intended to display the path as text.
40
+
41
+ ## 🔧 内部改进 / Internal Improvements
42
+
43
+ - **Zod Schema 拆分兼容 Web UI / Zod Schema split for Web UI compatibility**
44
+ 将 `DingtalkConfigSchema` 拆分为 `DingtalkConfigBaseSchema`(纯 ZodObject)和带 `superRefine` 的完整 Schema,解决 `superRefine` 将 Schema 转为 `ZodEffects` 后无法用于 `buildChannelConfigSchema` 生成 JSON Schema 的问题。
45
+ Split `DingtalkConfigSchema` into `DingtalkConfigBaseSchema` (pure ZodObject) and the full schema with `superRefine`, fixing incompatibility with `buildChannelConfigSchema` JSON Schema generation.
46
+
47
+ - **configSchema 类型简化 / configSchema type simplification**
48
+ 将 `clientId`、`clientSecret`、`allowFrom`、`groupAllowFrom` 等字段的 JSON Schema 从 `oneOf` 联合类型简化为单一 `string` 类型,移除不再需要的 `secretInputJsonSchema`,降低配置复杂度。
49
+ Simplified JSON Schema for `clientId`, `clientSecret`, `allowFrom`, `groupAllowFrom` from `oneOf` union types to single `string` type, removing the no-longer-needed `secretInputJsonSchema`.
50
+
51
+ - **reply-dispatcher logger 统一 / reply-dispatcher logger unification**
52
+ 将 `reply-dispatcher.ts` 中手动构建的 log 对象替换为 `createLoggerFromConfig`,与项目其他模块的日志规范保持一致。
53
+ Replaced manually constructed log object in `reply-dispatcher.ts` with `createLoggerFromConfig`, aligning with the project's logging conventions.
54
+
55
+ - **锁定 axios 版本 / Pin axios version**
56
+ 将 `axios` 依赖从 `^1.6.0` 锁定为 `1.6.0`,避免自动升级引入不兼容变更。
57
+ Pinned `axios` dependency from `^1.6.0` to `1.6.0` to prevent automatic upgrades from introducing incompatible changes.
58
+
59
+ ## 📥 安装升级 / Installation & Upgrade
60
+
61
+ ```bash
62
+ # 通过 npm 安装最新版本 / Install latest version via npm
63
+ openclaw plugins install @dingtalk-real-ai/dingtalk-connector
64
+
65
+ # 或升级现有版本 / Or upgrade existing version
66
+ openclaw plugins update dingtalk-connector
67
+
68
+ # 通过 Git 安装 / Install via Git
69
+ openclaw plugins install https://github.com/DingTalk-Real-AI/dingtalk-openclaw-connector.git
70
+ ```
71
+
72
+ ## 🔗 相关链接 / Related Links
73
+
74
+ - [完整变更日志 / Full Changelog](https://github.com/DingTalk-Real-AI/dingtalk-openclaw-connector/blob/main/CHANGELOG.md)
75
+ - [使用文档 / Documentation](https://github.com/DingTalk-Real-AI/dingtalk-openclaw-connector/blob/main/README.md)
76
+
77
+ ---
78
+
79
+ **发布日期 / Release Date**:2026-03-31
80
+ **版本号 / Version**:v0.8.9
81
+ **兼容性 / Compatibility**:OpenClaw Gateway 0.4.0+
@@ -0,0 +1,142 @@
1
+ # Release Notes - v0.7.0
2
+
3
+ ## 🎉 新版本亮点 / Highlights
4
+
5
+ 本次更新带来了丰富的富媒体和文档处理能力,让 AI 助手能够更好地理解和处理各种类型的内容。新增了图片识别、文件解析、钉钉文档操作和多 Agent 路由等核心功能。
6
+
7
+ This update brings rich media and document processing capabilities, enabling AI assistants to better understand and process various types of content. New core features include image recognition, file parsing, DingTalk document operations, and multi-Agent routing.
8
+
9
+ ## ✨ 新增功能 / Added Features
10
+
11
+ ### 富媒体接收支持 / Rich Media Reception Support
12
+ - ✅ **JPEG 图片消息** - 支持接收钉钉中直接发送的 JPEG 图片,自动下载到 `~/.openclaw/workspace/media/inbound/` 目录
13
+ **JPEG Image Messages** - Support receiving JPEG images sent directly in DingTalk, automatically downloaded to `~/.openclaw/workspace/media/inbound/` directory
14
+ - ✅ **PNG 图片(富文本)** - 支持接收富文本消息中包含的 PNG 图片,自动提取 URL 和 downloadCode 并下载
15
+ **PNG Images (Rich Text)** - Support receiving PNG images contained in rich text messages, automatically extract URL and downloadCode and download
16
+ - ✅ **视觉模型集成** - 下载的图片自动传递给视觉模型,AI 可以识别和分析图片内容
17
+ **Vision Model Integration** - Downloaded images are automatically passed to vision models, AI can recognize and analyze image content
18
+ - ✅ **媒体文件管理** - 统一的文件命名格式 `openclaw-media-{timestamp}.{ext}`,便于管理和追踪
19
+ **Media File Management** - Unified file naming format `openclaw-media-{timestamp}.{ext}` for easy management and tracking
20
+
21
+ ### 文件附件提取 / File Attachment Extraction
22
+ - ✅ **Word 文档解析** - 支持解析 `.docx` 文件,通过 `mammoth` 库提取文本内容并注入到 AI 上下文
23
+ **Word Document Parsing** - Support parsing `.docx` files, extract text content via `mammoth` library and inject into AI context
24
+ - ✅ **PDF 文档解析** - 支持解析 `.pdf` 文件,通过 `pdf-parse` 库提取文本内容并注入到 AI 上下文
25
+ **PDF Document Parsing** - Support parsing `.pdf` files, extract text content via `pdf-parse` library and inject into AI context
26
+ - ✅ **纯文本文件** - 支持读取 `.txt`、`.md`、`.json` 等纯文本文件,内容直接注入到消息中
27
+ **Plain Text Files** - Support reading plain text files (`.txt`, `.md`, `.json`, etc.), content directly injected into messages
28
+ - ✅ **二进制文件处理** - 支持处理 `.xlsx`、`.pptx`、`.zip` 等二进制文件,文件保存到磁盘并在消息中报告路径
29
+ **Binary File Processing** - Support processing binary files (`.xlsx`, `.pptx`, `.zip`, etc.), files saved to disk and paths reported in messages
30
+
31
+ ### 钉钉文档 API / DingTalk Document API
32
+ - ✅ **创建文档** - `docs.create()` - 在指定空间中创建新的钉钉文档
33
+ **Create Document** - `docs.create()` - Create new DingTalk documents in specified spaces
34
+ - ✅ **追加内容** - `docs.append()` - 在现有文档上追加 Markdown 内容
35
+ **Append Content** - `docs.append()` - Append Markdown content to existing documents
36
+ - ✅ **搜索文档** - `docs.search()` - 根据关键词搜索钉钉文档
37
+ **Search Documents** - `docs.search()` - Search DingTalk documents by keywords
38
+ - ✅ **列举文档** - `docs.list()` - 列举指定空间下的所有文档
39
+ **List Documents** - `docs.list()` - List all documents under specified spaces
40
+ - ⚠️ **读取文档** - `docs.read()` - 当前不可用(见已知问题)
41
+ **Read Document** - `docs.read()` - Currently unavailable (see Known Issues)
42
+
43
+ ### 多 Agent 路由支持 / Multi-Agent Routing Support
44
+ - ✅ **多 Agent 会话隔离** - 支持一个连接器实例同时连接多个 Agent
45
+ **Multi-Agent Session Isolation** - Support one connector instance connecting to multiple Agents simultaneously
46
+ - ✅ **多机器人绑定** - 支持多个钉钉机器人分别绑定到不同的 Agent,实现角色分工和专业化服务
47
+ **Multi-Bot Binding** - Support multiple DingTalk bots binding to different Agents, enabling role division and specialized services
48
+ - ✅ **独立会话空间** - 每个 Agent 拥有独立的会话上下文,互不干扰
49
+ **Independent Session Space** - Each Agent has an independent session context without interference
50
+ - ✅ **灵活配置** - 通过 `accounts` 和 `bindings` 配置多个机器人,提供详细的配置示例和说明
51
+ **Flexible Configuration** - Configure multiple bots via `accounts` and `bindings`, with detailed configuration examples and instructions
52
+ - ✅ **向后兼容** - 单 Agent 场景下功能完全兼容,无需额外配置
53
+ **Backward Compatible** - Fully compatible with single Agent scenarios, no additional configuration required
54
+
55
+ ## 🐛 修复 / Fixes
56
+
57
+ - **语音消息播放异常修复** - 修复机器人发送语音消息播放异常问题,音频进度和播放功能现已正常工作
58
+ **Voice Message Playback Fix** - Fixed bot voice message playback issues, audio progress and playback functionality now work correctly
59
+
60
+ ## 🔧 改进 / Improvements
61
+
62
+ - **媒体文件处理优化** - 优化了媒体文件下载和存储机制,提升处理效率
63
+ **Media File Processing Optimization** - Optimized media file download and storage mechanism, improved processing efficiency
64
+ - **文件附件流程改进** - 改进了文件附件处理流程,支持更多文件类型,错误处理更完善
65
+ **File Attachment Process Improvement** - Improved file attachment processing flow, supporting more file types with better error handling
66
+ - **Markdown 表格转换** - 自动将 Markdown 表格转换为钉钉支持的文本格式,提升消息可读性
67
+ **Markdown Table Conversion** - Automatically convert Markdown tables to DingTalk-supported text format for better message readability
68
+ - **日志增强** - 增强了错误处理和日志输出,便于问题排查和调试
69
+ **Log Enhancement** - Enhanced error handling and log output for easier troubleshooting and debugging
70
+
71
+ ## 📦 依赖更新 / Dependency Updates
72
+
73
+ - 新增 `mammoth@^1.8.0` - Word 文档(.docx)解析库
74
+ Added `mammoth@^1.8.0` - Word document (.docx) parsing library
75
+ - 新增 `pdf-parse@^1.1.1` - PDF 文档解析库
76
+ Added `pdf-parse@^1.1.1` - PDF document parsing library
77
+
78
+ ## ⚠️ 已知问题 / Known Issues
79
+
80
+ ### 1. 钉钉文档读取功能不可用 / DingTalk Document Reading Unavailable
81
+
82
+ **问题描述 / Issue Description**:`docs.read()` API 当前无法正常工作
83
+ `docs.read()` API is currently not working properly
84
+
85
+ **原因 / Cause**:MCP(Model Context Protocol)中未提供读取文档的 tool,虽然代码层面实现正常,但缺少底层支持
86
+ MCP (Model Context Protocol) does not provide the tool for reading documents. While the implementation is correct at the code level, underlying support is missing
87
+
88
+ **影响范围 / Impact**:仅影响文档读取功能,其他文档操作(创建、追加、搜索、列举)均正常
89
+ Only affects document reading functionality, other document operations (create, append, search, list) work normally
90
+
91
+ **解决方案 / Solution**:等待 MCP 提供相应的 tool 支持,或使用其他文档操作 API 作为替代方案
92
+ Wait for MCP to provide corresponding tool support, or use other document operation APIs as alternatives
93
+
94
+ **状态 / Status**:已记录,等待上游支持
95
+ Recorded, waiting for upstream support
96
+
97
+ ## 📚 文档更新 / Documentation Updates
98
+
99
+ - ✅ 更新 README.md,添加新功能使用说明
100
+ Updated README.md, added usage instructions for new features
101
+ - ✅ 新增"富媒体接收"章节,说明图片消息处理方式
102
+ Added "Rich Media Reception" section, explaining image message processing
103
+ - ✅ 新增"文件附件提取"章节,列出支持的文件类型和处理方式
104
+ Added "File Attachment Extraction" section, listing supported file types and processing methods
105
+ - ✅ 新增"钉钉文档 API"章节,提供 API 使用示例
106
+ Added "DingTalk Document API" section, providing API usage examples
107
+ - ✅ 新增"多 Agent 路由支持"章节,说明多 Agent 会话隔离功能
108
+ Added "Multi-Agent Routing Support" section, explaining multi-Agent session isolation functionality
109
+ - ✅ 新增"多 Agent 配置"章节,提供详细的配置示例和说明(`accounts` 和 `bindings` 配置)
110
+ Added "Multi-Agent Configuration" section with detailed configuration examples and instructions (`accounts` and `bindings` configuration)
111
+ - ✅ 补充常见问题解答,包括新功能的故障排查
112
+ Added FAQ section, including troubleshooting for new features
113
+
114
+ ## 🔗 相关链接 / Related Links
115
+
116
+ - [完整变更日志 / Full Changelog](https://github.com/DingTalk-Real-AI/dingtalk-openclaw-connector/blob/main/CHANGELOG.md)
117
+ - [使用文档 / Documentation](https://github.com/DingTalk-Real-AI/dingtalk-openclaw-connector/blob/main/README.md)
118
+ - [问题反馈 / Issue Feedback](https://github.com/DingTalk-Real-AI/dingtalk-openclaw-connector/issues)
119
+
120
+ ## 📥 安装升级 / Installation & Upgrade
121
+
122
+ ```bash
123
+ # 通过 npm 安装最新版本 / Install latest version via npm
124
+ openclaw plugins install @dingtalk-real-ai/dingtalk-connector
125
+
126
+ # 或升级现有版本 / Or upgrade existing version
127
+ openclaw plugins update dingtalk-connector
128
+
129
+ # 通过 Git 安装 / Install via Git
130
+ openclaw plugins install https://github.com/DingTalk-Real-AI/dingtalk-openclaw-connector.git
131
+ ```
132
+
133
+ ## 🙏 致谢 / Acknowledgments
134
+
135
+ 感谢所有贡献者和用户的支持与反馈!
136
+ Thanks to all contributors and users for their support and feedback!
137
+
138
+ ---
139
+
140
+ **发布日期 / Release Date**:2026-03-05
141
+ **版本号 / Version**:v0.7.0
142
+ **兼容性 / Compatibility**:OpenClaw Gateway 0.4.0+
@@ -0,0 +1,74 @@
1
+ # Release Notes - v0.7.1
2
+
3
+ ## 🐛 修复版本 / Bug Fix Release
4
+
5
+ 本次更新修复了 stream 模式下的关键问题,确保 Agent 路由功能正常工作。
6
+
7
+ This update fixes critical issues in stream mode to ensure Agent routing functionality works correctly.
8
+
9
+ ## 🐛 修复 / Fixes
10
+
11
+ ### 1. Stream 模式 Session 路由失败问题 / Stream Mode Session Routing Failure
12
+
13
+ **问题描述 / Issue Description**:stream 模式下 model 参数错误导致 session 路由失败
14
+ Incorrect model parameter in stream mode caused session routing failures
15
+
16
+ **修复内容 / Fix**:
17
+ - 将 Gateway 请求中的 `model` 参数从 `'default'` 更正为 `'main'`
18
+ Corrected `model` parameter in Gateway requests from `'default'` to `'main'`
19
+ - 确保正确的 Agent 路由和会话管理
20
+ Ensures proper Agent routing and session management
21
+
22
+ **影响范围 / Impact**:影响所有使用 stream 模式的用户,修复后 Agent 路由将正常工作
23
+ Affects all users using stream mode. After the fix, Agent routing will work correctly.
24
+
25
+ ### 2. 多 Agent 路由问题修复 / Multi-Agent Routing Fix
26
+
27
+ **问题描述 / Issue Description**:多个钉钉机器人绑定到不同 Agent 时路由异常
28
+ Multiple DingTalk bots binding to different Agents failed to route correctly
29
+
30
+ **修复内容 / Fix**:
31
+ - 修复多 Agent 路由机制,确保多个钉钉机器人可以正确绑定到不同的 Agent
32
+ Fixed multi-Agent routing mechanism, ensuring multiple DingTalk bots can correctly bind to different Agents
33
+ - 改进会话隔离和路由逻辑
34
+ Improved session isolation and routing logic
35
+
36
+ **影响范围 / Impact**:影响使用多 Agent 配置的用户,修复后多机器人多 Agent 场景将正常工作
37
+ Affects users with multi-Agent configurations. After the fix, multi-bot multi-Agent scenarios will work correctly.
38
+
39
+ ## 🔧 改进 / Improvements
40
+
41
+ - **异步模式优化** - 优化异步模式处理流程,改进错误处理和日志输出
42
+ **Async Mode Optimization** - Optimized async mode processing flow, improved error handling and log output
43
+ - **DM Policy 增强** - 增强 DM Policy 检查机制,支持白名单配置
44
+ **DM Policy Enhancement** - Enhanced DM Policy check mechanism, supporting allowlist configuration
45
+
46
+ ## 📥 安装升级 / Installation & Upgrade
47
+
48
+ ```bash
49
+ # 通过 npm 安装最新版本 / Install latest version via npm
50
+ openclaw plugins install @dingtalk-real-ai/dingtalk-connector
51
+
52
+ # 或升级现有版本 / Or upgrade existing version
53
+ openclaw plugins update dingtalk-connector
54
+
55
+ # 通过 Git 安装 / Install via Git
56
+ openclaw plugins install https://github.com/DingTalk-Real-AI/dingtalk-openclaw-connector.git
57
+ ```
58
+
59
+ ## 🔗 相关链接 / Related Links
60
+
61
+ - [完整变更日志 / Full Changelog](https://github.com/DingTalk-Real-AI/dingtalk-openclaw-connector/blob/main/CHANGELOG.md)
62
+ - [使用文档 / Documentation](https://github.com/DingTalk-Real-AI/dingtalk-openclaw-connector/blob/main/README.md)
63
+ - [问题反馈 / Issue Feedback](https://github.com/DingTalk-Real-AI/dingtalk-openclaw-connector/issues)
64
+
65
+ ## 🙏 致谢 / Acknowledgments
66
+
67
+ 感谢所有贡献者和用户的支持与反馈!
68
+ Thanks to all contributors and users for their support and feedback!
69
+
70
+ ---
71
+
72
+ **发布日期 / Release Date**:2026-03-05
73
+ **版本号 / Version**:v0.7.1
74
+ **兼容性 / Compatibility**:OpenClaw Gateway 0.4.0+
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "dingtalk-connector",
3
3
  "name": "DingTalk Channel",
4
- "version": "0.8.12",
4
+ "version": "0.8.13",
5
5
  "description": "DingTalk (钉钉) messaging channel via Stream mode with AI Card streaming",
6
6
  "author": "DingTalk Real Team",
7
7
  "main": "index.ts",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dingtalk-real-ai/dingtalk-connector",
3
- "version": "0.8.12",
3
+ "version": "0.8.13",
4
4
  "description": "DingTalk (钉钉) channel connector — Stream mode with AI Card streaming",
5
5
  "main": "index.ts",
6
6
  "type": "module",
@@ -40,11 +40,22 @@
40
40
  },
41
41
  "homepage": "https://github.com/DingTalk-Real-AI/dingtalk-openclaw-connector#readme",
42
42
  "bugs": "https://github.com/DingTalk-Real-AI/dingtalk-openclaw-connector/issues",
43
+ "files": [
44
+ "index.ts",
45
+ "src/",
46
+ "docs/*.md",
47
+ "openclaw.plugin.json",
48
+ "tsconfig.json",
49
+ "LICENSE",
50
+ "README.md",
51
+ "README.en.md",
52
+ "CHANGELOG.md"
53
+ ],
43
54
  "publishConfig": {
44
55
  "access": "public"
45
56
  },
46
57
  "dependencies": {
47
- "axios": "1.6.0",
58
+ "axios": "1.14.0",
48
59
  "dingtalk-stream": "2.1.4",
49
60
  "form-data": "^4.0.0",
50
61
  "zod": "^4.3.6"
package/src/channel.ts CHANGED
@@ -162,10 +162,10 @@ export const dingtalkPlugin: ChannelPlugin<ResolvedDingtalkAccount> = {
162
162
  name: account.name,
163
163
  clientId: account.clientId,
164
164
  }),
165
- resolveAllowFrom: ({ cfg, accountId }) => {
166
- const account = resolveDingtalkAccount({ cfg, accountId });
167
- return (account.config?.allowFrom ?? []).map((entry) => String(entry));
168
- },
165
+ // 返回空列表,禁止框架层对发送者做全局过滤。
166
+ // 连接器内部(message-handler.ts)已按 dmPolicy/groupPolicy 各自独立检查,
167
+ // allowFrom 仅用于私聊,groupAllowFrom 仅用于群聊,不应被框架层全局应用。
168
+ resolveAllowFrom: () => [],
169
169
  formatAllowFrom: ({ allowFrom }) =>
170
170
  allowFrom
171
171
  .map((entry) => String(entry).trim())
@@ -289,8 +289,14 @@ export const dingtalkPlugin: ChannelPlugin<ResolvedDingtalkAccount> = {
289
289
  textChunkLimit: 2000,
290
290
  sendText: async ({ cfg, to, text, accountId, replyToId, threadId }) => {
291
291
  const account = resolveDingtalkAccount({ cfg, accountId });
292
+ // 使用已解析的凭据覆盖原始 config,防止 clientId/clientSecret 为 SecretInput 对象或 undefined
293
+ const resolvedConfig: DingtalkConfig = {
294
+ ...account.config,
295
+ ...(account.clientId != null ? { clientId: account.clientId } : {}),
296
+ ...(account.clientSecret != null ? { clientSecret: account.clientSecret } : {}),
297
+ };
292
298
  const result = await sendTextToDingTalk({
293
- config: account.config,
299
+ config: resolvedConfig,
294
300
  target: to,
295
301
  text,
296
302
  replyToId,
@@ -303,6 +309,12 @@ export const dingtalkPlugin: ChannelPlugin<ResolvedDingtalkAccount> = {
303
309
  },
304
310
  sendMedia: async ({ cfg, to, text, mediaUrl, accountId, mediaLocalRoots, replyToId, threadId }) => {
305
311
  const account = resolveDingtalkAccount({ cfg, accountId });
312
+ // 使用已解析的凭据覆盖原始 config,防止 clientId/clientSecret 为 SecretInput 对象或 undefined
313
+ const resolvedConfig: DingtalkConfig = {
314
+ ...account.config,
315
+ ...(account.clientId != null ? { clientId: account.clientId } : {}),
316
+ ...(account.clientSecret != null ? { clientSecret: account.clientSecret } : {}),
317
+ };
306
318
  const logger = createLogger(account.config?.debug ?? false, 'DingTalk:SendMedia');
307
319
 
308
320
  logger.info('开始处理,参数:', JSON.stringify({
@@ -326,7 +338,7 @@ export const dingtalkPlugin: ChannelPlugin<ResolvedDingtalkAccount> = {
326
338
  }
327
339
 
328
340
  const result = await sendMediaToDingTalk({
329
- config: account.config,
341
+ config: resolvedConfig,
330
342
  target: to,
331
343
  text,
332
344
  mediaUrl,
@@ -66,6 +66,8 @@ const DingtalkSharedConfigShape = {
66
66
  ackText: z.string().optional(),
67
67
  endpoint: z.string().optional(), // DWClient gateway endpoint
68
68
  debug: z.boolean().optional(), // DWClient debug mode
69
+ enableMediaUpload: z.boolean().optional(),
70
+ systemPrompt: z.string().optional(),
69
71
  };
70
72
 
71
73
  /**
@@ -93,8 +95,6 @@ export const DingtalkConfigBaseSchema = z
93
95
  // Top-level credentials (backward compatible for single-account mode)
94
96
  clientId: z.union([z.string(), z.number()]).optional(),
95
97
  clientSecret: buildSecretInputSchema().optional(),
96
- enableMediaUpload: z.boolean().optional(),
97
- systemPrompt: z.string().optional(),
98
98
  ...DingtalkSharedConfigShape,
99
99
  dmPolicy: DmPolicySchema.optional().default("open"),
100
100
  groupPolicy: GroupPolicySchema.optional().default("open"),
@@ -664,7 +664,7 @@ export async function monitorSingleAccount(
664
664
 
665
665
  // 处理 400 错误(请求参数错误)
666
666
  if (error.response?.status === 400 || error.message?.includes("status code 400") || error.message?.includes("400")) {
667
- throw new Error(
667
+ reject(new Error(
668
668
  `[DingTalk][${accountId}] Bad Request (400):\n` +
669
669
  ` - clientId or clientSecret format is invalid\n` +
670
670
  ` - clientId: ${clientIdStr} (type: ${typeof account.clientId}, length: ${clientIdStr.length})\n` +
@@ -676,24 +676,27 @@ export async function monitorSingleAccount(
676
676
  ` 4. Check if clientId starts with 'ding' prefix\n` +
677
677
  ` - Error details: ${error.message}\n` +
678
678
  ` - Response data: ${JSON.stringify(error.response?.data || {})}`,
679
- );
679
+ ));
680
+ return;
680
681
  }
681
682
 
682
683
  // 处理 401 认证错误
683
684
  if (error.response?.status === 401 || error.message?.includes("401")) {
684
- throw new Error(
685
+ reject(new Error(
685
686
  `[DingTalk][${accountId}] Authentication failed (401 Unauthorized):\n` +
686
687
  ` - Your clientId or clientSecret is invalid, expired, or revoked\n` +
687
688
  ` - clientId: ${clientIdStr.substring(0, 8)}...\n` +
688
689
  ` - Please verify your credentials at DingTalk Developer Console\n` +
689
690
  ` - Error details: ${error.message}`,
690
- );
691
+ ));
692
+ return;
691
693
  }
692
694
 
693
695
  // 处理其他连接错误
694
- throw new Error(
696
+ reject(new Error(
695
697
  `[DingTalk][${accountId}] Failed to connect to DingTalk Stream: ${error.message}`,
696
- );
698
+ ));
699
+ return;
697
700
  }
698
701
 
699
702
  // Handle disconnection(已被自定义 close 监听器替代)
@@ -49,7 +49,7 @@ import {
49
49
  processLocalImages,
50
50
  processVideoMarkers,
51
51
  processAudioMarkers,
52
- processFileMarkers
52
+ uploadAndReplaceFileMarkers
53
53
  } from "../services/media/index.ts";
54
54
  import { sendProactive, type AICardTarget } from "../services/messaging/index.ts";
55
55
  import { createAICardForTarget, streamAICard, type AICardInstance } from "../services/messaging/card.ts";
@@ -701,7 +701,7 @@ export async function downloadMediaByCode(
701
701
 
702
702
  const resp = await dingtalkHttp.post(
703
703
  `${DINGTALK_API}/v1.0/robot/messageFiles/download`,
704
- { downloadCode, robotCode: config.clientId },
704
+ { downloadCode, robotCode: String(config.clientId) },
705
705
  {
706
706
  headers: { 'x-acs-dingtalk-access-token': token, 'Content-Type': 'application/json' },
707
707
  timeout: 30_000,
@@ -733,7 +733,7 @@ export async function getFileDownloadUrl(
733
733
 
734
734
  const resp = await dingtalkHttp.post(
735
735
  `${DINGTALK_API}/v1.0/robot/messageFiles/download`,
736
- { downloadCode, robotCode: config.clientId },
736
+ { downloadCode, robotCode: String(config.clientId) },
737
737
  {
738
738
  headers: { 'x-acs-dingtalk-access-token': token, 'Content-Type': 'application/json' },
739
739
  timeout: 30_000,
@@ -857,20 +857,40 @@ async function parsePdfFile(filePath: string, log?: any): Promise<string | null>
857
857
  try {
858
858
  log?.info?.(`开始解析 PDF 文档: ${filePath}`);
859
859
 
860
- let pdfParse: any;
860
+ let pdfParseV1: any;
861
+ let pdfParseV2: any;
861
862
  try {
862
- pdfParse = (await import('pdf-parse')).default;
863
+ const mod = await import('pdf-parse');
864
+ if (mod.PDFParse) {
865
+ pdfParseV2 = mod.PDFParse; // v2.x API
866
+ } else if (mod.default) {
867
+ pdfParseV1 = mod.default; // v1.x API
868
+ } else {
869
+ throw new Error('pdf-parse module format not recognized');
870
+ }
863
871
  } catch {
864
872
  log?.warn?.('pdf-parse 库未安装,无法解析 .pdf 文件。请运行: npm install pdf-parse');
865
873
  return null;
866
874
  }
867
875
 
868
876
  const buffer = fs.readFileSync(filePath);
869
- const data = await pdfParse(buffer);
870
- const text = data.text.trim();
871
-
877
+ let text: string;
878
+ let numPages: number | undefined;
879
+
880
+ if (pdfParseV2) {
881
+ const parser = new pdfParseV2({ data: buffer });
882
+ const result = await parser.getText();
883
+ text = (result.text ?? '').trim();
884
+ numPages = result.total;
885
+ parser.destroy?.();
886
+ } else {
887
+ const data = await pdfParseV1(buffer);
888
+ text = (data.text ?? '').trim();
889
+ numPages = data.numpages;
890
+ }
891
+
872
892
  if (text) {
873
- log?.info?.(`PDF 文档解析成功: ${filePath}, 文本长度=${text.length}, 页数=${data.numpages}`);
893
+ log?.info?.(`PDF 文档解析成功: ${filePath}, 文本长度=${text.length}, 页数=${numPages}`);
874
894
  return text;
875
895
  } else {
876
896
  log?.warn?.(`PDF 文档解析结果为空: ${filePath}`);
@@ -1493,7 +1513,7 @@ export async function handleDingTalkMessageInternal(params: HandleMessageParams)
1493
1513
  true, // ✅ 使用主动 API 模式
1494
1514
  mediaTarget
1495
1515
  );
1496
- finalText = await processFileMarkers(
1516
+ finalText = await uploadAndReplaceFileMarkers(
1497
1517
  finalText,
1498
1518
  '',
1499
1519
  config,
@@ -43,7 +43,7 @@ import {
43
43
  processLocalImages,
44
44
  processVideoMarkers,
45
45
  processAudioMarkers,
46
- processFileMarkers,
46
+ uploadAndReplaceFileMarkers,
47
47
  } from "./services/media/index.ts";
48
48
 
49
49
 
@@ -314,7 +314,7 @@ export function createDingtalkReplyDispatcher(params: CreateDingtalkReplyDispatc
314
314
  true, // ✅ 使用主动 API 模式
315
315
  target
316
316
  );
317
- finalText = await processFileMarkers(
317
+ finalText = await uploadAndReplaceFileMarkers(
318
318
  finalText,
319
319
  '',
320
320
  account.config as DingtalkConfig,
@@ -607,7 +607,8 @@ export function createDingtalkReplyDispatcher(params: CreateDingtalkReplyDispatc
607
607
  // 安全检查:确保 code 存在且为字符串
608
608
  const errorCode = err.response?.data?.code;
609
609
  if (err.response?.status === 403 && typeof errorCode === 'string' && errorCode.includes('QpsLimit')) {
610
- // QPS 限流,跳过本次更新
610
+ // QPS 限流,跳过本次更新;同步更新节流时间,防止立即重试再次触发限流
611
+ lastUpdateTime = now;
611
612
  log.warn(`[DingTalk][AICard] QPS 限流,跳过本次更新`);
612
613
  } else {
613
614
  log.error(`[DingTalk][onPartialReply] ❌ AI Card 更新失败:${err.message}`);
@@ -29,9 +29,14 @@ export async function parseDocumentFile(filePath: string, log?: any): Promise<st
29
29
  }
30
30
 
31
31
  /**
32
- * 提取文件标记并发送文件消息
32
+ * 提取文件标记,上传文件到钉钉,并用文本替换标记。
33
+ *
34
+ * 注意:此函数只做「上传 + 文本替换」,不会发送独立的文件消息。
35
+ * 如果需要上传后再发送独立文件消息,请使用 media.ts 中的 processFileMarkers。
36
+ *
37
+ * 调用方:reply-dispatcher.ts、message-handler.ts(通过 media/index.ts 导入)
33
38
  */
34
- export async function processFileMarkers(
39
+ export async function uploadAndReplaceFileMarkers(
35
40
  content: string,
36
41
  sessionWebhook: string,
37
42
  config: DingtalkConfig,