@sunnoy/wecom 2.2.0 → 2.3.0
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/README.md +2 -1
- package/index.js +13 -2
- package/openclaw.plugin.json +137 -1
- package/package.json +2 -3
- package/skills/wecom-contact-lookup/SKILL.md +167 -0
- package/skills/wecom-doc-manager/SKILL.md +106 -0
- package/skills/wecom-doc-manager/references/api-create-doc.md +56 -0
- package/skills/wecom-doc-manager/references/api-edit-doc-content.md +68 -0
- package/skills/wecom-doc-manager/references/api-export-document.md +88 -0
- package/skills/wecom-edit-todo/SKILL.md +254 -0
- package/skills/wecom-get-todo-detail/SKILL.md +148 -0
- package/skills/wecom-get-todo-list/SKILL.md +132 -0
- package/skills/wecom-meeting-create/SKILL.md +163 -0
- package/skills/wecom-meeting-create/references/example-full.md +30 -0
- package/skills/wecom-meeting-create/references/example-reminder.md +46 -0
- package/skills/wecom-meeting-create/references/example-security.md +22 -0
- package/skills/wecom-meeting-manage/SKILL.md +141 -0
- package/skills/wecom-meeting-query/SKILL.md +335 -0
- package/skills/wecom-preflight/SKILL.md +103 -0
- package/skills/wecom-schedule/SKILL.md +164 -0
- package/skills/wecom-schedule/references/api-check-availability.md +56 -0
- package/skills/wecom-schedule/references/api-create-schedule.md +38 -0
- package/skills/wecom-schedule/references/api-get-schedule-detail.md +81 -0
- package/skills/wecom-schedule/references/api-update-schedule.md +30 -0
- package/skills/wecom-schedule/references/ref-reminders.md +24 -0
- package/skills/wecom-smartsheet-data/SKILL.md +76 -0
- package/skills/wecom-smartsheet-data/references/api-get-records.md +61 -0
- package/skills/wecom-smartsheet-data/references/cell-value-formats.md +120 -0
- package/skills/wecom-smartsheet-schema/SKILL.md +96 -0
- package/skills/wecom-smartsheet-schema/references/field-types.md +43 -0
- package/wecom/accounts.js +2 -0
- package/wecom/callback-inbound.js +9 -5
- package/wecom/channel-plugin.js +65 -1
- package/wecom/constants.js +18 -7
- package/wecom/image-studio-tool.js +764 -0
- package/wecom/mcp-tool.js +660 -0
- package/wecom/parent-resolver.js +26 -0
- package/wecom/plugin-config.js +484 -0
- package/wecom/target.js +3 -2
- package/wecom/welcome-messages-file.js +155 -0
- package/wecom/workspace-template.js +40 -4
- package/wecom/ws-monitor.js +186 -12
- package/skills/wecom-doc/SKILL.md +0 -363
- package/skills/wecom-doc/references/doc-api.md +0 -224
package/wecom/channel-plugin.js
CHANGED
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
} from "./constants.js";
|
|
37
37
|
import { uploadAndSendMedia } from "./media-uploader.js";
|
|
38
38
|
import { getExtendedMediaLocalRoots } from "./openclaw-compat.js";
|
|
39
|
+
import { extractParentAgentId } from "./parent-resolver.js";
|
|
39
40
|
import { sendWsMessage, startWsMonitor } from "./ws-monitor.js";
|
|
40
41
|
import { getWsClient } from "./ws-state.js";
|
|
41
42
|
|
|
@@ -262,6 +263,7 @@ export const wecomChannelPlugin = {
|
|
|
262
263
|
websocketUrl: { type: "string" },
|
|
263
264
|
sendThinkingMessage: { type: "boolean" },
|
|
264
265
|
welcomeMessage: { type: "string" },
|
|
266
|
+
welcomeMessagesFile: { type: "string" },
|
|
265
267
|
dmPolicy: { enum: ["pairing", "allowlist", "open", "disabled"] },
|
|
266
268
|
allowFrom: { type: "array", items: { type: "string" } },
|
|
267
269
|
groupPolicy: { enum: ["open", "allowlist", "disabled"] },
|
|
@@ -291,6 +293,10 @@ export const wecomChannelPlugin = {
|
|
|
291
293
|
secret: { label: "Secret", sensitive: true },
|
|
292
294
|
websocketUrl: { label: "WebSocket URL", placeholder: DEFAULT_WS_URL },
|
|
293
295
|
welcomeMessage: { label: "Welcome Message" },
|
|
296
|
+
welcomeMessagesFile: {
|
|
297
|
+
label: "Welcome Messages File",
|
|
298
|
+
placeholder: "welcome-messages.json",
|
|
299
|
+
},
|
|
294
300
|
"agent.corpSecret": { sensitive: true, label: "Application Secret" },
|
|
295
301
|
"agent.replyFormat": { label: "Reply Format", placeholder: "text" },
|
|
296
302
|
"agent.callback.token": { label: "Callback Token" },
|
|
@@ -404,6 +410,7 @@ export const wecomChannelPlugin = {
|
|
|
404
410
|
try {
|
|
405
411
|
if (!target.toParty && !target.toTag) {
|
|
406
412
|
const wsTarget = target.chatId || target.toUser || to;
|
|
413
|
+
logger.debug(`[wecom] sendText: trying WS accountId=${resolvedAccountId} target=${wsTarget}`);
|
|
407
414
|
return await sendWsMessage({
|
|
408
415
|
to: wsTarget,
|
|
409
416
|
content: text,
|
|
@@ -411,9 +418,17 @@ export const wecomChannelPlugin = {
|
|
|
411
418
|
});
|
|
412
419
|
}
|
|
413
420
|
} catch (error) {
|
|
414
|
-
logger.warn(`[wecom] WS sendText failed, falling back
|
|
421
|
+
logger.warn(`[wecom] WS sendText failed (accountId=${resolvedAccountId}), falling back: ${error.message}`);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Webhook fallback for accounts without Agent API (e.g. WS bot mode)
|
|
425
|
+
const account = resolveAccount(cfg, resolvedAccountId);
|
|
426
|
+
if (!account?.agentCredentials && account?.config?.webhooks?.default) {
|
|
427
|
+
logger.debug(`[wecom] sendText: Agent API unavailable, using webhook fallback accountId=${resolvedAccountId}`);
|
|
428
|
+
return sendViaWebhook({ cfg, accountId: resolvedAccountId, webhookName: "default", text });
|
|
415
429
|
}
|
|
416
430
|
|
|
431
|
+
logger.debug(`[wecom] sendText: trying Agent API accountId=${resolvedAccountId}`);
|
|
417
432
|
return sendViaAgent({
|
|
418
433
|
cfg,
|
|
419
434
|
accountId: resolvedAccountId,
|
|
@@ -631,6 +646,55 @@ export const wecomChannelPlugin = {
|
|
|
631
646
|
};
|
|
632
647
|
},
|
|
633
648
|
},
|
|
649
|
+
hooks: {
|
|
650
|
+
/**
|
|
651
|
+
* Ensure announce delivery uses a valid WeCom channel accountId.
|
|
652
|
+
*
|
|
653
|
+
* When a dynamic agent (e.g. wecom-yoyo-dm-xxx) spawns a sub-agent,
|
|
654
|
+
* the announce delivery may reference the dynamic agent ID as accountId.
|
|
655
|
+
* This hook resolves it to the actual WeCom account (e.g. yoyo) so the
|
|
656
|
+
* outbound sendText can find valid WS/Agent API credentials.
|
|
657
|
+
*/
|
|
658
|
+
subagent_delivery_target: async (event, ctx) => {
|
|
659
|
+
const origin = event.requesterOrigin;
|
|
660
|
+
if (!origin?.channel || origin.channel !== CHANNEL_ID) return;
|
|
661
|
+
|
|
662
|
+
const cfg = ctx?.cfg ?? getOpenclawConfig();
|
|
663
|
+
|
|
664
|
+
// Check whether current accountId already resolves to a valid account
|
|
665
|
+
const currentAccount = resolveAccount(cfg, origin.accountId);
|
|
666
|
+
if (currentAccount?.enabled) return;
|
|
667
|
+
|
|
668
|
+
// Try to extract the base account from a dynamic agent ID
|
|
669
|
+
const baseId = extractParentAgentId(origin.accountId);
|
|
670
|
+
if (baseId && baseId !== origin.accountId) {
|
|
671
|
+
const baseAccount = resolveAccount(cfg, baseId);
|
|
672
|
+
if (baseAccount?.enabled) {
|
|
673
|
+
logger.info(`[wecom] subagent_delivery_target: ${origin.accountId} → ${baseId}`);
|
|
674
|
+
return { origin: { ...origin, accountId: baseId } };
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
// Fallback to default account
|
|
679
|
+
const defaultId = resolveDefaultAccountId(cfg);
|
|
680
|
+
if (defaultId && defaultId !== origin.accountId) {
|
|
681
|
+
logger.info(`[wecom] subagent_delivery_target: fallback → ${defaultId}`);
|
|
682
|
+
return { origin: { ...origin, accountId: defaultId } };
|
|
683
|
+
}
|
|
684
|
+
},
|
|
685
|
+
|
|
686
|
+
subagent_spawned: async (event) => {
|
|
687
|
+
logger.info(
|
|
688
|
+
`[wecom] subagent spawned: child=${event.childSessionKey} requester=${event.requesterSessionKey}`,
|
|
689
|
+
);
|
|
690
|
+
},
|
|
691
|
+
|
|
692
|
+
subagent_ended: async (event) => {
|
|
693
|
+
logger.info(
|
|
694
|
+
`[wecom] subagent ended: target=${event.targetSessionKey} reason=${event.reason} outcome=${event.outcome}`,
|
|
695
|
+
);
|
|
696
|
+
},
|
|
697
|
+
},
|
|
634
698
|
};
|
|
635
699
|
|
|
636
700
|
export const wecomChannelPluginTesting = {};
|
package/wecom/constants.js
CHANGED
|
@@ -26,6 +26,10 @@ export const REQID_FLUSH_DEBOUNCE_MS = 1_000;
|
|
|
26
26
|
export const PENDING_REPLY_TTL_MS = 5 * 60 * 1000;
|
|
27
27
|
export const PENDING_REPLY_MAX_SIZE = 50;
|
|
28
28
|
|
|
29
|
+
// WeCom stream messages expire ~6 minutes after creation. Rotate the stream
|
|
30
|
+
// before hitting that hard limit so the user never sees a dead stream.
|
|
31
|
+
export const STREAM_MAX_LIFETIME_MS = 5 * 60 * 1000;
|
|
32
|
+
|
|
29
33
|
export const IMAGE_MAX_BYTES = 10 * 1024 * 1024;
|
|
30
34
|
export const VIDEO_MAX_BYTES = 10 * 1024 * 1024;
|
|
31
35
|
export const VOICE_MAX_BYTES = 2 * 1024 * 1024;
|
|
@@ -43,7 +47,8 @@ export const DEFAULT_WELCOME_MESSAGES = [
|
|
|
43
47
|
"/compact 压缩对话",
|
|
44
48
|
"/help 帮助",
|
|
45
49
|
"/status 查看状态",
|
|
46
|
-
"
|
|
50
|
+
"你可以让我生成和编辑图片了",
|
|
51
|
+
"你可以用语音跟我对话",
|
|
47
52
|
].join("\n"),
|
|
48
53
|
[
|
|
49
54
|
"终于唤醒我啦,我已经准备就绪!😄",
|
|
@@ -53,7 +58,8 @@ export const DEFAULT_WELCOME_MESSAGES = [
|
|
|
53
58
|
"/compact 压缩对话",
|
|
54
59
|
"/help 帮助",
|
|
55
60
|
"/status 查看状态",
|
|
56
|
-
"
|
|
61
|
+
"你可以让我生成和编辑图片了",
|
|
62
|
+
"你可以用语音跟我对话",
|
|
57
63
|
].join("\n"),
|
|
58
64
|
[
|
|
59
65
|
"欢迎回来,准备开始今天的工作吧!✨",
|
|
@@ -63,7 +69,8 @@ export const DEFAULT_WELCOME_MESSAGES = [
|
|
|
63
69
|
"/compact 压缩对话",
|
|
64
70
|
"/help 帮助",
|
|
65
71
|
"/status 查看状态",
|
|
66
|
-
"
|
|
72
|
+
"你可以让我生成和编辑图片了",
|
|
73
|
+
"你可以用语音跟我对话",
|
|
67
74
|
].join("\n"),
|
|
68
75
|
[
|
|
69
76
|
"嗨,我已经在线!🤖",
|
|
@@ -73,7 +80,8 @@ export const DEFAULT_WELCOME_MESSAGES = [
|
|
|
73
80
|
"/compact 压缩对话",
|
|
74
81
|
"/help 帮助",
|
|
75
82
|
"/status 查看状态",
|
|
76
|
-
"
|
|
83
|
+
"你可以让我生成和编辑图片了",
|
|
84
|
+
"你可以用语音跟我对话",
|
|
77
85
|
].join("\n"),
|
|
78
86
|
[
|
|
79
87
|
"今天也一起高效开工吧!🚀",
|
|
@@ -83,7 +91,8 @@ export const DEFAULT_WELCOME_MESSAGES = [
|
|
|
83
91
|
"/compact 压缩对话",
|
|
84
92
|
"/help 帮助",
|
|
85
93
|
"/status 查看状态",
|
|
86
|
-
"
|
|
94
|
+
"你可以让我生成和编辑图片了",
|
|
95
|
+
"你可以用语音跟我对话",
|
|
87
96
|
].join("\n"),
|
|
88
97
|
[
|
|
89
98
|
"叮咚,你的数字助手已就位!🎉",
|
|
@@ -93,7 +102,8 @@ export const DEFAULT_WELCOME_MESSAGES = [
|
|
|
93
102
|
"/compact 压缩对话",
|
|
94
103
|
"/help 帮助",
|
|
95
104
|
"/status 查看状态",
|
|
96
|
-
"
|
|
105
|
+
"你可以让我生成和编辑图片了",
|
|
106
|
+
"你可以用语音跟我对话",
|
|
97
107
|
].join("\n"),
|
|
98
108
|
[
|
|
99
109
|
"灵感加载完成,随时可以开聊!💡",
|
|
@@ -103,7 +113,8 @@ export const DEFAULT_WELCOME_MESSAGES = [
|
|
|
103
113
|
"/compact 压缩对话",
|
|
104
114
|
"/help 帮助",
|
|
105
115
|
"/status 查看状态",
|
|
106
|
-
"
|
|
116
|
+
"你可以让我生成和编辑图片了",
|
|
117
|
+
"你可以用语音跟我对话",
|
|
107
118
|
].join("\n"),
|
|
108
119
|
];
|
|
109
120
|
export const DEFAULT_WELCOME_MESSAGE = DEFAULT_WELCOME_MESSAGES[0];
|