@yanhaidao/wecom 2.4.160 → 2.5.110

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 (313) hide show
  1. package/dist/index.js +68 -0
  2. package/dist/src/accounts.js +20 -0
  3. package/dist/src/agent/handler.js +895 -0
  4. package/dist/src/agent/index.js +5 -0
  5. package/dist/src/app/account-runtime.js +216 -0
  6. package/dist/src/app/bootstrap.js +19 -0
  7. package/dist/src/app/index.js +118 -0
  8. package/dist/src/capability/agent/delivery-service.js +63 -0
  9. package/dist/src/capability/agent/fallback-policy.js +6 -0
  10. package/dist/src/capability/agent/ingress-service.js +33 -0
  11. package/dist/src/capability/agent/upstream-delivery-service.js +71 -0
  12. package/dist/src/capability/bot/dispatch-config.js +45 -0
  13. package/dist/src/capability/bot/fallback-delivery.js +147 -0
  14. package/dist/src/capability/bot/local-path-delivery.js +178 -0
  15. package/dist/src/capability/bot/sandbox-media.js +138 -0
  16. package/dist/src/capability/bot/service.js +49 -0
  17. package/dist/src/capability/bot/stream-delivery.js +321 -0
  18. package/dist/src/capability/bot/stream-finalizer.js +81 -0
  19. package/dist/src/capability/bot/stream-orchestrator.js +318 -0
  20. package/dist/src/capability/bot/types.js +1 -0
  21. package/{src/capability/calendar/client.ts → dist/src/capability/calendar/client.js} +118 -241
  22. package/{src/capability/calendar/schema.ts → dist/src/capability/calendar/schema.js} +0 -38
  23. package/dist/src/capability/calendar/tool.js +365 -0
  24. package/dist/src/capability/calendar/types.js +12 -0
  25. package/{src/capability/doc/client.ts → dist/src/capability/doc/client.js} +370 -605
  26. package/{src/capability/doc/schema.ts → dist/src/capability/doc/schema.js} +345 -394
  27. package/dist/src/capability/doc/tool.js +1556 -0
  28. package/dist/src/capability/doc/types.js +113 -0
  29. package/dist/src/capability/mcp/index.js +3 -0
  30. package/dist/src/capability/mcp/schema.js +102 -0
  31. package/dist/src/capability/mcp/tool.js +146 -0
  32. package/dist/src/capability/mcp/transport.js +293 -0
  33. package/dist/src/channel.js +224 -0
  34. package/dist/src/config/accounts.js +236 -0
  35. package/dist/src/config/derived-paths.js +31 -0
  36. package/dist/src/config/index.js +7 -0
  37. package/dist/src/config/media.js +110 -0
  38. package/dist/src/config/network.js +32 -0
  39. package/dist/src/config/routing.js +20 -0
  40. package/dist/src/config/runtime-config.js +25 -0
  41. package/dist/src/config/schema.js +4 -0
  42. package/{src/config-schema.ts → dist/src/config-schema.js} +1 -1
  43. package/dist/src/context-store.js +219 -0
  44. package/{src/crypto/aes.ts → dist/src/crypto/aes.js} +11 -28
  45. package/dist/src/crypto/index.js +9 -0
  46. package/{src/crypto/signature.ts → dist/src/crypto/signature.js} +3 -18
  47. package/{src/crypto/xml.ts → dist/src/crypto/xml.js} +3 -11
  48. package/dist/src/crypto.js +145 -0
  49. package/dist/src/domain/models.js +1 -0
  50. package/dist/src/domain/policies.js +32 -0
  51. package/{src/dynamic-agent.ts → dist/src/dynamic-agent.js} +36 -73
  52. package/dist/src/gateway-monitor.js +139 -0
  53. package/dist/src/http.js +114 -0
  54. package/{src/media.ts → dist/src/media.js} +21 -40
  55. package/dist/src/monitor/limits.js +7 -0
  56. package/dist/src/monitor/state.js +28 -0
  57. package/dist/src/monitor.js +84 -0
  58. package/dist/src/observability/audit-log.js +30 -0
  59. package/dist/src/observability/legacy-operational-event-store.js +22 -0
  60. package/dist/src/observability/raw-envelope-log.js +24 -0
  61. package/dist/src/observability/status-registry.js +9 -0
  62. package/dist/src/observability/transport-session-view.js +14 -0
  63. package/dist/src/onboarding.js +546 -0
  64. package/dist/src/outbound.js +557 -0
  65. package/dist/src/runtime/dispatcher.js +57 -0
  66. package/{src/runtime/index.ts → dist/src/runtime/index.js} +0 -1
  67. package/dist/src/runtime/outbound-intent.js +1 -0
  68. package/dist/src/runtime/reply-orchestrator.js +38 -0
  69. package/dist/src/runtime/routing-bridge.js +26 -0
  70. package/dist/src/runtime/session-manager.js +112 -0
  71. package/dist/src/runtime/source-registry.js +174 -0
  72. package/dist/src/runtime.js +1 -0
  73. package/dist/src/shared/command-auth.js +57 -0
  74. package/{src/shared/index.ts → dist/src/shared/index.js} +0 -1
  75. package/dist/src/shared/media-asset.js +65 -0
  76. package/dist/src/shared/media-service.js +59 -0
  77. package/dist/src/shared/media-types.js +1 -0
  78. package/{src/shared/xml-parser.ts → dist/src/shared/xml-parser.js} +72 -63
  79. package/dist/src/store/active-reply-store.js +41 -0
  80. package/dist/src/store/interfaces.js +1 -0
  81. package/dist/src/store/memory-store.js +33 -0
  82. package/dist/src/store/stream-batch-store.js +319 -0
  83. package/{src/target.ts → dist/src/target.js} +15 -48
  84. package/dist/src/transport/agent-api/client.js +168 -0
  85. package/dist/src/transport/agent-api/core.js +337 -0
  86. package/dist/src/transport/agent-api/delivery.js +28 -0
  87. package/dist/src/transport/agent-api/media-upload.js +4 -0
  88. package/dist/src/transport/agent-api/reply.js +24 -0
  89. package/dist/src/transport/agent-api/upstream-delivery.js +30 -0
  90. package/dist/src/transport/agent-api/upstream-media-upload.js +46 -0
  91. package/dist/src/transport/agent-api/upstream-reply.js +26 -0
  92. package/dist/src/transport/agent-callback/http-handler.js +30 -0
  93. package/dist/src/transport/agent-callback/inbound.js +4 -0
  94. package/dist/src/transport/agent-callback/reply.js +8 -0
  95. package/dist/src/transport/agent-callback/request-handler.js +189 -0
  96. package/dist/src/transport/agent-callback/session.js +15 -0
  97. package/dist/src/transport/bot-webhook/active-reply.js +27 -0
  98. package/dist/src/transport/bot-webhook/http-handler.js +31 -0
  99. package/dist/src/transport/bot-webhook/inbound-normalizer.js +496 -0
  100. package/dist/src/transport/bot-webhook/inbound.js +4 -0
  101. package/dist/src/transport/bot-webhook/message-shape.js +98 -0
  102. package/dist/src/transport/bot-webhook/protocol.js +124 -0
  103. package/dist/src/transport/bot-webhook/reply.js +9 -0
  104. package/dist/src/transport/bot-webhook/request-handler.js +285 -0
  105. package/dist/src/transport/bot-webhook/session.js +15 -0
  106. package/dist/src/transport/bot-ws/inbound.js +147 -0
  107. package/dist/src/transport/bot-ws/media.js +236 -0
  108. package/dist/src/transport/bot-ws/reply.js +310 -0
  109. package/dist/src/transport/bot-ws/sdk-adapter.js +257 -0
  110. package/dist/src/transport/bot-ws/session.js +15 -0
  111. package/dist/src/transport/http/common.js +78 -0
  112. package/dist/src/transport/http/registry.js +71 -0
  113. package/dist/src/transport/http/request-handler.js +51 -0
  114. package/{src/transport/index.ts → dist/src/transport/index.js} +2 -10
  115. package/dist/src/types/account.js +1 -0
  116. package/dist/src/types/config.js +1 -0
  117. package/dist/src/types/constants.js +28 -0
  118. package/dist/src/types/events.js +1 -0
  119. package/dist/src/types/index.js +1 -0
  120. package/dist/src/types/legacy-stream.js +1 -0
  121. package/dist/src/types/message.js +5 -0
  122. package/dist/src/types/runtime-context.js +1 -0
  123. package/dist/src/types/runtime.js +1 -0
  124. package/dist/src/types.js +1 -0
  125. package/dist/src/upstream/index.js +111 -0
  126. package/dist/src/wecom_msg_adapter/markdown_adapter.js +280 -0
  127. package/openclaw.plugin.json +15 -0
  128. package/package.json +18 -1
  129. package/.github/workflows/release.yml +0 -143
  130. package/GOVERNANCE.md +0 -26
  131. package/SKILLS_CAL.md +0 -895
  132. package/SKILLS_DOC.md +0 -2288
  133. package/UPSTREAM_CONFIG.md +0 -170
  134. package/UPSTREAM_PLAN.md +0 -175
  135. package/assets/01.bot-add.png +0 -0
  136. package/assets/01.bot-setp2.png +0 -0
  137. package/assets/01.image.jpg +0 -0
  138. package/assets/02.agent.add.png +0 -0
  139. package/assets/02.agent.api-set.png +0 -0
  140. package/assets/02.image.jpg +0 -0
  141. package/assets/03.agent.page.png +0 -0
  142. package/assets/03.bot.page.png +0 -0
  143. package/assets/link-me.jpg +0 -0
  144. package/assets/register.png +0 -0
  145. package/changelog/v2.2.28.md +0 -70
  146. package/changelog/v2.3.10.md +0 -17
  147. package/changelog/v2.3.11.md +0 -19
  148. package/changelog/v2.3.12.md +0 -25
  149. package/changelog/v2.3.13.md +0 -19
  150. package/changelog/v2.3.14.md +0 -48
  151. package/changelog/v2.3.15.md +0 -15
  152. package/changelog/v2.3.16.md +0 -11
  153. package/changelog/v2.3.18.md +0 -22
  154. package/changelog/v2.3.19.md +0 -73
  155. package/changelog/v2.3.2.md +0 -28
  156. package/changelog/v2.3.26.md +0 -21
  157. package/changelog/v2.3.27.md +0 -33
  158. package/changelog/v2.3.4.md +0 -20
  159. package/changelog/v2.3.9.md +0 -22
  160. package/changelog/v2.4.12.md +0 -37
  161. package/changelog/v2.4.16.md +0 -19
  162. package/compat-single-account.md +0 -148
  163. package/index.test.ts +0 -38
  164. package/scripts/test-proxy.ts +0 -70
  165. package/src/accounts.ts +0 -34
  166. package/src/agent/api-client.upload.test.ts +0 -109
  167. package/src/agent/handler.event-filter.test.ts +0 -100
  168. package/src/agent/handler.ts +0 -1105
  169. package/src/agent/index.ts +0 -12
  170. package/src/app/account-runtime.ts +0 -276
  171. package/src/app/bootstrap.ts +0 -29
  172. package/src/app/index.ts +0 -192
  173. package/src/capability/agent/delivery-service.ts +0 -87
  174. package/src/capability/agent/fallback-policy.ts +0 -13
  175. package/src/capability/agent/ingress-service.ts +0 -38
  176. package/src/capability/agent/upstream-delivery-service.ts +0 -96
  177. package/src/capability/bot/dispatch-config.ts +0 -47
  178. package/src/capability/bot/fallback-delivery.ts +0 -178
  179. package/src/capability/bot/local-path-delivery.ts +0 -215
  180. package/src/capability/bot/sandbox-media.test.ts +0 -221
  181. package/src/capability/bot/sandbox-media.ts +0 -176
  182. package/src/capability/bot/service.ts +0 -56
  183. package/src/capability/bot/stream-delivery.ts +0 -379
  184. package/src/capability/bot/stream-finalizer.ts +0 -120
  185. package/src/capability/bot/stream-orchestrator.ts +0 -371
  186. package/src/capability/bot/types.ts +0 -8
  187. package/src/capability/calendar/SKILLS_CHECKLIST.md +0 -251
  188. package/src/capability/calendar/tool.ts +0 -417
  189. package/src/capability/calendar/types.ts +0 -309
  190. package/src/capability/doc/tool.ts +0 -1629
  191. package/src/capability/doc/types.ts +0 -792
  192. package/src/capability/mcp/index.ts +0 -10
  193. package/src/capability/mcp/schema.ts +0 -107
  194. package/src/capability/mcp/tool.ts +0 -174
  195. package/src/capability/mcp/transport.ts +0 -394
  196. package/src/channel.config.test.ts +0 -147
  197. package/src/channel.lifecycle.test.ts +0 -255
  198. package/src/channel.meta.test.ts +0 -26
  199. package/src/channel.ts +0 -256
  200. package/src/config/accounts.resolve.test.ts +0 -75
  201. package/src/config/accounts.ts +0 -296
  202. package/src/config/derived-paths.test.ts +0 -111
  203. package/src/config/derived-paths.ts +0 -41
  204. package/src/config/index.ts +0 -26
  205. package/src/config/media.test.ts +0 -113
  206. package/src/config/media.ts +0 -139
  207. package/src/config/network.ts +0 -53
  208. package/src/config/routing.test.ts +0 -88
  209. package/src/config/routing.ts +0 -26
  210. package/src/config/runtime-config.ts +0 -46
  211. package/src/config/schema.ts +0 -90
  212. package/src/context-store.ts +0 -297
  213. package/src/crypto/index.ts +0 -24
  214. package/src/crypto.test.ts +0 -32
  215. package/src/crypto.ts +0 -176
  216. package/src/domain/models.ts +0 -7
  217. package/src/domain/policies.ts +0 -36
  218. package/src/dynamic-agent.account-scope.test.ts +0 -17
  219. package/src/gateway-monitor.ts +0 -181
  220. package/src/http.ts +0 -145
  221. package/src/media.test.ts +0 -82
  222. package/src/monitor/limits.ts +0 -7
  223. package/src/monitor/state.queue.test.ts +0 -185
  224. package/src/monitor/state.ts +0 -34
  225. package/src/monitor.active.test.ts +0 -245
  226. package/src/monitor.inbound-filter.test.ts +0 -63
  227. package/src/monitor.integration.test.ts +0 -208
  228. package/src/monitor.ts +0 -121
  229. package/src/monitor.webhook.test.ts +0 -774
  230. package/src/observability/audit-log.ts +0 -48
  231. package/src/observability/legacy-operational-event-store.ts +0 -36
  232. package/src/observability/raw-envelope-log.ts +0 -28
  233. package/src/observability/status-registry.ts +0 -13
  234. package/src/observability/transport-session-view.ts +0 -14
  235. package/src/onboarding.test.ts +0 -336
  236. package/src/onboarding.ts +0 -704
  237. package/src/outbound.test.ts +0 -1271
  238. package/src/outbound.ts +0 -746
  239. package/src/runtime/dispatcher.ts +0 -71
  240. package/src/runtime/outbound-intent.ts +0 -4
  241. package/src/runtime/reply-orchestrator.test.ts +0 -71
  242. package/src/runtime/reply-orchestrator.ts +0 -67
  243. package/src/runtime/routing-bridge.test.ts +0 -115
  244. package/src/runtime/routing-bridge.ts +0 -44
  245. package/src/runtime/session-manager.test.ts +0 -174
  246. package/src/runtime/session-manager.ts +0 -139
  247. package/src/runtime/source-registry.ts +0 -249
  248. package/src/runtime.ts +0 -14
  249. package/src/shared/command-auth.ts +0 -87
  250. package/src/shared/media-asset.ts +0 -78
  251. package/src/shared/media-service.test.ts +0 -111
  252. package/src/shared/media-service.ts +0 -84
  253. package/src/shared/media-types.ts +0 -5
  254. package/src/shared/xml-parser.test.ts +0 -50
  255. package/src/store/active-reply-store.ts +0 -42
  256. package/src/store/interfaces.ts +0 -11
  257. package/src/store/memory-store.ts +0 -43
  258. package/src/store/stream-batch-store.ts +0 -350
  259. package/src/transport/agent-api/client.ts +0 -277
  260. package/src/transport/agent-api/core.ts +0 -463
  261. package/src/transport/agent-api/delivery.ts +0 -41
  262. package/src/transport/agent-api/media-upload.ts +0 -11
  263. package/src/transport/agent-api/reply.ts +0 -39
  264. package/src/transport/agent-api/upstream-delivery.ts +0 -45
  265. package/src/transport/agent-api/upstream-media-upload.ts +0 -70
  266. package/src/transport/agent-api/upstream-reply.ts +0 -43
  267. package/src/transport/agent-callback/http-handler.ts +0 -47
  268. package/src/transport/agent-callback/inbound.ts +0 -5
  269. package/src/transport/agent-callback/reply.ts +0 -13
  270. package/src/transport/agent-callback/request-handler.ts +0 -244
  271. package/src/transport/agent-callback/session.ts +0 -23
  272. package/src/transport/bot-webhook/active-reply.ts +0 -39
  273. package/src/transport/bot-webhook/http-handler.ts +0 -48
  274. package/src/transport/bot-webhook/inbound-normalizer.test.ts +0 -433
  275. package/src/transport/bot-webhook/inbound-normalizer.ts +0 -558
  276. package/src/transport/bot-webhook/inbound.ts +0 -5
  277. package/src/transport/bot-webhook/message-shape.ts +0 -92
  278. package/src/transport/bot-webhook/protocol.ts +0 -148
  279. package/src/transport/bot-webhook/reply.ts +0 -15
  280. package/src/transport/bot-webhook/request-handler.ts +0 -394
  281. package/src/transport/bot-webhook/session.ts +0 -23
  282. package/src/transport/bot-ws/inbound.test.ts +0 -290
  283. package/src/transport/bot-ws/inbound.ts +0 -163
  284. package/src/transport/bot-ws/media.test.ts +0 -44
  285. package/src/transport/bot-ws/media.ts +0 -321
  286. package/src/transport/bot-ws/reply.test.ts +0 -450
  287. package/src/transport/bot-ws/reply.ts +0 -365
  288. package/src/transport/bot-ws/sdk-adapter.test.ts +0 -187
  289. package/src/transport/bot-ws/sdk-adapter.ts +0 -314
  290. package/src/transport/bot-ws/session.ts +0 -28
  291. package/src/transport/http/common.ts +0 -109
  292. package/src/transport/http/registry.ts +0 -92
  293. package/src/transport/http/request-handler.ts +0 -84
  294. package/src/types/account.ts +0 -70
  295. package/src/types/config.ts +0 -114
  296. package/src/types/constants.ts +0 -31
  297. package/src/types/events.ts +0 -21
  298. package/src/types/global.d.ts +0 -9
  299. package/src/types/index.ts +0 -17
  300. package/src/types/legacy-stream.ts +0 -50
  301. package/src/types/message.ts +0 -189
  302. package/src/types/runtime-context.ts +0 -28
  303. package/src/types/runtime.ts +0 -165
  304. package/src/types.ts +0 -41
  305. package/src/upstream/index.ts +0 -150
  306. package/src/upstream.test.ts +0 -84
  307. package/src/wecom_msg_adapter/markdown_adapter.ts +0 -331
  308. package/tsconfig.json +0 -22
  309. package/vitest.config.ts +0 -26
  310. /package/{src/capability/agent/index.ts → dist/src/capability/agent/index.js} +0 -0
  311. /package/{src/capability/bot/index.ts → dist/src/capability/bot/index.js} +0 -0
  312. /package/{src/capability/calendar/index.ts → dist/src/capability/calendar/index.js} +0 -0
  313. /package/{src/capability/index.ts → dist/src/capability/index.js} +0 -0
@@ -1,371 +0,0 @@
1
- import { pathToFileURL } from "node:url";
2
-
3
- import type { PluginRuntime } from "openclaw/plugin-sdk";
4
-
5
- import { resolveWecomMediaMaxBytes, shouldRejectWecomDefaultRoute } from "../../config/index.js";
6
- import { ensureDynamicAgentListed, generateAgentId, shouldUseDynamicAgent } from "../../dynamic-agent.js";
7
- import { LIMITS, type StreamStore } from "../../monitor/state.js";
8
- import { getWecomRuntime } from "../../runtime.js";
9
- import { buildWecomUnauthorizedCommandPrompt, resolveWecomCommandAuthorization } from "../../shared/command-auth.js";
10
- import type { PendingInbound } from "../../types/legacy-stream.js";
11
- import type { WecomBotInboundMessage as WecomInboundMessage } from "../../types/index.js";
12
- import type { WecomWebhookTarget } from "../../types/runtime-context.js";
13
- import { looksLikeSendLocalFileIntent, processBotInboundMessage } from "../../transport/bot-webhook/inbound-normalizer.js";
14
- import { resolveWecomSenderUserId } from "../../transport/bot-webhook/message-shape.js";
15
- import { buildWecomBotDispatchConfig } from "./dispatch-config.js";
16
- import { sendBotFallbackPromptNow } from "./fallback-delivery.js";
17
- import { finalizeBotStream } from "./stream-finalizer.js";
18
- import { handleDirectLocalPathIntent } from "./local-path-delivery.js";
19
- import { stageWecomInboundMediaForSession } from "./sandbox-media.js";
20
- import { createBotReplyDispatcher } from "./stream-delivery.js";
21
- import type { BotRuntimeLogger, RecordBotOperationalEvent } from "./types.js";
22
-
23
- export type StartBotAgentStreamParams = {
24
- target: WecomWebhookTarget;
25
- accountId: string;
26
- msg: WecomInboundMessage;
27
- streamId: string;
28
- mergedContents?: string[] | string;
29
- mergedMsgids?: string[];
30
- };
31
-
32
- export function createBotStreamOrchestrator(params: {
33
- streamStore: StreamStore;
34
- recordBotOperationalEvent: RecordBotOperationalEvent;
35
- }) {
36
- const { streamStore, recordBotOperationalEvent } = params;
37
-
38
- const logVerbose: BotRuntimeLogger = (target, message) => {
39
- const should =
40
- target.core.logging?.shouldLogVerbose?.() ??
41
- (() => {
42
- try {
43
- return getWecomRuntime().logging.shouldLogVerbose();
44
- } catch {
45
- return false;
46
- }
47
- })();
48
- if (!should) return;
49
- target.runtime.log?.(`[wecom] ${message}`);
50
- };
51
-
52
- const logInfo: BotRuntimeLogger = (target, message) => {
53
- target.runtime.log?.(`[wecom] ${message}`);
54
- };
55
-
56
- const truncateUtf8Bytes = (text: string, maxBytes: number): string => {
57
- const buf = Buffer.from(text, "utf8");
58
- if (buf.length <= maxBytes) return text;
59
- return buf.subarray(buf.length - maxBytes).toString("utf8");
60
- };
61
-
62
- const computeTaskKey = (target: WecomWebhookTarget, msg: WecomInboundMessage): string | undefined => {
63
- const msgid = msg.msgid ? String(msg.msgid) : "";
64
- if (!msgid) return undefined;
65
- const aibotid = String((msg as any).aibotid ?? "unknown").trim() || "unknown";
66
- return `bot:${target.account.accountId}:${aibotid}:${msgid}`;
67
- };
68
-
69
- async function flushPending(pending: PendingInbound): Promise<void> {
70
- const { streamId, target, msg, contents, msgids, conversationKey, batchKey } = pending;
71
- const mergedContents = contents.filter((c) => c.trim()).join("\n").trim();
72
-
73
- let core: PluginRuntime | null = null;
74
- try {
75
- core = getWecomRuntime();
76
- } catch (err) {
77
- logVerbose(target, `flush pending: runtime not ready: ${String(err)}`);
78
- streamStore.markFinished(streamId);
79
- logInfo(target, `queue: runtime not ready,结束批次并推进 streamId=${streamId}`);
80
- streamStore.onStreamFinished(streamId);
81
- return;
82
- }
83
-
84
- if (!core) return;
85
-
86
- streamStore.markStarted(streamId);
87
- const enrichedTarget: WecomWebhookTarget = { ...target, core };
88
- logInfo(
89
- target,
90
- `flush pending: start batch streamId=${streamId} batchKey=${batchKey} conversationKey=${conversationKey} mergedCount=${contents.length}`,
91
- );
92
- logVerbose(target, `防抖结束: 开始处理聚合消息 数量=${contents.length} streamId=${streamId}`);
93
-
94
- startAgentForStream({
95
- target: enrichedTarget,
96
- accountId: target.account.accountId,
97
- msg,
98
- streamId,
99
- mergedContents: contents.length > 1 ? mergedContents : undefined,
100
- mergedMsgids: msgids.length > 1 ? msgids : undefined,
101
- }).catch((err) => {
102
- streamStore.updateStream(streamId, (state) => {
103
- state.error = err instanceof Error ? err.message : String(err);
104
- state.content = state.content || `Error: ${state.error}`;
105
- state.finished = true;
106
- });
107
- target.runtime.error?.(`[${target.account.accountId}] wecom agent failed (处理失败): ${String(err)}`);
108
- streamStore.onStreamFinished(streamId);
109
- });
110
- }
111
-
112
- async function startAgentForStream(params: StartBotAgentStreamParams): Promise<void> {
113
- const { target, msg, streamId } = params;
114
- const core = target.core;
115
- const config = target.config;
116
- const account = target.account;
117
-
118
- const userId = resolveWecomSenderUserId(msg) || "unknown";
119
- const chatType = msg.chattype === "group" ? "group" : "direct";
120
- const chatId = msg.chattype === "group" ? (msg.chatid?.trim() || "unknown") : userId;
121
- const taskKey = computeTaskKey(target, msg);
122
- const aibotid = String((msg as any).aibotid ?? "").trim() || undefined;
123
-
124
- streamStore.updateStream(streamId, (s) => {
125
- s.userId = userId;
126
- s.chatType = chatType;
127
- s.chatId = chatId;
128
- s.taskKey = taskKey;
129
- s.aibotid = aibotid;
130
- });
131
-
132
- let { body: rawBody, media } = await processBotInboundMessage({
133
- target,
134
- msg,
135
- recordOperationalIssue: (event) => recordBotOperationalEvent(target, event),
136
- });
137
-
138
- if (params.mergedContents) {
139
- rawBody = Array.isArray(params.mergedContents) ? params.mergedContents.join("\n") : params.mergedContents;
140
- }
141
-
142
- const handledLocalPath = await handleDirectLocalPathIntent({
143
- streamStore,
144
- target,
145
- streamId,
146
- rawBody,
147
- userId,
148
- chatType,
149
- logVerbose,
150
- looksLikeSendLocalFileIntent,
151
- });
152
- if (handledLocalPath) return;
153
-
154
- let mediaPath: string | undefined;
155
- let mediaType: string | undefined;
156
- const mediaFilename = media?.filename;
157
- if (media) {
158
- try {
159
- const maxBytes = resolveWecomMediaMaxBytes(target.config, target.account.accountId);
160
- const saved = await core.channel.media.saveMediaBuffer(media.buffer, media.contentType, "inbound", maxBytes, media.filename);
161
- mediaPath = saved.path;
162
- mediaType = saved.contentType;
163
- logVerbose(target, `saved inbound media to ${mediaPath} (${mediaType})`);
164
- } catch (err) {
165
- target.runtime.error?.(`Failed to save inbound media: ${String(err)}`);
166
- }
167
- }
168
-
169
- const route = core.channel.routing.resolveAgentRoute({
170
- cfg: config,
171
- channel: "wecom",
172
- accountId: account.accountId,
173
- peer: { kind: chatType === "group" ? "group" : "direct", id: chatId },
174
- });
175
-
176
- const useDynamicAgent = shouldUseDynamicAgent({
177
- chatType: chatType === "group" ? "group" : "dm",
178
- senderId: userId,
179
- config,
180
- });
181
-
182
- if (shouldRejectWecomDefaultRoute({ cfg: config, matchedBy: route.matchedBy, useDynamicAgent })) {
183
- const prompt =
184
- `当前账号(${account.accountId})未绑定 OpenClaw Agent,已拒绝回退到默认主智能体。` +
185
- `请在 bindings 中添加:{"agentId":"你的Agent","match":{"channel":"wecom","accountId":"${account.accountId}"}}`;
186
- target.runtime.error?.(
187
- `[wecom] routing guard: blocked default fallback accountId=${account.accountId} matchedBy=${route.matchedBy} streamId=${streamId}`,
188
- );
189
- streamStore.updateStream(streamId, (s) => {
190
- s.finished = true;
191
- s.content = prompt;
192
- });
193
- try {
194
- await sendBotFallbackPromptNow({ streamId, text: prompt });
195
- } catch (err) {
196
- target.runtime.error?.(`routing guard prompt push failed streamId=${streamId}: ${String(err)}`);
197
- }
198
- streamStore.onStreamFinished(streamId);
199
- return;
200
- }
201
-
202
- if (useDynamicAgent) {
203
- const targetAgentId = generateAgentId(chatType === "group" ? "group" : "dm", chatId, account.accountId);
204
- route.agentId = targetAgentId;
205
- route.sessionKey = `agent:${targetAgentId}:wecom:${account.accountId}:${chatType === "group" ? "group" : "dm"}:${chatId}`;
206
- ensureDynamicAgentListed(targetAgentId, core).catch(() => { });
207
- logVerbose(target, `dynamic agent routing: ${targetAgentId}, sessionKey=${route.sessionKey}`);
208
- }
209
-
210
- if (mediaPath) {
211
- try {
212
- const stagedSessionPath = await stageWecomInboundMediaForSession({
213
- cfg: target.config,
214
- accountId: target.account.accountId,
215
- agentId: route.agentId,
216
- sessionKey: route.sessionKey,
217
- mediaPath,
218
- filename: mediaFilename,
219
- });
220
- mediaPath = stagedSessionPath;
221
- logVerbose(target, `session media staged to ${mediaPath}`);
222
- } catch (err) {
223
- target.runtime.error?.(`Failed to stage inbound media for session workspace: ${String(err)}`);
224
- }
225
- }
226
-
227
- logVerbose(target, `starting agent processing (streamId=${streamId}, agentId=${route.agentId}, peerKind=${chatType}, peerId=${chatId})`);
228
- logVerbose(target, `启动 Agent 处理: streamId=${streamId} 路由=${route.agentId} 类型=${chatType} ID=${chatId}`);
229
-
230
- const fromLabel = chatType === "group" ? `group:${chatId}` : `user:${userId}`;
231
- const storePath = core.channel.session.resolveStorePath(config.session?.store, { agentId: route.agentId });
232
- const envelopeOptions = core.channel.reply.resolveEnvelopeFormatOptions(config);
233
- const previousTimestamp = core.channel.session.readSessionUpdatedAt({
234
- storePath,
235
- sessionKey: route.sessionKey,
236
- });
237
- const body = core.channel.reply.formatAgentEnvelope({
238
- channel: "WeCom",
239
- from: fromLabel,
240
- previousTimestamp,
241
- envelope: envelopeOptions,
242
- body: rawBody,
243
- });
244
-
245
- const authz = await resolveWecomCommandAuthorization({
246
- core,
247
- cfg: config,
248
- accountConfig: account.config,
249
- rawBody,
250
- senderUserId: userId,
251
- });
252
- const commandAuthorized = authz.commandAuthorized;
253
- logVerbose(
254
- target,
255
- `authz: dmPolicy=${authz.dmPolicy} shouldCompute=${authz.shouldComputeAuth} sender=${userId.toLowerCase()} senderAllowed=${authz.senderAllowed} authorizerConfigured=${authz.authorizerConfigured} commandAuthorized=${String(authz.commandAuthorized)}`,
256
- );
257
-
258
- if (authz.shouldComputeAuth && authz.commandAuthorized !== true) {
259
- const prompt = buildWecomUnauthorizedCommandPrompt({ senderUserId: userId, dmPolicy: authz.dmPolicy, scope: "bot" });
260
- streamStore.updateStream(streamId, (s) => {
261
- s.finished = true;
262
- s.content = prompt;
263
- });
264
- try {
265
- await sendBotFallbackPromptNow({ streamId, text: prompt });
266
- logInfo(target, `authz: 未授权命令已提示用户 streamId=${streamId}`);
267
- } catch (err) {
268
- target.runtime.error?.(`authz: 未授权命令提示推送失败 streamId=${streamId}: ${String(err)}`);
269
- }
270
- streamStore.onStreamFinished(streamId);
271
- return;
272
- }
273
-
274
- const attachments = mediaPath
275
- ? [
276
- {
277
- name: media?.filename || "file",
278
- mimeType: mediaType,
279
- url: pathToFileURL(mediaPath).href,
280
- },
281
- ]
282
- : undefined;
283
-
284
- const ctxPayload = core.channel.reply.finalizeInboundContext({
285
- Body: body,
286
- RawBody: rawBody,
287
- CommandBody: rawBody,
288
- Attachments: attachments,
289
- From: chatType === "group" ? `wecom:group:${chatId}` : `wecom:user:${userId}`,
290
- To: chatType === "group" ? `wecom:group:${chatId}` : `wecom:user:${chatId}`,
291
- SessionKey: route.sessionKey,
292
- AccountId: route.accountId,
293
- ChatType: chatType,
294
- ConversationLabel: fromLabel,
295
- SenderName: userId,
296
- SenderId: userId,
297
- Provider: "wecom",
298
- Surface: "wecom",
299
- MessageSid: msg.msgid,
300
- CommandAuthorized: commandAuthorized,
301
- OriginatingChannel: "wecom",
302
- OriginatingTo: chatType === "group" ? `wecom:group:${chatId}` : `wecom:user:${chatId}`,
303
- MediaPath: mediaPath,
304
- MediaType: mediaType,
305
- MediaUrl: mediaPath,
306
- });
307
-
308
- await core.channel.session.recordInboundSession({
309
- storePath,
310
- sessionKey: ctxPayload.SessionKey ?? route.sessionKey,
311
- ctx: ctxPayload,
312
- onRecordError: (err) => {
313
- target.runtime.error?.(`wecom: failed updating session meta: ${String(err)}`);
314
- },
315
- });
316
-
317
- const tableMode = core.channel.text.resolveMarkdownTableMode({
318
- cfg: config,
319
- channel: "wecom",
320
- accountId: account.accountId,
321
- });
322
- const cfgForDispatch = buildWecomBotDispatchConfig(config);
323
- logVerbose(target, "tool-policy: WeCom Bot 会话已禁用 message 工具(tools.deny += message;并同步到 tools.sandbox.tools.deny,防止绕过 Bot 交付)");
324
-
325
- await core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
326
- ctx: ctxPayload,
327
- cfg: cfgForDispatch,
328
- replyOptions: { disableBlockStreaming: false },
329
- dispatcherOptions: createBotReplyDispatcher({
330
- streamStore,
331
- target,
332
- accountId: account.accountId,
333
- config,
334
- msg,
335
- streamId,
336
- rawBody,
337
- chatType,
338
- userId,
339
- core,
340
- tableMode,
341
- logVerbose,
342
- truncateUtf8Bytes,
343
- recordBotOperationalEvent,
344
- }),
345
- });
346
-
347
- const rawBodyNormalized = rawBody.trim();
348
- const isResetCommand = /^\/(new|reset)(?:\s|$)/i.test(rawBodyNormalized);
349
- const resetCommandKind = isResetCommand ? (rawBodyNormalized.match(/^\/(new|reset)/i)?.[1]?.toLowerCase() ?? "new") : null;
350
-
351
- await finalizeBotStream({
352
- streamStore,
353
- target,
354
- streamId,
355
- chatType,
356
- core,
357
- config,
358
- accountId: account.accountId,
359
- isResetCommand,
360
- resetCommandKind,
361
- logInfo,
362
- logVerbose,
363
- recordBotOperationalEvent,
364
- });
365
- }
366
-
367
- return {
368
- flushPending,
369
- startAgentForStream,
370
- };
371
- }
@@ -1,8 +0,0 @@
1
- import type { WecomRuntimeAuditEvent, WecomWebhookTarget } from "../../types/runtime-context.js";
2
-
3
- export type BotRuntimeLogger = (target: WecomWebhookTarget, message: string) => void;
4
-
5
- export type RecordBotOperationalEvent = (
6
- target: Pick<WecomWebhookTarget, "account" | "auditSink">,
7
- event: Omit<WecomRuntimeAuditEvent, "transport">,
8
- ) => void;
@@ -1,251 +0,0 @@
1
- # WeCom Calendar Skills 技能清单
2
-
3
- ## 技能列表
4
-
5
- ### wecom_calendar - 企业微信日历工具
6
-
7
- **技能 ID**: `wecom_calendar`
8
- **标签**: `WeCom Calendar`
9
- **描述**: 企业微信日历工具。支持创建/更新/删除日历和日程,管理日程参与者,获取日历详情等功能。
10
-
11
- ## 支持的 Actions (13 个)
12
-
13
- ### 日历管理 (4 个)
14
-
15
- #### 1. calendar_create - 创建日历
16
- **参数**:
17
- - `summary` (必填): 日历标题,1-128 字符
18
- - `color` (必填): RGB 颜色编码,如 #FF3030
19
- - `description` (可选): 日历描述,0-512 字符
20
- - `admins` (可选): 日历管理员 userid 列表,最多 3 人
21
- - `set_as_default` (可选): 是否设为默认日历,0-否,1-是(第三方应用不支持)
22
- - `shares` (可选): 通知范围成员列表,最多 2000 人
23
- - `is_public` (可选): 是否公共日历,0-否,1-是
24
- - `public_range` (可选): 公开范围
25
- - `userids`: 公开的成员列表,最多 1000 个
26
- - `partyids`: 公开的部门列表,最多 100 个
27
- - `is_corp_calendar` (可选): 是否全员日历,0-否,1-是
28
-
29
- **返回**: `{ ok: true, action: "calendar_create", calId: string, raw: object }`
30
-
31
- #### 2. calendar_update - 更新日历
32
- **参数**:
33
- - `cal_id` (必填): 日历 ID
34
- - `summary` (必填): 日历标题,1-128 字符
35
- - `color` (必填): RGB 颜色编码
36
- - `description` (可选): 日历描述,0-512 字符
37
- - `admins` (可选): 日历管理员,最多 3 人
38
- - `shares` (可选): 通知范围成员,最多 2000 人
39
- - `public_range` (可选): 公开范围
40
- - `skip_public_range` (可选): 是否不更新可订阅范围,0-否,1-是
41
-
42
- **返回**: `{ ok: true, action: "calendar_update", calId: string, raw: object }`
43
-
44
- #### 3. calendar_get - 获取日历详情
45
- **参数**:
46
- - `cal_id_list` (必填): 日历 ID 列表,一次最多 1000 条
47
-
48
- **返回**: `{ ok: true, action: "calendar_get", calendarList: array, raw: object }`
49
-
50
- #### 4. calendar_delete - 删除日历
51
- **参数**:
52
- - `cal_id` (必填): 日历 ID
53
-
54
- **返回**: `{ ok: true, action: "calendar_delete", calId: string, raw: object }`
55
-
56
- ### 日程管理 (7 个)
57
-
58
- #### 5. schedule_create - 创建日程
59
- **参数**:
60
- - `start_time` (必填): 日程开始时间,Unix 时间戳(秒)
61
- - `end_time` (必填): 日程结束时间,Unix 时间戳(秒)
62
- - `is_whole_day` (可选): 是否全天日程,0-否,1-是
63
- - `summary` (可选): 日程标题,0-128 字符
64
- - `description` (可选): 日程描述,不多于 1000 字符
65
- - `location` (可选): 日程地址,不多于 128 字符
66
- - `attendees` (可选): 日程参与者列表,最多 1000 人
67
- - `admins` (可选): 日程管理员,最多 3 人
68
- - `reminders` (可选): 提醒相关信息
69
- - `is_remind`: 是否需要提醒,0-否,1-是
70
- - `is_repeat`: 是否重复日程,0-否,1-是
71
- - `remind_before_event_secs`: 日程开始前多少秒提醒 [0,300,900,3600,86400]
72
- - `remind_time_diffs`: 提醒时间与日程开始时间的差值数组
73
- - `repeat_type`: 重复类型 [0-每日,1-每周,2-每月,5-每年,7-工作日]
74
- - `repeat_until`: 重复结束时刻,Unix 时间戳
75
- - `is_custom_repeat`: 是否自定义重复,0-否,1-是
76
- - `repeat_interval`: 重复间隔
77
- - `repeat_day_of_week`: 每周周几重复 [1-7]
78
- - `repeat_day_of_month`: 每月哪几天重复 [1-31]
79
- - `timezone`: 时区 [-12 到 +12]
80
- - `cal_id` (可选): 日程所属日历 ID(第三方应用必须指定)
81
-
82
- **返回**: `{ ok: true, action: "schedule_create", scheduleId: string, raw: object }`
83
-
84
- #### 6. schedule_update - 更新日程
85
- **参数**:
86
- - `schedule_id` (必填): 日程 ID
87
- - `start_time` (必填): 日程开始时间
88
- - `end_time` (必填): 日程结束时间
89
- - `is_whole_day` (可选): 是否全天日程
90
- - `summary` (可选): 日程标题
91
- - `description` (可选): 日程描述
92
- - `location` (可选): 日程地址
93
- - `attendees` (可选): 日程参与者
94
- - `admins` (可选): 日程管理员
95
- - `reminders` (可选): 提醒相关信息
96
- - `skip_attendees` (可选): 是否不更新参与人,0-否,1-是
97
- - `op_mode` (可选): 操作模式 [0-全部修改,1-仅修改此日程,2-修改将来的所有日程]
98
- - `op_start_time` (可选): 操作起始时间
99
-
100
- **返回**: `{ ok: true, action: "schedule_update", scheduleId: string, raw: object }`
101
-
102
- #### 7. schedule_add_attendees - 新增日程参与者
103
- **参数**:
104
- - `schedule_id` (必填): 日程 ID
105
- - `attendees` (必填): 日程参与者列表,累计最多 1000 人
106
-
107
- **返回**: `{ ok: true, action: "schedule_add_attendees", scheduleId: string, raw: object }`
108
-
109
- #### 8. schedule_del_attendees - 删除日程参与者
110
- **参数**:
111
- - `schedule_id` (必填): 日程 ID
112
- - `attendees` (必填): 日程参与者列表,最多 1000 人
113
-
114
- **返回**: `{ ok: true, action: "schedule_del_attendees", scheduleId: string, raw: object }`
115
-
116
- #### 9. schedule_get_by_calendar - 获取日历下的日程列表
117
- **参数**:
118
- - `cal_id` (必填): 日历 ID
119
- - `offset` (可选): 分页偏移量,默认 0
120
- - `limit` (可选): 分页大小,默认 500,范围 1-1000
121
-
122
- **返回**: `{ ok: true, action: "schedule_get_by_calendar", scheduleList: array, raw: object }`
123
-
124
- #### 10. schedule_get - 获取日程详情
125
- **参数**:
126
- - `schedule_id_list` (必填): 日程 ID 列表,一次最多 1000 条
127
-
128
- **返回**: `{ ok: true, action: "schedule_get", scheduleList: array, meetingCode: string, meetingLink: string, raw: object }`
129
-
130
- #### 11. schedule_delete - 取消日程
131
- **参数**:
132
- - `schedule_id` (必填): 日程 ID
133
- - `op_mode` (可选): 操作模式 [0-删除所有,1-仅删除此日程,2-删除本次及后续]
134
- - `op_start_time` (可选): 操作起始时间
135
-
136
- **返回**: `{ ok: true, action: "schedule_delete", scheduleId: string, raw: object }`
137
-
138
- ### 默认日历管理 (2 个)
139
-
140
- #### 12. schedule_get_system_calid - 获取默认日历本 ID
141
- **参数**:
142
- - `userid` (必填): 指定成员的 userid
143
-
144
- **返回**: `{ ok: true, action: "schedule_get_system_calid", calId: string, raw: object }`
145
-
146
- #### 13. schedule_create_in_system - 在默认日历创建日程
147
- **参数**:
148
- - `organizer` (必填): 日程创建者 userid
149
- - `start_time` (必填): 日程开始时间
150
- - `end_time` (必填): 日程结束时间
151
- - `is_whole_day` (可选): 是否全天日程
152
- - `summary` (可选): 日程标题
153
- - `description` (可选): 日程描述
154
- - `location` (可选): 日程地址
155
- - `attendees` (可选): 日程参与者
156
- - `reminders` (可选): 提醒相关信息
157
-
158
- **返回**: `{ ok: true, action: "schedule_create_in_system", scheduleId: string, raw: object }`
159
-
160
- ## 与官方文档对比验证
161
-
162
- ### 接口完整性 ✓
163
- - [x] 创建日历 (calendar/add) - 完整实现
164
- - [x] 更新日历 (calendar/update) - 完整实现
165
- - [x] 获取日历 (calendar/get) - 完整实现
166
- - [x] 删除日历 (calendar/del) - 完整实现
167
- - [x] 创建日程 (schedule/add) - 完整实现
168
- - [x] 更新日程 (schedule/update) - 完整实现
169
- - [x] 新增参与者 (schedule/add_attendees) - 完整实现
170
- - [x] 删除参与者 (schedule/del_attendees) - 完整实现
171
- - [x] 获取日程列表 (schedule/get_by_calendar) - 完整实现
172
- - [x] 获取日程详情 (schedule/get) - 完整实现
173
- - [x] 取消日程 (schedule/del) - 完整实现
174
- - [x] 获取默认日历 ID (calendar/get_system_calid) - 完整实现
175
- - [x] 创建默认日历日程 (schedule/add_schedule_in_system_cal) - 完整实现
176
- - [x] 更新日程回执 (schedule/respond) - 已实现(client.ts)
177
- - [x] 同步日程 (schedule/sync) - 已实现(client.ts)
178
-
179
- ### 参数验证 ✓
180
- - [x] 所有必填参数都有 required 声明
181
- - [x] 所有参数的类型、格式、取值范围都正确
182
- - [x] 所有接口限制都有验证(数量、字符)
183
- - [x] 所有枚举值都正确定义
184
-
185
- ### 返回值处理 ✓
186
- - [x] 所有接口返回结果结构正确
187
- - [x] 错误处理完善(HTTP 错误、JSON 错误、业务错误)
188
- - [x] 重试机制实现(3 次)
189
-
190
- ### 特殊功能 ✓
191
- - [x] op_mode 操作模式支持(0/1/2)
192
- - [x] op_start_time 重复日程操作
193
- - [x] 提醒时间枚举值验证
194
- - [x] 时区范围验证(-12 到 +12)
195
- - [x] 重复日程自定义设置
196
-
197
- ## 已知限制和注意事项
198
-
199
- 1. **第三方应用**:不支持 `set_as_default` 参数
200
- 2. **全员日历**:每个企业最多 20 个,不支持指定颜色
201
- 3. **公共日历**:每人最多创建或订阅 100 个
202
- 4. **日程数量**:每个应用每天最多 2 万个
203
- 5. **重复日程修改**:需指定 op_mode 和 op_start_time
204
- 6. **会议室关联**:已预约会议室的日程更新时间受限
205
-
206
- ## 待实现功能
207
-
208
- 1. **回调事件处理** - 需要在 webhook 中添加以下事件处理:
209
- - delete_calendar
210
- - modify_calendar
211
- - modify_schedule
212
- - delete_schedule
213
- - respond_schedule
214
- - add_schedule
215
-
216
- 2. **完整实现** - client.ts 和 tool.ts 需要完善所有方法的具体实现
217
-
218
- ## 使用示例
219
-
220
- ```json
221
- // 创建日历
222
- {
223
- "action": "calendar_create",
224
- "summary": "团队日历",
225
- "color": "#FF3030",
226
- "description": "团队共享日历",
227
- "admins": ["zhangsan", "lisi"],
228
- "shares": [{"userid": "wangwu", "permission": 1}]
229
- }
230
-
231
- // 创建日程
232
- {
233
- "action": "schedule_create",
234
- "start_time": 1679011200,
235
- "end_time": 1679014800,
236
- "summary": "项目评审会议",
237
- "location": "10 楼会议室",
238
- "attendees": [{"userid": "user1"}, {"userid": "user2"}],
239
- "reminders": {
240
- "is_remind": 1,
241
- "remind_before_event_secs": 3600,
242
- "timezone": 8
243
- }
244
- }
245
-
246
- // 获取日程详情
247
- {
248
- "action": "schedule_get",
249
- "schedule_id_list": ["schedule_id_1", "schedule_id_2"]
250
- }
251
- ```