@dingxiang-me/openclaw-wechat 1.4.1 → 1.7.2
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 +119 -0
- package/README.en.md +89 -12
- package/README.md +103 -15
- package/docs/channels/wecom.md +28 -3
- package/openclaw.plugin.json +467 -10
- package/package.json +13 -2
- package/src/core/agent-routing.js +6 -0
- package/src/core.js +564 -35
- package/src/wecom/account-config-core.js +28 -8
- package/src/wecom/account-config.js +55 -0
- package/src/wecom/account-diagnostics.js +121 -0
- package/src/wecom/account-paths.js +39 -0
- package/src/wecom/agent-inbound-dispatch.js +9 -0
- package/src/wecom/agent-inbound-guards.js +24 -4
- package/src/wecom/agent-inbound-processor.js +27 -0
- package/src/wecom/agent-webhook-handler.js +11 -0
- package/src/wecom/bot-context.js +2 -1
- package/src/wecom/bot-dispatch-fallback.js +2 -1
- package/src/wecom/bot-inbound-content.js +73 -3
- package/src/wecom/bot-inbound-dispatch-runtime.js +2 -1
- package/src/wecom/bot-inbound-executor-helpers.js +56 -5
- package/src/wecom/bot-inbound-executor.js +19 -0
- package/src/wecom/bot-inbound-guards.js +36 -4
- package/src/wecom/bot-runtime-context.js +5 -3
- package/src/wecom/bot-webhook-dispatch.js +45 -12
- package/src/wecom/bot-webhook-handler.js +45 -13
- package/src/wecom/command-handlers.js +26 -0
- package/src/wecom/command-status-text.js +76 -7
- package/src/wecom/observability-metrics.js +133 -0
- package/src/wecom/outbound-agent-push.js +2 -1
- package/src/wecom/outbound-bot-card.js +103 -0
- package/src/wecom/outbound-delivery.js +92 -7
- package/src/wecom/outbound-response-delivery.js +10 -6
- package/src/wecom/outbound-webhook-delivery.js +42 -1
- package/src/wecom/plugin-account-policy-services.js +19 -0
- package/src/wecom/plugin-base-services.js +13 -0
- package/src/wecom/plugin-constants.js +1 -1
- package/src/wecom/plugin-delivery-inbound-services.js +8 -0
- package/src/wecom/plugin-processing-deps.js +4 -0
- package/src/wecom/plugin-route-runtime-deps.js +5 -0
- package/src/wecom/plugin-services.js +7 -0
- package/src/wecom/policy-resolvers.js +82 -5
- package/src/wecom/register-runtime.js +31 -2
- package/src/wecom/route-registration.js +173 -41
- package/src/wecom/runtime-utils.js +7 -2
- package/src/wecom/webhook-adapter.js +61 -0
- package/src/wecom/webhook-bot.js +26 -0
|
@@ -8,12 +8,16 @@ import { createWecomResponseUrlSender } from "./outbound-response-url.js";
|
|
|
8
8
|
import { createWecomWebhookBotDeliverer } from "./outbound-webhook-delivery.js";
|
|
9
9
|
import { createWecomWebhookBotMediaSender } from "./outbound-webhook-media.js";
|
|
10
10
|
import { buildActiveStreamMsgItems } from "./outbound-stream-msg-item.js";
|
|
11
|
+
import { buildWecomBotCardPayload } from "./outbound-bot-card.js";
|
|
11
12
|
import {
|
|
12
13
|
resolveWebhookBotSendUrl,
|
|
13
14
|
webhookSendFileBuffer,
|
|
14
15
|
webhookSendImage,
|
|
16
|
+
webhookSendMarkdown,
|
|
17
|
+
webhookSendTemplateCard,
|
|
15
18
|
webhookSendText,
|
|
16
19
|
} from "./webhook-bot.js";
|
|
20
|
+
import { stat } from "node:fs/promises";
|
|
17
21
|
|
|
18
22
|
function assertFunction(name, fn) {
|
|
19
23
|
if (typeof fn !== "function") {
|
|
@@ -27,6 +31,7 @@ export function createWecomBotReplyDeliverer({
|
|
|
27
31
|
resolveWecomWebhookBotDeliveryPolicy,
|
|
28
32
|
resolveWecomObservabilityPolicy,
|
|
29
33
|
resolveWecomBotProxyConfig,
|
|
34
|
+
resolveWecomBotConfig,
|
|
30
35
|
buildWecomBotSessionId,
|
|
31
36
|
upsertBotResponseUrlCache,
|
|
32
37
|
getBotResponseUrlCache,
|
|
@@ -43,6 +48,10 @@ export function createWecomBotReplyDeliverer({
|
|
|
43
48
|
webhookSendTextFn = webhookSendText,
|
|
44
49
|
webhookSendImageFn = webhookSendImage,
|
|
45
50
|
webhookSendFileBufferFn = webhookSendFileBuffer,
|
|
51
|
+
extractWorkspacePathsFromText = () => [],
|
|
52
|
+
resolveWorkspacePathToHost = () => "",
|
|
53
|
+
recordDeliveryMetric = () => {},
|
|
54
|
+
statImpl = stat,
|
|
46
55
|
fetchImpl = fetch,
|
|
47
56
|
} = {}) {
|
|
48
57
|
assertFunction("attachWecomProxyDispatcher", attachWecomProxyDispatcher);
|
|
@@ -50,6 +59,7 @@ export function createWecomBotReplyDeliverer({
|
|
|
50
59
|
assertFunction("resolveWecomWebhookBotDeliveryPolicy", resolveWecomWebhookBotDeliveryPolicy);
|
|
51
60
|
assertFunction("resolveWecomObservabilityPolicy", resolveWecomObservabilityPolicy);
|
|
52
61
|
assertFunction("resolveWecomBotProxyConfig", resolveWecomBotProxyConfig);
|
|
62
|
+
assertFunction("resolveWecomBotConfig", resolveWecomBotConfig);
|
|
53
63
|
assertFunction("buildWecomBotSessionId", buildWecomBotSessionId);
|
|
54
64
|
assertFunction("upsertBotResponseUrlCache", upsertBotResponseUrlCache);
|
|
55
65
|
assertFunction("getBotResponseUrlCache", getBotResponseUrlCache);
|
|
@@ -66,6 +76,43 @@ export function createWecomBotReplyDeliverer({
|
|
|
66
76
|
assertFunction("webhookSendTextFn", webhookSendTextFn);
|
|
67
77
|
assertFunction("webhookSendImageFn", webhookSendImageFn);
|
|
68
78
|
assertFunction("webhookSendFileBufferFn", webhookSendFileBufferFn);
|
|
79
|
+
assertFunction("extractWorkspacePathsFromText", extractWorkspacePathsFromText);
|
|
80
|
+
assertFunction("resolveWorkspacePathToHost", resolveWorkspacePathToHost);
|
|
81
|
+
assertFunction("recordDeliveryMetric", recordDeliveryMetric);
|
|
82
|
+
assertFunction("statImpl", statImpl);
|
|
83
|
+
|
|
84
|
+
const inlineImageExts = new Set([".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp", ".heic", ".heif"]);
|
|
85
|
+
|
|
86
|
+
async function collectInlineWorkspaceImageMediaUrls({ text, routeAgentId }) {
|
|
87
|
+
const normalizedText = String(text ?? "");
|
|
88
|
+
const normalizedRouteAgentId = String(routeAgentId ?? "").trim();
|
|
89
|
+
if (!normalizedText || !normalizedRouteAgentId) return [];
|
|
90
|
+
const workspacePaths = extractWorkspacePathsFromText(normalizedText, 6);
|
|
91
|
+
if (!Array.isArray(workspacePaths) || workspacePaths.length === 0) return [];
|
|
92
|
+
|
|
93
|
+
const out = [];
|
|
94
|
+
const seen = new Set();
|
|
95
|
+
for (const workspacePath of workspacePaths) {
|
|
96
|
+
const hostPath = resolveWorkspacePathToHost({
|
|
97
|
+
workspacePath,
|
|
98
|
+
agentId: normalizedRouteAgentId,
|
|
99
|
+
});
|
|
100
|
+
const normalizedHostPath = String(hostPath ?? "").trim();
|
|
101
|
+
if (!normalizedHostPath || seen.has(normalizedHostPath)) continue;
|
|
102
|
+
const lower = normalizedHostPath.toLowerCase();
|
|
103
|
+
const ext = lower.includes(".") ? `.${lower.split(".").pop()}` : "";
|
|
104
|
+
if (!inlineImageExts.has(ext)) continue;
|
|
105
|
+
try {
|
|
106
|
+
const fileStat = await statImpl(normalizedHostPath);
|
|
107
|
+
if (!fileStat?.isFile?.()) continue;
|
|
108
|
+
seen.add(normalizedHostPath);
|
|
109
|
+
out.push(normalizedHostPath);
|
|
110
|
+
} catch {
|
|
111
|
+
// ignore non-existing paths
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return out;
|
|
115
|
+
}
|
|
69
116
|
|
|
70
117
|
const sendWebhookBotMediaBatch = createWecomWebhookBotMediaSender({
|
|
71
118
|
resolveWebhookBotSendUrl: resolveWebhookBotSendUrlFn,
|
|
@@ -94,6 +141,8 @@ export function createWecomBotReplyDeliverer({
|
|
|
94
141
|
attachWecomProxyDispatcher,
|
|
95
142
|
resolveWebhookBotSendUrl: resolveWebhookBotSendUrlFn,
|
|
96
143
|
webhookSendText: webhookSendTextFn,
|
|
144
|
+
webhookSendMarkdown,
|
|
145
|
+
webhookSendTemplateCard,
|
|
97
146
|
sendWebhookBotMediaBatch,
|
|
98
147
|
fetchImpl,
|
|
99
148
|
});
|
|
@@ -109,30 +158,49 @@ export function createWecomBotReplyDeliverer({
|
|
|
109
158
|
async function deliverBotReplyText({
|
|
110
159
|
api,
|
|
111
160
|
fromUser,
|
|
161
|
+
accountId = "default",
|
|
112
162
|
sessionId,
|
|
113
163
|
streamId,
|
|
114
164
|
responseUrl,
|
|
115
165
|
text,
|
|
166
|
+
routeAgentId = "",
|
|
116
167
|
mediaUrl,
|
|
117
168
|
mediaUrls,
|
|
118
169
|
mediaType,
|
|
119
170
|
reason = "reply",
|
|
120
171
|
} = {}) {
|
|
172
|
+
const normalizedAccountId = String(accountId ?? "default").trim().toLowerCase() || "default";
|
|
121
173
|
const fallbackPolicy = resolveWecomDeliveryFallbackPolicy(api);
|
|
122
174
|
const webhookBotPolicy = resolveWecomWebhookBotDeliveryPolicy(api);
|
|
123
175
|
const observabilityPolicy = resolveWecomObservabilityPolicy(api);
|
|
124
|
-
const botProxyUrl = resolveWecomBotProxyConfig(api);
|
|
176
|
+
const botProxyUrl = resolveWecomBotProxyConfig(api, normalizedAccountId);
|
|
177
|
+
const botModeConfig = resolveWecomBotConfig(api, normalizedAccountId);
|
|
125
178
|
const normalizedText = String(text ?? "").trim();
|
|
126
|
-
const
|
|
127
|
-
const mixedPayload = buildWecomBotMixedPayload({
|
|
179
|
+
const inlineWorkspaceMediaUrls = await collectInlineWorkspaceImageMediaUrls({
|
|
128
180
|
text: normalizedText,
|
|
129
|
-
|
|
181
|
+
routeAgentId,
|
|
182
|
+
});
|
|
183
|
+
const normalizedMediaUrls = normalizeWecomBotOutboundMediaUrls({
|
|
184
|
+
mediaUrl,
|
|
185
|
+
mediaUrls: [...(Array.isArray(mediaUrls) ? mediaUrls : []), ...inlineWorkspaceMediaUrls],
|
|
186
|
+
});
|
|
187
|
+
const mixedPayload =
|
|
188
|
+
normalizedMediaUrls.length > 0
|
|
189
|
+
? buildWecomBotMixedPayload({
|
|
190
|
+
text: normalizedText,
|
|
191
|
+
mediaUrls: normalizedMediaUrls,
|
|
192
|
+
})
|
|
193
|
+
: null;
|
|
194
|
+
const fallbackText = normalizedText || "已收到模型返回的媒体结果,请查看以下链接。";
|
|
195
|
+
const cardPayload = buildWecomBotCardPayload({
|
|
196
|
+
text: normalizedText || fallbackText,
|
|
197
|
+
cardPolicy: botModeConfig?.card,
|
|
198
|
+
hasMedia: normalizedMediaUrls.length > 0,
|
|
130
199
|
});
|
|
131
200
|
const mediaFallbackSuffix =
|
|
132
201
|
normalizedMediaUrls.length > 0 ? `\n\n媒体链接:\n${normalizedMediaUrls.join("\n")}` : "";
|
|
133
|
-
const fallbackText = normalizedText || "已收到模型返回的媒体结果,请查看以下链接。";
|
|
134
202
|
|
|
135
|
-
const normalizedSessionId = String(sessionId ?? "").trim() || buildWecomBotSessionId(fromUser);
|
|
203
|
+
const normalizedSessionId = String(sessionId ?? "").trim() || buildWecomBotSessionId(fromUser, normalizedAccountId);
|
|
136
204
|
const inlineResponseUrl = String(responseUrl ?? "").trim();
|
|
137
205
|
if (inlineResponseUrl) {
|
|
138
206
|
upsertBotResponseUrlCache({
|
|
@@ -166,6 +234,10 @@ export function createWecomBotReplyDeliverer({
|
|
|
166
234
|
inlineResponseUrl,
|
|
167
235
|
cachedResponseUrl,
|
|
168
236
|
mixedPayload,
|
|
237
|
+
cardPayload:
|
|
238
|
+
botModeConfig?.card?.enabled === true && botModeConfig?.card?.responseUrlEnabled !== false
|
|
239
|
+
? cardPayload
|
|
240
|
+
: null,
|
|
169
241
|
content,
|
|
170
242
|
fallbackText,
|
|
171
243
|
logger: api.logger,
|
|
@@ -183,12 +255,15 @@ export function createWecomBotReplyDeliverer({
|
|
|
183
255
|
normalizedText,
|
|
184
256
|
normalizedMediaUrls,
|
|
185
257
|
mediaType,
|
|
258
|
+
cardPayload,
|
|
259
|
+
cardPolicy: botModeConfig?.card ?? {},
|
|
186
260
|
});
|
|
187
261
|
},
|
|
188
262
|
agent_push: async ({ text: content }) => {
|
|
189
263
|
return deliverAgentPushReply({
|
|
190
264
|
api,
|
|
191
265
|
fromUser,
|
|
266
|
+
accountId: normalizedAccountId,
|
|
192
267
|
content,
|
|
193
268
|
fallbackText,
|
|
194
269
|
mediaFallbackSuffix,
|
|
@@ -197,18 +272,28 @@ export function createWecomBotReplyDeliverer({
|
|
|
197
272
|
},
|
|
198
273
|
});
|
|
199
274
|
|
|
200
|
-
|
|
275
|
+
const deliveryResult = await router.deliverText({
|
|
201
276
|
text: normalizedText || fallbackText,
|
|
202
277
|
traceId,
|
|
203
278
|
meta: {
|
|
204
279
|
reason,
|
|
205
280
|
fromUser,
|
|
281
|
+
accountId: normalizedAccountId,
|
|
206
282
|
sessionId: normalizedSessionId,
|
|
207
283
|
streamId: streamId || "",
|
|
208
284
|
hasResponseUrl: Boolean(inlineResponseUrl || cachedResponseUrl?.url),
|
|
209
285
|
mediaCount: normalizedMediaUrls.length,
|
|
286
|
+
botCardMode: botModeConfig?.card?.enabled ? botModeConfig.card.mode : "off",
|
|
210
287
|
},
|
|
211
288
|
});
|
|
289
|
+
recordDeliveryMetric({
|
|
290
|
+
layer: deliveryResult?.layer || "",
|
|
291
|
+
ok: deliveryResult?.ok === true,
|
|
292
|
+
finalStatus: deliveryResult?.finalStatus || "",
|
|
293
|
+
accountId: normalizedAccountId,
|
|
294
|
+
attempts: deliveryResult?.attempts,
|
|
295
|
+
});
|
|
296
|
+
return deliveryResult;
|
|
212
297
|
}
|
|
213
298
|
|
|
214
299
|
return {
|
|
@@ -16,6 +16,7 @@ export function createWecomResponseUrlDeliverer({
|
|
|
16
16
|
inlineResponseUrl = "",
|
|
17
17
|
cachedResponseUrl = null,
|
|
18
18
|
mixedPayload = null,
|
|
19
|
+
cardPayload = null,
|
|
19
20
|
content = "",
|
|
20
21
|
fallbackText = "",
|
|
21
22
|
logger,
|
|
@@ -29,12 +30,14 @@ export function createWecomResponseUrlDeliverer({
|
|
|
29
30
|
if (cachedResponseUrl?.used) {
|
|
30
31
|
return { ok: false, reason: "response-url-used" };
|
|
31
32
|
}
|
|
32
|
-
const payload =
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
const payload =
|
|
34
|
+
mixedPayload ||
|
|
35
|
+
cardPayload || {
|
|
36
|
+
msgtype: "text",
|
|
37
|
+
text: {
|
|
38
|
+
content: content || fallbackText,
|
|
39
|
+
},
|
|
40
|
+
};
|
|
38
41
|
const result = await sendWecomBotPayloadViaResponseUrl({
|
|
39
42
|
responseUrl: targetUrl,
|
|
40
43
|
payload,
|
|
@@ -48,6 +51,7 @@ export function createWecomResponseUrlDeliverer({
|
|
|
48
51
|
meta: {
|
|
49
52
|
status: result.status,
|
|
50
53
|
errcode: result.errcode ?? 0,
|
|
54
|
+
msgtype: String(payload?.msgtype ?? "text").trim().toLowerCase() || "text",
|
|
51
55
|
},
|
|
52
56
|
};
|
|
53
57
|
};
|
|
@@ -8,12 +8,16 @@ export function createWecomWebhookBotDeliverer({
|
|
|
8
8
|
attachWecomProxyDispatcher,
|
|
9
9
|
resolveWebhookBotSendUrl,
|
|
10
10
|
webhookSendText,
|
|
11
|
+
webhookSendMarkdown,
|
|
12
|
+
webhookSendTemplateCard,
|
|
11
13
|
sendWebhookBotMediaBatch,
|
|
12
14
|
fetchImpl = fetch,
|
|
13
15
|
} = {}) {
|
|
14
16
|
assertFunction("attachWecomProxyDispatcher", attachWecomProxyDispatcher);
|
|
15
17
|
assertFunction("resolveWebhookBotSendUrl", resolveWebhookBotSendUrl);
|
|
16
18
|
assertFunction("webhookSendText", webhookSendText);
|
|
19
|
+
assertFunction("webhookSendMarkdown", webhookSendMarkdown);
|
|
20
|
+
assertFunction("webhookSendTemplateCard", webhookSendTemplateCard);
|
|
17
21
|
assertFunction("sendWebhookBotMediaBatch", sendWebhookBotMediaBatch);
|
|
18
22
|
assertFunction("fetchImpl", fetchImpl);
|
|
19
23
|
|
|
@@ -26,6 +30,8 @@ export function createWecomWebhookBotDeliverer({
|
|
|
26
30
|
normalizedText = "",
|
|
27
31
|
normalizedMediaUrls = [],
|
|
28
32
|
mediaType,
|
|
33
|
+
cardPayload = null,
|
|
34
|
+
cardPolicy = {},
|
|
29
35
|
} = {}) {
|
|
30
36
|
if (!webhookBotPolicy?.enabled) {
|
|
31
37
|
return { ok: false, reason: "webhook-bot-disabled" };
|
|
@@ -41,8 +47,42 @@ export function createWecomWebhookBotDeliverer({
|
|
|
41
47
|
const dispatcher = attachWecomProxyDispatcher(sendUrl, {}, { proxyUrl: botProxyUrl, logger: api?.logger })?.dispatcher;
|
|
42
48
|
const textPayload = `${content || fallbackText}`.trim();
|
|
43
49
|
let sentAny = false;
|
|
50
|
+
let usedCardMode = "";
|
|
44
51
|
|
|
45
|
-
|
|
52
|
+
const cardEnabledForWebhook = cardPolicy?.enabled === true && cardPolicy?.webhookBotEnabled !== false;
|
|
53
|
+
const canTryCard = cardEnabledForWebhook && normalizedMediaUrls.length === 0 && cardPayload && typeof cardPayload === "object";
|
|
54
|
+
if (canTryCard) {
|
|
55
|
+
try {
|
|
56
|
+
const cardMsgType = String(cardPayload?.msgtype ?? "").trim().toLowerCase();
|
|
57
|
+
if (cardMsgType === "template_card" && cardPayload?.template_card) {
|
|
58
|
+
await webhookSendTemplateCard({
|
|
59
|
+
url: webhookBotPolicy?.url,
|
|
60
|
+
key: webhookBotPolicy?.key,
|
|
61
|
+
templateCard: cardPayload.template_card,
|
|
62
|
+
timeoutMs: webhookBotPolicy?.timeoutMs,
|
|
63
|
+
dispatcher,
|
|
64
|
+
fetchImpl,
|
|
65
|
+
});
|
|
66
|
+
sentAny = true;
|
|
67
|
+
usedCardMode = "template_card";
|
|
68
|
+
} else if (cardMsgType === "markdown" && cardPayload?.markdown?.content) {
|
|
69
|
+
await webhookSendMarkdown({
|
|
70
|
+
url: webhookBotPolicy?.url,
|
|
71
|
+
key: webhookBotPolicy?.key,
|
|
72
|
+
content: String(cardPayload.markdown.content ?? ""),
|
|
73
|
+
timeoutMs: webhookBotPolicy?.timeoutMs,
|
|
74
|
+
dispatcher,
|
|
75
|
+
fetchImpl,
|
|
76
|
+
});
|
|
77
|
+
sentAny = true;
|
|
78
|
+
usedCardMode = "markdown";
|
|
79
|
+
}
|
|
80
|
+
} catch (err) {
|
|
81
|
+
api?.logger?.warn?.(`wecom: webhook bot card send failed, fallback to text: ${String(err?.message || err)}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (!sentAny && textPayload && (normalizedText || normalizedMediaUrls.length === 0)) {
|
|
46
86
|
await webhookSendText({
|
|
47
87
|
url: webhookBotPolicy?.url,
|
|
48
88
|
key: webhookBotPolicy?.key,
|
|
@@ -86,6 +126,7 @@ export function createWecomWebhookBotDeliverer({
|
|
|
86
126
|
meta: {
|
|
87
127
|
mediaSent: mediaMeta.sentCount,
|
|
88
128
|
mediaFailed: mediaMeta.failedCount,
|
|
129
|
+
cardMode: usedCardMode || undefined,
|
|
89
130
|
},
|
|
90
131
|
};
|
|
91
132
|
};
|
|
@@ -12,9 +12,12 @@ import {
|
|
|
12
12
|
pickAudioFileExtension,
|
|
13
13
|
resolveVoiceTranscriptionConfig,
|
|
14
14
|
resolveWecomAllowFromPolicyConfig,
|
|
15
|
+
resolveWecomBotModeAccountsConfig,
|
|
15
16
|
resolveWecomBotModeConfig,
|
|
16
17
|
resolveWecomCommandPolicyConfig,
|
|
17
18
|
resolveWecomDebounceConfig,
|
|
19
|
+
resolveWecomDmPolicyConfig,
|
|
20
|
+
resolveWecomEventPolicyConfig,
|
|
18
21
|
resolveWecomDeliveryFallbackConfig,
|
|
19
22
|
resolveWecomDynamicAgentConfig,
|
|
20
23
|
resolveWecomGroupChatConfig,
|
|
@@ -28,6 +31,7 @@ import {
|
|
|
28
31
|
export function createWecomPluginAccountPolicyServices({
|
|
29
32
|
processEnv = process.env,
|
|
30
33
|
getGatewayRuntime,
|
|
34
|
+
getWecomObservabilityMetrics = () => ({}),
|
|
31
35
|
normalizeWecomResolvedTarget,
|
|
32
36
|
formatWecomTargetForLog,
|
|
33
37
|
sendWecomWebhookText,
|
|
@@ -45,6 +49,7 @@ export function createWecomPluginAccountPolicyServices({
|
|
|
45
49
|
normalizeAccountId,
|
|
46
50
|
getWecomConfig,
|
|
47
51
|
listWecomAccountIds,
|
|
52
|
+
listEnabledWecomAccounts,
|
|
48
53
|
listWebhookTargetAliases,
|
|
49
54
|
listAllWebhookTargetAliases,
|
|
50
55
|
groupAccountsByWebhookPath,
|
|
@@ -66,10 +71,13 @@ export function createWecomPluginAccountPolicyServices({
|
|
|
66
71
|
});
|
|
67
72
|
|
|
68
73
|
const {
|
|
74
|
+
resolveWecomBotConfigs,
|
|
69
75
|
resolveWecomBotConfig,
|
|
70
76
|
resolveWecomBotProxyConfig,
|
|
71
77
|
resolveWecomCommandPolicy,
|
|
72
78
|
resolveWecomAllowFromPolicy,
|
|
79
|
+
resolveWecomDmPolicy,
|
|
80
|
+
resolveWecomEventPolicy,
|
|
73
81
|
resolveWecomGroupChatPolicy,
|
|
74
82
|
resolveWecomTextDebouncePolicy,
|
|
75
83
|
resolveWecomReplyStreamingPolicy,
|
|
@@ -82,9 +90,12 @@ export function createWecomPluginAccountPolicyServices({
|
|
|
82
90
|
getGatewayRuntime,
|
|
83
91
|
normalizeAccountId,
|
|
84
92
|
resolveWecomBotModeConfig,
|
|
93
|
+
resolveWecomBotModeAccountsConfig,
|
|
85
94
|
resolveWecomProxyConfig,
|
|
86
95
|
resolveWecomCommandPolicyConfig,
|
|
87
96
|
resolveWecomAllowFromPolicyConfig,
|
|
97
|
+
resolveWecomDmPolicyConfig,
|
|
98
|
+
resolveWecomEventPolicyConfig,
|
|
88
99
|
resolveWecomGroupChatConfig,
|
|
89
100
|
resolveWecomDebounceConfig,
|
|
90
101
|
resolveWecomStreamingConfig,
|
|
@@ -109,11 +120,14 @@ export function createWecomPluginAccountPolicyServices({
|
|
|
109
120
|
sendWecomText,
|
|
110
121
|
getWecomConfig,
|
|
111
122
|
listWecomAccountIds,
|
|
123
|
+
listEnabledWecomAccounts,
|
|
112
124
|
listWebhookTargetAliases,
|
|
113
125
|
listAllWebhookTargetAliases,
|
|
114
126
|
resolveWecomVoiceTranscriptionConfig,
|
|
115
127
|
resolveWecomCommandPolicy,
|
|
116
128
|
resolveWecomAllowFromPolicy,
|
|
129
|
+
resolveWecomDmPolicy,
|
|
130
|
+
resolveWecomEventPolicy,
|
|
117
131
|
resolveWecomGroupChatPolicy,
|
|
118
132
|
resolveWecomTextDebouncePolicy,
|
|
119
133
|
resolveWecomReplyStreamingPolicy,
|
|
@@ -122,6 +136,7 @@ export function createWecomPluginAccountPolicyServices({
|
|
|
122
136
|
resolveWecomWebhookBotDeliveryPolicy,
|
|
123
137
|
resolveWecomDynamicAgentPolicy,
|
|
124
138
|
resolveWecomBotConfig,
|
|
139
|
+
getWecomObservabilityMetrics,
|
|
125
140
|
pluginVersion: PLUGIN_VERSION,
|
|
126
141
|
});
|
|
127
142
|
|
|
@@ -129,14 +144,18 @@ export function createWecomPluginAccountPolicyServices({
|
|
|
129
144
|
normalizeAccountId,
|
|
130
145
|
getWecomConfig,
|
|
131
146
|
listWecomAccountIds,
|
|
147
|
+
listEnabledWecomAccounts,
|
|
132
148
|
listWebhookTargetAliases,
|
|
133
149
|
listAllWebhookTargetAliases,
|
|
134
150
|
groupAccountsByWebhookPath,
|
|
135
151
|
WecomChannelPlugin,
|
|
136
152
|
resolveWecomBotConfig,
|
|
153
|
+
resolveWecomBotConfigs,
|
|
137
154
|
resolveWecomBotProxyConfig,
|
|
138
155
|
resolveWecomCommandPolicy,
|
|
139
156
|
resolveWecomAllowFromPolicy,
|
|
157
|
+
resolveWecomDmPolicy,
|
|
158
|
+
resolveWecomEventPolicy,
|
|
140
159
|
resolveWecomGroupChatPolicy,
|
|
141
160
|
resolveWecomTextDebouncePolicy,
|
|
142
161
|
resolveWecomReplyStreamingPolicy,
|
|
@@ -13,6 +13,7 @@ import { createWecomBotEncryptedResponseBuilder } from "./bot-encrypted-response
|
|
|
13
13
|
import { createWecomDefaultLimiters } from "./rate-limiter.js";
|
|
14
14
|
import { createWecomMediaFetcher, normalizeOutboundMediaUrls, resolveWecomOutboundMediaTarget } from "./media-url-utils.js";
|
|
15
15
|
import { createWecomOutboundSender } from "./outbound-sender.js";
|
|
16
|
+
import { createWecomObservabilityMetricsStore } from "./observability-metrics.js";
|
|
16
17
|
import { createWecomRequestParsers } from "./request-parsers.js";
|
|
17
18
|
import { createWecomTargetResolver } from "./target-utils.js";
|
|
18
19
|
import { createDeliveredTranscriptReplyTracker } from "./transcript-utils.js";
|
|
@@ -38,6 +39,12 @@ export function createWecomPluginBaseServices({
|
|
|
38
39
|
fetchImpl = fetch,
|
|
39
40
|
proxyAgentCtor = ProxyAgent,
|
|
40
41
|
} = {}) {
|
|
42
|
+
const {
|
|
43
|
+
recordInboundMetric,
|
|
44
|
+
recordDeliveryMetric,
|
|
45
|
+
recordRuntimeErrorMetric,
|
|
46
|
+
getWecomObservabilityMetrics,
|
|
47
|
+
} = createWecomObservabilityMetricsStore();
|
|
41
48
|
const { markTranscriptReplyDelivered, hasTranscriptReplyBeenDelivered } = createDeliveredTranscriptReplyTracker({
|
|
42
49
|
ttlMs: TRANSCRIPT_REPLY_CACHE_TTL_MS,
|
|
43
50
|
});
|
|
@@ -146,6 +153,10 @@ export function createWecomPluginBaseServices({
|
|
|
146
153
|
return {
|
|
147
154
|
markTranscriptReplyDelivered,
|
|
148
155
|
hasTranscriptReplyBeenDelivered,
|
|
156
|
+
recordInboundMetric,
|
|
157
|
+
recordDeliveryMetric,
|
|
158
|
+
recordRuntimeErrorMetric,
|
|
159
|
+
getWecomObservabilityMetrics,
|
|
149
160
|
scheduleTempFileCleanup,
|
|
150
161
|
setBotStreamExpireMs,
|
|
151
162
|
resolveBotActiveStream,
|
|
@@ -185,6 +196,8 @@ export function createWecomPluginBaseServices({
|
|
|
185
196
|
sendWecomWebhookMediaBatch,
|
|
186
197
|
sendWecomOutboundMediaBatch,
|
|
187
198
|
autoSendWorkspaceFilesFromReplyText,
|
|
199
|
+
extractWorkspacePathsFromText,
|
|
200
|
+
resolveWorkspacePathToHost,
|
|
188
201
|
normalizeWecomResolvedTarget,
|
|
189
202
|
formatWecomTargetForLog,
|
|
190
203
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export const MAX_REQUEST_BODY_SIZE = 1024 * 1024;
|
|
2
|
-
export const PLUGIN_VERSION = "
|
|
2
|
+
export const PLUGIN_VERSION = "1.7.1";
|
|
3
3
|
export const WECOM_TEMP_DIR_NAME = "openclaw-wechat";
|
|
4
4
|
export const WECOM_TEMP_FILE_RETENTION_MS = 30 * 60 * 1000;
|
|
5
5
|
export const WECOM_MIN_FILE_SIZE = 5;
|
|
@@ -16,6 +16,7 @@ export function createWecomPluginDeliveryInboundServices({
|
|
|
16
16
|
resolveWecomWebhookBotDeliveryPolicy,
|
|
17
17
|
resolveWecomObservabilityPolicy,
|
|
18
18
|
resolveWecomBotProxyConfig,
|
|
19
|
+
resolveWecomBotConfig,
|
|
19
20
|
upsertBotResponseUrlCache,
|
|
20
21
|
getBotResponseUrlCache,
|
|
21
22
|
markBotResponseUrlUsed,
|
|
@@ -26,6 +27,9 @@ export function createWecomPluginDeliveryInboundServices({
|
|
|
26
27
|
getWecomConfig,
|
|
27
28
|
sendWecomText,
|
|
28
29
|
fetchMediaFromUrl,
|
|
30
|
+
extractWorkspacePathsFromText,
|
|
31
|
+
resolveWorkspacePathToHost,
|
|
32
|
+
recordDeliveryMetric,
|
|
29
33
|
downloadWecomMedia,
|
|
30
34
|
resolveWecomVoiceTranscriptionConfig,
|
|
31
35
|
transcribeInboundVoice,
|
|
@@ -48,6 +52,7 @@ export function createWecomPluginDeliveryInboundServices({
|
|
|
48
52
|
resolveWecomWebhookBotDeliveryPolicy,
|
|
49
53
|
resolveWecomObservabilityPolicy,
|
|
50
54
|
resolveWecomBotProxyConfig,
|
|
55
|
+
resolveWecomBotConfig,
|
|
51
56
|
buildWecomBotSessionId,
|
|
52
57
|
upsertBotResponseUrlCache,
|
|
53
58
|
getBotResponseUrlCache,
|
|
@@ -60,6 +65,9 @@ export function createWecomPluginDeliveryInboundServices({
|
|
|
60
65
|
getWecomConfig,
|
|
61
66
|
sendWecomText,
|
|
62
67
|
fetchMediaFromUrl,
|
|
68
|
+
extractWorkspacePathsFromText,
|
|
69
|
+
resolveWorkspacePathToHost,
|
|
70
|
+
recordDeliveryMetric,
|
|
63
71
|
});
|
|
64
72
|
|
|
65
73
|
const { buildInboundContent } = createWecomInboundContentBuilder({
|
|
@@ -22,6 +22,8 @@ export function createPluginProcessingDeps(context = {}) {
|
|
|
22
22
|
stripWecomGroupMentions: context.stripWecomGroupMentions,
|
|
23
23
|
resolveWecomCommandPolicy: context.resolveWecomCommandPolicy,
|
|
24
24
|
resolveWecomAllowFromPolicy: context.resolveWecomAllowFromPolicy,
|
|
25
|
+
resolveWecomDmPolicy: context.resolveWecomDmPolicy,
|
|
26
|
+
resolveWecomEventPolicy: context.resolveWecomEventPolicy,
|
|
25
27
|
isWecomSenderAllowed: context.isWecomSenderAllowed,
|
|
26
28
|
extractLeadingSlashCommand: context.extractLeadingSlashCommand,
|
|
27
29
|
buildWecomBotHelpText: context.buildWecomBotHelpText,
|
|
@@ -54,6 +56,8 @@ export function createPluginProcessingDeps(context = {}) {
|
|
|
54
56
|
stripWecomGroupMentions: context.stripWecomGroupMentions,
|
|
55
57
|
resolveWecomCommandPolicy: context.resolveWecomCommandPolicy,
|
|
56
58
|
resolveWecomAllowFromPolicy: context.resolveWecomAllowFromPolicy,
|
|
59
|
+
resolveWecomDmPolicy: context.resolveWecomDmPolicy,
|
|
60
|
+
resolveWecomEventPolicy: context.resolveWecomEventPolicy,
|
|
57
61
|
isWecomSenderAllowed: context.isWecomSenderAllowed,
|
|
58
62
|
sendWecomText: context.sendWecomText,
|
|
59
63
|
extractLeadingSlashCommand: context.extractLeadingSlashCommand,
|
|
@@ -9,6 +9,7 @@ export function createPluginRouteRuntimeDeps(context = {}) {
|
|
|
9
9
|
return {
|
|
10
10
|
routeRegistrarDeps: {
|
|
11
11
|
resolveWecomBotConfig: context.resolveWecomBotConfig,
|
|
12
|
+
resolveWecomBotConfigs: context.resolveWecomBotConfigs,
|
|
12
13
|
normalizePluginHttpPath: context.normalizePluginHttpPath,
|
|
13
14
|
ensureBotStreamCleanupTimer: context.ensureBotStreamCleanupTimer,
|
|
14
15
|
cleanupExpiredBotStreams: context.cleanupExpiredBotStreams,
|
|
@@ -38,6 +39,8 @@ export function createPluginRouteRuntimeDeps(context = {}) {
|
|
|
38
39
|
deliverBotReplyText: context.deliverBotReplyText,
|
|
39
40
|
finishBotStream: context.finishBotStream,
|
|
40
41
|
groupAccountsByWebhookPath: context.groupAccountsByWebhookPath,
|
|
42
|
+
recordInboundMetric: context.recordInboundMetric,
|
|
43
|
+
recordRuntimeErrorMetric: context.recordRuntimeErrorMetric,
|
|
41
44
|
},
|
|
42
45
|
registerRuntimeDeps: {
|
|
43
46
|
setGatewayRuntime: context.setGatewayRuntime,
|
|
@@ -47,6 +50,8 @@ export function createPluginRouteRuntimeDeps(context = {}) {
|
|
|
47
50
|
resolveWecomObservabilityPolicy: context.resolveWecomObservabilityPolicy,
|
|
48
51
|
resolveWecomDynamicAgentPolicy: context.resolveWecomDynamicAgentPolicy,
|
|
49
52
|
resolveWecomBotConfig: context.resolveWecomBotConfig,
|
|
53
|
+
resolveWecomBotConfigs: context.resolveWecomBotConfigs,
|
|
54
|
+
listEnabledWecomAccounts: context.listEnabledWecomAccounts,
|
|
50
55
|
getWecomConfig: context.getWecomConfig,
|
|
51
56
|
wecomChannelPlugin: context.wecomChannelPlugin,
|
|
52
57
|
},
|
|
@@ -73,6 +73,7 @@ export function createWecomPluginServices({
|
|
|
73
73
|
const accountPolicy = createWecomPluginAccountPolicyServices({
|
|
74
74
|
processEnv,
|
|
75
75
|
getGatewayRuntime: base.getGatewayRuntime,
|
|
76
|
+
getWecomObservabilityMetrics: base.getWecomObservabilityMetrics,
|
|
76
77
|
normalizeWecomResolvedTarget: base.normalizeWecomResolvedTarget,
|
|
77
78
|
formatWecomTargetForLog: base.formatWecomTargetForLog,
|
|
78
79
|
sendWecomWebhookText: base.sendWecomWebhookText,
|
|
@@ -89,6 +90,7 @@ export function createWecomPluginServices({
|
|
|
89
90
|
resolveWecomWebhookBotDeliveryPolicy: accountPolicy.resolveWecomWebhookBotDeliveryPolicy,
|
|
90
91
|
resolveWecomObservabilityPolicy: accountPolicy.resolveWecomObservabilityPolicy,
|
|
91
92
|
resolveWecomBotProxyConfig: accountPolicy.resolveWecomBotProxyConfig,
|
|
93
|
+
resolveWecomBotConfig: accountPolicy.resolveWecomBotConfig,
|
|
92
94
|
upsertBotResponseUrlCache: base.upsertBotResponseUrlCache,
|
|
93
95
|
getBotResponseUrlCache: base.getBotResponseUrlCache,
|
|
94
96
|
markBotResponseUrlUsed: base.markBotResponseUrlUsed,
|
|
@@ -99,6 +101,9 @@ export function createWecomPluginServices({
|
|
|
99
101
|
getWecomConfig: accountPolicy.getWecomConfig,
|
|
100
102
|
sendWecomText: base.sendWecomText,
|
|
101
103
|
fetchMediaFromUrl: base.fetchMediaFromUrl,
|
|
104
|
+
extractWorkspacePathsFromText: base.extractWorkspacePathsFromText,
|
|
105
|
+
resolveWorkspacePathToHost: base.resolveWorkspacePathToHost,
|
|
106
|
+
recordDeliveryMetric: base.recordDeliveryMetric,
|
|
102
107
|
downloadWecomMedia: base.downloadWecomMedia,
|
|
103
108
|
resolveWecomVoiceTranscriptionConfig: accountPolicy.resolveWecomVoiceTranscriptionConfig,
|
|
104
109
|
transcribeInboundVoice: accountPolicy.transcribeInboundVoice,
|
|
@@ -108,6 +113,8 @@ export function createWecomPluginServices({
|
|
|
108
113
|
detectImageContentTypeFromBuffer,
|
|
109
114
|
decryptWecomMediaBuffer,
|
|
110
115
|
pickImageFileExtension,
|
|
116
|
+
resolveWecomVoiceTranscriptionConfig: accountPolicy.resolveWecomVoiceTranscriptionConfig,
|
|
117
|
+
transcribeInboundVoice: accountPolicy.transcribeInboundVoice,
|
|
111
118
|
inferFilenameFromMediaDownload,
|
|
112
119
|
smartDecryptWecomFileBuffer,
|
|
113
120
|
basename,
|