@wecom/wecom-openclaw-plugin 2026.3.31-beta.0 → 2026.4.1-beta.1

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.
Files changed (209) hide show
  1. package/README.md +4 -251
  2. package/dist/cjs/index.js +45 -0
  3. package/dist/cjs/index.js.map +1 -0
  4. package/dist/cjs/src/channel.js +339 -0
  5. package/dist/cjs/src/channel.js.map +1 -0
  6. package/dist/cjs/src/const.js +137 -0
  7. package/dist/cjs/src/const.js.map +1 -0
  8. package/dist/cjs/src/dm-policy.js +89 -0
  9. package/dist/cjs/src/dm-policy.js.map +1 -0
  10. package/dist/cjs/src/group-policy.js +133 -0
  11. package/dist/cjs/src/group-policy.js.map +1 -0
  12. package/dist/cjs/src/mcp/interceptors/biz-error.js +70 -0
  13. package/dist/cjs/src/mcp/interceptors/biz-error.js.map +1 -0
  14. package/dist/cjs/src/mcp/interceptors/index.js +73 -0
  15. package/dist/cjs/src/mcp/interceptors/index.js.map +1 -0
  16. package/dist/cjs/src/mcp/interceptors/msg-media.js +159 -0
  17. package/dist/cjs/src/mcp/interceptors/msg-media.js.map +1 -0
  18. package/dist/cjs/src/mcp/interceptors/smartpage-create.js +157 -0
  19. package/dist/cjs/src/mcp/interceptors/smartpage-create.js.map +1 -0
  20. package/dist/cjs/src/mcp/interceptors/smartpage-export.js +93 -0
  21. package/dist/cjs/src/mcp/interceptors/smartpage-export.js.map +1 -0
  22. package/dist/cjs/src/mcp/schema.js +104 -0
  23. package/dist/cjs/src/mcp/schema.js.map +1 -0
  24. package/dist/cjs/src/mcp/tool.js +208 -0
  25. package/dist/cjs/src/mcp/tool.js.map +1 -0
  26. package/dist/cjs/src/mcp/transport.js +417 -0
  27. package/dist/cjs/src/mcp/transport.js.map +1 -0
  28. package/dist/cjs/src/media-handler.js +129 -0
  29. package/dist/cjs/src/media-handler.js.map +1 -0
  30. package/dist/cjs/src/media-uploader.js +284 -0
  31. package/dist/cjs/src/media-uploader.js.map +1 -0
  32. package/dist/cjs/src/message-parser.js +134 -0
  33. package/dist/cjs/src/message-parser.js.map +1 -0
  34. package/dist/cjs/src/message-sender.js +89 -0
  35. package/dist/cjs/src/message-sender.js.map +1 -0
  36. package/dist/cjs/src/monitor.js +991 -0
  37. package/dist/cjs/src/monitor.js.map +1 -0
  38. package/dist/cjs/src/onboarding.js +182 -0
  39. package/dist/cjs/src/onboarding.js.map +1 -0
  40. package/dist/cjs/src/openclaw-compat.js +400 -0
  41. package/dist/cjs/src/openclaw-compat.js.map +1 -0
  42. package/dist/cjs/src/reqid-store.js +88 -0
  43. package/dist/cjs/src/reqid-store.js.map +1 -0
  44. package/dist/cjs/src/runtime.js +16 -0
  45. package/dist/cjs/src/runtime.js.map +1 -0
  46. package/dist/cjs/src/state-dir-resolve.js +35 -0
  47. package/dist/cjs/src/state-dir-resolve.js.map +1 -0
  48. package/dist/cjs/src/state-manager.js +158 -0
  49. package/dist/cjs/src/state-manager.js.map +1 -0
  50. package/dist/cjs/src/template-card-parser.js +641 -0
  51. package/dist/cjs/src/template-card-parser.js.map +1 -0
  52. package/dist/cjs/src/timeout.js +42 -0
  53. package/dist/cjs/src/timeout.js.map +1 -0
  54. package/dist/cjs/src/utils.js +60 -0
  55. package/dist/cjs/src/utils.js.map +1 -0
  56. package/dist/cjs/src/version.js +26 -0
  57. package/dist/cjs/src/version.js.map +1 -0
  58. package/dist/esm/index.js +41 -0
  59. package/dist/esm/index.js.map +1 -0
  60. package/dist/esm/src/channel.js +337 -0
  61. package/dist/esm/src/channel.js.map +1 -0
  62. package/dist/{src → esm/src}/const.js +30 -77
  63. package/dist/esm/src/const.js.map +1 -0
  64. package/dist/{src → esm/src}/dm-policy.js +9 -6
  65. package/dist/esm/src/dm-policy.js.map +1 -0
  66. package/dist/{src → esm/src}/group-policy.js +7 -3
  67. package/dist/esm/src/group-policy.js.map +1 -0
  68. package/dist/{src → esm/src}/mcp/interceptors/biz-error.js +6 -2
  69. package/dist/esm/src/mcp/interceptors/biz-error.js.map +1 -0
  70. package/dist/{src → esm/src}/mcp/interceptors/index.js +10 -6
  71. package/dist/esm/src/mcp/interceptors/index.js.map +1 -0
  72. package/dist/{src → esm/src}/mcp/interceptors/msg-media.js +10 -6
  73. package/dist/esm/src/mcp/interceptors/msg-media.js.map +1 -0
  74. package/dist/{src → esm/src}/mcp/interceptors/smartpage-create.js +6 -2
  75. package/dist/esm/src/mcp/interceptors/smartpage-create.js.map +1 -0
  76. package/dist/{src → esm/src}/mcp/interceptors/smartpage-export.js +6 -2
  77. package/dist/esm/src/mcp/interceptors/smartpage-export.js.map +1 -0
  78. package/dist/{src → esm/src}/mcp/schema.js +4 -1
  79. package/dist/esm/src/mcp/schema.js.map +1 -0
  80. package/dist/{src → esm/src}/mcp/tool.js +8 -4
  81. package/dist/esm/src/mcp/tool.js.map +1 -0
  82. package/dist/{src → esm/src}/mcp/transport.js +16 -15
  83. package/dist/esm/src/mcp/transport.js.map +1 -0
  84. package/dist/{src → esm/src}/media-handler.js +10 -6
  85. package/dist/esm/src/media-handler.js.map +1 -0
  86. package/dist/{src → esm/src}/media-uploader.js +10 -64
  87. package/dist/esm/src/media-uploader.js.map +1 -0
  88. package/dist/{src → esm/src}/message-parser.js +4 -1
  89. package/dist/esm/src/message-parser.js.map +1 -0
  90. package/dist/{src → esm/src}/message-sender.js +11 -46
  91. package/dist/esm/src/message-sender.js.map +1 -0
  92. package/dist/{src → esm/src}/monitor.js +282 -151
  93. package/dist/esm/src/monitor.js.map +1 -0
  94. package/dist/{src → esm/src}/onboarding.js +26 -22
  95. package/dist/esm/src/onboarding.js.map +1 -0
  96. package/dist/{src → esm/src}/openclaw-compat.js +27 -143
  97. package/dist/esm/src/openclaw-compat.js.map +1 -0
  98. package/dist/{src → esm/src}/reqid-store.js +7 -4
  99. package/dist/esm/src/reqid-store.js.map +1 -0
  100. package/dist/{src → esm/src}/runtime.js +5 -2
  101. package/dist/esm/src/runtime.js.map +1 -0
  102. package/dist/esm/src/state-dir-resolve.js +13 -0
  103. package/dist/esm/src/state-dir-resolve.js.map +1 -0
  104. package/dist/{src → esm/src}/state-manager.js +16 -84
  105. package/dist/esm/src/state-manager.js.map +1 -0
  106. package/dist/{src → esm/src}/template-card-parser.js +8 -17
  107. package/dist/esm/src/template-card-parser.js.map +1 -0
  108. package/dist/{src → esm/src}/timeout.js +5 -2
  109. package/dist/esm/src/timeout.js.map +1 -0
  110. package/dist/{src → esm/src}/utils.js +10 -24
  111. package/dist/esm/src/utils.js.map +1 -0
  112. package/dist/esm/src/version.js +23 -0
  113. package/dist/esm/src/version.js.map +1 -0
  114. package/dist/esm/types/index.d.ts +9 -0
  115. package/dist/{src → esm/types/src}/const.d.ts +0 -46
  116. package/dist/{src → esm/types/src}/interface.d.ts +2 -0
  117. package/dist/{src → esm/types/src}/message-sender.d.ts +0 -18
  118. package/dist/{src → esm/types/src}/openclaw-compat.d.ts +0 -49
  119. package/dist/esm/types/src/state-dir-resolve.d.ts +2 -0
  120. package/dist/{src → esm/types/src}/utils.d.ts +0 -39
  121. package/dist/esm/types/src/version.d.ts +2 -0
  122. package/dist/index.d.ts +4 -2
  123. package/package.json +7 -15
  124. package/dist/index.js +0 -113
  125. package/dist/src/accounts.d.ts +0 -57
  126. package/dist/src/accounts.js +0 -222
  127. package/dist/src/agent/api-client.d.ts +0 -94
  128. package/dist/src/agent/api-client.js +0 -292
  129. package/dist/src/agent/handler.d.ts +0 -63
  130. package/dist/src/agent/handler.js +0 -532
  131. package/dist/src/agent/index.d.ts +0 -5
  132. package/dist/src/agent/index.js +0 -5
  133. package/dist/src/agent/webhook.d.ts +0 -23
  134. package/dist/src/agent/webhook.js +0 -226
  135. package/dist/src/agent/xml.d.ts +0 -21
  136. package/dist/src/agent/xml.js +0 -41
  137. package/dist/src/channel.js +0 -564
  138. package/dist/src/chat-queue.d.ts +0 -31
  139. package/dist/src/chat-queue.js +0 -45
  140. package/dist/src/http.d.ts +0 -26
  141. package/dist/src/http.js +0 -93
  142. package/dist/src/interface.js +0 -4
  143. package/dist/src/mcp/index.js +0 -6
  144. package/dist/src/mcp/interceptors/types.js +0 -7
  145. package/dist/src/shared/command-auth.d.ts +0 -23
  146. package/dist/src/shared/command-auth.js +0 -73
  147. package/dist/src/shared/xml-parser.d.ts +0 -46
  148. package/dist/src/shared/xml-parser.js +0 -210
  149. package/dist/src/target.d.ts +0 -35
  150. package/dist/src/target.js +0 -67
  151. package/dist/src/template-card-manager.d.ts +0 -55
  152. package/dist/src/template-card-manager.js +0 -205
  153. package/dist/src/types/account.d.ts +0 -29
  154. package/dist/src/types/account.js +0 -4
  155. package/dist/src/types/config.d.ts +0 -80
  156. package/dist/src/types/config.js +0 -7
  157. package/dist/src/types/constants.d.ts +0 -42
  158. package/dist/src/types/constants.js +0 -42
  159. package/dist/src/types/index.d.ts +0 -7
  160. package/dist/src/types/index.js +0 -5
  161. package/dist/src/types/message.d.ts +0 -238
  162. package/dist/src/types/message.js +0 -5
  163. package/dist/src/version.d.ts +0 -2
  164. package/dist/src/version.js +0 -24
  165. package/dist/src/webhook/command-auth.d.ts +0 -47
  166. package/dist/src/webhook/command-auth.js +0 -96
  167. package/dist/src/webhook/gateway.d.ts +0 -36
  168. package/dist/src/webhook/gateway.js +0 -227
  169. package/dist/src/webhook/handler.d.ts +0 -18
  170. package/dist/src/webhook/handler.js +0 -420
  171. package/dist/src/webhook/helpers.d.ts +0 -156
  172. package/dist/src/webhook/helpers.js +0 -833
  173. package/dist/src/webhook/http.d.ts +0 -26
  174. package/dist/src/webhook/http.js +0 -94
  175. package/dist/src/webhook/index.d.ts +0 -11
  176. package/dist/src/webhook/index.js +0 -14
  177. package/dist/src/webhook/media.d.ts +0 -29
  178. package/dist/src/webhook/media.js +0 -88
  179. package/dist/src/webhook/monitor.d.ts +0 -59
  180. package/dist/src/webhook/monitor.js +0 -1147
  181. package/dist/src/webhook/state.d.ts +0 -220
  182. package/dist/src/webhook/state.js +0 -491
  183. package/dist/src/webhook/target.d.ts +0 -41
  184. package/dist/src/webhook/target.js +0 -132
  185. package/dist/src/webhook/types.d.ts +0 -347
  186. package/dist/src/webhook/types.js +0 -33
  187. /package/dist/{src → esm/types/src}/channel.d.ts +0 -0
  188. /package/dist/{src → esm/types/src}/dm-policy.d.ts +0 -0
  189. /package/dist/{src → esm/types/src}/group-policy.d.ts +0 -0
  190. /package/dist/{src → esm/types/src}/mcp/index.d.ts +0 -0
  191. /package/dist/{src → esm/types/src}/mcp/interceptors/biz-error.d.ts +0 -0
  192. /package/dist/{src → esm/types/src}/mcp/interceptors/index.d.ts +0 -0
  193. /package/dist/{src → esm/types/src}/mcp/interceptors/msg-media.d.ts +0 -0
  194. /package/dist/{src → esm/types/src}/mcp/interceptors/smartpage-create.d.ts +0 -0
  195. /package/dist/{src → esm/types/src}/mcp/interceptors/smartpage-export.d.ts +0 -0
  196. /package/dist/{src → esm/types/src}/mcp/interceptors/types.d.ts +0 -0
  197. /package/dist/{src → esm/types/src}/mcp/schema.d.ts +0 -0
  198. /package/dist/{src → esm/types/src}/mcp/tool.d.ts +0 -0
  199. /package/dist/{src → esm/types/src}/mcp/transport.d.ts +0 -0
  200. /package/dist/{src → esm/types/src}/media-handler.d.ts +0 -0
  201. /package/dist/{src → esm/types/src}/media-uploader.d.ts +0 -0
  202. /package/dist/{src → esm/types/src}/message-parser.d.ts +0 -0
  203. /package/dist/{src → esm/types/src}/monitor.d.ts +0 -0
  204. /package/dist/{src → esm/types/src}/onboarding.d.ts +0 -0
  205. /package/dist/{src → esm/types/src}/reqid-store.d.ts +0 -0
  206. /package/dist/{src → esm/types/src}/runtime.d.ts +0 -0
  207. /package/dist/{src → esm/types/src}/state-manager.d.ts +0 -0
  208. /package/dist/{src → esm/types/src}/template-card-parser.d.ts +0 -0
  209. /package/dist/{src → esm/types/src}/timeout.d.ts +0 -0
package/dist/src/http.js DELETED
@@ -1,93 +0,0 @@
1
- import { ProxyAgent, fetch as undiciFetch } from "undici";
2
- const proxyDispatchers = new Map();
3
- /**
4
- * **getProxyDispatcher (获取代理 Dispatcher)**
5
- *
6
- * 缓存并复用 ProxyAgent,避免重复创建连接池。
7
- */
8
- function getProxyDispatcher(proxyUrl) {
9
- const existing = proxyDispatchers.get(proxyUrl);
10
- if (existing)
11
- return existing;
12
- const created = new ProxyAgent(proxyUrl);
13
- proxyDispatchers.set(proxyUrl, created);
14
- return created;
15
- }
16
- function mergeAbortSignal(params) {
17
- const signals = [];
18
- if (params.signal)
19
- signals.push(params.signal);
20
- if (params.timeoutMs && Number.isFinite(params.timeoutMs) && params.timeoutMs > 0) {
21
- signals.push(AbortSignal.timeout(params.timeoutMs));
22
- }
23
- if (!signals.length)
24
- return undefined;
25
- if (signals.length === 1)
26
- return signals[0];
27
- return AbortSignal.any(signals);
28
- }
29
- /**
30
- * **wecomFetch (统一 HTTP 请求)**
31
- *
32
- * 基于 `undici` 的 fetch 封装,自动处理 ProxyAgent 和 Timeout。
33
- * 所有对企业微信 API 的调用都应经过此函数。
34
- */
35
- export async function wecomFetch(input, init, opts) {
36
- const proxyUrl = opts?.proxyUrl?.trim() ?? "";
37
- const dispatcher = proxyUrl ? getProxyDispatcher(proxyUrl) : undefined;
38
- const initSignal = init?.signal ?? undefined;
39
- const signal = mergeAbortSignal({ signal: opts?.signal ?? initSignal, timeoutMs: opts?.timeoutMs });
40
- const headers = new Headers(init?.headers ?? {});
41
- if (!headers.has("User-Agent")) {
42
- headers.set("User-Agent", "OpenClaw/2.0 (WeCom-Agent)");
43
- }
44
- const nextInit = {
45
- ...(init ?? {}),
46
- ...(signal ? { signal } : {}),
47
- ...(dispatcher ? { dispatcher } : {}),
48
- headers,
49
- };
50
- try {
51
- return await undiciFetch(input, nextInit);
52
- }
53
- catch (err) {
54
- if (err instanceof Error && err.name === "TypeError" && err.message === "fetch failed") {
55
- const cause = err.cause;
56
- console.error(`[wecom-http] fetch failed: ${input} (proxy: ${proxyUrl || "none"})${cause ? ` - cause: ${String(cause)}` : ""}`);
57
- }
58
- throw err;
59
- }
60
- }
61
- /**
62
- * **readResponseBodyAsBuffer (读取响应 Body)**
63
- *
64
- * 将 Response Body 读取为 Buffer,支持最大字节限制以防止内存溢出。
65
- * 适用于下载媒体文件等场景。
66
- */
67
- export async function readResponseBodyAsBuffer(res, maxBytes) {
68
- if (!res.body)
69
- return Buffer.alloc(0);
70
- const limit = maxBytes && Number.isFinite(maxBytes) && maxBytes > 0 ? maxBytes : undefined;
71
- const chunks = [];
72
- let total = 0;
73
- const reader = res.body.getReader();
74
- while (true) {
75
- const { done, value } = await reader.read();
76
- if (done)
77
- break;
78
- if (!value)
79
- continue;
80
- total += value.byteLength;
81
- if (limit && total > limit) {
82
- try {
83
- await reader.cancel("body too large");
84
- }
85
- catch {
86
- // ignore
87
- }
88
- throw new Error(`response body too large (>${limit} bytes)`);
89
- }
90
- chunks.push(value);
91
- }
92
- return Buffer.concat(chunks.map((c) => Buffer.from(c)));
93
- }
@@ -1,4 +0,0 @@
1
- /**
2
- * 企业微信渠道类型定义
3
- */
4
- export {};
@@ -1,6 +0,0 @@
1
- /**
2
- * MCP 模块统一导出
3
- */
4
- export { createWeComMcpTool } from "./tool.js";
5
- export { sendJsonRpc, clearCategoryCache, McpRpcError, McpHttpError } from "./transport.js";
6
- export { cleanSchemaForGemini } from "./schema.js";
@@ -1,7 +0,0 @@
1
- /**
2
- * MCP call 拦截器类型定义
3
- *
4
- * 拦截器用于在 tools/call 调用前后注入特殊逻辑,
5
- * 如修改超时配置、变换响应结果等,避免在 tool.ts 中堆积 if/else。
6
- */
7
- export {};
@@ -1,23 +0,0 @@
1
- import type { OpenClawConfig, PluginRuntime } from "openclaw/plugin-sdk";
2
- import type { WecomAgentConfig, WecomBotConfig } from "../types/index.js";
3
- type WecomCommandAuthAccountConfig = Pick<WecomBotConfig, "dmPolicy" | "allowFrom"> | Pick<WecomAgentConfig, "dmPolicy" | "allowFrom">;
4
- export declare function resolveWecomCommandAuthorization(params: {
5
- core: PluginRuntime;
6
- cfg: OpenClawConfig;
7
- accountConfig: WecomCommandAuthAccountConfig;
8
- rawBody: string;
9
- senderUserId: string;
10
- }): Promise<{
11
- shouldComputeAuth: boolean;
12
- dmPolicy: "pairing" | "allowlist" | "open" | "disabled";
13
- senderAllowed: boolean;
14
- authorizerConfigured: boolean;
15
- commandAuthorized: boolean | undefined;
16
- effectiveAllowFrom: string[];
17
- }>;
18
- export declare function buildWecomUnauthorizedCommandPrompt(params: {
19
- senderUserId: string;
20
- dmPolicy: "pairing" | "allowlist" | "open" | "disabled";
21
- scope: "bot" | "agent";
22
- }): string;
23
- export {};
@@ -1,73 +0,0 @@
1
- function normalizeWecomAllowFromEntry(raw) {
2
- return raw
3
- .trim()
4
- .toLowerCase()
5
- .replace(/^wecom:/, "")
6
- .replace(/^user:/, "")
7
- .replace(/^userid:/, "");
8
- }
9
- function isWecomSenderAllowed(senderUserId, allowFrom) {
10
- const list = allowFrom.map((entry) => normalizeWecomAllowFromEntry(entry)).filter(Boolean);
11
- if (list.includes("*"))
12
- return true;
13
- const normalizedSender = normalizeWecomAllowFromEntry(senderUserId);
14
- if (!normalizedSender)
15
- return false;
16
- return list.includes(normalizedSender);
17
- }
18
- export async function resolveWecomCommandAuthorization(params) {
19
- const { core, cfg, accountConfig, rawBody, senderUserId } = params;
20
- const dmPolicy = (accountConfig.dmPolicy ?? "pairing");
21
- const configAllowFrom = (accountConfig.allowFrom ?? []).map((v) => String(v));
22
- const shouldComputeAuth = core.channel.commands.shouldComputeCommandAuthorized(rawBody, cfg);
23
- // WeCom channel currently does NOT support the `openclaw pairing` CLI workflow
24
- // ("Channel wecom does not support pairing"). So we must not rely on pairing
25
- // store approvals for command authorization here.
26
- //
27
- // Policy semantics:
28
- // - open: commands are allowed for everyone by default (unless higher-level access-groups deny).
29
- // - allowlist: commands require allowFrom entries.
30
- // - pairing: treated the same as allowlist for WeCom (since pairing CLI is unsupported).
31
- const effectiveAllowFrom = dmPolicy === "open" ? ["*"] : configAllowFrom;
32
- const senderAllowed = isWecomSenderAllowed(senderUserId, effectiveAllowFrom);
33
- const allowAllConfigured = effectiveAllowFrom.some((entry) => normalizeWecomAllowFromEntry(entry) === "*");
34
- const authorizerConfigured = allowAllConfigured || effectiveAllowFrom.length > 0;
35
- const useAccessGroups = cfg.commands?.useAccessGroups !== false;
36
- const commandAuthorized = shouldComputeAuth
37
- ? core.channel.commands.resolveCommandAuthorizedFromAuthorizers({
38
- useAccessGroups,
39
- authorizers: [{ configured: authorizerConfigured, allowed: senderAllowed }],
40
- })
41
- : undefined;
42
- return {
43
- shouldComputeAuth,
44
- dmPolicy,
45
- senderAllowed,
46
- authorizerConfigured,
47
- commandAuthorized,
48
- effectiveAllowFrom,
49
- };
50
- }
51
- export function buildWecomUnauthorizedCommandPrompt(params) {
52
- const user = params.senderUserId || "unknown";
53
- const policy = params.dmPolicy;
54
- const scopeLabel = params.scope === "bot" ? "Bot(智能机器人)" : "Agent(自建应用)";
55
- const dmPrefix = params.scope === "bot" ? "channels.wecom.bot" : "channels.wecom.agent";
56
- const allowCmd = (value) => `openclaw config set ${dmPrefix}.allowFrom '${value}'`;
57
- const policyCmd = (value) => `openclaw config set ${dmPrefix}.dmPolicy "${value}"`;
58
- if (policy === "disabled") {
59
- return [
60
- `无权限执行命令(${scopeLabel} 已禁用:dmPolicy=disabled)`,
61
- `触发者:${user}`,
62
- `管理员:${policyCmd("open")}(全放开)或 ${policyCmd("allowlist")}(白名单)`,
63
- ].join("\n");
64
- }
65
- // WeCom 不支持 pairing CLI,因此这里统一给出“open / allowlist”两种明确的配置指令
66
- return [
67
- `无权限执行命令(入口:${scopeLabel},userid:${user})`,
68
- `管理员全放开:${policyCmd("open")}`,
69
- `管理员放行该用户:${policyCmd("allowlist")}`,
70
- `然后设置白名单:${allowCmd(JSON.stringify([user]))}`,
71
- `如果仍被拦截:检查 commands.useAccessGroups/访问组`,
72
- ].join("\n");
73
- }
@@ -1,46 +0,0 @@
1
- /**
2
- * WeCom XML 解析器
3
- * 用于 Agent 模式解析 XML 格式消息
4
- */
5
- import type { WecomAgentInboundMessage } from "../types/index.js";
6
- /**
7
- * 解析 XML 字符串为消息对象
8
- */
9
- export declare function parseXml(xml: string): WecomAgentInboundMessage;
10
- /**
11
- * 从 XML 中提取消息类型
12
- */
13
- export declare function extractMsgType(msg: WecomAgentInboundMessage): string;
14
- /**
15
- * 从 XML 中提取发送者 ID
16
- */
17
- export declare function extractFromUser(msg: WecomAgentInboundMessage): string;
18
- /**
19
- * 从 XML 中提取文件名(主要用于 file 消息)
20
- */
21
- export declare function extractFileName(msg: WecomAgentInboundMessage): string | undefined;
22
- /**
23
- * 从 XML 中提取接收者 ID (CorpID)
24
- */
25
- export declare function extractToUser(msg: WecomAgentInboundMessage): string;
26
- /**
27
- * 从 XML 中提取群聊 ID
28
- */
29
- export declare function extractChatId(msg: WecomAgentInboundMessage): string | undefined;
30
- /**
31
- * 从 XML 中提取 AgentID(兼容 AgentID/agentid 等大小写)
32
- */
33
- export declare function extractAgentId(msg: WecomAgentInboundMessage): string | number | undefined;
34
- /**
35
- * 从 XML 中提取消息内容
36
- */
37
- export declare function extractContent(msg: WecomAgentInboundMessage): string;
38
- /**
39
- * 从 XML 中提取媒体 ID (Image, Voice, Video)
40
- * 根据官方文档,MediaId 在 Agent 回调中直接位于根节点
41
- */
42
- export declare function extractMediaId(msg: WecomAgentInboundMessage): string | undefined;
43
- /**
44
- * 从 XML 中提取 MsgId(用于去重)
45
- */
46
- export declare function extractMsgId(msg: WecomAgentInboundMessage): string | undefined;
@@ -1,210 +0,0 @@
1
- /**
2
- * WeCom XML 解析器
3
- * 用于 Agent 模式解析 XML 格式消息
4
- */
5
- import { XMLParser } from "fast-xml-parser";
6
- const xmlParser = new XMLParser({
7
- ignoreAttributes: false,
8
- trimValues: true,
9
- processEntities: false,
10
- parseTagValue: false,
11
- parseAttributeValue: false,
12
- });
13
- /**
14
- * 解析 XML 字符串为消息对象
15
- */
16
- export function parseXml(xml) {
17
- const obj = xmlParser.parse(xml);
18
- const root = obj?.xml ?? obj;
19
- return root ?? {};
20
- }
21
- /**
22
- * 从 XML 中提取消息类型
23
- */
24
- export function extractMsgType(msg) {
25
- return String(msg.MsgType ?? "").toLowerCase();
26
- }
27
- /**
28
- * 从 XML 中提取发送者 ID
29
- */
30
- export function extractFromUser(msg) {
31
- return String(msg.FromUserName ?? "");
32
- }
33
- /**
34
- * 从 XML 中提取文件名(主要用于 file 消息)
35
- */
36
- export function extractFileName(msg) {
37
- const raw = msg.FileName ?? msg.Filename ?? msg.fileName ?? msg.filename;
38
- if (raw == null)
39
- return undefined;
40
- if (typeof raw === "string")
41
- return raw.trim() || undefined;
42
- if (typeof raw === "number" || typeof raw === "boolean" || typeof raw === "bigint")
43
- return String(raw);
44
- if (Array.isArray(raw)) {
45
- const merged = raw.map((v) => (v == null ? "" : String(v))).join("\n").trim();
46
- return merged || undefined;
47
- }
48
- if (typeof raw === "object") {
49
- const obj = raw;
50
- const text = (typeof obj["#text"] === "string" ? obj["#text"] :
51
- typeof obj["_text"] === "string" ? obj["_text"] :
52
- typeof obj["text"] === "string" ? obj["text"] : undefined);
53
- if (text && text.trim())
54
- return text.trim();
55
- }
56
- const s = String(raw);
57
- return s.trim() || undefined;
58
- }
59
- /**
60
- * 从 XML 中提取接收者 ID (CorpID)
61
- */
62
- export function extractToUser(msg) {
63
- return String(msg.ToUserName ?? "");
64
- }
65
- /**
66
- * 从 XML 中提取群聊 ID
67
- */
68
- export function extractChatId(msg) {
69
- return msg.ChatId ? String(msg.ChatId) : undefined;
70
- }
71
- /**
72
- * 从 XML 中提取 AgentID(兼容 AgentID/agentid 等大小写)
73
- */
74
- export function extractAgentId(msg) {
75
- const raw = msg.AgentID ??
76
- msg.AgentId ??
77
- msg.agentid ??
78
- msg.agentId;
79
- if (raw == null)
80
- return undefined;
81
- if (typeof raw === "string")
82
- return raw.trim() || undefined;
83
- if (typeof raw === "number")
84
- return raw;
85
- const asString = String(raw).trim();
86
- return asString || undefined;
87
- }
88
- /**
89
- * 从 XML 中提取消息内容
90
- */
91
- export function extractContent(msg) {
92
- const msgType = extractMsgType(msg);
93
- const asText = (value) => {
94
- if (value == null)
95
- return "";
96
- if (typeof value === "string")
97
- return value;
98
- if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint")
99
- return String(value);
100
- if (Array.isArray(value))
101
- return value.map(asText).filter(Boolean).join("\n");
102
- if (typeof value === "object") {
103
- const obj = value;
104
- // fast-xml-parser 在某些情况下(例如带属性)会把文本放在 "#text"
105
- if (typeof obj["#text"] === "string")
106
- return obj["#text"];
107
- if (typeof obj["_text"] === "string")
108
- return obj["_text"];
109
- if (typeof obj["text"] === "string")
110
- return obj["text"];
111
- try {
112
- return JSON.stringify(obj);
113
- }
114
- catch {
115
- return String(value);
116
- }
117
- }
118
- return String(value);
119
- };
120
- switch (msgType) {
121
- case "text":
122
- return asText(msg.Content);
123
- case "voice":
124
- // 语音识别结果
125
- return asText(msg.Recognition) || "[语音消息]";
126
- case "image":
127
- return `[图片] ${asText(msg.PicUrl)}`;
128
- case "file":
129
- return "[文件消息]";
130
- case "video":
131
- return "[视频消息]";
132
- case "location":
133
- return `[位置] ${asText(msg.Label)} (${asText(msg.Location_X)}, ${asText(msg.Location_Y)})`;
134
- case "link":
135
- return `[链接] ${asText(msg.Title)}\n${asText(msg.Description)}\n${asText(msg.Url)}`;
136
- case "event":
137
- return `[事件] ${asText(msg.Event)} - ${asText(msg.EventKey)}`;
138
- default:
139
- return `[${msgType || "未知消息类型"}]`;
140
- }
141
- }
142
- /**
143
- * 从 XML 中提取媒体 ID (Image, Voice, Video)
144
- * 根据官方文档,MediaId 在 Agent 回调中直接位于根节点
145
- */
146
- export function extractMediaId(msg) {
147
- const raw = msg.MediaId ?? msg.MediaID ?? msg.mediaid ?? msg.mediaId;
148
- if (raw == null)
149
- return undefined;
150
- if (typeof raw === "string")
151
- return raw.trim() || undefined;
152
- if (typeof raw === "number" || typeof raw === "boolean" || typeof raw === "bigint")
153
- return String(raw);
154
- if (Array.isArray(raw)) {
155
- const merged = raw.map((v) => (v == null ? "" : String(v))).join("\n").trim();
156
- return merged || undefined;
157
- }
158
- if (typeof raw === "object") {
159
- const obj = raw;
160
- const text = (typeof obj["#text"] === "string" ? obj["#text"] :
161
- typeof obj["_text"] === "string" ? obj["_text"] :
162
- typeof obj["text"] === "string" ? obj["text"] : undefined);
163
- if (text && text.trim())
164
- return text.trim();
165
- try {
166
- const s = JSON.stringify(obj);
167
- return s.trim() || undefined;
168
- }
169
- catch {
170
- const s = String(raw);
171
- return s.trim() || undefined;
172
- }
173
- }
174
- const s = String(raw);
175
- return s.trim() || undefined;
176
- }
177
- /**
178
- * 从 XML 中提取 MsgId(用于去重)
179
- */
180
- export function extractMsgId(msg) {
181
- const raw = msg.MsgId ?? msg.MsgID ?? msg.msgid ?? msg.msgId;
182
- if (raw == null)
183
- return undefined;
184
- if (typeof raw === "string")
185
- return raw.trim() || undefined;
186
- if (typeof raw === "number" || typeof raw === "boolean" || typeof raw === "bigint")
187
- return String(raw);
188
- if (Array.isArray(raw)) {
189
- const merged = raw.map((v) => (v == null ? "" : String(v))).join("\n").trim();
190
- return merged || undefined;
191
- }
192
- if (typeof raw === "object") {
193
- const obj = raw;
194
- const text = (typeof obj["#text"] === "string" ? obj["#text"] :
195
- typeof obj["_text"] === "string" ? obj["_text"] :
196
- typeof obj["text"] === "string" ? obj["text"] : undefined);
197
- if (text && text.trim())
198
- return text.trim();
199
- try {
200
- const s = JSON.stringify(obj);
201
- return s.trim() || undefined;
202
- }
203
- catch {
204
- const s = String(raw);
205
- return s.trim() || undefined;
206
- }
207
- }
208
- const s = String(raw);
209
- return s.trim() || undefined;
210
- }
@@ -1,35 +0,0 @@
1
- /**
2
- * WeCom Target Resolver (企业微信目标解析器)
3
- *
4
- * 解析 OpenClaw 的 `to` 字段(原始目标字符串),将其转换为企业微信支持的具体接收对象。
5
- * 支持显式前缀 (party:, tag: 等) 和基于规则的启发式推断。
6
- *
7
- * **关于“目标发送”与“消息记录”的对应关系 (Target vs Inbound):**
8
- * - **发送 (Outbound)**: 支持一对多广播 (Party/Tag)。
9
- * 例如发送给 `party:1`,消息会触达该部门下所有成员。
10
- * - **接收 (Inbound)**: 总是来自具体的 **用户 (User)** 或 **群聊 (Chat)**。
11
- * 当成员回复部门广播消息时,可以视为一个新的单聊会话或在该成员的现有单聊中回复。
12
- * 因此,Outbound Target (如 Party) 与 Inbound Source (User) 不需要也不可能 1:1 强匹配。
13
- * 广播是“发后即忘” (Fire-and-Forget) 的通知模式,而回复是具体的会话模式。
14
- */
15
- export interface WecomTarget {
16
- touser?: string;
17
- toparty?: string;
18
- totag?: string;
19
- chatid?: string;
20
- }
21
- /**
22
- * Parses a raw target string into a WeComTarget object.
23
- * 解析原始目标字符串为 WeComTarget 对象。
24
- *
25
- * 逻辑:
26
- * 1. 移除标准命名空间前缀 (wecom:, qywx: 等)。
27
- * 2. 检查显式类型前缀 (party:, tag:, group:, user:)。
28
- * 3. 启发式回退 (无前缀时):
29
- * - 以 "wr" 或 "wc" 开头 -> Chat ID (群聊)
30
- * - 纯数字 -> Party ID (部门)
31
- * - 其他 -> User ID (用户)
32
- *
33
- * @param raw - The raw target string (e.g. "party:1", "zhangsan", "wecom:wr123")
34
- */
35
- export declare function resolveWecomTarget(raw: string | undefined): WecomTarget | undefined;
@@ -1,67 +0,0 @@
1
- /**
2
- * WeCom Target Resolver (企业微信目标解析器)
3
- *
4
- * 解析 OpenClaw 的 `to` 字段(原始目标字符串),将其转换为企业微信支持的具体接收对象。
5
- * 支持显式前缀 (party:, tag: 等) 和基于规则的启发式推断。
6
- *
7
- * **关于“目标发送”与“消息记录”的对应关系 (Target vs Inbound):**
8
- * - **发送 (Outbound)**: 支持一对多广播 (Party/Tag)。
9
- * 例如发送给 `party:1`,消息会触达该部门下所有成员。
10
- * - **接收 (Inbound)**: 总是来自具体的 **用户 (User)** 或 **群聊 (Chat)**。
11
- * 当成员回复部门广播消息时,可以视为一个新的单聊会话或在该成员的现有单聊中回复。
12
- * 因此,Outbound Target (如 Party) 与 Inbound Source (User) 不需要也不可能 1:1 强匹配。
13
- * 广播是“发后即忘” (Fire-and-Forget) 的通知模式,而回复是具体的会话模式。
14
- */
15
- /**
16
- * Parses a raw target string into a WeComTarget object.
17
- * 解析原始目标字符串为 WeComTarget 对象。
18
- *
19
- * 逻辑:
20
- * 1. 移除标准命名空间前缀 (wecom:, qywx: 等)。
21
- * 2. 检查显式类型前缀 (party:, tag:, group:, user:)。
22
- * 3. 启发式回退 (无前缀时):
23
- * - 以 "wr" 或 "wc" 开头 -> Chat ID (群聊)
24
- * - 纯数字 -> Party ID (部门)
25
- * - 其他 -> User ID (用户)
26
- *
27
- * @param raw - The raw target string (e.g. "party:1", "zhangsan", "wecom:wr123")
28
- */
29
- export function resolveWecomTarget(raw) {
30
- if (!raw?.trim())
31
- return undefined;
32
- // 1. Remove standard namespace prefixes (移除标准命名空间前缀)
33
- let clean = raw.trim().replace(/^(wecom-agent|wecom|wechatwork|wework|qywx):/i, "");
34
- // 2. Explicit Type Prefixes (显式类型前缀)
35
- if (/^party:/i.test(clean)) {
36
- return { toparty: clean.replace(/^party:/i, "").trim() };
37
- }
38
- if (/^dept:/i.test(clean)) {
39
- return { toparty: clean.replace(/^dept:/i, "").trim() };
40
- }
41
- if (/^tag:/i.test(clean)) {
42
- return { totag: clean.replace(/^tag:/i, "").trim() };
43
- }
44
- if (/^group:/i.test(clean)) {
45
- return { chatid: clean.replace(/^group:/i, "").trim() };
46
- }
47
- if (/^chat:/i.test(clean)) {
48
- return { chatid: clean.replace(/^chat:/i, "").trim() };
49
- }
50
- if (/^user:/i.test(clean)) {
51
- return { touser: clean.replace(/^user:/i, "").trim() };
52
- }
53
- // 3. Heuristics (启发式规则)
54
- // Chat ID typically starts with 'wr' or 'wc'
55
- // 群聊 ID 通常以 'wr' (外部群) 或 'wc' 开头
56
- if (/^(wr|wc)/i.test(clean)) {
57
- return { chatid: clean };
58
- }
59
- // Pure digits are likely Department IDs (Parties)
60
- // 纯数字优先被视为部门 ID (Parties),方便运维配置 (如 "1" 代表根部门)
61
- // 如果必须要发送给纯数字 ID 的用户,请使用显式前缀 "user:1001"
62
- if (/^\d+$/.test(clean)) {
63
- return { toparty: clean };
64
- }
65
- // Default to User (默认为用户)
66
- return { touser: clean };
67
- }
@@ -1,55 +0,0 @@
1
- /**
2
- * 模板卡片管理器
3
- *
4
- * 负责:
5
- * - 模板卡片缓存管理(内存级,带 TTL 和大小限制)
6
- * - 卡片交互事件处理(更新卡片 UI 状态)
7
- * - 模板卡片发送(通过 wsClient.sendMessage 主动推送)
8
- * - 从 LLM 回复中检测并处理模板卡片
9
- */
10
- import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env";
11
- import type { WSClient, WsFrame, TemplateCard } from "@wecom/aibot-node-sdk";
12
- import type { ResolvedWeComAccount } from "./utils.js";
13
- import type { MessageState, ExtractedTemplateCard } from "./interface.js";
14
- export declare function saveTemplateCardToCache(params: {
15
- accountId: string;
16
- templateCard: TemplateCard;
17
- runtime: RuntimeEnv;
18
- }): void;
19
- export declare function getTemplateCardFromCache(accountId: string, taskId: string): TemplateCard | undefined;
20
- export declare function updateTemplateCardOnEvent(params: {
21
- frame: WsFrame;
22
- accountId: string;
23
- runtime: RuntimeEnv;
24
- wsClient: WSClient;
25
- }): Promise<void>;
26
- /**
27
- * 逐个发送已提取的模板卡片(通过 wsClient.sendMessage 主动推送)
28
- *
29
- * 发送失败不阻塞流程,仅记录错误日志。
30
- */
31
- export declare function sendTemplateCards(params: {
32
- wsClient: WSClient;
33
- frame: WsFrame;
34
- state: MessageState;
35
- account: ResolvedWeComAccount;
36
- runtime: RuntimeEnv;
37
- cards: ExtractedTemplateCard[];
38
- }): Promise<void>;
39
- /**
40
- * 从累积文本中检测并发送模板卡片。
41
- *
42
- * 在 finishThinkingStream 之前调用,将卡片处理和流关闭解耦。
43
- *
44
- * @returns 移除卡片代码块后的剩余文本(如果没有卡片则返回 null,表示无需修改)
45
- */
46
- export declare function processTemplateCardsIfNeeded(params: {
47
- wsClient: WSClient;
48
- frame: WsFrame;
49
- state: MessageState;
50
- account: ResolvedWeComAccount;
51
- runtime: RuntimeEnv;
52
- }): Promise<{
53
- remainingText: string;
54
- cardsDetected: boolean;
55
- } | null>;