@jeik/dingtalk-connector 0.8.21-fix47 → 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 +25 -0
- package/README.en.md +130 -31
- package/README.md +113 -54
- package/dist/entry-bundled.mjs +1 -1
- package/dist/gateway-methods-BnjDzM0H.mjs +2 -0
- package/dist/{gateway-methods-DNvtOYEG.mjs → gateway-methods-KiwXV8w1.mjs} +1 -1
- package/dist/index.d.mts +2 -0
- package/dist/index.mjs +2 -2
- package/dist/{message-handler-DVXM5olz.mjs → message-handler-BpyhuanG.mjs} +2 -2
- package/dist/{messaging-msXFq5IJ.mjs → messaging-CgX-cHZa.mjs} +41 -18
- package/dist/{runtime-f78QdJj5.mjs → runtime-DOR9z5p2.mjs} +12 -5
- package/docs/RELEASE_NOTES_V0.8.21-fix48.md +71 -0
- package/docs/RELEASE_NOTES_V0.8.21-fix49.md +16 -0
- package/openclaw.plugin.json +48 -3
- package/package.json +1 -1
- package/src/config/schema.ts +10 -3
- package/src/services/messaging/card.ts +4 -2
- package/src/services/messaging/index.ts +2 -0
- package/src/services/messaging.ts +83 -15
- package/dist/gateway-methods-DHMdV0k8.mjs +0 -2
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,31 @@ 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
|
+
|
|
20
|
+
## [0.8.21-fix48] - 2026-07-21
|
|
21
|
+
|
|
22
|
+
### 新增 / Added
|
|
23
|
+
- ✨ **`messageAnswerCard`(默认 `true`)** — message 工具正文默认走**答案静态卡**(`answerCardTemplateId` 或内置模板,`skipInputingWalk`);失败降级普通消息。显式 `false` 关闭。
|
|
24
|
+
已注册:`schema.ts`、`openclaw.plugin.json`(channels + accounts + uiHints)。
|
|
25
|
+
与会话流式 `answerCard` 独立;图/音/视/文件仍走普通通道。
|
|
26
|
+
|
|
27
|
+
### 安装 / Install
|
|
28
|
+
```bash
|
|
29
|
+
npx -y @jeik/dingtalk-connector install --force
|
|
30
|
+
openclaw gateway restart
|
|
31
|
+
```
|
|
32
|
+
|
|
8
33
|
## [0.8.21-fix47] - 2026-07-20
|
|
9
34
|
|
|
10
35
|
### 修复 / Fixed
|
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-
|
|
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,18 +23,24 @@
|
|
|
23
23
|
|
|
24
24
|
## 🔧 Recent Updates
|
|
25
25
|
|
|
26
|
-
### 🚀 v0.8.21-
|
|
26
|
+
### 🚀 v0.8.21-fix49 · 2026-07-21 (current)
|
|
27
27
|
|
|
28
|
-
**Theme:
|
|
28
|
+
**Theme: message tool answer card by default (toggle)**
|
|
29
29
|
|
|
30
30
|
| | Change |
|
|
31
31
|
|--|--------|
|
|
32
|
-
|
|
|
32
|
+
| ✨ **`messageAnswerCard`** | **Default `true`**: message body uses static answer card; set `false` for plain text/markdown |
|
|
33
|
+
| 🔧 **Registered** | `schema` + `openclaw.plugin.json` (channels / accounts / uiHints) |
|
|
34
|
+
| 📎 **Independent** | Separate from session-stream `answerCard`; media still uses normal APIs |
|
|
33
35
|
|
|
34
36
|
```bash
|
|
35
37
|
npx -y @jeik/dingtalk-connector install --force && openclaw gateway restart
|
|
36
38
|
```
|
|
37
39
|
|
|
40
|
+
### 📦 v0.8.21-fix47 · 2026-07-20
|
|
41
|
+
|
|
42
|
+
`file://` no longer misclassified as remote (grey-image fix).
|
|
43
|
+
|
|
38
44
|
### 📦 v0.8.21-fix46 · 2026-07-20
|
|
39
45
|
|
|
40
46
|
Always-on local MD image diagnostics.
|
|
@@ -49,14 +55,7 @@ Remote `media` download-then-upload.
|
|
|
49
55
|
|
|
50
56
|
### 📦 v0.8.21-fix37 · 2026-07-20
|
|
51
57
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
| | Change |
|
|
55
|
-
|--|--------|
|
|
56
|
-
| 📷 **Local MD images** | Any absolute path (incl. **`/mnt`**, Chinese paths); upload retries via `/tmp` copy |
|
|
57
|
-
| 📦 **Code-block safe** | Paths inside fenced/inline code are **not** uploaded (param samples stay literal) |
|
|
58
|
-
| ⚙️ **`messageImageMd`** | Default `false`: message tool sends **text then image** separately; `true` merges only multi-image + text into one markdown |
|
|
59
|
-
| 🔍 **Diagnostics** | Prefix `[DingTalk][LocalImage]` — **no `debug` flag required** |
|
|
58
|
+
Local images (incl. `/mnt`) · `messageImageMd` · LocalImage diagnostics.
|
|
60
59
|
|
|
61
60
|
---
|
|
62
61
|
|
|
@@ -69,22 +68,69 @@ Remote `media` download-then-upload.
|
|
|
69
68
|
| 2026-06-28 | npm `@jeik/dingtalk-connector`; premature finalization fix |
|
|
70
69
|
| 2026-05 | MD images; multi-turn spam; 4.29 empty reply; WS phantom reconnect |
|
|
71
70
|
|
|
72
|
-
Full log: [CHANGELOG.md](CHANGELOG.md) · [FIXES.md](FIXES.md) · [Release
|
|
71
|
+
Full log: [CHANGELOG.md](CHANGELOG.md) · [FIXES.md](FIXES.md) · [Release fix48](docs/RELEASE_NOTES_V0.8.21-fix49.md)
|
|
73
72
|
|
|
74
73
|
---
|
|
75
74
|
|
|
76
75
|
## ✨ Enhanced Features
|
|
77
76
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
77
|
+
### 🖼️ Image sending: full fix & upgrade
|
|
78
|
+
|
|
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
|
|
81
|
+
|
|
82
|
+
Full-path image fixes — every channel below renders correctly:
|
|
83
|
+
|
|
84
|
+
| | Path | Capability |
|
|
85
|
+
|--|------|------------|
|
|
86
|
+
| 💬 | **Normal chat reply** | Agent embeds ``; 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
|
|
82
92
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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…` |
|
|
86
101
|
|
|
87
|
-
|
|
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
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
"channels": {
|
|
117
|
+
"dingtalk-connector": {
|
|
118
|
+
"enabled": true,
|
|
119
|
+
"clientId": "your-clientId",
|
|
120
|
+
"clientSecret": "your-clientSecret"
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Defaults apply: stream card `0d2c84b3-…schema`, session answer card on, message answer card on, `messageImageMd=false`.
|
|
126
|
+
|
|
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.
|
|
128
|
+
|
|
129
|
+
### Maximal config (for illustration; defaults written out)
|
|
130
|
+
|
|
131
|
+
**Single Agent** and **multi Agent** (all values are defaults — **not extra features**).
|
|
132
|
+
|
|
133
|
+
**Single Agent (top-level credentials):**
|
|
88
134
|
|
|
89
135
|
```json
|
|
90
136
|
"channels": {
|
|
@@ -92,21 +138,74 @@ Full log: [CHANGELOG.md](CHANGELOG.md) · [FIXES.md](FIXES.md) · [Release fix38
|
|
|
92
138
|
"enabled": true,
|
|
93
139
|
"clientId": "your-clientId",
|
|
94
140
|
"clientSecret": "your-clientSecret",
|
|
95
|
-
"cardTemplateId": "
|
|
96
|
-
"cardContentVar": "content"
|
|
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
|
|
97
148
|
}
|
|
98
149
|
}
|
|
99
150
|
```
|
|
100
151
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
152
|
+
**Multi Agent (`accounts`, one credential/card set per bot):**
|
|
153
|
+
|
|
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
|
+
```
|
|
108
190
|
|
|
109
|
-
|
|
191
|
+
### DingTalk-specific fields
|
|
192
|
+
|
|
193
|
+
| Field | Type | Default | Description |
|
|
194
|
+
|-------|------|---------|-------------|
|
|
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.
|
|
110
209
|
|
|
111
210
|
---
|
|
112
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-
|
|
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,18 +23,24 @@
|
|
|
23
23
|
|
|
24
24
|
## 🔧 最近更新
|
|
25
25
|
|
|
26
|
-
### 🚀 v0.8.21-
|
|
26
|
+
### 🚀 v0.8.21-fix49 · 2026-07-21(当前)
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
**主题:message 工具默认答案卡(可关)**
|
|
29
29
|
|
|
30
30
|
| | 改动 |
|
|
31
31
|
|--|------|
|
|
32
|
-
|
|
|
32
|
+
| ✨ **`messageAnswerCard`** | **默认 `true`**:message 正文走答案静态卡;`false` 恢复普通 text/markdown |
|
|
33
|
+
| 🔧 **注册** | `schema` + `openclaw.plugin.json`(channels / accounts / uiHints) |
|
|
34
|
+
| 📎 **独立** | 与会话流式 `answerCard` 分开;媒体消息仍普通通道 |
|
|
33
35
|
|
|
34
36
|
```bash
|
|
35
37
|
npx -y @jeik/dingtalk-connector install --force && openclaw gateway restart
|
|
36
38
|
```
|
|
37
39
|
|
|
40
|
+
### 📦 v0.8.21-fix47 · 2026-07-20
|
|
41
|
+
|
|
42
|
+
`file://` 本地图误判远程修复(不再 `fetch failed` 灰图)。
|
|
43
|
+
|
|
38
44
|
### 📦 v0.8.21-fix46 · 2026-07-20
|
|
39
45
|
|
|
40
46
|
本地 MD 图灰图诊断日志(LocalImage / MediaIdTrace)。
|
|
@@ -49,14 +55,7 @@ message 远程 `media` 下载上传。
|
|
|
49
55
|
|
|
50
56
|
### 📦 v0.8.21-fix37 · 2026-07-20
|
|
51
57
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
| | 改动 |
|
|
55
|
-
|--|------|
|
|
56
|
-
| 📷 **MD 本地图** | 支持任意绝对路径(含 **`/mnt` 共享盘**、中文目录);上传失败会拷到 `/tmp` 再试 |
|
|
57
|
-
| 📦 **代码块保护** | 围栏 / 行内 code 里的路径**不会上传**,参数示例不会被改成 `mediaId` |
|
|
58
|
-
| ⚙️ **`messageImageMd`** | 默认 `false`:message 工具**文图分开**;`true` 时仅「多图 + 文字」合并为一条 markdown |
|
|
59
|
-
| 🔍 **诊断日志** | 前缀 `[DingTalk][LocalImage]`,**无需开 debug** 也能看到匹配 / 上传 / 失败原因 |
|
|
58
|
+
本地图(含 `/mnt`)· `messageImageMd` · LocalImage 诊断日志。
|
|
60
59
|
|
|
61
60
|
---
|
|
62
61
|
|
|
@@ -69,26 +68,69 @@ message 远程 `media` 下载上传。
|
|
|
69
68
|
| 2026-06-28 | 上线 npm `@jeik/dingtalk-connector`;过程消息提前定稿修复 |
|
|
70
69
|
| 2026-05 | MD 直链/本地图;多轮刷屏;4.29+ 无文本输出;WebSocket 幻影重连 |
|
|
71
70
|
|
|
72
|
-
完整说明:[CHANGELOG.md](CHANGELOG.md) · [FIXES.md](FIXES.md) · [Release
|
|
71
|
+
完整说明:[CHANGELOG.md](CHANGELOG.md) · [FIXES.md](FIXES.md) · [Release fix48](docs/RELEASE_NOTES_V0.8.21-fix49.md)
|
|
73
72
|
|
|
74
73
|
---
|
|
75
74
|
|
|
76
75
|
## ✨ 增强功能
|
|
77
76
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
77
|
+
### 🖼️ 图片发送:全面修复与增强
|
|
78
|
+
|
|
79
|
+
> 🔥 **毫无死角** · 混合发图 · 全面碾压官方薄弱的图片机制
|
|
80
|
+
> ✅ 对话发图 · ✅ message 直发 · ✅ markdown 嵌图 · ✅ 文图可分可合
|
|
81
|
+
|
|
82
|
+
对官方图片发送做了**全路径修复增强**,多通道混合发图,全部显示正常:
|
|
84
83
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
| | 发送方式 | 能力 |
|
|
85
|
+
|--|----------|------|
|
|
86
|
+
| 💬 | **普通对话回复** | Agent 用 `` 嵌图,定稿前自动上传 mediaId |
|
|
87
|
+
| 📤 | **message · mediaUrl** | 机器人主动触发直发(本地 / 内网 / 公网) |
|
|
88
|
+
| 📝 | **message · markdown 正文** | 正文嵌 ``(本地 / `file://` / 直链)与文字同条 |
|
|
89
|
+
| ⚙️ | **文图策略可配** | 默认 📎 **分开**;`messageImageMd: true` → 🧩 **合并**一条 markdown |
|
|
88
90
|
|
|
89
|
-
|
|
91
|
+
#### 🌐 路径与协议全覆盖
|
|
90
92
|
|
|
91
|
-
|
|
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(顶层凭证):**
|
|
92
134
|
|
|
93
135
|
```json
|
|
94
136
|
"channels": {
|
|
@@ -96,57 +138,74 @@ message 远程 `media` 下载上传。
|
|
|
96
138
|
"enabled": true,
|
|
97
139
|
"clientId": "你的clientId",
|
|
98
140
|
"clientSecret": "你的clientSecret",
|
|
99
|
-
"cardTemplateId": "
|
|
141
|
+
"cardTemplateId": "0d2c84b3-12c1-473b-b14a-f329a7a102cd.schema",
|
|
100
142
|
"cardContentVar": "content",
|
|
101
|
-
"
|
|
102
|
-
"
|
|
143
|
+
"answerCard": true,
|
|
144
|
+
"answerActToken": 500,
|
|
145
|
+
"answerCardTemplateId": "d246b7f5-1783-4e9b-bb46-bef52d63050e.schema",
|
|
146
|
+
"messageAnswerCard": true,
|
|
147
|
+
"messageImageMd": false
|
|
103
148
|
}
|
|
104
149
|
}
|
|
105
150
|
```
|
|
106
151
|
|
|
107
|
-
|
|
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": "
|
|
118
|
-
"clientSecret": "
|
|
119
|
-
"cardTemplateId": "
|
|
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
|
-
"
|
|
173
|
+
"guide-bot": {
|
|
123
174
|
"enabled": true,
|
|
124
|
-
"name": "
|
|
125
|
-
"clientId": "
|
|
126
|
-
"clientSecret": "
|
|
127
|
-
"cardTemplateId": "
|
|
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
|
-
|
|
136
|
-
|
|
137
|
-
|
|
|
138
|
-
|
|
139
|
-
| `
|
|
140
|
-
| `
|
|
141
|
-
| `accounts
|
|
142
|
-
| `accounts.*.
|
|
143
|
-
| `
|
|
144
|
-
| `
|
|
145
|
-
| `
|
|
146
|
-
| `
|
|
147
|
-
| `
|
|
148
|
-
|
|
149
|
-
|
|
191
|
+
### 钉钉专属配置字段
|
|
192
|
+
|
|
193
|
+
| 字段 | 类型 | 默认 | 说明 |
|
|
194
|
+
|------|------|------|------|
|
|
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 工具外发。
|
|
150
209
|
|
|
151
210
|
---
|
|
152
211
|
|
package/dist/entry-bundled.mjs
CHANGED
|
@@ -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-
|
|
26
|
+
const { registerGatewayMethods } = await import("./gateway-methods-BnjDzM0H.mjs");
|
|
27
27
|
registerGatewayMethods(api);
|
|
28
28
|
}
|
|
29
29
|
});
|
|
@@ -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-
|
|
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.d.mts
CHANGED
|
@@ -70,6 +70,7 @@ declare const DingtalkConfigSchema: z$1.ZodObject<{
|
|
|
70
70
|
enableMediaUpload: z$1.ZodOptional<z$1.ZodBoolean>;
|
|
71
71
|
systemPrompt: z$1.ZodOptional<z$1.ZodString>;
|
|
72
72
|
messageImageMd: z$1.ZodOptional<z$1.ZodBoolean>;
|
|
73
|
+
messageAnswerCard: z$1.ZodOptional<z$1.ZodBoolean>;
|
|
73
74
|
groupReplyMode: z$1.ZodOptional<z$1.ZodEnum<{
|
|
74
75
|
aicard: "aicard";
|
|
75
76
|
text: "text";
|
|
@@ -127,6 +128,7 @@ declare const DingtalkConfigSchema: z$1.ZodObject<{
|
|
|
127
128
|
enableMediaUpload: z$1.ZodOptional<z$1.ZodBoolean>;
|
|
128
129
|
systemPrompt: z$1.ZodOptional<z$1.ZodString>;
|
|
129
130
|
messageImageMd: z$1.ZodOptional<z$1.ZodBoolean>;
|
|
131
|
+
messageAnswerCard: z$1.ZodOptional<z$1.ZodBoolean>;
|
|
130
132
|
groupReplyMode: z$1.ZodOptional<z$1.ZodEnum<{
|
|
131
133
|
aicard: "aicard";
|
|
132
134
|
text: "text";
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as initDingtalkPluginConfigSchema, i as dingtalkPlugin, n as setDingtalkRuntime } from "./runtime-
|
|
2
|
-
import { t as registerGatewayMethods } from "./gateway-methods-
|
|
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-
|
|
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-
|
|
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
|
-
|
|
57
|
-
const
|
|
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 等非流式调用留余量。
|
|
@@ -582,6 +584,28 @@ function prepareMultiBotMentions(params) {
|
|
|
582
584
|
//#endregion
|
|
583
585
|
//#region src/services/messaging.ts
|
|
584
586
|
/**
|
|
587
|
+
* message 工具是否用答案卡(默认开;显式 false 才关)。
|
|
588
|
+
* 与会话流式 answerCard 独立。
|
|
589
|
+
*/
|
|
590
|
+
function isMessageAnswerCardEnabled(config) {
|
|
591
|
+
return config?.messageAnswerCard !== false;
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* message 工具正文发送的卡片选项:答案卡模板 + 静态 FINISHED,失败降级普通消息。
|
|
595
|
+
*/
|
|
596
|
+
function messageToolProactiveCardOptions(config) {
|
|
597
|
+
if (!isMessageAnswerCardEnabled(config)) return {
|
|
598
|
+
useAICard: false,
|
|
599
|
+
fallbackToNormal: true
|
|
600
|
+
};
|
|
601
|
+
return {
|
|
602
|
+
useAICard: true,
|
|
603
|
+
fallbackToNormal: true,
|
|
604
|
+
cardTemplateId: typeof config.answerCardTemplateId === "string" && config.answerCardTemplateId.trim() || "d246b7f5-1783-4e9b-bb46-bef52d63050e.schema",
|
|
605
|
+
skipInputingWalk: true
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
585
609
|
* 发送 Markdown 消息
|
|
586
610
|
* 支持 @用户(atUserId)和 @机器人(atDingtalkIds)
|
|
587
611
|
*/
|
|
@@ -898,12 +922,13 @@ async function sendTextToDingTalk(params) {
|
|
|
898
922
|
console.warn(`[DingTalk][LocalImage] sendTextToDingTalk 图片处理失败: ${err?.message || err}`);
|
|
899
923
|
}
|
|
900
924
|
const msgType = shouldSendAsMarkdown(text) ? "markdown" : "text";
|
|
901
|
-
|
|
925
|
+
const cardOpts = messageToolProactiveCardOptions(config);
|
|
926
|
+
logMediaIdTrace("sendTextToDingTalk:API前", text, `msgType=${msgType} messageAnswerCard=${isMessageAnswerCardEnabled(config)} useAICard=${cardOpts.useAICard}`, true);
|
|
927
|
+
console.log(`[DingTalk][MessageCard] sendTextToDingTalk | messageAnswerCard=${isMessageAnswerCardEnabled(config)} useAICard=${cardOpts.useAICard} tpl=${cardOpts.cardTemplateId || "-"}`);
|
|
902
928
|
return sendProactive(config, targetParam, text, {
|
|
903
929
|
msgType,
|
|
904
930
|
replyToId,
|
|
905
|
-
|
|
906
|
-
fallbackToNormal: true,
|
|
931
|
+
...cardOpts,
|
|
907
932
|
skipProcessLocalImages: true
|
|
908
933
|
});
|
|
909
934
|
}
|
|
@@ -1000,8 +1025,7 @@ async function sendMediaToDingTalk(params) {
|
|
|
1000
1025
|
if (text?.trim()) await sendProactive(config, targetParam, text.trim(), {
|
|
1001
1026
|
msgType: shouldSendAsMarkdown(text) ? "markdown" : "text",
|
|
1002
1027
|
replyToId,
|
|
1003
|
-
|
|
1004
|
-
fallbackToNormal: true
|
|
1028
|
+
...messageToolProactiveCardOptions(config)
|
|
1005
1029
|
});
|
|
1006
1030
|
if (isRemoteHttpUrl(mediaUrl) && mediaType === "image") {
|
|
1007
1031
|
console.log(`[DingTalk][RemoteMedia] 下载失败,尝试 photoURL 直链发送 | ${mediaUrl}`);
|
|
@@ -1041,8 +1065,7 @@ async function sendMediaToDingTalk(params) {
|
|
|
1041
1065
|
if (caption) await sendProactive(config, targetParam, caption, {
|
|
1042
1066
|
msgType: shouldSendAsMarkdown(caption) ? "markdown" : "text",
|
|
1043
1067
|
replyToId,
|
|
1044
|
-
|
|
1045
|
-
fallbackToNormal: true
|
|
1068
|
+
...messageToolProactiveCardOptions(config)
|
|
1046
1069
|
});
|
|
1047
1070
|
if (isRemoteHttpUrl(mediaUrl)) {
|
|
1048
1071
|
console.log(`[DingTalk][RemoteMedia] 再上传失败,photoURL 直链兜底 | ${mediaUrl}`);
|
|
@@ -1068,8 +1091,7 @@ async function sendMediaToDingTalk(params) {
|
|
|
1068
1091
|
const result = await sendProactive(config, targetParam, `${caption}\n\n`, {
|
|
1069
1092
|
msgType: "markdown",
|
|
1070
1093
|
replyToId,
|
|
1071
|
-
|
|
1072
|
-
fallbackToNormal: true
|
|
1094
|
+
...messageToolProactiveCardOptions(config)
|
|
1073
1095
|
});
|
|
1074
1096
|
return {
|
|
1075
1097
|
...result,
|
|
@@ -1079,8 +1101,7 @@ async function sendMediaToDingTalk(params) {
|
|
|
1079
1101
|
if (caption) await sendProactive(config, targetParam, caption, {
|
|
1080
1102
|
msgType: shouldSendAsMarkdown(caption) ? "markdown" : "text",
|
|
1081
1103
|
replyToId,
|
|
1082
|
-
|
|
1083
|
-
fallbackToNormal: true
|
|
1104
|
+
...messageToolProactiveCardOptions(config)
|
|
1084
1105
|
});
|
|
1085
1106
|
const result = await sendProactive(config, targetParam, mediaId, {
|
|
1086
1107
|
msgType: "image",
|
|
@@ -1102,8 +1123,7 @@ async function sendMediaToDingTalk(params) {
|
|
|
1102
1123
|
await sendProactive(config, targetParam, caption, {
|
|
1103
1124
|
msgType: shouldSendAsMarkdown(caption) ? "markdown" : "text",
|
|
1104
1125
|
replyToId,
|
|
1105
|
-
|
|
1106
|
-
fallbackToNormal: true
|
|
1126
|
+
...messageToolProactiveCardOptions(config)
|
|
1107
1127
|
});
|
|
1108
1128
|
}
|
|
1109
1129
|
const uploadResult = await uploadMediaToDingTalk(resolvedMediaUrl, mediaType, oapiToken, maxSize, log);
|
|
@@ -1219,12 +1239,13 @@ async function sendProactiveInternal(config, target, content, options) {
|
|
|
1219
1239
|
usedAICard: false
|
|
1220
1240
|
};
|
|
1221
1241
|
}
|
|
1222
|
-
const { msgType = "text", useAICard = true, fallbackToNormal = true, log: externalLog } = options;
|
|
1242
|
+
const { msgType = "text", useAICard = true, fallbackToNormal = true, cardTemplateId, skipInputingWalk = false, log: externalLog } = options;
|
|
1223
1243
|
const isMediaMessage = MEDIA_MSG_TYPES.has(msgType);
|
|
1224
1244
|
if (useAICard && !isMediaMessage) try {
|
|
1225
|
-
const card = await createAICardForTarget(config, target, externalLog);
|
|
1245
|
+
const card = await createAICardForTarget(config, target, externalLog, cardTemplateId);
|
|
1226
1246
|
if (card) {
|
|
1227
|
-
await finishAICard(card, content, config, externalLog);
|
|
1247
|
+
await finishAICard(card, content, config, externalLog, void 0, skipInputingWalk);
|
|
1248
|
+
console.log(`[DingTalk][MessageCard] AI Card 发送成功 | outTrack=${card.cardInstanceId} tpl=${cardTemplateId || "default"} skipInputing=${skipInputingWalk}`);
|
|
1228
1249
|
return {
|
|
1229
1250
|
ok: true,
|
|
1230
1251
|
cardInstanceId: card.cardInstanceId,
|
|
@@ -1236,8 +1257,10 @@ async function sendProactiveInternal(config, target, content, options) {
|
|
|
1236
1257
|
error: "Failed to create AI Card",
|
|
1237
1258
|
usedAICard: false
|
|
1238
1259
|
};
|
|
1260
|
+
console.warn(`[DingTalk][MessageCard] AI Card 创建失败,fallbackToNormal=${fallbackToNormal}`);
|
|
1239
1261
|
} catch (err) {
|
|
1240
1262
|
externalLog?.error?.(`AI Card 发送失败: ${err.message}`);
|
|
1263
|
+
console.warn(`[DingTalk][MessageCard] AI Card 异常: ${err?.message || err},fallbackToNormal=${fallbackToNormal}`);
|
|
1241
1264
|
if (!fallbackToNormal) return {
|
|
1242
1265
|
ok: false,
|
|
1243
1266
|
error: err.message,
|
|
@@ -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-
|
|
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
|
|
@@ -102,16 +102,23 @@ const DingtalkSharedConfigShape = {
|
|
|
102
102
|
* 单张图文、纯媒体文件仍分开发送
|
|
103
103
|
*/
|
|
104
104
|
messageImageMd: z$1.boolean().optional(),
|
|
105
|
+
/**
|
|
106
|
+
* message 工具是否用答案卡发送正文(默认 true,显式 false 才关):
|
|
107
|
+
* - true / 未配:走答案专用静态卡(answerCardTemplateId 或内置模板),失败降级普通消息
|
|
108
|
+
* - false:直接普通 text/markdown(旧行为)
|
|
109
|
+
* 与会话流式的 answerCard 独立;媒体消息(图/音/视/文件)仍走普通通道。
|
|
110
|
+
*/
|
|
111
|
+
messageAnswerCard: z$1.boolean().optional(),
|
|
105
112
|
groupReplyMode: GroupReplyModeSchema,
|
|
106
113
|
/** AI Card 模板 ID,不填则使用官方默认模板 */
|
|
107
114
|
cardTemplateId: z$1.string().optional(),
|
|
108
|
-
/** AI Card 内容变量名,对应卡片模板中的变量字段,不填默认
|
|
109
|
-
cardContentVar: z$1.string().optional().default("
|
|
115
|
+
/** AI Card 内容变量名,对应卡片模板中的变量字段,不填默认 content(与默认增强模板一致) */
|
|
116
|
+
cardContentVar: z$1.string().optional().default("content"),
|
|
110
117
|
/** 答案专用卡模式:超过 answerActToken 的最终答案投到一张新的静态文本卡,原流式卡定格"思考完成",
|
|
111
118
|
* 规避钉钉流式卡 FINISHED 后仍抖动的官方 bug。默认开启(显式设 false 才关)。 */
|
|
112
119
|
answerCard: z$1.boolean().optional(),
|
|
113
120
|
/** 答案卡触发阈值(token):最终答案估算 token ≤ 此值时直接在原卡定稿(不另建卡),
|
|
114
|
-
* > 此值才新建答案卡。避免简单任务也多一张卡。默认
|
|
121
|
+
* > 此值才新建答案卡。避免简单任务也多一张卡。默认 500(见 reply-dispatcher)。 */
|
|
115
122
|
answerActToken: z$1.number().int().positive().optional(),
|
|
116
123
|
/** 答案专用卡模板 ID:不填用内置默认模板。需是钉钉后台已发布、含 content 变量的卡片模板。 */
|
|
117
124
|
answerCardTemplateId: z$1.string().optional()
|
|
@@ -930,7 +937,7 @@ async function monitorDingtalkProvider(opts = {}) {
|
|
|
930
937
|
const log = createLogger(cfg.channels?.["dingtalk-connector"]?.debug ?? false);
|
|
931
938
|
const [accountsModule, monitorAccountModule, monitorSingleModule] = await Promise.all([
|
|
932
939
|
import("./accounts-BQptOmgB.mjs"),
|
|
933
|
-
import("./message-handler-
|
|
940
|
+
import("./message-handler-BpyhuanG.mjs"),
|
|
934
941
|
import("./connection-DHHFFNQJ.mjs")
|
|
935
942
|
]);
|
|
936
943
|
const { resolveDingtalkAccount, listEnabledDingtalkAccounts } = accountsModule;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Release Notes — v0.8.21-fix48(2026-07-21)
|
|
2
|
+
|
|
3
|
+
生产稳定版 / Production-stable community build of `@jeik/dingtalk-connector`。
|
|
4
|
+
|
|
5
|
+
## 安装 / Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx -y @jeik/dingtalk-connector install --force
|
|
9
|
+
openclaw gateway restart
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
本地 tgz:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
openclaw plugins install ./jeik-dingtalk-connector-0.8.21-fix48.tgz --force
|
|
16
|
+
openclaw gateway restart
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## 本版要点 / Highlights
|
|
20
|
+
|
|
21
|
+
| 领域 | 说明 |
|
|
22
|
+
|------|------|
|
|
23
|
+
| **message 答案卡** | 新增配置 **`messageAnswerCard`(默认 `true`)**:message 工具正文默认走**答案静态卡** |
|
|
24
|
+
| 模板 | 使用 `answerCardTemplateId` 或内置答案卡模板;`skipInputingWalk` 直接 FINISHED |
|
|
25
|
+
| 降级 | 建卡失败 → 自动普通 text/markdown |
|
|
26
|
+
| 关闭 | `"messageAnswerCard": false` 恢复旧行为(普通消息) |
|
|
27
|
+
| 注册 | `schema.ts` + `openclaw.plugin.json`(channels / accounts / uiHints) |
|
|
28
|
+
| 独立 | 与会话流式 **`answerCard`** 互不影响;图/音/视/文件仍走普通通道 |
|
|
29
|
+
|
|
30
|
+
## 配置示例
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
"channels": {
|
|
34
|
+
"dingtalk-connector": {
|
|
35
|
+
"messageAnswerCard": true,
|
|
36
|
+
"answerCardTemplateId": "可选-自定义答案卡模板.schema"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
关闭 message 答案卡:
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
"messageAnswerCard": false
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 钉钉专属字段(文档)
|
|
48
|
+
|
|
49
|
+
见 README 最小/最大化配置与字段表:
|
|
50
|
+
|
|
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)
|
|
55
|
+
|
|
56
|
+
## 日志
|
|
57
|
+
|
|
58
|
+
```text
|
|
59
|
+
[DingTalk][MessageCard] sendTextToDingTalk | messageAnswerCard=true useAICard=true tpl=...
|
|
60
|
+
[DingTalk][MessageCard] AI Card 发送成功 | outTrack=card_... skipInputing=true
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## 含此前修复
|
|
64
|
+
|
|
65
|
+
- fix47:`file://` 本地图不再误判远程
|
|
66
|
+
- fix46:LocalImage / MediaIdTrace 诊断日志
|
|
67
|
+
- fix45:图+下载同泡、只认 `![]`、CardCache、residual 误报
|
|
68
|
+
|
|
69
|
+
## 升级
|
|
70
|
+
|
|
71
|
+
从任意 fix37+ 直接 `--force` 安装即可。
|
|
@@ -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` 安装即可。
|
package/openclaw.plugin.json
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"additionalProperties": false,
|
|
15
15
|
"properties": {
|
|
16
16
|
"cardTemplateId": { "type": "string" },
|
|
17
|
-
"cardContentVar": { "type": "string", "default": "
|
|
17
|
+
"cardContentVar": { "type": "string", "default": "content" }
|
|
18
18
|
}
|
|
19
19
|
},
|
|
20
20
|
"channelConfigs": {
|
|
@@ -247,6 +247,11 @@
|
|
|
247
247
|
"default": false,
|
|
248
248
|
"description": "message 工具图文策略:false=文图分开(默认);true=多图+文字时才合并为 markdown"
|
|
249
249
|
},
|
|
250
|
+
"messageAnswerCard": {
|
|
251
|
+
"type": "boolean",
|
|
252
|
+
"default": true,
|
|
253
|
+
"description": "message 工具是否用答案卡发送正文:true(默认)= 答案静态卡;false= 普通 text/markdown。媒体消息仍走普通通道。"
|
|
254
|
+
},
|
|
250
255
|
"groupReplyMode": {
|
|
251
256
|
"type": "string",
|
|
252
257
|
"enum": [
|
|
@@ -260,7 +265,7 @@
|
|
|
260
265
|
},
|
|
261
266
|
"cardContentVar": {
|
|
262
267
|
"type": "string",
|
|
263
|
-
"default": "
|
|
268
|
+
"default": "content"
|
|
264
269
|
},
|
|
265
270
|
"answerCard": {
|
|
266
271
|
"type": "boolean"
|
|
@@ -493,6 +498,11 @@
|
|
|
493
498
|
"default": false,
|
|
494
499
|
"description": "message 工具图文策略:false=文图分开(默认);true=多图+文字时才合并为 markdown"
|
|
495
500
|
},
|
|
501
|
+
"messageAnswerCard": {
|
|
502
|
+
"type": "boolean",
|
|
503
|
+
"default": true,
|
|
504
|
+
"description": "message 工具是否用答案卡发送正文:true(默认)= 答案静态卡;false= 普通 text/markdown。媒体消息仍走普通通道。"
|
|
505
|
+
},
|
|
496
506
|
"groupReplyMode": {
|
|
497
507
|
"type": "string",
|
|
498
508
|
"enum": [
|
|
@@ -506,7 +516,7 @@
|
|
|
506
516
|
},
|
|
507
517
|
"cardContentVar": {
|
|
508
518
|
"type": "string",
|
|
509
|
-
"default": "
|
|
519
|
+
"default": "content"
|
|
510
520
|
},
|
|
511
521
|
"answerCard": {
|
|
512
522
|
"type": "boolean"
|
|
@@ -557,6 +567,41 @@
|
|
|
557
567
|
"help": "message 工具图文策略。false(默认):文字与图片分开发送,阅读体验更好。true:仅当多图与文字结合时合并为一条 markdown;单张图文、纯媒体仍分开。",
|
|
558
568
|
"advanced": true
|
|
559
569
|
},
|
|
570
|
+
"channels.dingtalk-connector.messageAnswerCard": {
|
|
571
|
+
"label": "Message Answer Card",
|
|
572
|
+
"help": "message 工具是否用答案卡发正文。默认开启(答案静态卡,失败降级普通消息);设为 false 则直接发 text/markdown。与会话流式的 answerCard 独立。",
|
|
573
|
+
"advanced": true
|
|
574
|
+
},
|
|
575
|
+
"channels.dingtalk-connector.groupReplyMode": {
|
|
576
|
+
"label": "Group Reply Mode",
|
|
577
|
+
"help": "群回复形态:aicard(默认,流式 AI 卡)/ text / markdown。text、markdown 时群聊不用 AI 卡,便于多机器人互相 @。",
|
|
578
|
+
"advanced": true
|
|
579
|
+
},
|
|
580
|
+
"channels.dingtalk-connector.cardTemplateId": {
|
|
581
|
+
"label": "AI Card Template ID",
|
|
582
|
+
"help": "会话流式 AI Card 模板 ID;不填默认 0d2c84b3-12c1-473b-b14a-f329a7a102cd.schema。",
|
|
583
|
+
"advanced": true
|
|
584
|
+
},
|
|
585
|
+
"channels.dingtalk-connector.cardContentVar": {
|
|
586
|
+
"label": "Card Content Variable",
|
|
587
|
+
"help": "流式卡内容变量名,默认 content(过程/工具/终稿写入此字段)。",
|
|
588
|
+
"advanced": true
|
|
589
|
+
},
|
|
590
|
+
"channels.dingtalk-connector.answerCard": {
|
|
591
|
+
"label": "Session Answer Card",
|
|
592
|
+
"help": "会话流式答案卡开关,默认开启。长答案另开静态卡,原卡定格思考完成;显式 false 关闭。",
|
|
593
|
+
"advanced": true
|
|
594
|
+
},
|
|
595
|
+
"channels.dingtalk-connector.answerActToken": {
|
|
596
|
+
"label": "Answer Card Token Threshold",
|
|
597
|
+
"help": "会话答案卡触发阈值(token),默认 500。≤ 阈值在原卡定稿;> 阈值才新建答案卡。",
|
|
598
|
+
"advanced": true
|
|
599
|
+
},
|
|
600
|
+
"channels.dingtalk-connector.answerCardTemplateId": {
|
|
601
|
+
"label": "Answer Card Template ID",
|
|
602
|
+
"help": "答案静态卡模板 ID;message 答案卡与会话答案卡共用。不填用内置默认模板。",
|
|
603
|
+
"advanced": true
|
|
604
|
+
},
|
|
560
605
|
"channels.dingtalk-connector.endpoint": {
|
|
561
606
|
"label": "Gateway Endpoint",
|
|
562
607
|
"help": "自定义 DWClient 网关地址(高级)",
|
package/package.json
CHANGED
package/src/config/schema.ts
CHANGED
|
@@ -91,16 +91,23 @@ const DingtalkSharedConfigShape = {
|
|
|
91
91
|
* 单张图文、纯媒体文件仍分开发送
|
|
92
92
|
*/
|
|
93
93
|
messageImageMd: z.boolean().optional(),
|
|
94
|
+
/**
|
|
95
|
+
* message 工具是否用答案卡发送正文(默认 true,显式 false 才关):
|
|
96
|
+
* - true / 未配:走答案专用静态卡(answerCardTemplateId 或内置模板),失败降级普通消息
|
|
97
|
+
* - false:直接普通 text/markdown(旧行为)
|
|
98
|
+
* 与会话流式的 answerCard 独立;媒体消息(图/音/视/文件)仍走普通通道。
|
|
99
|
+
*/
|
|
100
|
+
messageAnswerCard: z.boolean().optional(),
|
|
94
101
|
groupReplyMode: GroupReplyModeSchema,
|
|
95
102
|
/** AI Card 模板 ID,不填则使用官方默认模板 */
|
|
96
103
|
cardTemplateId: z.string().optional(),
|
|
97
|
-
/** AI Card 内容变量名,对应卡片模板中的变量字段,不填默认
|
|
98
|
-
cardContentVar: z.string().optional().default("
|
|
104
|
+
/** AI Card 内容变量名,对应卡片模板中的变量字段,不填默认 content(与默认增强模板一致) */
|
|
105
|
+
cardContentVar: z.string().optional().default("content"),
|
|
99
106
|
/** 答案专用卡模式:超过 answerActToken 的最终答案投到一张新的静态文本卡,原流式卡定格"思考完成",
|
|
100
107
|
* 规避钉钉流式卡 FINISHED 后仍抖动的官方 bug。默认开启(显式设 false 才关)。 */
|
|
101
108
|
answerCard: z.boolean().optional(),
|
|
102
109
|
/** 答案卡触发阈值(token):最终答案估算 token ≤ 此值时直接在原卡定稿(不另建卡),
|
|
103
|
-
* > 此值才新建答案卡。避免简单任务也多一张卡。默认
|
|
110
|
+
* > 此值才新建答案卡。避免简单任务也多一张卡。默认 500(见 reply-dispatcher)。 */
|
|
104
111
|
answerActToken: z.number().int().positive().optional(),
|
|
105
112
|
/** 答案专用卡模板 ID:不填用内置默认模板。需是钉钉后台已发布、含 content 变量的卡片模板。 */
|
|
106
113
|
answerCardTemplateId: z.string().optional(),
|
|
@@ -28,8 +28,10 @@ export function getActiveCardForConversation(openConversationId: string): AICard
|
|
|
28
28
|
|
|
29
29
|
// ============ 常量 ============
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
const
|
|
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 次/秒)。
|
|
@@ -22,11 +22,43 @@ import {
|
|
|
22
22
|
createAICardForTarget,
|
|
23
23
|
streamAICard,
|
|
24
24
|
finishAICard,
|
|
25
|
+
ANSWER_CARD_TEMPLATE_ID,
|
|
25
26
|
type AICardInstance,
|
|
26
27
|
type AICardTarget,
|
|
27
28
|
} from "./messaging/card.ts";
|
|
28
29
|
import { substituteBotMentions } from "./messaging/mentions.ts";
|
|
29
30
|
|
|
31
|
+
/**
|
|
32
|
+
* message 工具是否用答案卡(默认开;显式 false 才关)。
|
|
33
|
+
* 与会话流式 answerCard 独立。
|
|
34
|
+
*/
|
|
35
|
+
export function isMessageAnswerCardEnabled(config: DingtalkConfig | null | undefined): boolean {
|
|
36
|
+
return (config as any)?.messageAnswerCard !== false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* message 工具正文发送的卡片选项:答案卡模板 + 静态 FINISHED,失败降级普通消息。
|
|
41
|
+
*/
|
|
42
|
+
export function messageToolProactiveCardOptions(
|
|
43
|
+
config: DingtalkConfig,
|
|
44
|
+
): Pick<
|
|
45
|
+
ProactiveSendOptions,
|
|
46
|
+
"useAICard" | "fallbackToNormal" | "cardTemplateId" | "skipInputingWalk"
|
|
47
|
+
> {
|
|
48
|
+
if (!isMessageAnswerCardEnabled(config)) {
|
|
49
|
+
return { useAICard: false, fallbackToNormal: true };
|
|
50
|
+
}
|
|
51
|
+
const tpl =
|
|
52
|
+
(typeof config.answerCardTemplateId === "string" && config.answerCardTemplateId.trim()) ||
|
|
53
|
+
ANSWER_CARD_TEMPLATE_ID;
|
|
54
|
+
return {
|
|
55
|
+
useAICard: true,
|
|
56
|
+
fallbackToNormal: true,
|
|
57
|
+
cardTemplateId: tpl,
|
|
58
|
+
skipInputingWalk: true,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
30
62
|
// ============ 常量 ============
|
|
31
63
|
// 注意:AI Card 相关的类型和函数已移至 ./messaging/card.ts,通过上方 import 引入
|
|
32
64
|
|
|
@@ -55,6 +87,15 @@ export interface ProactiveSendOptions {
|
|
|
55
87
|
log?: any;
|
|
56
88
|
useAICard?: boolean;
|
|
57
89
|
fallbackToNormal?: boolean;
|
|
90
|
+
/**
|
|
91
|
+
* 覆盖 AI Card / 答案卡模板 ID(如 message 工具答案卡)。
|
|
92
|
+
* 不传则 createAICardForTarget 用 config.cardTemplateId / 默认流式模板。
|
|
93
|
+
*/
|
|
94
|
+
cardTemplateId?: string;
|
|
95
|
+
/**
|
|
96
|
+
* 答案静态卡:finish 时跳过 INPUTING 过渡,直接 FINISHED(与 closeStreaming 答案卡一致)。
|
|
97
|
+
*/
|
|
98
|
+
skipInputingWalk?: boolean;
|
|
58
99
|
/**
|
|
59
100
|
* 已在上层 processLocalImages 过则跳过,避免二次处理干扰 MediaIdTrace。
|
|
60
101
|
*/
|
|
@@ -873,13 +914,21 @@ export async function sendTextToDingTalk(params: {
|
|
|
873
914
|
}
|
|
874
915
|
|
|
875
916
|
const msgType: DingTalkMsgType = shouldSendAsMarkdown(text) ? "markdown" : "text";
|
|
876
|
-
|
|
917
|
+
const cardOpts = messageToolProactiveCardOptions(config);
|
|
918
|
+
logMediaIdTrace(
|
|
919
|
+
"sendTextToDingTalk:API前",
|
|
920
|
+
text,
|
|
921
|
+
`msgType=${msgType} messageAnswerCard=${isMessageAnswerCardEnabled(config)} useAICard=${cardOpts.useAICard}`,
|
|
922
|
+
true,
|
|
923
|
+
);
|
|
924
|
+
console.log(
|
|
925
|
+
`[DingTalk][MessageCard] sendTextToDingTalk | messageAnswerCard=${isMessageAnswerCardEnabled(config)} useAICard=${cardOpts.useAICard} tpl=${cardOpts.cardTemplateId || "-"}`,
|
|
926
|
+
);
|
|
877
927
|
|
|
878
928
|
return sendProactive(config, targetParam, text, {
|
|
879
929
|
msgType,
|
|
880
930
|
replyToId,
|
|
881
|
-
|
|
882
|
-
fallbackToNormal: true,
|
|
931
|
+
...cardOpts,
|
|
883
932
|
skipProcessLocalImages: true,
|
|
884
933
|
});
|
|
885
934
|
}
|
|
@@ -992,8 +1041,7 @@ export async function sendMediaToDingTalk(params: {
|
|
|
992
1041
|
await sendProactive(config, targetParam, text.trim(), {
|
|
993
1042
|
msgType: shouldSendAsMarkdown(text) ? "markdown" : "text",
|
|
994
1043
|
replyToId,
|
|
995
|
-
|
|
996
|
-
fallbackToNormal: true,
|
|
1044
|
+
...messageToolProactiveCardOptions(config),
|
|
997
1045
|
});
|
|
998
1046
|
}
|
|
999
1047
|
// 远程图可再尝试 photoURL 直链(部分环境可用)
|
|
@@ -1052,8 +1100,7 @@ export async function sendMediaToDingTalk(params: {
|
|
|
1052
1100
|
await sendProactive(config, targetParam, caption, {
|
|
1053
1101
|
msgType: shouldSendAsMarkdown(caption) ? "markdown" : "text",
|
|
1054
1102
|
replyToId,
|
|
1055
|
-
|
|
1056
|
-
fallbackToNormal: true,
|
|
1103
|
+
...messageToolProactiveCardOptions(config),
|
|
1057
1104
|
});
|
|
1058
1105
|
}
|
|
1059
1106
|
if (isRemoteHttpUrl(mediaUrl)) {
|
|
@@ -1089,8 +1136,7 @@ export async function sendMediaToDingTalk(params: {
|
|
|
1089
1136
|
const result = await sendProactive(config, targetParam, combined, {
|
|
1090
1137
|
msgType: "markdown",
|
|
1091
1138
|
replyToId,
|
|
1092
|
-
|
|
1093
|
-
fallbackToNormal: true,
|
|
1139
|
+
...messageToolProactiveCardOptions(config),
|
|
1094
1140
|
});
|
|
1095
1141
|
return {
|
|
1096
1142
|
...result,
|
|
@@ -1102,8 +1148,7 @@ export async function sendMediaToDingTalk(params: {
|
|
|
1102
1148
|
await sendProactive(config, targetParam, caption, {
|
|
1103
1149
|
msgType: shouldSendAsMarkdown(caption) ? "markdown" : "text",
|
|
1104
1150
|
replyToId,
|
|
1105
|
-
|
|
1106
|
-
fallbackToNormal: true,
|
|
1151
|
+
...messageToolProactiveCardOptions(config),
|
|
1107
1152
|
});
|
|
1108
1153
|
}
|
|
1109
1154
|
const result = await sendProactive(config, targetParam, mediaId, {
|
|
@@ -1130,8 +1175,7 @@ export async function sendMediaToDingTalk(params: {
|
|
|
1130
1175
|
await sendProactive(config, targetParam, caption, {
|
|
1131
1176
|
msgType: shouldSendAsMarkdown(caption) ? "markdown" : "text",
|
|
1132
1177
|
replyToId,
|
|
1133
|
-
|
|
1134
|
-
fallbackToNormal: true,
|
|
1178
|
+
...messageToolProactiveCardOptions(config),
|
|
1135
1179
|
});
|
|
1136
1180
|
}
|
|
1137
1181
|
|
|
@@ -1321,6 +1365,8 @@ async function sendProactiveInternal(
|
|
|
1321
1365
|
msgType = "text",
|
|
1322
1366
|
useAICard = true, // 默认启用 AI Card,让主动发送消息优先使用卡片形式
|
|
1323
1367
|
fallbackToNormal = true, // 默认降级,AI Card 失败时自动回退到普通消息
|
|
1368
|
+
cardTemplateId,
|
|
1369
|
+
skipInputingWalk = false,
|
|
1324
1370
|
log: externalLog,
|
|
1325
1371
|
} = options;
|
|
1326
1372
|
|
|
@@ -1330,9 +1376,25 @@ async function sendProactiveInternal(
|
|
|
1330
1376
|
// 如果启用 AI Card(媒体消息强制跳过)
|
|
1331
1377
|
if (useAICard && !isMediaMessage) {
|
|
1332
1378
|
try {
|
|
1333
|
-
const card = await createAICardForTarget(
|
|
1379
|
+
const card = await createAICardForTarget(
|
|
1380
|
+
config,
|
|
1381
|
+
target,
|
|
1382
|
+
externalLog,
|
|
1383
|
+
cardTemplateId,
|
|
1384
|
+
);
|
|
1334
1385
|
if (card) {
|
|
1335
|
-
|
|
1386
|
+
// 答案静态卡:skipInputingWalk=true 直接 FINISHED;普通卡仍走 INPUTING 再定稿
|
|
1387
|
+
await finishAICard(
|
|
1388
|
+
card,
|
|
1389
|
+
content,
|
|
1390
|
+
config,
|
|
1391
|
+
externalLog,
|
|
1392
|
+
undefined,
|
|
1393
|
+
skipInputingWalk,
|
|
1394
|
+
);
|
|
1395
|
+
console.log(
|
|
1396
|
+
`[DingTalk][MessageCard] AI Card 发送成功 | outTrack=${card.cardInstanceId} tpl=${cardTemplateId || "default"} skipInputing=${skipInputingWalk}`,
|
|
1397
|
+
);
|
|
1336
1398
|
return {
|
|
1337
1399
|
ok: true,
|
|
1338
1400
|
cardInstanceId: card.cardInstanceId,
|
|
@@ -1346,8 +1408,14 @@ async function sendProactiveInternal(
|
|
|
1346
1408
|
usedAICard: false,
|
|
1347
1409
|
};
|
|
1348
1410
|
}
|
|
1411
|
+
console.warn(
|
|
1412
|
+
`[DingTalk][MessageCard] AI Card 创建失败,fallbackToNormal=${fallbackToNormal}`,
|
|
1413
|
+
);
|
|
1349
1414
|
} catch (err: any) {
|
|
1350
1415
|
externalLog?.error?.(`AI Card 发送失败: ${err.message}`);
|
|
1416
|
+
console.warn(
|
|
1417
|
+
`[DingTalk][MessageCard] AI Card 异常: ${err?.message || err},fallbackToNormal=${fallbackToNormal}`,
|
|
1418
|
+
);
|
|
1351
1419
|
if (!fallbackToNormal) {
|
|
1352
1420
|
return { ok: false, error: err.message, usedAICard: false };
|
|
1353
1421
|
}
|