@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
@@ -0,0 +1,557 @@
1
+ import { WecomAgentDeliveryService } from "./capability/agent/index.js";
2
+ import { WecomUpstreamAgentDeliveryService } from "./capability/agent/upstream-delivery-service.js";
3
+ import { resolveWecomMergedMediaLocalRoots, resolveWecomMediaMaxBytes, resolveWecomAccount, resolveWecomAccountConflict, resolveWecomAccounts, } from "./config/index.js";
4
+ import { getAccountRuntime, getActiveBotWsReplyHandle, getBotWsPushHandle, getWecomRuntime, } from "./runtime.js";
5
+ import { getPeerUpstreamCorpId } from "./context-store.js";
6
+ import { resolveWecomSourceSnapshot } from "./runtime/source-registry.js";
7
+ import { resolveOutboundMediaAsset } from "./shared/media-asset.js";
8
+ import { resolveScopedWecomTarget } from "./target.js";
9
+ import { toWeComMarkdownV2 } from "./wecom_msg_adapter/markdown_adapter.js";
10
+ import { parseUpstreamAgentSessionTarget, createUpstreamAgentConfig, resolveUpstreamCorpConfig } from "./upstream/index.js";
11
+ function resolveOutboundContext(params) {
12
+ const rawTo = String(params.to ?? "").trim();
13
+ const fallbackAccountId = params.accountId?.trim();
14
+ const scoped = resolveScopedWecomTarget(params.to, fallbackAccountId);
15
+ const scopedAccountId = scoped?.accountId?.trim() || fallbackAccountId;
16
+ const peerId = scoped?.target.touser?.trim() || scoped?.target.chatid?.trim();
17
+ const peerKind = scoped?.target.chatid ? "group" : scoped?.target.touser ? "direct" : undefined;
18
+ const source = scopedAccountId
19
+ ? resolveWecomSourceSnapshot({
20
+ accountId: scopedAccountId,
21
+ sessionKey: params.sessionKey,
22
+ peerKind,
23
+ peerId,
24
+ })
25
+ : undefined;
26
+ const peerUpstreamCorpId = scopedAccountId && peerKind === "direct" && peerId
27
+ ? getPeerUpstreamCorpId(scopedAccountId, peerId)?.trim()
28
+ : undefined;
29
+ return {
30
+ rawTo,
31
+ explicitAgentTarget: isExplicitAgentTarget(params.to),
32
+ scopedAccountId,
33
+ peerKind,
34
+ peerId,
35
+ source,
36
+ peerUpstreamCorpId,
37
+ };
38
+ }
39
+ function logOutboundDecision(params) {
40
+ const resolved = resolveOutboundContext(params);
41
+ const runtimeAccountId = resolved.scopedAccountId || params.accountId?.trim();
42
+ const logger = runtimeAccountId ? getAccountRuntime(runtimeAccountId)?.log.info : undefined;
43
+ logger?.(`[wecom-outbound] ${params.phase} rawTo=${resolved.rawTo || "N/A"} scopedAccount=${resolved.scopedAccountId ?? "N/A"} ` +
44
+ `peer=${resolved.peerKind && resolved.peerId ? `${resolved.peerKind}:${resolved.peerId}` : "N/A"} ` +
45
+ `explicitAgent=${String(resolved.explicitAgentTarget)} source=${resolved.source?.source ?? "none"} ` +
46
+ `sourceUpstreamCorpId=${resolved.source?.upstreamCorpId ?? "none"} peerUpstreamCorpId=${resolved.peerUpstreamCorpId ?? "none"} ` +
47
+ `sessionKey=${params.sessionKey?.trim() || "N/A"} textLen=${String(params.textLen ?? 0)} ` +
48
+ `mediaUrl=${params.mediaUrl ?? "N/A"}${params.extra ? ` ${params.extra}` : ""}`);
49
+ }
50
+ function resolveOutboundAccountOrThrow(params) {
51
+ const resolvedAccounts = resolveWecomAccounts(params.cfg);
52
+ const conflictAccountId = params.accountId?.trim() || resolvedAccounts.defaultAccountId;
53
+ const conflict = resolveWecomAccountConflict({
54
+ cfg: params.cfg,
55
+ accountId: conflictAccountId,
56
+ });
57
+ if (conflict) {
58
+ throw new Error(conflict.message);
59
+ }
60
+ const requestedAccountId = params.accountId?.trim();
61
+ if (requestedAccountId) {
62
+ if (!resolvedAccounts.accounts[requestedAccountId]) {
63
+ throw new Error(`WeCom outbound account "${requestedAccountId}" not found. Configure channels.wecom.accounts.${requestedAccountId} or use an existing accountId.`);
64
+ }
65
+ }
66
+ return resolveWecomAccount({
67
+ cfg: params.cfg,
68
+ accountId: params.accountId,
69
+ });
70
+ }
71
+ function resolveAgentConfigOrThrow(params) {
72
+ const account = resolveOutboundAccountOrThrow(params).agent;
73
+ if (!account?.apiConfigured) {
74
+ throw new Error(`WeCom outbound requires Agent mode for account=${params.accountId ?? "default"}. Configure channels.wecom.accounts.<accountId>.agent (or legacy channels.wecom.agent).`);
75
+ }
76
+ if (typeof account.agentId !== "number" || !Number.isFinite(account.agentId)) {
77
+ throw new Error(`WeCom outbound requires channels.wecom.accounts.<accountId>.agent.agentId (or legacy channels.wecom.agent.agentId) for account=${params.accountId ?? account.accountId}.`);
78
+ }
79
+ // 注意:不要在日志里输出 corpSecret 等敏感信息
80
+ getAccountRuntime(account.accountId)?.log.info?.(`[wecom-outbound] Using agent config: accountId=${account.accountId}, corpId=${account.corpId}, agentId=${account.agentId}`);
81
+ return account;
82
+ }
83
+ function isExplicitAgentTarget(raw) {
84
+ return /^wecom-agent(?:-upstream)?:/i.test(String(raw ?? "").trim());
85
+ }
86
+ function isAgentConversationTarget(params) {
87
+ if (isExplicitAgentTarget(params.to)) {
88
+ return true;
89
+ }
90
+ const fallbackAccountId = params.accountId?.trim();
91
+ const scoped = resolveScopedWecomTarget(params.to, fallbackAccountId);
92
+ const resolvedAccountId = scoped?.accountId?.trim() || fallbackAccountId;
93
+ if (!resolvedAccountId) {
94
+ return false;
95
+ }
96
+ const peerId = scoped?.target.touser?.trim() || scoped?.target.chatid?.trim();
97
+ const peerKind = scoped?.target.chatid ? "group" : scoped?.target.touser ? "direct" : undefined;
98
+ const source = resolveWecomSourceSnapshot({
99
+ accountId: resolvedAccountId,
100
+ sessionKey: params.sessionKey,
101
+ peerKind,
102
+ peerId,
103
+ });
104
+ return source?.source === "agent-callback";
105
+ }
106
+ /**
107
+ * 解析上下游目标,返回解析后的信息或 undefined
108
+ */
109
+ function resolveUpstreamTarget(params) {
110
+ const parsedExplicit = parseUpstreamAgentSessionTarget(params.to ?? "");
111
+ const isExplicitUpstreamTarget = Boolean(parsedExplicit);
112
+ const parsed = (() => {
113
+ if (parsedExplicit) {
114
+ return parsedExplicit;
115
+ }
116
+ const fallbackAccountId = params.accountId?.trim();
117
+ const scoped = resolveScopedWecomTarget(params.to, fallbackAccountId);
118
+ const toUser = scoped?.target.touser?.trim();
119
+ const resolvedAccountId = scoped?.accountId?.trim() || fallbackAccountId;
120
+ if (!toUser || !resolvedAccountId) {
121
+ return undefined;
122
+ }
123
+ const source = resolveWecomSourceSnapshot({
124
+ accountId: resolvedAccountId,
125
+ sessionKey: params.sessionKey,
126
+ peerKind: "direct",
127
+ peerId: toUser,
128
+ });
129
+ const upstreamCorpId = source?.upstreamCorpId?.trim() || getPeerUpstreamCorpId(resolvedAccountId, toUser)?.trim();
130
+ if (!upstreamCorpId) {
131
+ return undefined;
132
+ }
133
+ return {
134
+ accountId: resolvedAccountId,
135
+ upstreamCorpId,
136
+ userId: toUser,
137
+ };
138
+ })();
139
+ if (!parsed) {
140
+ return undefined;
141
+ }
142
+ const { accountId, upstreamCorpId, userId } = parsed;
143
+ const account = resolveOutboundAccountOrThrow({ cfg: params.cfg, accountId });
144
+ if (!account.agent?.apiConfigured) {
145
+ if (isExplicitUpstreamTarget) {
146
+ throw new Error(`WeCom upstream outbound requires Agent mode for account=${accountId}.`);
147
+ }
148
+ return undefined;
149
+ }
150
+ // 查找上下游配置
151
+ const upstreamConfig = resolveUpstreamCorpConfig({
152
+ upstreamCorpId,
153
+ upstreamCorps: account.agent.config.upstreamCorps,
154
+ });
155
+ if (!upstreamConfig) {
156
+ if (isExplicitUpstreamTarget) {
157
+ throw new Error(`WeCom upstream outbound: no upstream corp config found for corpId=${upstreamCorpId}. ` +
158
+ `Please configure channels.wecom.accounts.${accountId}.agent.upstreamCorps with corpId=${upstreamCorpId}.`);
159
+ }
160
+ return undefined;
161
+ }
162
+ // 创建上下游 Agent 配置
163
+ // 注意:使用下游企业的 corpId 和 agentId,但保持主企业的 corpSecret
164
+ const upstreamAgent = createUpstreamAgentConfig({
165
+ baseAgent: account.agent,
166
+ upstreamCorpId,
167
+ upstreamAgentId: upstreamConfig.agentId,
168
+ });
169
+ return { upstreamAgent, primaryAgent: account.agent, toUser: userId };
170
+ }
171
+ function resolveBotWsChatTarget(params) {
172
+ const scoped = resolveScopedWecomTarget(params.to, params.accountId);
173
+ if (!scoped) {
174
+ return undefined;
175
+ }
176
+ if (scoped.accountId && scoped.accountId !== params.accountId) {
177
+ throw new Error(`WeCom outbound account mismatch: target belongs to account=${scoped.accountId}, current account=${params.accountId}.`);
178
+ }
179
+ if (scoped.target.chatid) {
180
+ return scoped.target.chatid;
181
+ }
182
+ if (scoped.target.touser) {
183
+ return scoped.target.touser;
184
+ }
185
+ return undefined;
186
+ }
187
+ function resolveOutboundPeer(params) {
188
+ const scoped = resolveScopedWecomTarget(params.to, params.accountId);
189
+ if (!scoped) {
190
+ return undefined;
191
+ }
192
+ if (scoped.accountId && scoped.accountId !== params.accountId) {
193
+ return undefined;
194
+ }
195
+ if (scoped.target.chatid) {
196
+ return { peerKind: "group", peerId: scoped.target.chatid };
197
+ }
198
+ if (scoped.target.touser) {
199
+ return { peerKind: "direct", peerId: scoped.target.touser };
200
+ }
201
+ return undefined;
202
+ }
203
+ function shouldPreferBotWsOutbound(params) {
204
+ const account = resolveOutboundAccountOrThrow({
205
+ cfg: params.cfg,
206
+ accountId: params.accountId,
207
+ });
208
+ const peer = resolveOutboundPeer({
209
+ to: params.to,
210
+ accountId: account.accountId,
211
+ });
212
+ const source = resolveWecomSourceSnapshot({
213
+ accountId: account.accountId,
214
+ sessionKey: params.sessionKey,
215
+ peerKind: peer?.peerKind,
216
+ peerId: peer?.peerId,
217
+ });
218
+ const pinnedToAgent = source?.source === "agent-callback";
219
+ const pinnedToBotWs = source?.source === "bot-ws";
220
+ return {
221
+ preferred: !isExplicitAgentTarget(params.to) &&
222
+ !pinnedToAgent &&
223
+ Boolean(account.bot?.configured &&
224
+ account.bot.wsConfigured &&
225
+ (pinnedToBotWs || account.bot.primaryTransport === "ws")),
226
+ accountId: account.accountId,
227
+ };
228
+ }
229
+ function markActiveBotWsReplyHandleActivity(params) {
230
+ const peer = resolveOutboundPeer({
231
+ to: params.to,
232
+ accountId: params.accountId,
233
+ });
234
+ const handle = getActiveBotWsReplyHandle({
235
+ accountId: params.accountId,
236
+ sessionKey: params.sessionKey,
237
+ peerKind: peer?.peerKind,
238
+ peerId: peer?.peerId,
239
+ });
240
+ handle?.markExternalActivity?.();
241
+ }
242
+ async function sendTextViaBotWs(params) {
243
+ const { preferred, accountId } = shouldPreferBotWsOutbound(params);
244
+ if (!preferred) {
245
+ return false;
246
+ }
247
+ const chatId = resolveBotWsChatTarget({
248
+ to: params.to,
249
+ accountId,
250
+ });
251
+ if (!chatId) {
252
+ return false;
253
+ }
254
+ const handle = getBotWsPushHandle(accountId);
255
+ if (!handle) {
256
+ throw new Error(`WeCom outbound account=${accountId} is configured for Bot WS active push, but no live WS runtime is registered.`);
257
+ }
258
+ if (!handle.isConnected()) {
259
+ throw new Error(`WeCom outbound account=${accountId} is configured for Bot WS active push, but the WS transport is not connected.`);
260
+ }
261
+ const markdownText = toWeComMarkdownV2(params.text);
262
+ console.log(`[wecom-outbound] Sending Bot WS active message to target=${String(params.to ?? "")} chatId=${chatId} (len=${markdownText.length})`);
263
+ await handle.sendMarkdown(chatId, markdownText);
264
+ markActiveBotWsReplyHandleActivity({
265
+ accountId,
266
+ sessionKey: params.sessionKey,
267
+ to: params.to,
268
+ });
269
+ console.log(`[wecom-outbound] Successfully sent Bot WS active message to ${chatId}`);
270
+ return true;
271
+ }
272
+ async function sendMediaViaBotWs(params) {
273
+ const { preferred, accountId } = shouldPreferBotWsOutbound(params);
274
+ if (!preferred) {
275
+ return { attempted: false, sent: false };
276
+ }
277
+ const chatId = resolveBotWsChatTarget({
278
+ to: params.to,
279
+ accountId,
280
+ });
281
+ if (!chatId) {
282
+ return { attempted: false, sent: false };
283
+ }
284
+ const handle = getBotWsPushHandle(accountId);
285
+ if (!handle) {
286
+ throw new Error(`WeCom outbound account=${accountId} is configured for Bot WS active push, but no live WS runtime is registered.`);
287
+ }
288
+ if (!handle.isConnected()) {
289
+ throw new Error(`WeCom outbound account=${accountId} is configured for Bot WS active push, but the WS transport is not connected.`);
290
+ }
291
+ console.log(`[wecom-outbound] Sending Bot WS media to target=${String(params.to ?? "")} chatId=${chatId} media=${params.mediaUrl}`);
292
+ const effectiveMediaLocalRoots = resolveWecomMergedMediaLocalRoots({
293
+ cfg: params.cfg,
294
+ baseRoots: params.mediaLocalRoots,
295
+ });
296
+ const result = await handle.sendMedia({
297
+ chatId,
298
+ mediaUrl: params.mediaUrl,
299
+ text: params.text,
300
+ mediaLocalRoots: effectiveMediaLocalRoots,
301
+ maxBytes: resolveWecomMediaMaxBytes(params.cfg, accountId),
302
+ });
303
+ if (result.ok) {
304
+ markActiveBotWsReplyHandleActivity({
305
+ accountId,
306
+ sessionKey: params.sessionKey,
307
+ to: params.to,
308
+ });
309
+ console.log(`[wecom-outbound] Successfully sent Bot WS media to ${chatId}`);
310
+ return { attempted: true, sent: true };
311
+ }
312
+ const reason = result.rejectReason || result.error || "unknown";
313
+ console.warn(`[wecom-outbound] Bot WS media failed for ${chatId}: ${reason}`);
314
+ return { attempted: true, sent: false, reason };
315
+ }
316
+ export const wecomOutbound = {
317
+ deliveryMode: "direct",
318
+ chunkerMode: "text",
319
+ textChunkLimit: 20480,
320
+ chunker: (text, limit) => {
321
+ try {
322
+ return getWecomRuntime().channel.text.chunkText(text, limit);
323
+ }
324
+ catch {
325
+ return [text];
326
+ }
327
+ },
328
+ sendText: async ({ cfg, to, text, accountId, sessionKey }) => {
329
+ // signal removed - not supported in current SDK
330
+ // Defer Agent resolution until the Agent fallback path
331
+ // sendTextViaBotWs() can already deliver without Agent mode
332
+ // 体验优化:/new /reset 的“New session started”回执在 OpenClaw 核心里是英文固定文案,
333
+ // 且通过 routeReply 走 wecom outbound(Agent 主动发送)。
334
+ // 在 WeCom“双模式”场景下,这会造成:
335
+ // - 用户在 Bot 会话发 /new,但却收到一条 Agent 私信回执(双重回复/错会话)。
336
+ // 因此:
337
+ // - Bot 会话目标:抑制该回执(Bot 会话里由 wecom 插件补中文回执)。
338
+ // - Agent 会话目标(wecom-agent:):允许发送,但改写成中文。
339
+ let outgoingText = text;
340
+ const trimmed = String(outgoingText ?? "").trim();
341
+ logOutboundDecision({
342
+ phase: "sendText:start",
343
+ to,
344
+ accountId,
345
+ sessionKey,
346
+ textLen: trimmed.length,
347
+ });
348
+ const isAgentSessionTarget = isAgentConversationTarget({ to, accountId, sessionKey });
349
+ const looksLikeNewSessionAck = /new session started/i.test(trimmed) && /model:/i.test(trimmed);
350
+ if (looksLikeNewSessionAck) {
351
+ if (!isAgentSessionTarget) {
352
+ logOutboundDecision({
353
+ phase: "sendText:suppress-new-session-ack",
354
+ to,
355
+ accountId,
356
+ sessionKey,
357
+ textLen: trimmed.length,
358
+ });
359
+ // Suppress ack without agent resolution
360
+ return { channel: "wecom", messageId: `suppressed-${Date.now()}`, timestamp: Date.now() };
361
+ }
362
+ const modelLabel = (() => {
363
+ const m = trimmed.match(/model:\s*([^\n()]+)\s*/i);
364
+ return m?.[1]?.trim();
365
+ })();
366
+ const rewritten = modelLabel ? `✅ 已开启新会话(模型:${modelLabel})` : "✅ 已开启新会话。";
367
+ outgoingText = rewritten;
368
+ logOutboundDecision({
369
+ phase: "sendText:rewrite-new-session-ack",
370
+ to,
371
+ accountId,
372
+ sessionKey,
373
+ textLen: outgoingText.length,
374
+ });
375
+ }
376
+ let sentViaBotWs = false;
377
+ let agent = null;
378
+ let upstreamTarget;
379
+ try {
380
+ // 首先检查是否是上下游用户
381
+ upstreamTarget = resolveUpstreamTarget({ to, cfg, accountId, sessionKey });
382
+ if (upstreamTarget) {
383
+ logOutboundDecision({
384
+ phase: "sendText:path-upstream",
385
+ to,
386
+ accountId,
387
+ sessionKey,
388
+ textLen: outgoingText.length,
389
+ extra: `resolvedUser=${upstreamTarget.toUser} corpId=${upstreamTarget.upstreamAgent.corpId}`,
390
+ });
391
+ // 上下游用户使用专门的 DeliveryService 发送
392
+ getAccountRuntime(upstreamTarget.upstreamAgent.accountId)?.log.info?.(`[wecom-outbound] Sending text to upstream target corpId=${upstreamTarget.upstreamAgent.corpId} (len=${outgoingText.length})`);
393
+ const deliveryService = new WecomUpstreamAgentDeliveryService(upstreamTarget.upstreamAgent, upstreamTarget.primaryAgent);
394
+ await deliveryService.sendText({
395
+ to,
396
+ text: outgoingText,
397
+ });
398
+ return {
399
+ channel: "wecom",
400
+ messageId: `upstream-agent-${Date.now()}`,
401
+ timestamp: Date.now(),
402
+ };
403
+ }
404
+ sentViaBotWs = await sendTextViaBotWs({
405
+ cfg,
406
+ accountId,
407
+ to,
408
+ text: outgoingText,
409
+ sessionKey,
410
+ });
411
+ if (!sentViaBotWs) {
412
+ // Defer Agent resolution until needed for fallback
413
+ agent = resolveAgentConfigOrThrow({ cfg, accountId });
414
+ logOutboundDecision({
415
+ phase: "sendText:path-agent",
416
+ to,
417
+ accountId: agent.accountId,
418
+ sessionKey,
419
+ textLen: outgoingText.length,
420
+ });
421
+ getAccountRuntime(agent.accountId)?.log.info?.(`[wecom-outbound] Sending text to target=${String(to ?? "")} (len=${outgoingText.length})`);
422
+ const deliveryService = new WecomAgentDeliveryService(agent);
423
+ await deliveryService.sendText({
424
+ to,
425
+ text: outgoingText,
426
+ });
427
+ }
428
+ else {
429
+ logOutboundDecision({
430
+ phase: "sendText:path-bot-ws",
431
+ to,
432
+ accountId,
433
+ sessionKey,
434
+ textLen: outgoingText.length,
435
+ });
436
+ }
437
+ }
438
+ catch (err) {
439
+ console.error(`[wecom-outbound] FAILED to send: ${err instanceof Error ? err.message : String(err)}`);
440
+ if (agent) {
441
+ getAccountRuntime(agent.accountId)?.log.error?.(`[wecom-outbound] Failed to send text to ${String(to ?? "")}: ${err instanceof Error ? err.message : String(err)}`);
442
+ }
443
+ throw err;
444
+ }
445
+ return {
446
+ channel: "wecom",
447
+ messageId: `${sentViaBotWs ? "bot-ws" : "agent"}-${Date.now()}`,
448
+ timestamp: Date.now(),
449
+ };
450
+ },
451
+ sendMedia: async ({ cfg, to, text, mediaUrl, accountId, mediaLocalRoots, sessionKey, }) => {
452
+ // signal removed - not supported in current SDK
453
+ if (!mediaUrl) {
454
+ throw new Error("WeCom outbound requires mediaUrl.");
455
+ }
456
+ logOutboundDecision({
457
+ phase: "sendMedia:start",
458
+ to,
459
+ accountId,
460
+ sessionKey,
461
+ textLen: String(text ?? "").trim().length,
462
+ mediaUrl,
463
+ });
464
+ // 首先检查是否是上下游用户
465
+ const upstreamTarget = resolveUpstreamTarget({ to, cfg, accountId, sessionKey });
466
+ if (upstreamTarget) {
467
+ logOutboundDecision({
468
+ phase: "sendMedia:path-upstream",
469
+ to,
470
+ accountId,
471
+ sessionKey,
472
+ textLen: String(text ?? "").trim().length,
473
+ mediaUrl,
474
+ extra: `resolvedUser=${upstreamTarget.toUser} corpId=${upstreamTarget.upstreamAgent.corpId}`,
475
+ });
476
+ getAccountRuntime(upstreamTarget.upstreamAgent.accountId)?.log.info?.(`[wecom-outbound] Sending media to upstream target corpId=${upstreamTarget.upstreamAgent.corpId} (filename=${mediaUrl})`);
477
+ const { buffer, contentType, filename } = await resolveOutboundMediaAsset({
478
+ mediaUrl,
479
+ network: upstreamTarget.upstreamAgent.network,
480
+ });
481
+ const deliveryService = new WecomUpstreamAgentDeliveryService(upstreamTarget.upstreamAgent, upstreamTarget.primaryAgent);
482
+ await deliveryService.sendMedia({
483
+ to,
484
+ text,
485
+ buffer,
486
+ filename,
487
+ contentType,
488
+ });
489
+ return {
490
+ channel: "wecom",
491
+ messageId: `upstream-agent-media-${Date.now()}`,
492
+ timestamp: Date.now(),
493
+ };
494
+ }
495
+ const botWs = await sendMediaViaBotWs({
496
+ cfg,
497
+ accountId,
498
+ to,
499
+ text,
500
+ mediaUrl,
501
+ mediaLocalRoots,
502
+ sessionKey,
503
+ });
504
+ if (botWs.sent) {
505
+ logOutboundDecision({
506
+ phase: "sendMedia:path-bot-ws",
507
+ to,
508
+ accountId,
509
+ sessionKey,
510
+ textLen: String(text ?? "").trim().length,
511
+ mediaUrl,
512
+ });
513
+ return {
514
+ channel: "wecom",
515
+ messageId: `bot-ws-media-${Date.now()}`,
516
+ timestamp: Date.now(),
517
+ };
518
+ }
519
+ if (botWs.attempted) {
520
+ throw new Error(`WeCom Bot WS media delivery failed for ${String(to ?? "")}: ${botWs.reason ?? "unknown"}`);
521
+ }
522
+ const agent = resolveAgentConfigOrThrow({ cfg, accountId });
523
+ logOutboundDecision({
524
+ phase: "sendMedia:path-agent",
525
+ to,
526
+ accountId: agent.accountId,
527
+ sessionKey,
528
+ textLen: String(text ?? "").trim().length,
529
+ mediaUrl,
530
+ });
531
+ const deliveryService = new WecomAgentDeliveryService(agent);
532
+ const { buffer, contentType, filename } = await resolveOutboundMediaAsset({
533
+ mediaUrl,
534
+ network: agent.network,
535
+ });
536
+ console.log(`[wecom-outbound] Sending media to ${String(to ?? "")} (filename=${filename}, contentType=${contentType})`);
537
+ try {
538
+ await deliveryService.sendMedia({
539
+ to,
540
+ text,
541
+ buffer,
542
+ filename,
543
+ contentType,
544
+ });
545
+ console.log(`[wecom-outbound] Successfully sent media to ${String(to ?? "")}`);
546
+ }
547
+ catch (err) {
548
+ console.error(`[wecom-outbound] Failed to send media to ${String(to ?? "")}:`, err);
549
+ throw err;
550
+ }
551
+ return {
552
+ channel: "wecom",
553
+ messageId: `${botWs.attempted ? "agent-fallback-media" : "agent-media"}-${Date.now()}`,
554
+ timestamp: Date.now(),
555
+ };
556
+ },
557
+ };
@@ -0,0 +1,57 @@
1
+ import { prepareInboundSession } from "./session-manager.js";
2
+ import { dispatchRuntimeReply } from "./reply-orchestrator.js";
3
+ import { buildRawEnvelopeSummary } from "../observability/raw-envelope-log.js";
4
+ import { registerActiveBotWsReplyHandle, unregisterActiveBotWsReplyHandle } from "../runtime.js";
5
+ export async function dispatchInboundEvent(params) {
6
+ const { core, cfg, store, auditLog, mediaService, event, replyHandle } = params;
7
+ if (!store.markInboundSeen(event)) {
8
+ auditLog.appendOperational({
9
+ accountId: event.accountId,
10
+ transport: event.transport,
11
+ category: "duplicate-inbound",
12
+ messageId: event.messageId,
13
+ summary: buildRawEnvelopeSummary(event),
14
+ raw: event.raw,
15
+ });
16
+ return;
17
+ }
18
+ auditLog.appendInbound({
19
+ accountId: event.accountId,
20
+ transport: event.transport,
21
+ messageId: event.messageId,
22
+ summary: buildRawEnvelopeSummary(event),
23
+ raw: event.raw,
24
+ });
25
+ store.writeReplyContext(event.messageId, event.replyContext);
26
+ const session = await prepareInboundSession({
27
+ core,
28
+ cfg,
29
+ event,
30
+ mediaService,
31
+ });
32
+ const sessionKey = session.ctx.SessionKey ?? session.route.sessionKey;
33
+ registerActiveBotWsReplyHandle({
34
+ accountId: event.accountId,
35
+ sessionKey,
36
+ peerKind: event.conversation.peerKind,
37
+ peerId: event.conversation.peerId,
38
+ handle: replyHandle,
39
+ });
40
+ try {
41
+ await dispatchRuntimeReply({
42
+ core,
43
+ cfg,
44
+ session,
45
+ replyHandle,
46
+ });
47
+ }
48
+ finally {
49
+ unregisterActiveBotWsReplyHandle({
50
+ accountId: event.accountId,
51
+ sessionKey,
52
+ peerKind: event.conversation.peerKind,
53
+ peerId: event.conversation.peerId,
54
+ handle: replyHandle,
55
+ });
56
+ }
57
+ }
@@ -1,4 +1,3 @@
1
1
  export { dispatchInboundEvent } from "./dispatcher.js";
2
2
  export { prepareInboundSession } from "./session-manager.js";
3
3
  export { dispatchRuntimeReply } from "./reply-orchestrator.js";
4
- export type { OutboundIntent } from "./outbound-intent.js";
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,38 @@
1
+ export async function dispatchReplyPayload(params) {
2
+ await params.replyHandle.deliver(params.payload, { kind: params.kind });
3
+ }
4
+ export async function dispatchRuntimeReply(params) {
5
+ const { core, cfg, session, replyHandle } = params;
6
+ const result = await core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
7
+ ctx: session.ctx,
8
+ cfg,
9
+ replyOptions: replyHandle.context.transport === "bot-ws"
10
+ ? {
11
+ // WS bot replies should emit block updates instead of waiting for a final-only flush.
12
+ disableBlockStreaming: false,
13
+ }
14
+ : undefined,
15
+ dispatcherOptions: {
16
+ deliver: async (payload, info) => {
17
+ await dispatchReplyPayload({
18
+ replyHandle,
19
+ payload,
20
+ kind: info?.kind === "final" ? "final" : "block",
21
+ });
22
+ },
23
+ onError: async (error) => {
24
+ await replyHandle.fail?.(error);
25
+ },
26
+ },
27
+ });
28
+ if (replyHandle.context.transport === "bot-ws" &&
29
+ result &&
30
+ result.queuedFinal !== true &&
31
+ (result.counts?.block ?? 0) > 0) {
32
+ await dispatchReplyPayload({
33
+ replyHandle,
34
+ payload: { text: "" },
35
+ kind: "final",
36
+ });
37
+ }
38
+ }
@@ -0,0 +1,26 @@
1
+ import { ensureDynamicAgentListed, generateAgentId, shouldUseDynamicAgent, } from "../dynamic-agent.js";
2
+ export function resolveRuntimeRoute(params) {
3
+ const route = params.core.channel.routing.resolveAgentRoute({
4
+ cfg: params.cfg,
5
+ channel: "wecom",
6
+ accountId: params.event.accountId,
7
+ peer: {
8
+ kind: params.event.conversation.peerKind,
9
+ id: params.event.conversation.peerId,
10
+ },
11
+ });
12
+ const chatType = params.event.conversation.peerKind === "group" ? "group" : "dm";
13
+ const useDynamicAgent = shouldUseDynamicAgent({
14
+ chatType,
15
+ senderId: params.event.conversation.senderId,
16
+ config: params.cfg,
17
+ });
18
+ if (!useDynamicAgent) {
19
+ return route;
20
+ }
21
+ const targetAgentId = generateAgentId(chatType, params.event.conversation.peerId, params.event.accountId);
22
+ route.agentId = targetAgentId;
23
+ route.sessionKey = `agent:${targetAgentId}:wecom:${params.event.accountId}:${chatType}:${params.event.conversation.peerId}`;
24
+ ensureDynamicAgentListed(targetAgentId, params.core).catch(() => { });
25
+ return route;
26
+ }