@jeik/dingtalk-connector 0.8.21-fix48 → 0.8.21-fix49

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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.8.21-fix49] - 2026-07-21
9
+
10
+ ### 变更 / Changed
11
+ - 🎨 **默认流式 AI Card 模板** — `cardTemplateId` 默认 `0d2c84b3-12c1-473b-b14a-f329a7a102cd.schema`;`cardContentVar` 默认 `content`(与增强模板字段一致)。
12
+ - 📚 文档:图片发送全面修复叙述;钉钉专属配置最小/最大化(单·多 Agent);`messageAnswerCard` 等。
13
+
14
+ ### 安装 / Install
15
+ ```bash
16
+ npx -y @jeik/dingtalk-connector install --force
17
+ openclaw gateway restart
18
+ ```
19
+
8
20
  ## [0.8.21-fix48] - 2026-07-21
9
21
 
10
22
  ### 新增 / Added
package/README.en.md CHANGED
@@ -4,7 +4,7 @@
4
4
  <p>Community maintained fork of the official <strong>v0.8.20</strong> release, tracking and fixing bugs the official team hasn't addressed.<br/>
5
5
  Identical to the official release in functionality — only community-critical fixes applied.</p>
6
6
 
7
- <p><strong>Current published release: <a href="https://www.npmjs.com/package/@jeik/dingtalk-connector">@jeik/dingtalk-connector</a> v0.8.21-fix48</strong> (production-stable; install: <code>npx -y @jeik/dingtalk-connector install</code>).</p>
7
+ <p><strong>Current published release: <a href="https://www.npmjs.com/package/@jeik/dingtalk-connector">@jeik/dingtalk-connector</a> v0.8.21-fix49</strong> (production-stable; install: <code>npx -y @jeik/dingtalk-connector install</code>).</p>
8
8
 
9
9
  <p>
10
10
  <a href="https://www.npmjs.com/package/@jeik/dingtalk-connector"><img src="https://img.shields.io/npm/v/@jeik/dingtalk-connector.svg?style=flat&colorA=18181B&colorB=28CF8D" alt="npm version" /></a>
@@ -23,7 +23,7 @@
23
23
 
24
24
  ## 🔧 Recent Updates
25
25
 
26
- ### 🚀 v0.8.21-fix48 · 2026-07-21 (current)
26
+ ### 🚀 v0.8.21-fix49 · 2026-07-21 (current)
27
27
 
28
28
  **Theme: message tool answer card by default (toggle)**
29
29
 
@@ -68,120 +68,144 @@ Local images (incl. `/mnt`) · `messageImageMd` · LocalImage diagnostics.
68
68
  | 2026-06-28 | npm `@jeik/dingtalk-connector`; premature finalization fix |
69
69
  | 2026-05 | MD images; multi-turn spam; 4.29 empty reply; WS phantom reconnect |
70
70
 
71
- Full log: [CHANGELOG.md](CHANGELOG.md) · [FIXES.md](FIXES.md) · [Release fix48](docs/RELEASE_NOTES_V0.8.21-fix48.md)
71
+ Full log: [CHANGELOG.md](CHANGELOG.md) · [FIXES.md](FIXES.md) · [Release fix48](docs/RELEASE_NOTES_V0.8.21-fix49.md)
72
72
 
73
73
  ---
74
74
 
75
75
  ## ✨ Enhanced Features
76
76
 
77
- - 🔧 Markdown image support for direct URLs and local paths, no download required:
78
- - Markdown syntax `![](direct-url)` or `![](local-path)` sends images directly
79
- - Compatible with mediaId format
80
- - ⚠️ This plugin supports image messages, but DingTalk side won't trigger this feature automatically. Use the following prompt to guide the Agent:
77
+ ### 🖼️ Image sending: full fix & upgrade
81
78
 
82
- ```
83
- Please write a DingTalk image sending skill following this approach: use markdown to send images, with image captions for rich text; direct URLs or local paths can be embedded directly in markdown, and if local paths contain spaces, rename to remove spaces first before sending.
84
- ```
79
+ > 🔥 **No dead corners** · mixed send paths · far beyond the official’s weak image pipeline
80
+ > ✅ Chat · ✅ message direct · ✅ markdown embed · ✅ split or merge layout
85
81
 
86
- - 🎨 Custom AI Card template support for user-prebuilt cards (with copy button), uses official default card if not set:
82
+ Full-path image fixes — every channel below renders correctly:
83
+
84
+ | | Path | Capability |
85
+ |--|------|------------|
86
+ | 💬 | **Normal chat reply** | Agent embeds `![alt](…)`; upload to mediaId before finalize |
87
+ | 📤 | **message · mediaUrl** | Proactive direct send (local / LAN / public) |
88
+ | 📝 | **message · markdown body** | Nested `![](…)` (local / `file://` / URL) with text |
89
+ | ⚙️ | **Configurable layout** | Default 📎 **separate**; `messageImageMd: true` → 🧩 **merge** one markdown |
90
+
91
+ #### 🌐 Source types covered
92
+
93
+ | | Type | Examples |
94
+ |--|------|----------|
95
+ | 🌍 | Public URL | `https://…` |
96
+ | 🏠 | Private / LAN URL | `http://intranet/…` |
97
+ | 📁 | Local absolute path | `/tmp/…` · `/root/…` |
98
+ | 💾 | **`/mnt` mounts** | Chinese paths · SMB shares |
99
+ | 🔗 | `file://` URI | `file:///mnt/…` · `file:///tmp/…` |
100
+ | 🆔 | Existing mediaId | `@lADP…` |
101
+
102
+ #### 🛡️ Extra safeguards
103
+
104
+ - 📦 Code-block / inline-code paths are **not** uploaded
105
+ - ⬇️ Remote: **download then upload**; local: **`/tmp` retry** on failure
106
+ - 🫧 Image + download link in **one bubble**: `![]` → mediaId, URL kept as-is
107
+
108
+ ### 🎨 AI Card template
109
+
110
+ - ✨ Custom stream cards; **if `cardTemplateId` is omitted**, defaults to
111
+ `0d2c84b3-12c1-473b-b14a-f329a7a102cd.schema` (📋 copy button, etc.)
112
+
113
+ ### ⚙️ Minimal config
87
114
 
88
115
  ```json
89
116
  "channels": {
90
117
  "dingtalk-connector": {
91
118
  "enabled": true,
92
119
  "clientId": "your-clientId",
93
- "clientSecret": "your-clientSecret",
94
- "cardTemplateId": "your-card-template-id.schema",
95
- "cardContentVar": "content",
96
- "messageAnswerCard": true
120
+ "clientSecret": "your-clientSecret"
97
121
  }
98
122
  }
99
123
  ```
100
124
 
101
- ### Full config reference (`channels.dingtalk-connector`)
125
+ Defaults apply: stream card `0d2c84b3-…schema`, session answer card on, message answer card on, `messageImageMd=false`.
102
126
 
103
- Source of truth: `src/config/schema.ts` + `openclaw.plugin.json`.
104
- Top-level single-bot fields and `accounts.<id>` share the same **shared shape**; missing account fields inherit top-level.
127
+ > **Maximal config ≡ minimal config.** The blocks below only spell out defaults so the fields are easier to understand. Behavior is the same as the credential-only minimal config — use minimal in production.
105
128
 
106
- #### 1. Enable / credentials / multi-account
129
+ ### Maximal config (for illustration; defaults written out)
107
130
 
108
- | Field | Type | Default | Description |
109
- |-------|------|---------|-------------|
110
- | `enabled` | boolean | — | Enable this channel |
111
- | `defaultAccount` | string | — | Default account key (must exist under `accounts`) |
112
- | `clientId` | string \| number | — | AppKey / Client ID (single-bot top-level) |
113
- | `clientSecret` | string \| SecretRef | — | AppSecret; plain string or `{ source, provider, id }` |
114
- | `accounts` | object | — | Multi-bot map; keys are account IDs |
115
- | `accounts.*.enabled` | boolean | — | Enable this account |
116
- | `accounts.*.name` | string | — | Display name |
117
- | `accounts.*.clientId` | string \| number | — | Account Client ID |
118
- | `accounts.*.clientSecret` | string \| SecretRef | — | Account secret |
119
- | `accounts.*.chatbotUserId` | string | — | Encrypted bot id for @-mentioning bots in groups (see `[BotIdentity]` logs) |
120
- | `accounts.*.chatbotCorpId` | string | — | Bot corp id |
131
+ **Single Agent** and **multi Agent** (all values are defaults — **not extra features**).
121
132
 
122
- #### 2. Access policy
133
+ **Single Agent (top-level credentials):**
123
134
 
124
- | Field | Type | Default | Description |
125
- |-------|------|---------|-------------|
126
- | `dmPolicy` | `"open"` \| `"pairing"` \| `"allowlist"` | `"open"` | DM policy |
127
- | `allowFrom` | (string\|number)[] | — | DM allowlist; **required (≥1)** when `dmPolicy=allowlist` |
128
- | `groupPolicy` | `"open"` \| `"allowlist"` \| `"disabled"` | `"open"` | Group policy |
129
- | `groupAllowFrom` | (string\|number)[] | — | Group allowlist; **required (≥1)** when `groupPolicy=allowlist` |
130
- | `requireMention` | boolean | `true` | Require @bot in groups |
131
- | `groups` | object | — | Per-group overrides (below) |
132
-
133
- **`groups.<openConversationId>`:**
134
-
135
- | Field | Type | Description |
136
- |-------|------|-------------|
137
- | `enabled` | boolean | Enable this group |
138
- | `requireMention` | boolean | Override @ requirement |
139
- | `allowFrom` | (string\|number)[] | Per-group sender allowlist |
140
- | `systemPrompt` | string | Extra system prompt for this group |
141
- | `groupSessionScope` | `"group"` \| `"group_sender"` | Session scope for this group |
142
- | `tools.allow` / `tools.deny` | string[] | Per-group tool policy |
143
-
144
- #### 3. Session / behavior
135
+ ```json
136
+ "channels": {
137
+ "dingtalk-connector": {
138
+ "enabled": true,
139
+ "clientId": "your-clientId",
140
+ "clientSecret": "your-clientSecret",
141
+ "cardTemplateId": "0d2c84b3-12c1-473b-b14a-f329a7a102cd.schema",
142
+ "cardContentVar": "content",
143
+ "answerCard": true,
144
+ "answerActToken": 500,
145
+ "answerCardTemplateId": "d246b7f5-1783-4e9b-bb46-bef52d63050e.schema",
146
+ "messageAnswerCard": true,
147
+ "messageImageMd": false
148
+ }
149
+ }
150
+ ```
145
151
 
146
- | Field | Type | Default | Description |
147
- |-------|------|---------|-------------|
148
- | `groupSessionScope` | `"group"` \| `"group_sender"` | `"group"` | One session per group vs per group+sender |
149
- | `separateSessionByConversation` | boolean | `true` | Isolate sessions by conversation |
150
- | `sharedMemoryAcrossConversations` | boolean | `false` | Share memory across conversations |
151
- | `historyLimit` | int ≥0 | — | History length cap |
152
- | `textChunkLimit` | int >0 | — | Text chunk size cap |
153
- | `mediaMaxMb` | number >0 | — | Media size cap (MB) |
154
- | `typingIndicator` | boolean | — | Typing indicator |
155
- | `resolveSenderNames` | boolean | — | Resolve sender display names |
156
- | `asyncMode` | boolean | — | Async mode |
157
- | `ackText` | string | — | Inbound ACK text |
158
- | `systemPrompt` | string | — | Channel-level extra system prompt |
159
- | `enableMediaUpload` | boolean | — | Enable media upload features |
160
- | `endpoint` | string | — | Custom DWClient gateway (advanced) |
161
- | `debug` | boolean | — | Debug logging |
162
-
163
- #### 4. Tools
152
+ **Multi Agent (`accounts`, one credential/card set per bot):**
164
153
 
165
- | Field | Type | Default | Description |
166
- |-------|------|---------|-------------|
167
- | `tools.docs` | boolean | true (semantic) | Document tools |
168
- | `tools.media` | boolean | true (semantic) | Media upload tools |
154
+ ```json
155
+ "channels": {
156
+ "dingtalk-connector": {
157
+ "enabled": true,
158
+ "defaultAccount": "main-bot",
159
+ "accounts": {
160
+ "main-bot": {
161
+ "enabled": true,
162
+ "name": "main-bot",
163
+ "clientId": "main-bot-clientId",
164
+ "clientSecret": "main-bot-clientSecret",
165
+ "cardTemplateId": "0d2c84b3-12c1-473b-b14a-f329a7a102cd.schema",
166
+ "cardContentVar": "content",
167
+ "answerCard": true,
168
+ "answerActToken": 500,
169
+ "answerCardTemplateId": "d246b7f5-1783-4e9b-bb46-bef52d63050e.schema",
170
+ "messageAnswerCard": true,
171
+ "messageImageMd": false
172
+ },
173
+ "guide-bot": {
174
+ "enabled": true,
175
+ "name": "guide-bot",
176
+ "clientId": "guide-bot-clientId",
177
+ "clientSecret": "guide-bot-clientSecret",
178
+ "cardTemplateId": "0d2c84b3-12c1-473b-b14a-f329a7a102cd.schema",
179
+ "cardContentVar": "content",
180
+ "answerCard": true,
181
+ "answerActToken": 500,
182
+ "answerCardTemplateId": "d246b7f5-1783-4e9b-bb46-bef52d63050e.schema",
183
+ "messageAnswerCard": true,
184
+ "messageImageMd": false
185
+ }
186
+ }
187
+ }
188
+ }
189
+ ```
169
190
 
170
- #### 5. Group reply / AI card / answer card / message tool
191
+ ### DingTalk-specific fields
171
192
 
172
193
  | Field | Type | Default | Description |
173
194
  |-------|------|---------|-------------|
174
- | `groupReplyMode` | `"aicard"` \| `"text"` \| `"markdown"` | `"aicard"` | Group reply style; `text`/`markdown` disables streaming AI card in groups (multi-bot @) |
175
- | `cardTemplateId` | string | official stream template | Streaming AI Card template id |
176
- | `cardContentVar` | string | `"msgContent"` | Stream card content variable (process/tool/final) |
177
- | `answerCard` | boolean | **true** (unless `false`) | **Session-stream** answer card: long answers on a static card; original card freezes at “thinking done” |
178
- | `answerActToken` | int >0 | **500** | Token threshold: ≤ stay on stream card; > spawn answer card |
179
- | `answerCardTemplateId` | string | built-in answer template | Static answer card template id |
180
- | `messageAnswerCard` | boolean | **true** (unless `false`) | **message tool** body via static answer card; `false` = plain text/markdown. **Independent** of `answerCard`; media still normal APIs |
181
- | `messageImageMd` | boolean | **false** | message tool layout: `false` text then image; `true` merge multi-image+text markdown |
182
-
183
- > Create/publish card templates in [DingTalk Open Platform](https://open.dingtalk.com/).
184
- > `answerCard` = conversational stream finalize; `messageAnswerCard` = Agent `message` tool outbound. Do not conflate them.
195
+ | `clientId` | string \| number | — | AppKey / Client ID |
196
+ | `clientSecret` | string \| SecretRef | — | AppSecret |
197
+ | `accounts` | object | — | Multi-bot map |
198
+ | `accounts.*.name` | string | — | Display name |
199
+ | `accounts.*.clientId` / `clientSecret` | — | — | Per-bot credentials |
200
+ | `cardTemplateId` | string | `0d2c84b3-12c1-473b-b14a-f329a7a102cd.schema` | Streaming AI Card template |
201
+ | `cardContentVar` | string | `"content"` | Stream card content variable |
202
+ | `answerCard` | boolean | **true** | Session-stream answer card; `false` disables |
203
+ | `answerActToken` | int | **500** | Token threshold for spawning answer card |
204
+ | `answerCardTemplateId` | string | `d246b7f5-1783-4e9b-bb46-bef52d63050e.schema` | Static answer card template |
205
+ | `messageAnswerCard` | boolean | **true** | message-tool body via answer card; `false` = plain message |
206
+ | `messageImageMd` | boolean | **false** | message images: separate vs merge markdown |
207
+
208
+ > `answerCard` = conversation finalize; `messageAnswerCard` = message-tool outbound.
185
209
 
186
210
  ---
187
211
 
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  <p>基于官方 <strong>v0.8.20</strong> 的社区维护版本,由社区持续跟进修复官方无暇处理的 Bug。<br/>
5
5
  功能与官方完全一致,拥有最快的修复速度,及时合并官方pr和个人发现的bug和社区急需的 Bug。</p>
6
6
 
7
- <p><strong>当前发布版:<a href="https://www.npmjs.com/package/@jeik/dingtalk-connector">@jeik/dingtalk-connector</a> v0.8.21-fix48</strong>(稳定生产可用;一键安装:`npx -y @jeik/dingtalk-connector install`;本地 tgz:`openclaw plugins install ./jeik-dingtalk-connector-0.8.21-fix48.tgz --force`)</p>
7
+ <p><strong>当前发布版:<a href="https://www.npmjs.com/package/@jeik/dingtalk-connector">@jeik/dingtalk-connector</a> v0.8.21-fix49</strong>(稳定生产可用;一键安装:`npx -y @jeik/dingtalk-connector install`;本地 tgz:`openclaw plugins install ./jeik-dingtalk-connector-0.8.21-fix49.tgz --force`)</p>
8
8
 
9
9
  <p>
10
10
  <a href="https://www.npmjs.com/package/@jeik/dingtalk-connector"><img src="https://img.shields.io/npm/v/@jeik/dingtalk-connector.svg?style=flat&colorA=18181B&colorB=28CF8D" alt="npm version" /></a>
@@ -23,7 +23,7 @@
23
23
 
24
24
  ## 🔧 最近更新
25
25
 
26
- ### 🚀 v0.8.21-fix48 · 2026-07-21(当前)
26
+ ### 🚀 v0.8.21-fix49 · 2026-07-21(当前)
27
27
 
28
28
  **主题:message 工具默认答案卡(可关)**
29
29
 
@@ -68,26 +68,69 @@ message 远程 `media` 下载上传。
68
68
  | 2026-06-28 | 上线 npm `@jeik/dingtalk-connector`;过程消息提前定稿修复 |
69
69
  | 2026-05 | MD 直链/本地图;多轮刷屏;4.29+ 无文本输出;WebSocket 幻影重连 |
70
70
 
71
- 完整说明:[CHANGELOG.md](CHANGELOG.md) · [FIXES.md](FIXES.md) · [Release fix48](docs/RELEASE_NOTES_V0.8.21-fix48.md)
71
+ 完整说明:[CHANGELOG.md](CHANGELOG.md) · [FIXES.md](FIXES.md) · [Release fix48](docs/RELEASE_NOTES_V0.8.21-fix49.md)
72
72
 
73
73
  ---
74
74
 
75
75
  ## ✨ 增强功能
76
76
 
77
- - 🔧 Markdown 图片发送支持直链和本地路径(含 **`/mnt` 共享盘**、中文路径):
78
- - 语法 `![注释](直链URL)` 或 `![注释](/绝对/本地路径)` → 自动上传 mediaId 后发出
79
- - **代码块 / 行内 code 内的路径不会上传**(参数说明原文保留)
80
- - 兼容已有 mediaId 格式
81
- - message 工具默认**文图分开**;可选 `messageImageMd: true` 在多图+文字时合并 markdown
82
- - ⚠️ 需引导 Agent 使用 markdown 发图时可用:
77
+ ### 🖼️ 图片发送:全面修复与增强
83
78
 
84
- ```
85
- 请你把以下发送图片的方式写成你的钉钉图片发送skill,当涉及到图片发送,则调用该技能:用markdown语法发送图片,支持添加图片注释实现图文并茂;直链图片或本地路径文件均可直接嵌入markdown发送,如本地路径含空格请先重命名去除空格再发送。展示工具参数时请放在代码块中,避免被当作待发送图片。
86
- ```
79
+ > 🔥 **毫无死角** · 混合发图 · 全面碾压官方薄弱的图片机制
80
+ > ✅ 对话发图 · ✅ message 直发 · ✅ markdown 嵌图 · ✅ 文图可分可合
87
81
 
88
- - 🎨 支持自定义 AI Card 模板,可使用本人预制的卡片(含内容复制按钮),不填则使用官方默认卡片。
82
+ 对官方图片发送做了**全路径修复增强**,多通道混合发图,全部显示正常:
89
83
 
90
- **单机器人:**
84
+ | | 发送方式 | 能力 |
85
+ |--|----------|------|
86
+ | 💬 | **普通对话回复** | Agent 用 `![注释](…)` 嵌图,定稿前自动上传 mediaId |
87
+ | 📤 | **message · mediaUrl** | 机器人主动触发直发(本地 / 内网 / 公网) |
88
+ | 📝 | **message · markdown 正文** | 正文嵌 `![](…)`(本地 / `file://` / 直链)与文字同条 |
89
+ | ⚙️ | **文图策略可配** | 默认 📎 **分开**;`messageImageMd: true` → 🧩 **合并**一条 markdown |
90
+
91
+ #### 🌐 路径与协议全覆盖
92
+
93
+ | | 类型 | 示例 |
94
+ |--|------|------|
95
+ | 🌍 | 公网直链 | `https://…` |
96
+ | 🏠 | 内网直链 | `http://内网主机/…` |
97
+ | 📁 | 本地绝对路径 | `/tmp/…` · `/root/…` |
98
+ | 💾 | **`/mnt` 挂载盘** | 中文目录 · 共享盘 · SMB |
99
+ | 🔗 | `file://` URI | `file:///mnt/…` · `file:///tmp/…` |
100
+ | 🆔 | 已有 mediaId | `@lADP…` |
101
+
102
+ #### 🛡️ 细节兜底
103
+
104
+ - 📦 代码块 / 行内 code 路径 **不会误上传**(参数说明原文保留)
105
+ - ⬇️ 远程图 **先下载再上传**;本地失败会 **`/tmp` 重试**
106
+ - 🫧 图 + 下载链接 **同泡共存**:`![]` → mediaId,下载 URL 仍是原链
107
+
108
+ ### 🎨 AI Card 模板
109
+
110
+ - ✨ 支持自定义流式卡;**不填 `cardTemplateId` 默认**
111
+ `0d2c84b3-12c1-473b-b14a-f329a7a102cd.schema`(含 📋 复制按钮等)
112
+
113
+ ### ⚙️ 最小配置(够跑)
114
+
115
+ ```json
116
+ "channels": {
117
+ "dingtalk-connector": {
118
+ "enabled": true,
119
+ "clientId": "你的clientId",
120
+ "clientSecret": "你的clientSecret"
121
+ }
122
+ }
123
+ ```
124
+
125
+ 未写的项走默认:流式卡 `0d2c84b3-…schema`、会话答案卡开、message 答案卡开、`messageImageMd=false`。
126
+
127
+ > **最大化配置 ≡ 最小化配置。** 下面只是把默认值显式写出来,方便对照字段含义;效果与只填凭证的最小配置相同,生产环境直接用最小配置即可。
128
+
129
+ ### 最大化配置(展示用,默认值写全)
130
+
131
+ 按单 Agent / 多 Agent 两种写法(值均为默认,**不等于额外能力**)。
132
+
133
+ **单 Agent(顶层凭证):**
91
134
 
92
135
  ```json
93
136
  "channels": {
@@ -95,127 +138,74 @@ message 远程 `media` 下载上传。
95
138
  "enabled": true,
96
139
  "clientId": "你的clientId",
97
140
  "clientSecret": "你的clientSecret",
98
- "cardTemplateId": "你的卡片模板ID.schema",
141
+ "cardTemplateId": "0d2c84b3-12c1-473b-b14a-f329a7a102cd.schema",
99
142
  "cardContentVar": "content",
100
- "messageImageMd": false,
143
+ "answerCard": true,
144
+ "answerActToken": 500,
145
+ "answerCardTemplateId": "d246b7f5-1783-4e9b-bb46-bef52d63050e.schema",
101
146
  "messageAnswerCard": true,
102
- "debug": false
147
+ "messageImageMd": false
103
148
  }
104
149
  }
105
150
  ```
106
151
 
107
- **多机器人(多 Agent):** 每个账号可绑定不同机器人
152
+ **多 Agent(`accounts`,每个机器人一套凭证与卡片选项):**
108
153
 
109
154
  ```json
110
155
  "channels": {
111
156
  "dingtalk-connector": {
112
157
  "enabled": true,
158
+ "defaultAccount": "main-bot",
113
159
  "accounts": {
114
160
  "main-bot": {
115
161
  "enabled": true,
116
- "name": "工作流机器人",
117
- "clientId": "你的clientId",
118
- "clientSecret": "你的clientSecret",
119
- "cardTemplateId": "f9b75aac-713c-40e8-a17f-e236d7b5422b.schema",
120
- "cardContentVar": "content"
162
+ "name": "主机器人",
163
+ "clientId": "主机器人clientId",
164
+ "clientSecret": "主机器人clientSecret",
165
+ "cardTemplateId": "0d2c84b3-12c1-473b-b14a-f329a7a102cd.schema",
166
+ "cardContentVar": "content",
167
+ "answerCard": true,
168
+ "answerActToken": 500,
169
+ "answerCardTemplateId": "d246b7f5-1783-4e9b-bb46-bef52d63050e.schema",
170
+ "messageAnswerCard": true,
171
+ "messageImageMd": false
121
172
  },
122
- "another-bot": {
173
+ "guide-bot": {
123
174
  "enabled": true,
124
- "name": "另一个机器人",
125
- "clientId": "另一个clientId",
126
- "clientSecret": "另一个clientSecret",
127
- "cardTemplateId": "f9b75aac-713c-40e8-a17f-e236d7b5422b.schema",
128
- "cardContentVar": "content"
175
+ "name": "引导机器人",
176
+ "clientId": "引导机器人clientId",
177
+ "clientSecret": "引导机器人clientSecret",
178
+ "cardTemplateId": "0d2c84b3-12c1-473b-b14a-f329a7a102cd.schema",
179
+ "cardContentVar": "content",
180
+ "answerCard": true,
181
+ "answerActToken": 500,
182
+ "answerCardTemplateId": "d246b7f5-1783-4e9b-bb46-bef52d63050e.schema",
183
+ "messageAnswerCard": true,
184
+ "messageImageMd": false
129
185
  }
130
186
  }
131
187
  }
132
188
  }
133
189
  ```
134
190
 
135
- ### 完整配置字段(`channels.dingtalk-connector`)
136
-
137
- 源码权威:`src/config/schema.ts` + `openclaw.plugin.json`。
138
- **顶层单账号**与 **`accounts.<id>`** 共用同一批「共享字段」;账号级缺省时继承顶层。
139
-
140
- #### 1. 启用 / 凭证 / 多账号
141
-
142
- | 字段 | 类型 | 默认 | 说明 |
143
- |------|------|------|------|
144
- | `enabled` | boolean | — | 是否启用本渠道 |
145
- | `defaultAccount` | string | — | 默认账号 key;须存在于 `accounts` |
146
- | `clientId` | string \| number | — | AppKey / Client ID(单账号顶层) |
147
- | `clientSecret` | string \| SecretRef | — | AppSecret;支持明文或 `{ source, provider, id }` |
148
- | `accounts` | object | — | 多账号;key 为账号 ID(如 `main-bot`) |
149
- | `accounts.*.enabled` | boolean | — | 是否启用该账号 |
150
- | `accounts.*.name` | string | — | 显示名 |
151
- | `accounts.*.clientId` | string \| number | — | 该账号 Client ID |
152
- | `accounts.*.clientSecret` | string \| SecretRef | — | 该账号 Secret |
153
- | `accounts.*.chatbotUserId` | string | — | 机器人加密 ID(群内 @ 其它 bot 用);见日志 `[BotIdentity] chatbotUserId=...` |
154
- | `accounts.*.chatbotCorpId` | string | — | 机器人所属 corpId(身份日志) |
155
-
156
- #### 2. 访问策略
157
-
158
- | 字段 | 类型 | 默认 | 说明 |
159
- |------|------|------|------|
160
- | `dmPolicy` | `"open"` \| `"pairing"` \| `"allowlist"` | `"open"` | 单聊策略 |
161
- | `allowFrom` | (string\|number)[] | — | 单聊白名单;`dmPolicy=allowlist` 时**必填至少 1 项** |
162
- | `groupPolicy` | `"open"` \| `"allowlist"` \| `"disabled"` | `"open"` | 群聊策略 |
163
- | `groupAllowFrom` | (string\|number)[] | — | 群白名单;`groupPolicy=allowlist` 时**必填至少 1 项** |
164
- | `requireMention` | boolean | `true` | 群聊是否需 @机器人 才响应 |
165
- | `groups` | object | — | 按群 ID 覆盖策略(见下表) |
166
-
167
- **`groups.<openConversationId>`:**
168
-
169
- | 字段 | 类型 | 说明 |
170
- |------|------|------|
171
- | `enabled` | boolean | 该群是否启用 |
172
- | `requireMention` | boolean | 覆盖全局 @ 要求 |
173
- | `allowFrom` | (string\|number)[] | 该群发送者白名单 |
174
- | `systemPrompt` | string | 该群额外 system 提示 |
175
- | `groupSessionScope` | `"group"` \| `"group_sender"` | 该群会话维度 |
176
- | `tools.allow` / `tools.deny` | string[] | 该群工具策略 |
177
-
178
- #### 3. 会话 / 行为
179
-
180
- | 字段 | 类型 | 默认 | 说明 |
181
- |------|------|------|------|
182
- | `groupSessionScope` | `"group"` \| `"group_sender"` | `"group"` | 群会话:整群一份 / 群+发送者一份 |
183
- | `separateSessionByConversation` | boolean | `true` | 按会话隔离 |
184
- | `sharedMemoryAcrossConversations` | boolean | `false` | 跨会话共享记忆 |
185
- | `historyLimit` | int ≥0 | — | 历史条数上限 |
186
- | `textChunkLimit` | int >0 | — | 文本分片上限 |
187
- | `mediaMaxMb` | number >0 | — | 媒体大小上限(MB) |
188
- | `typingIndicator` | boolean | — | 输入中指示 |
189
- | `resolveSenderNames` | boolean | — | 解析发送者昵称 |
190
- | `asyncMode` | boolean | — | 异步模式 |
191
- | `ackText` | string | — | 收到消息时的 ACK 文案 |
192
- | `systemPrompt` | string | — | 渠道级附加 system 提示 |
193
- | `enableMediaUpload` | boolean | — | 是否启用媒体上传能力 |
194
- | `endpoint` | string | — | 自定义 DWClient 网关(高级) |
195
- | `debug` | boolean | — | 调试日志 |
196
-
197
- #### 4. 工具
198
-
199
- | 字段 | 类型 | 默认 | 说明 |
200
- |------|------|------|------|
201
- | `tools.docs` | boolean | true(语义) | 文档类工具 |
202
- | `tools.media` | boolean | true(语义) | 媒体上传类工具 |
203
-
204
- #### 5. 群回复形态 / AI 卡 / 答案卡 / message 工具
191
+ ### 钉钉专属配置字段
205
192
 
206
193
  | 字段 | 类型 | 默认 | 说明 |
207
194
  |------|------|------|------|
208
- | `groupReplyMode` | `"aicard"` \| `"text"` \| `"markdown"` | `"aicard"` | 群回复形态;`text`/`markdown` 时群聊不用 AI 流式卡(便于多 bot @) |
209
- | `cardTemplateId` | string | 官方默认流式模板 | 会话流式 AI Card 模板 ID |
210
- | `cardContentVar` | string | `"msgContent"` | 流式卡内容变量名(过程/工具/终稿写入此字段) |
211
- | `answerCard` | boolean | **true**(未配或非 false) | **会话流式**答案卡:长答案另开静态卡,原卡定格「思考完成」 |
212
- | `answerActToken` | int >0 | **500** | 会话答案卡阈值:估算 token ≤ 此值原卡定稿;> 此值才新建答案卡 |
213
- | `answerCardTemplateId` | string | 内置答案模板 | 答案静态卡模板 ID(需含内容变量) |
214
- | `messageAnswerCard` | boolean | **true**(未配或非 false) | **message 工具**正文是否走答案静态卡;`false`=普通 text/markdown。与 `answerCard` **独立**;图/音/视/文件仍普通通道 |
215
- | `messageImageMd` | boolean | **false** | message 工具图文:`false` 文图分开;`true` 仅多图+文字时合并一条 markdown |
216
-
217
- > 卡片模板需在[钉钉开放平台](https://open.dingtalk.com/)创建并发布。
218
- > `answerCard` = 对话流式收尾;`messageAnswerCard` = Agent 调 message 工具外发。不要混为一谈。
195
+ | `clientId` | string \| number | — | 钉钉 AppKey / Client ID |
196
+ | `clientSecret` | string \| SecretRef | — | AppSecret |
197
+ | `accounts` | object | — | 多机器人;key 为账号 ID |
198
+ | `accounts.*.name` | string | — | 账号显示名 |
199
+ | `accounts.*.clientId` / `clientSecret` | — | — | 该机器人凭证 |
200
+ | `cardTemplateId` | string | `0d2c84b3-12c1-473b-b14a-f329a7a102cd.schema` | 会话流式 AI Card 模板 |
201
+ | `cardContentVar` | string | `"content"` | 流式卡内容变量名 |
202
+ | `answerCard` | boolean | **true** | 会话流式答案卡;`false` 关闭 |
203
+ | `answerActToken` | int | **500** | 答案卡 token 阈值:≤ 原卡定稿,> 另开答案卡 |
204
+ | `answerCardTemplateId` | string | `d246b7f5-1783-4e9b-bb46-bef52d63050e.schema` | 答案静态卡模板 |
205
+ | `messageAnswerCard` | boolean | **true** | message 工具正文走答案静态卡;`false`=普通消息 |
206
+ | `messageImageMd` | boolean | **false** | message 图文:`false` 文图分开;`true` 可合并 markdown |
207
+
208
+ > `answerCard` = 对话流式收尾;`messageAnswerCard` = message 工具外发。
219
209
 
220
210
  ---
221
211
 
@@ -23,7 +23,7 @@ var entry_bundled_default = defineBundledChannelEntry({
23
23
  exportName: "setDingtalkRuntime"
24
24
  },
25
25
  async registerFull(api) {
26
- const { registerGatewayMethods } = await import("./gateway-methods-DtzGBBiy.mjs");
26
+ const { registerGatewayMethods } = await import("./gateway-methods-BnjDzM0H.mjs");
27
27
  registerGatewayMethods(api);
28
28
  }
29
29
  });
@@ -0,0 +1,2 @@
1
+ import { t as registerGatewayMethods } from "./gateway-methods-KiwXV8w1.mjs";
2
+ export { registerGatewayMethods };
@@ -1,7 +1,7 @@
1
1
  import { a as resolveDingtalkAccount, t as listDingtalkAccountIds } from "./accounts-BAzdqkAV.mjs";
2
2
  import { t as dingtalkHttp } from "./http-client-DFWZgO1n.mjs";
3
3
  import { r as getAccessToken, t as DINGTALK_API } from "./utils-CIfI_3Jh.mjs";
4
- import { c as prepareMultiBotMentions, d as finishAICard, i as sendProactive, s as buildBotMentionTable } from "./messaging-DOEBZgXQ.mjs";
4
+ import { c as prepareMultiBotMentions, d as finishAICard, i as sendProactive, s as buildBotMentionTable } from "./messaging-CgX-cHZa.mjs";
5
5
  import { c as getUnionId, d as recallEmotionReply } from "./utils-legacy-CALCPP1t.mjs";
6
6
  //#region src/docs.ts
7
7
  var DingtalkDocsClient = class {
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { a as initDingtalkPluginConfigSchema, i as dingtalkPlugin, n as setDingtalkRuntime } from "./runtime-hVrm4xYI.mjs";
2
- import { t as registerGatewayMethods } from "./gateway-methods-CuqlMAXE.mjs";
1
+ import { a as initDingtalkPluginConfigSchema, i as dingtalkPlugin, n as setDingtalkRuntime } from "./runtime-DOR9z5p2.mjs";
2
+ import { t as registerGatewayMethods } from "./gateway-methods-KiwXV8w1.mjs";
3
3
  //#region index.ts
4
4
  /**
5
5
  * 检测同一 plugin id 在多个路径被加载的情况。
@@ -1,9 +1,9 @@
1
1
  import { a as resolveDingtalkAccount } from "./accounts-BAzdqkAV.mjs";
2
- import { r as CHANNEL_ID, t as getDingtalkRuntime } from "./runtime-hVrm4xYI.mjs";
2
+ import { r as CHANNEL_ID, t as getDingtalkRuntime } from "./runtime-DOR9z5p2.mjs";
3
3
  import { n as createLoggerFromConfig } from "./logger-mZ9OSbmD.mjs";
4
4
  import { t as dingtalkHttp } from "./http-client-DFWZgO1n.mjs";
5
5
  import { i as getOapiAccessToken } from "./utils-CIfI_3Jh.mjs";
6
- import { S as finalClean, _ as FINAL_TAG, a as sendTextMessage, b as estimateTokens, d as finishAICard, g as unregisterActiveCard, h as streamAICard, i as sendProactive, m as registerActiveCard, p as isQpsLimitError, r as sendMessage, t as sendMarkdownMessage, u as createAICardForTarget, v as PROCESS_TAG, x as extractFinal, y as displayClean } from "./messaging-DOEBZgXQ.mjs";
6
+ import { S as finalClean, _ as FINAL_TAG, a as sendTextMessage, b as estimateTokens, d as finishAICard, g as unregisterActiveCard, h as streamAICard, i as sendProactive, m as registerActiveCard, p as isQpsLimitError, r as sendMessage, t as sendMarkdownMessage, u as createAICardForTarget, v as PROCESS_TAG, x as extractFinal, y as displayClean } from "./messaging-CgX-cHZa.mjs";
7
7
  import { a as QUEUE_BUSY_ACK_PHRASES, n as normalizeSlashCommand, t as buildSessionContext } from "./session-DJ4jYqPv.mjs";
8
8
  import { d as recallEmotionReply, o as getAccessToken, r as addEmotionReply, s as getOapiAccessToken$1, t as DINGTALK_API } from "./utils-legacy-CALCPP1t.mjs";
9
9
  import "./chunk-upload-BBQgGtcZ.mjs";
@@ -53,8 +53,10 @@ function unregisterActiveCard(openConversationId) {
53
53
  function getActiveCardForConversation(openConversationId) {
54
54
  return _activeCardRegistry.get(openConversationId) ?? null;
55
55
  }
56
- const DEFAULT_CARD_TEMPLATE_ID = "02fcf2f4-5e02-4a85-b672-46d1f715543e.schema";
57
- const DEFAULT_CARD_CONTENT_VAR = "msgContent";
56
+ /** 社区增强版流式 AI Card 默认模板(含复制按钮等) */
57
+ const DEFAULT_CARD_TEMPLATE_ID = "0d2c84b3-12c1-473b-b14a-f329a7a102cd.schema";
58
+ /** 与默认增强模板 0d2c84b3… 字段一致 */
59
+ const DEFAULT_CARD_CONTENT_VAR = "content";
58
60
  /**
59
61
  * 钉钉卡片 API 的最大 QPS(官方限制约 40 次/秒)。
60
62
  * 保守取 20,为 createAICardForTarget / finishAICard 等非流式调用留余量。
@@ -3,7 +3,7 @@ import { a as resolveDingtalkAccount, c as addWildcardAllowFrom, d as hasConfigu
3
3
  import { t as createLogger } from "./logger-mZ9OSbmD.mjs";
4
4
  import { t as dingtalkHttp } from "./http-client-DFWZgO1n.mjs";
5
5
  import "./utils-CIfI_3Jh.mjs";
6
- import { S as finalClean, f as getActiveCardForConversation, n as sendMediaToDingTalk, o as sendTextToDingTalk } from "./messaging-DOEBZgXQ.mjs";
6
+ import { S as finalClean, f as getActiveCardForConversation, n as sendMediaToDingTalk, o as sendTextToDingTalk } from "./messaging-CgX-cHZa.mjs";
7
7
  import { createRequire } from "node:module";
8
8
  import { z, z as z$1 } from "zod";
9
9
  //#region src/secret-input.ts
@@ -112,8 +112,8 @@ const DingtalkSharedConfigShape = {
112
112
  groupReplyMode: GroupReplyModeSchema,
113
113
  /** AI Card 模板 ID,不填则使用官方默认模板 */
114
114
  cardTemplateId: z$1.string().optional(),
115
- /** AI Card 内容变量名,对应卡片模板中的变量字段,不填默认 msgContent */
116
- cardContentVar: z$1.string().optional().default("msgContent"),
115
+ /** AI Card 内容变量名,对应卡片模板中的变量字段,不填默认 content(与默认增强模板一致) */
116
+ cardContentVar: z$1.string().optional().default("content"),
117
117
  /** 答案专用卡模式:超过 answerActToken 的最终答案投到一张新的静态文本卡,原流式卡定格"思考完成",
118
118
  * 规避钉钉流式卡 FINISHED 后仍抖动的官方 bug。默认开启(显式设 false 才关)。 */
119
119
  answerCard: z$1.boolean().optional(),
@@ -937,7 +937,7 @@ async function monitorDingtalkProvider(opts = {}) {
937
937
  const log = createLogger(cfg.channels?.["dingtalk-connector"]?.debug ?? false);
938
938
  const [accountsModule, monitorAccountModule, monitorSingleModule] = await Promise.all([
939
939
  import("./accounts-BQptOmgB.mjs"),
940
- import("./message-handler-DKPtnK0x.mjs"),
940
+ import("./message-handler-BpyhuanG.mjs"),
941
941
  import("./connection-DHHFFNQJ.mjs")
942
942
  ]);
943
943
  const { resolveDingtalkAccount, listEnabledDingtalkAccounts } = accountsModule;
@@ -44,16 +44,14 @@ openclaw gateway restart
44
44
  "messageAnswerCard": false
45
45
  ```
46
46
 
47
- ### 完整字段表
47
+ ### 钉钉专属字段(文档)
48
48
 
49
- 见仓库 README「完整配置字段」章节(中文 `README.md` / 英文 `README.en.md`),与 `src/config/schema.ts`、`openclaw.plugin.json` 对齐,含:
49
+ 见 README 最小/最大化配置与字段表:
50
50
 
51
- - 凭证 / `accounts` / `chatbotUserId`
52
- - `dmPolicy` / `groupPolicy` / `requireMention` / `groups.*`
53
- - 会话:`groupSessionScope` / `separateSessionByConversation` / …
54
- - 卡片:`groupReplyMode` / `cardTemplateId` / `cardContentVar`
55
- - 答案卡:`answerCard` / `answerActToken`(默认 500)/ `answerCardTemplateId`
56
- - message:`messageAnswerCard`(默认 true)/ `messageImageMd`(默认 false)
51
+ - 凭证 / `accounts`(name、clientId、clientSecret)
52
+ - `cardTemplateId`(默认 `0d2c84b3-12c1-473b-b14a-f329a7a102cd.schema`)/ `cardContentVar`(默认 `content`)
53
+ - `answerCard` / `answerActToken`(500)/ `answerCardTemplateId`
54
+ - `messageAnswerCard`(true)/ `messageImageMd`(false)
57
55
 
58
56
  ## 日志
59
57
 
@@ -0,0 +1,16 @@
1
+ # Release Notes — v0.8.21-fix49(2026-07-21)
2
+
3
+ ## 安装
4
+
5
+ ```bash
6
+ npx -y @jeik/dingtalk-connector install --force
7
+ openclaw gateway restart
8
+ ```
9
+
10
+ ## 本版要点
11
+
12
+ - 默认流式卡:`0d2c84b3-12c1-473b-b14a-f329a7a102cd.schema`,`cardContentVar=content`
13
+ - 含 fix48:`messageAnswerCard`(默认开)、`file://` 本地图修复、图片发送全路径增强
14
+ - 文档:最小/最大化配置、图片能力说明
15
+
16
+ 从 fix48 直接 `--force` 安装即可。
@@ -14,7 +14,7 @@
14
14
  "additionalProperties": false,
15
15
  "properties": {
16
16
  "cardTemplateId": { "type": "string" },
17
- "cardContentVar": { "type": "string", "default": "msgContent" }
17
+ "cardContentVar": { "type": "string", "default": "content" }
18
18
  }
19
19
  },
20
20
  "channelConfigs": {
@@ -265,7 +265,7 @@
265
265
  },
266
266
  "cardContentVar": {
267
267
  "type": "string",
268
- "default": "msgContent"
268
+ "default": "content"
269
269
  },
270
270
  "answerCard": {
271
271
  "type": "boolean"
@@ -516,7 +516,7 @@
516
516
  },
517
517
  "cardContentVar": {
518
518
  "type": "string",
519
- "default": "msgContent"
519
+ "default": "content"
520
520
  },
521
521
  "answerCard": {
522
522
  "type": "boolean"
@@ -579,12 +579,12 @@
579
579
  },
580
580
  "channels.dingtalk-connector.cardTemplateId": {
581
581
  "label": "AI Card Template ID",
582
- "help": "会话流式 AI Card 模板 ID;不填用官方默认流式模板。",
582
+ "help": "会话流式 AI Card 模板 ID;不填默认 0d2c84b3-12c1-473b-b14a-f329a7a102cd.schema。",
583
583
  "advanced": true
584
584
  },
585
585
  "channels.dingtalk-connector.cardContentVar": {
586
586
  "label": "Card Content Variable",
587
- "help": "流式卡内容变量名,默认 msgContent(过程/工具/终稿写入此字段)。",
587
+ "help": "流式卡内容变量名,默认 content(过程/工具/终稿写入此字段)。",
588
588
  "advanced": true
589
589
  },
590
590
  "channels.dingtalk-connector.answerCard": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jeik/dingtalk-connector",
3
- "version": "0.8.21-fix48",
3
+ "version": "0.8.21-fix49",
4
4
  "description": "OpenClaw DingTalk channel plugin (fork) | 钉钉 OpenClaw 渠道插件(fork 自官方,含标记/卡片渲染修复)",
5
5
  "type": "module",
6
6
  "exports": {
@@ -101,8 +101,8 @@ const DingtalkSharedConfigShape = {
101
101
  groupReplyMode: GroupReplyModeSchema,
102
102
  /** AI Card 模板 ID,不填则使用官方默认模板 */
103
103
  cardTemplateId: z.string().optional(),
104
- /** AI Card 内容变量名,对应卡片模板中的变量字段,不填默认 msgContent */
105
- cardContentVar: z.string().optional().default("msgContent"),
104
+ /** AI Card 内容变量名,对应卡片模板中的变量字段,不填默认 content(与默认增强模板一致) */
105
+ cardContentVar: z.string().optional().default("content"),
106
106
  /** 答案专用卡模式:超过 answerActToken 的最终答案投到一张新的静态文本卡,原流式卡定格"思考完成",
107
107
  * 规避钉钉流式卡 FINISHED 后仍抖动的官方 bug。默认开启(显式设 false 才关)。 */
108
108
  answerCard: z.boolean().optional(),
@@ -28,8 +28,10 @@ export function getActiveCardForConversation(openConversationId: string): AICard
28
28
 
29
29
  // ============ 常量 ============
30
30
 
31
- const DEFAULT_CARD_TEMPLATE_ID = "02fcf2f4-5e02-4a85-b672-46d1f715543e.schema";
32
- const DEFAULT_CARD_CONTENT_VAR = "msgContent";
31
+ /** 社区增强版流式 AI Card 默认模板(含复制按钮等) */
32
+ const DEFAULT_CARD_TEMPLATE_ID = "0d2c84b3-12c1-473b-b14a-f329a7a102cd.schema";
33
+ /** 与默认增强模板 0d2c84b3… 字段一致 */
34
+ const DEFAULT_CARD_CONTENT_VAR = "content";
33
35
 
34
36
  /**
35
37
  * 钉钉卡片 API 的最大 QPS(官方限制约 40 次/秒)。
@@ -1,2 +0,0 @@
1
- import { t as registerGatewayMethods } from "./gateway-methods-CuqlMAXE.mjs";
2
- export { registerGatewayMethods };