@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.
- package/CHANGELOG.md +36 -0
- package/README.en.md +31 -6
- package/README.md +31 -6
- package/docs/RELEASE_NOTES_V0.7.10.md +40 -0
- package/docs/RELEASE_NOTES_V0.7.2.md +143 -0
- package/docs/RELEASE_NOTES_V0.7.3.md +149 -0
- package/docs/RELEASE_NOTES_V0.7.4.md +206 -0
- package/docs/RELEASE_NOTES_V0.7.5.md +267 -0
- package/docs/RELEASE_NOTES_V0.7.6.md +219 -0
- package/docs/RELEASE_NOTES_V0.7.7.md +122 -0
- package/docs/RELEASE_NOTES_V0.7.8.md +101 -0
- package/docs/RELEASE_NOTES_V0.7.9.md +65 -0
- package/docs/RELEASE_NOTES_V0.8.0.md +53 -0
- package/docs/RELEASE_NOTES_V0.8.1.md +47 -0
- package/docs/RELEASE_NOTES_V0.8.10.md +49 -0
- package/docs/RELEASE_NOTES_V0.8.11.md +51 -0
- package/docs/RELEASE_NOTES_V0.8.12.md +63 -0
- package/docs/RELEASE_NOTES_V0.8.13-beta.0.md +69 -0
- package/docs/RELEASE_NOTES_V0.8.13.md +62 -0
- package/docs/RELEASE_NOTES_V0.8.2.md +55 -0
- package/docs/RELEASE_NOTES_V0.8.3.md +63 -0
- package/docs/RELEASE_NOTES_V0.8.4.md +45 -0
- package/docs/RELEASE_NOTES_V0.8.7.md +49 -0
- package/docs/RELEASE_NOTES_V0.8.8.md +63 -0
- package/docs/RELEASE_NOTES_V0.8.9.md +81 -0
- package/docs/RELEASE_NOTES_v0.7.0.md +142 -0
- package/docs/RELEASE_NOTES_v0.7.1.md +74 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +13 -2
- package/src/channel.ts +18 -6
- package/src/config/schema.ts +2 -2
- package/src/core/connection.ts +9 -6
- package/src/core/message-handler.ts +30 -10
- package/src/reply-dispatcher.ts +4 -3
- package/src/services/media/file.ts +7 -2
- package/src/services/media.ts +19 -12
- package/src/services/messaging/card.ts +1 -2
- package/src/services/messaging.ts +29 -16
- package/src/utils/http-client.ts +2 -1
- package/docs/images/dingtalk.svg +0 -1
- package/docs/images/image-1.png +0 -0
- package/docs/images/image-2.png +0 -0
- package/docs/images/image-3.png +0 -0
- package/docs/images/image-4.png +0 -0
- package/docs/images/image-5.png +0 -0
- package/docs/images/image-6.png +0 -0
- package/docs/images/image-7.png +0 -0
- package/install-beta.sh +0 -438
- package/install-npm.sh +0 -167
package/src/services/media.ts
CHANGED
|
@@ -607,7 +607,12 @@ export interface FileInfo {
|
|
|
607
607
|
}
|
|
608
608
|
|
|
609
609
|
/**
|
|
610
|
-
*
|
|
610
|
+
* 提取文件标记,上传文件到钉钉,并发送独立的文件消息(webhook 或 proactive API)。
|
|
611
|
+
*
|
|
612
|
+
* 注意:此函数既做「上传」也做「发送」,是完整版的文件处理流程。
|
|
613
|
+
* 与 media/file.ts 中的 uploadAndReplaceFileMarkers 不同,后者只做上传+文本替换。
|
|
614
|
+
*
|
|
615
|
+
* 调用方:messaging.ts(直接 import media.ts)
|
|
611
616
|
*/
|
|
612
617
|
export async function processFileMarkers(
|
|
613
618
|
content: string,
|
|
@@ -672,11 +677,11 @@ export async function processFileMarkers(
|
|
|
672
677
|
continue;
|
|
673
678
|
}
|
|
674
679
|
|
|
675
|
-
//
|
|
680
|
+
// 发送文件消息(钉钉 API 统一要求带 @ 前缀的 mediaId)
|
|
676
681
|
if (useProactiveApi && target) {
|
|
677
|
-
await sendFileProactive(config, target, fileInfo, uploadResult.
|
|
682
|
+
await sendFileProactive(config, target, fileInfo, uploadResult.mediaId, log);
|
|
678
683
|
} else {
|
|
679
|
-
await sendFileMessage(config, sessionWebhook, fileInfo, uploadResult.
|
|
684
|
+
await sendFileMessage(config, sessionWebhook, fileInfo, uploadResult.mediaId, log);
|
|
680
685
|
}
|
|
681
686
|
statusMessages.push(`✅ 文件已发送: ${fileName}`);
|
|
682
687
|
log?.info?.(`${logPrefix} 文件处理完成: ${fileName}`);
|
|
@@ -771,7 +776,7 @@ export async function sendVideoProactive(
|
|
|
771
776
|
};
|
|
772
777
|
|
|
773
778
|
const body: any = {
|
|
774
|
-
robotCode: config.clientId,
|
|
779
|
+
robotCode: String(config.clientId),
|
|
775
780
|
msgKey: 'sampleVideo',
|
|
776
781
|
msgParam: JSON.stringify(msgParam),
|
|
777
782
|
};
|
|
@@ -873,7 +878,7 @@ export async function sendAudioProactive(
|
|
|
873
878
|
};
|
|
874
879
|
|
|
875
880
|
const body: any = {
|
|
876
|
-
robotCode: config.clientId,
|
|
881
|
+
robotCode: String(config.clientId),
|
|
877
882
|
msgKey: 'sampleAudio',
|
|
878
883
|
msgParam: JSON.stringify(msgParam),
|
|
879
884
|
};
|
|
@@ -942,6 +947,7 @@ async function sendFileMessage(
|
|
|
942
947
|
}
|
|
943
948
|
} catch (err: any) {
|
|
944
949
|
log?.error?.(`发送文件消息异常: ${fileInfo.fileName}, 错误: ${err.message}`);
|
|
950
|
+
throw err;
|
|
945
951
|
}
|
|
946
952
|
}
|
|
947
953
|
|
|
@@ -960,14 +966,16 @@ export async function sendFileProactive(
|
|
|
960
966
|
const { DINGTALK_API } = await import('../utils/index.ts');
|
|
961
967
|
|
|
962
968
|
// 钉钉普通消息 API 的文件消息格式
|
|
969
|
+
const resolvedFileName = fileInfo.fileName || path.basename(fileInfo.path);
|
|
970
|
+
const resolvedFileType = fileInfo.fileType || resolvedFileName.split('.').pop() || 'file';
|
|
963
971
|
const msgParam = {
|
|
964
972
|
mediaId: mediaId,
|
|
965
|
-
fileName:
|
|
966
|
-
fileType:
|
|
973
|
+
fileName: resolvedFileName,
|
|
974
|
+
fileType: resolvedFileType,
|
|
967
975
|
};
|
|
968
976
|
|
|
969
977
|
const body: any = {
|
|
970
|
-
robotCode: config.clientId,
|
|
978
|
+
robotCode: String(config.clientId),
|
|
971
979
|
msgKey: 'sampleFile',
|
|
972
980
|
msgParam: JSON.stringify(msgParam),
|
|
973
981
|
};
|
|
@@ -994,6 +1002,7 @@ export async function sendFileProactive(
|
|
|
994
1002
|
}
|
|
995
1003
|
} catch (err: any) {
|
|
996
1004
|
log?.error?.(`File[Proactive] 发送文件消息失败: ${fileInfo.fileName}, 错误: ${err.message}`);
|
|
1005
|
+
throw err;
|
|
997
1006
|
}
|
|
998
1007
|
}
|
|
999
1008
|
|
|
@@ -1109,9 +1118,7 @@ export async function processRawMediaPaths(
|
|
|
1109
1118
|
};
|
|
1110
1119
|
|
|
1111
1120
|
if (target) {
|
|
1112
|
-
|
|
1113
|
-
// 文件消息使用媒体文件ID(cleanMediaId)通过主动API发送
|
|
1114
|
-
await sendFileProactive(config, target, fileInfo, uploadResult.cleanMediaId, log);
|
|
1121
|
+
await sendFileProactive(config, target, fileInfo, uploadResult.mediaId, log);
|
|
1115
1122
|
}
|
|
1116
1123
|
statusMessages.push(`✅ 文件已发送: ${fileName}`);
|
|
1117
1124
|
}
|
|
@@ -281,7 +281,6 @@ export async function streamAICard(
|
|
|
281
281
|
`[DingTalk][AICard] streaming 响应:status=${streamResp.status}`,
|
|
282
282
|
);
|
|
283
283
|
} catch (err: any) {
|
|
284
|
-
log?.error?.(`[DingTalk][AICard] streaming 更新失败:${err.message}`);
|
|
285
284
|
throw err;
|
|
286
285
|
}
|
|
287
286
|
}
|
|
@@ -304,7 +303,7 @@ export async function finishAICard(
|
|
|
304
303
|
`[DingTalk][AICard] 开始 finish,最终内容长度=${fixedContent.length}`,
|
|
305
304
|
);
|
|
306
305
|
|
|
307
|
-
await streamAICard(card, fixedContent, true, log);
|
|
306
|
+
await streamAICard(card, fixedContent, true, config, log);
|
|
308
307
|
|
|
309
308
|
const body = {
|
|
310
309
|
outTrackId: card.cardInstanceId,
|
|
@@ -229,7 +229,7 @@ export async function sendNormalToUser(
|
|
|
229
229
|
try {
|
|
230
230
|
const token = await getAccessToken(config);
|
|
231
231
|
const body = {
|
|
232
|
-
robotCode: config.clientId,
|
|
232
|
+
robotCode: String(config.clientId),
|
|
233
233
|
userIds: userIdArray,
|
|
234
234
|
msgKey: payload.msgKey,
|
|
235
235
|
msgParam: JSON.stringify(payload.msgParam),
|
|
@@ -306,7 +306,7 @@ export async function sendNormalToGroup(
|
|
|
306
306
|
try {
|
|
307
307
|
const token = await getAccessToken(config);
|
|
308
308
|
const body = {
|
|
309
|
-
robotCode: config.clientId,
|
|
309
|
+
robotCode: String(config.clientId),
|
|
310
310
|
openConversationId,
|
|
311
311
|
msgKey: payload.msgKey,
|
|
312
312
|
msgParam: JSON.stringify(payload.msgParam),
|
|
@@ -439,7 +439,7 @@ export async function sendAICardInternal(
|
|
|
439
439
|
}
|
|
440
440
|
|
|
441
441
|
// 7. 使用 finishAICard 设置内容
|
|
442
|
-
await finishAICard(card, processedContent, log);
|
|
442
|
+
await finishAICard(card, processedContent, config, log);
|
|
443
443
|
|
|
444
444
|
log?.info?.(
|
|
445
445
|
`AI Card 发送成功: ${targetDesc}, cardInstanceId=${card.cardInstanceId}`,
|
|
@@ -552,11 +552,17 @@ export async function sendTextToDingTalk(params: {
|
|
|
552
552
|
return { ok: false, error: "Invalid target parameter", usedAICard: false };
|
|
553
553
|
}
|
|
554
554
|
|
|
555
|
-
//
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
555
|
+
// 判断目标是用户还是群(支持 group:/user: 前缀,与 gateway-methods.ts 逻辑保持一致)
|
|
556
|
+
let targetParam: { type: "user"; userId: string } | { type: "group"; openConversationId: string };
|
|
557
|
+
if (target.startsWith("group:")) {
|
|
558
|
+
targetParam = { type: "group", openConversationId: target.slice(6) };
|
|
559
|
+
} else if (target.startsWith("user:")) {
|
|
560
|
+
targetParam = { type: "user", userId: target.slice(5) };
|
|
561
|
+
} else if (target.startsWith("cid")) {
|
|
562
|
+
targetParam = { type: "group", openConversationId: target };
|
|
563
|
+
} else {
|
|
564
|
+
targetParam = { type: "user", userId: target };
|
|
565
|
+
}
|
|
560
566
|
|
|
561
567
|
return sendProactive(config, targetParam, text, {
|
|
562
568
|
msgType: "text",
|
|
@@ -595,11 +601,17 @@ export async function sendMediaToDingTalk(params: {
|
|
|
595
601
|
return { ok: false, error: "Invalid target parameter", usedAICard: false };
|
|
596
602
|
}
|
|
597
603
|
|
|
598
|
-
//
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
604
|
+
// 判断目标是用户还是群(支持 group:/user: 前缀,与 gateway-methods.ts 逻辑保持一致)
|
|
605
|
+
let targetParam: { type: "user"; userId: string } | { type: "group"; openConversationId: string };
|
|
606
|
+
if (target.startsWith("group:")) {
|
|
607
|
+
targetParam = { type: "group", openConversationId: target.slice(6) };
|
|
608
|
+
} else if (target.startsWith("user:")) {
|
|
609
|
+
targetParam = { type: "user", userId: target.slice(5) };
|
|
610
|
+
} else if (target.startsWith("cid")) {
|
|
611
|
+
targetParam = { type: "group", openConversationId: target };
|
|
612
|
+
} else {
|
|
613
|
+
targetParam = { type: "user", userId: target };
|
|
614
|
+
}
|
|
603
615
|
|
|
604
616
|
log.info("参数解析完成,mediaUrl:", mediaUrl, "type:", typeof mediaUrl);
|
|
605
617
|
|
|
@@ -755,8 +767,9 @@ export async function sendMediaToDingTalk(params: {
|
|
|
755
767
|
// 获取文件扩展名作为 fileType
|
|
756
768
|
const fileType = ext || "file";
|
|
757
769
|
|
|
758
|
-
//
|
|
770
|
+
// 构建文件信息(path 字段用于 sendFileProactive 中 fileName 的 fallback)
|
|
759
771
|
const fileInfo = {
|
|
772
|
+
path: mediaUrl,
|
|
760
773
|
fileName: fileName,
|
|
761
774
|
fileType: fileType,
|
|
762
775
|
};
|
|
@@ -892,7 +905,7 @@ async function sendProactiveInternal(
|
|
|
892
905
|
try {
|
|
893
906
|
const card = await createAICardForTarget(config, target, externalLog);
|
|
894
907
|
if (card) {
|
|
895
|
-
await finishAICard(card, content, externalLog);
|
|
908
|
+
await finishAICard(card, content, config, externalLog);
|
|
896
909
|
return {
|
|
897
910
|
ok: true,
|
|
898
911
|
cardInstanceId: card.cardInstanceId,
|
|
@@ -944,7 +957,7 @@ async function sendProactiveInternal(
|
|
|
944
957
|
}
|
|
945
958
|
|
|
946
959
|
const body: any = {
|
|
947
|
-
robotCode: config.clientId,
|
|
960
|
+
robotCode: String(config.clientId),
|
|
948
961
|
msgKey: payload.msgKey,
|
|
949
962
|
msgParam: JSON.stringify(payload.msgParam),
|
|
950
963
|
};
|
package/src/utils/http-client.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* HTTP 客户端配置模块
|
|
3
3
|
*
|
|
4
4
|
* 提供统一的 axios 实例,用于钉钉 API 请求。
|
|
5
|
+
* 所有钉钉 API 调用必须使用此模块导出的实例,禁止直接使用 axios 或 fetch。
|
|
5
6
|
*
|
|
6
7
|
* 使用方式:
|
|
7
8
|
* ```typescript
|
|
@@ -13,7 +14,7 @@
|
|
|
13
14
|
|
|
14
15
|
import axios, { type AxiosInstance } from 'axios';
|
|
15
16
|
|
|
16
|
-
/**
|
|
17
|
+
/** 钉钉新版 API 专用 HTTP 客户端(30 秒超时,用于 api.dingtalk.com) */
|
|
17
18
|
export const dingtalkHttp: AxiosInstance = axios.create({
|
|
18
19
|
timeout: 30000,
|
|
19
20
|
headers: {
|
package/docs/images/dingtalk.svg
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="none" viewBox="0 0 48 48"><path fill="#171A1D" d="M37.05 22.783c-6.758-5.216-14.378-12.128-22.73-19.538-.655-.585-1.242-.354-1.536.42-1.88 4.973-.058 9.386 2.889 11.932s7.368 4.912 10.058 6.155c.105.049.013.203-.093.163-4.953-2.182-8.397-3.765-13.07-7.368-.497-.388-1.01-.242-1.07.521-.384 4.748 2.657 8.483 6.058 9.745 2.1.781 4.398 1.212 6.53 1.474.109.015.084.178-.027.178-2.747.01-6.058-.654-8.935-1.751-.606-.233-.818.25-.722.633.491 2.008 2.974 5.076 6.926 5.73a12 12 0 0 0 2.228.115c.164 0 .208.089.154.217q-2.685 4.6-2.803 4.797c-.091.152-.036.275.156.275h3.543c.164 0 .264.106.18.246l-4.958 8.196c-.191.328.035.565.395.301s15.212-11.133 15.636-11.448c.195-.142.148-.327-.124-.327h-3.18c-.206 0-.252-.14-.111-.28.14-.141 3.602-3.594 4.837-4.888 1.283-1.35 1.938-3.825-.231-5.498"/></svg>
|
package/docs/images/image-1.png
DELETED
|
Binary file
|
package/docs/images/image-2.png
DELETED
|
Binary file
|
package/docs/images/image-3.png
DELETED
|
Binary file
|
package/docs/images/image-4.png
DELETED
|
Binary file
|
package/docs/images/image-5.png
DELETED
|
Binary file
|
package/docs/images/image-6.png
DELETED
|
Binary file
|
package/docs/images/image-7.png
DELETED
|
Binary file
|