@openclaw/whatsapp 2026.5.2 → 2026.5.3-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 (302) hide show
  1. package/dist/access-control-BQ3tCkH8.js +288 -0
  2. package/dist/account-config-CNQ33oav.js +47 -0
  3. package/dist/account-ids-DG18xddX.js +5 -0
  4. package/dist/accounts-BDqgpFEB.js +116 -0
  5. package/dist/action-runtime-DTGNgG-i.js +74 -0
  6. package/dist/action-runtime-api.js +2 -0
  7. package/dist/action-runtime.runtime.js +2 -0
  8. package/dist/active-listener-N7GFKsuN.js +11 -0
  9. package/dist/agent-tools-login-DpRxLNRB.js +89 -0
  10. package/dist/api.js +148 -0
  11. package/dist/audio-preflight.runtime-Bcdsl_ri.js +7 -0
  12. package/dist/auth-presence.js +32 -0
  13. package/dist/auth-store-BjCb50Ry.js +381 -0
  14. package/dist/channel-DQ-5Xoj9.js +542 -0
  15. package/dist/channel-config-api.js +2 -0
  16. package/dist/channel-plugin-api.js +2 -0
  17. package/dist/channel-react-action-Df20qAy9.js +42 -0
  18. package/dist/channel.runtime-DKXRnA8x.js +55 -0
  19. package/dist/channel.setup-DOHR2BGp.js +20 -0
  20. package/dist/command-policy-O8sRnqUV.js +8 -0
  21. package/dist/config-schema-Dmo66Ubb.js +27 -0
  22. package/dist/connection-controller-BiHAsTM8.js +596 -0
  23. package/dist/connection-controller-registry-D_iIGz5m.js +22 -0
  24. package/dist/constants-DLGCIbfl.js +4 -0
  25. package/dist/constants.js +2 -0
  26. package/dist/contract-api.js +19 -0
  27. package/dist/creds-files-_2V8jzQa.js +19 -0
  28. package/dist/directory-config-DVs4ffXu.js +37 -0
  29. package/dist/directory-contract-api.js +2 -0
  30. package/dist/doctor-A9tXm9Om.js +48 -0
  31. package/dist/doctor-contract-api.js +10 -0
  32. package/dist/group-session-contract-B8QBn0I2.js +15 -0
  33. package/dist/identity-QHAlV7Fu.js +75 -0
  34. package/dist/index.js +18 -0
  35. package/dist/legacy-session-surface-api.js +8 -0
  36. package/dist/legacy-state-migrations-api.js +2 -0
  37. package/dist/light-runtime-api.js +5 -0
  38. package/dist/login-DymdrKca.js +52 -0
  39. package/dist/login-qr-DIS0Iv-7.js +378 -0
  40. package/dist/login-qr-api.js +2 -0
  41. package/dist/login-qr-runtime.js +16 -0
  42. package/dist/monitor-C4Fhg_lD.js +3349 -0
  43. package/dist/normalize-CWYiGkXw.js +2 -0
  44. package/dist/normalize-target-BPVHNsM5.js +74 -0
  45. package/dist/outbound-adapter-BssVnZdz.js +29 -0
  46. package/dist/outbound-base-Bq1UYEK5.js +119 -0
  47. package/dist/outbound-media-contract-CGss_QHy.js +163 -0
  48. package/dist/outbound-payload-test-api.js +2 -0
  49. package/dist/quoted-message-TENQzyxV.js +108 -0
  50. package/dist/reaction-level-CRVEVAfi.js +16 -0
  51. package/dist/reply-resolver.runtime-BRCgoO4C.js +2 -0
  52. package/dist/resolve-outbound-target-CN-Wo6IY.js +39 -0
  53. package/dist/rolldown-runtime-RkAeH_Qm.js +27 -0
  54. package/dist/runtime-6fZ67abR.js +8 -0
  55. package/dist/runtime-api.js +15 -0
  56. package/dist/runtime-group-policy-Gp1lQ0at.js +11 -0
  57. package/dist/secret-contract-api.js +5 -0
  58. package/dist/security-contract-DqH8JDX6.js +26 -0
  59. package/dist/security-contract-api.js +2 -0
  60. package/dist/send-CIyLFxdZ.js +234 -0
  61. package/dist/session-contract-B0efQf9P.js +27 -0
  62. package/dist/session-errors-CSuKZPub.js +63 -0
  63. package/dist/session.runtime-C1eSE_KK.js +13 -0
  64. package/dist/setup-core-DZKvpzbH.js +46 -0
  65. package/dist/setup-entry.js +23 -0
  66. package/dist/setup-plugin-api.js +2 -0
  67. package/dist/setup-surface-ieFnIW4g.js +344 -0
  68. package/dist/shared-D_wzSVar.js +307 -0
  69. package/dist/state-migrations-DnCdvoYD.js +39 -0
  70. package/dist/targets.js +2 -0
  71. package/dist/test-api.js +3 -0
  72. package/dist/text-runtime-C1zNiZeO.js +116 -0
  73. package/package.json +14 -6
  74. package/action-runtime-api.ts +0 -1
  75. package/action-runtime.runtime.ts +0 -1
  76. package/api.ts +0 -213
  77. package/auth-presence.ts +0 -80
  78. package/channel-config-api.ts +0 -1
  79. package/channel-plugin-api.ts +0 -3
  80. package/config-api.ts +0 -4
  81. package/constants.ts +0 -1
  82. package/contract-api.ts +0 -29
  83. package/directory-contract-api.ts +0 -4
  84. package/doctor-contract-api.ts +0 -8
  85. package/index.test.ts +0 -13
  86. package/index.ts +0 -16
  87. package/legacy-session-surface-api.ts +0 -6
  88. package/legacy-state-migrations-api.ts +0 -1
  89. package/light-runtime-api.ts +0 -12
  90. package/login-qr-api.ts +0 -1
  91. package/login-qr-runtime.ts +0 -23
  92. package/outbound-payload-test-api.ts +0 -1
  93. package/runtime-api.ts +0 -84
  94. package/secret-contract-api.ts +0 -4
  95. package/security-contract-api.ts +0 -4
  96. package/setup-entry.test.ts +0 -21
  97. package/setup-entry.ts +0 -21
  98. package/setup-plugin-api.ts +0 -3
  99. package/src/account-config.ts +0 -77
  100. package/src/account-ids.ts +0 -13
  101. package/src/account-types.ts +0 -5
  102. package/src/accounts.test.ts +0 -182
  103. package/src/accounts.ts +0 -176
  104. package/src/accounts.whatsapp-auth.test.ts +0 -59
  105. package/src/action-runtime-target-auth.ts +0 -27
  106. package/src/action-runtime.test.ts +0 -330
  107. package/src/action-runtime.ts +0 -76
  108. package/src/active-listener.test.ts +0 -65
  109. package/src/active-listener.ts +0 -17
  110. package/src/agent-tools-login.test.ts +0 -81
  111. package/src/agent-tools-login.ts +0 -113
  112. package/src/approval-auth.test.ts +0 -24
  113. package/src/approval-auth.ts +0 -27
  114. package/src/auth-store.runtime.ts +0 -1
  115. package/src/auth-store.test.ts +0 -311
  116. package/src/auth-store.ts +0 -502
  117. package/src/auto-reply/config.runtime.ts +0 -16
  118. package/src/auto-reply/constants.ts +0 -1
  119. package/src/auto-reply/deliver-reply.test.ts +0 -843
  120. package/src/auto-reply/deliver-reply.ts +0 -279
  121. package/src/auto-reply/loggers.ts +0 -6
  122. package/src/auto-reply/mentions.ts +0 -131
  123. package/src/auto-reply/monitor/ack-reaction.test.ts +0 -170
  124. package/src/auto-reply/monitor/ack-reaction.ts +0 -99
  125. package/src/auto-reply/monitor/audio-preflight.runtime.ts +0 -9
  126. package/src/auto-reply/monitor/broadcast.ts +0 -153
  127. package/src/auto-reply/monitor/commands.ts +0 -19
  128. package/src/auto-reply/monitor/echo.ts +0 -64
  129. package/src/auto-reply/monitor/group-activation.runtime.ts +0 -1
  130. package/src/auto-reply/monitor/group-activation.test.ts +0 -189
  131. package/src/auto-reply/monitor/group-activation.ts +0 -73
  132. package/src/auto-reply/monitor/group-gating.audio-preflight.test.ts +0 -103
  133. package/src/auto-reply/monitor/group-gating.runtime.ts +0 -8
  134. package/src/auto-reply/monitor/group-gating.ts +0 -217
  135. package/src/auto-reply/monitor/group-members.test.ts +0 -56
  136. package/src/auto-reply/monitor/group-members.ts +0 -65
  137. package/src/auto-reply/monitor/inbound-context.test.ts +0 -97
  138. package/src/auto-reply/monitor/inbound-context.ts +0 -92
  139. package/src/auto-reply/monitor/inbound-dispatch.runtime.ts +0 -21
  140. package/src/auto-reply/monitor/inbound-dispatch.test.ts +0 -895
  141. package/src/auto-reply/monitor/inbound-dispatch.ts +0 -422
  142. package/src/auto-reply/monitor/last-route.test.ts +0 -37
  143. package/src/auto-reply/monitor/last-route.ts +0 -61
  144. package/src/auto-reply/monitor/message-line.runtime.ts +0 -38
  145. package/src/auto-reply/monitor/message-line.ts +0 -54
  146. package/src/auto-reply/monitor/on-message.audio-preflight.test.ts +0 -354
  147. package/src/auto-reply/monitor/on-message.ts +0 -291
  148. package/src/auto-reply/monitor/peer.ts +0 -17
  149. package/src/auto-reply/monitor/process-message.audio-preflight.test.ts +0 -420
  150. package/src/auto-reply/monitor/process-message.test.ts +0 -355
  151. package/src/auto-reply/monitor/process-message.ts +0 -531
  152. package/src/auto-reply/monitor/runtime-api.ts +0 -30
  153. package/src/auto-reply/monitor-state.test.ts +0 -64
  154. package/src/auto-reply/monitor-state.ts +0 -106
  155. package/src/auto-reply/monitor.ts +0 -600
  156. package/src/auto-reply/reply-resolver.runtime.ts +0 -1
  157. package/src/auto-reply/types.ts +0 -48
  158. package/src/auto-reply/util.ts +0 -63
  159. package/src/auto-reply/web-auto-reply-monitor.test.ts +0 -687
  160. package/src/auto-reply/web-auto-reply-utils.test.ts +0 -392
  161. package/src/auto-reply.broadcast-groups.combined.test.ts +0 -246
  162. package/src/auto-reply.broadcast-groups.test-harness.ts +0 -47
  163. package/src/auto-reply.impl.ts +0 -6
  164. package/src/auto-reply.test-harness.ts +0 -421
  165. package/src/auto-reply.ts +0 -1
  166. package/src/auto-reply.web-auto-reply.compresses-common-formats-jpeg-cap.test.ts +0 -427
  167. package/src/auto-reply.web-auto-reply.connection-and-logging.e2e.test.ts +0 -908
  168. package/src/auto-reply.web-auto-reply.last-route.test.ts +0 -184
  169. package/src/channel-actions.runtime.ts +0 -7
  170. package/src/channel-actions.test.ts +0 -216
  171. package/src/channel-actions.ts +0 -84
  172. package/src/channel-outbound.test.ts +0 -131
  173. package/src/channel-outbound.ts +0 -36
  174. package/src/channel-react-action.runtime.ts +0 -7
  175. package/src/channel-react-action.test.ts +0 -294
  176. package/src/channel-react-action.ts +0 -84
  177. package/src/channel.runtime.ts +0 -117
  178. package/src/channel.setup.test.ts +0 -461
  179. package/src/channel.setup.ts +0 -28
  180. package/src/channel.ts +0 -339
  181. package/src/command-policy.ts +0 -7
  182. package/src/config-accessors.test.ts +0 -34
  183. package/src/config-accessors.ts +0 -22
  184. package/src/config-schema.test.ts +0 -121
  185. package/src/config-schema.ts +0 -6
  186. package/src/config-ui-hints.ts +0 -24
  187. package/src/connection-controller-registry.test.ts +0 -27
  188. package/src/connection-controller-registry.ts +0 -49
  189. package/src/connection-controller.test.ts +0 -282
  190. package/src/connection-controller.ts +0 -679
  191. package/src/creds-files.ts +0 -19
  192. package/src/creds-persistence.ts +0 -102
  193. package/src/directory-config.test.ts +0 -60
  194. package/src/directory-config.ts +0 -40
  195. package/src/directory-contract.test.ts +0 -56
  196. package/src/doctor-contract.ts +0 -11
  197. package/src/doctor.test.ts +0 -74
  198. package/src/doctor.ts +0 -56
  199. package/src/group-intro.ts +0 -15
  200. package/src/group-policy.test.ts +0 -36
  201. package/src/group-policy.ts +0 -40
  202. package/src/group-session-contract.ts +0 -20
  203. package/src/group-session-key.test.ts +0 -53
  204. package/src/group-session-key.ts +0 -41
  205. package/src/heartbeat.ts +0 -34
  206. package/src/identity.ts +0 -164
  207. package/src/inbound/access-control.test-harness.ts +0 -37
  208. package/src/inbound/access-control.test.ts +0 -375
  209. package/src/inbound/access-control.ts +0 -237
  210. package/src/inbound/dedupe.ts +0 -132
  211. package/src/inbound/extract.test.ts +0 -282
  212. package/src/inbound/extract.ts +0 -488
  213. package/src/inbound/lifecycle.ts +0 -39
  214. package/src/inbound/media.node.test.ts +0 -83
  215. package/src/inbound/media.ts +0 -102
  216. package/src/inbound/monitor.ts +0 -890
  217. package/src/inbound/runtime-api.ts +0 -7
  218. package/src/inbound/save-media.runtime.ts +0 -1
  219. package/src/inbound/send-api.test.ts +0 -319
  220. package/src/inbound/send-api.ts +0 -145
  221. package/src/inbound/send-result.ts +0 -61
  222. package/src/inbound/types.ts +0 -106
  223. package/src/inbound-context.contract.test.ts +0 -32
  224. package/src/inbound-policy.ts +0 -231
  225. package/src/inbound.media.test.ts +0 -320
  226. package/src/inbound.test.ts +0 -290
  227. package/src/inbound.ts +0 -9
  228. package/src/login-qr.test.ts +0 -483
  229. package/src/login-qr.ts +0 -542
  230. package/src/login.coverage.test.ts +0 -133
  231. package/src/login.test.ts +0 -89
  232. package/src/login.ts +0 -70
  233. package/src/logout.test.ts +0 -162
  234. package/src/media.test.ts +0 -480
  235. package/src/media.ts +0 -10
  236. package/src/monitor-inbox.allows-messages-from-senders-allowfrom-list.test-support.ts +0 -400
  237. package/src/monitor-inbox.append-upsert.test-support.ts +0 -133
  238. package/src/monitor-inbox.behavior.test.ts +0 -5
  239. package/src/monitor-inbox.blocks-messages-from-unauthorized-senders-not-allowfrom.test-support.ts +0 -362
  240. package/src/monitor-inbox.captures-media-path-image-messages.test-support.ts +0 -306
  241. package/src/monitor-inbox.streams-inbound-messages.test-support.ts +0 -729
  242. package/src/monitor-inbox.test-harness.ts +0 -304
  243. package/src/normalize-target.ts +0 -123
  244. package/src/normalize.ts +0 -7
  245. package/src/outbound-adapter.poll.test.ts +0 -62
  246. package/src/outbound-adapter.sendpayload.test.ts +0 -195
  247. package/src/outbound-adapter.ts +0 -36
  248. package/src/outbound-base.test.ts +0 -560
  249. package/src/outbound-base.ts +0 -244
  250. package/src/outbound-media-contract.ts +0 -278
  251. package/src/outbound-media.runtime.ts +0 -36
  252. package/src/outbound-payload.contract.test.ts +0 -61
  253. package/src/outbound-send-deps.ts +0 -1
  254. package/src/outbound-test-support.ts +0 -16
  255. package/src/pairing-security.test-harness.ts +0 -59
  256. package/src/qr-image.ts +0 -1
  257. package/src/qr-terminal.ts +0 -1
  258. package/src/quoted-message.test.ts +0 -83
  259. package/src/quoted-message.ts +0 -184
  260. package/src/reaction-level.test.ts +0 -94
  261. package/src/reaction-level.ts +0 -21
  262. package/src/reconnect.test.ts +0 -51
  263. package/src/reconnect.ts +0 -55
  264. package/src/resolve-outbound-target.test.ts +0 -288
  265. package/src/resolve-outbound-target.ts +0 -58
  266. package/src/resolve-target.test.ts +0 -120
  267. package/src/runtime-api.ts +0 -59
  268. package/src/runtime-group-policy.ts +0 -16
  269. package/src/runtime.ts +0 -9
  270. package/src/security-contract.ts +0 -47
  271. package/src/security-fix.ts +0 -71
  272. package/src/send.test.ts +0 -534
  273. package/src/send.ts +0 -292
  274. package/src/session-contract.test.ts +0 -31
  275. package/src/session-contract.ts +0 -43
  276. package/src/session-errors.ts +0 -125
  277. package/src/session-route.test.ts +0 -41
  278. package/src/session-route.ts +0 -32
  279. package/src/session.runtime.ts +0 -8
  280. package/src/session.test.ts +0 -559
  281. package/src/session.ts +0 -330
  282. package/src/setup-core.ts +0 -52
  283. package/src/setup-finalize.ts +0 -446
  284. package/src/setup-surface.test.ts +0 -367
  285. package/src/setup-surface.ts +0 -69
  286. package/src/setup-test-helpers.ts +0 -216
  287. package/src/shared.ts +0 -291
  288. package/src/socket-timing.test.ts +0 -49
  289. package/src/socket-timing.ts +0 -38
  290. package/src/state-migrations.ts +0 -54
  291. package/src/status-issues.test.ts +0 -137
  292. package/src/status-issues.ts +0 -185
  293. package/src/system-prompt.test.ts +0 -199
  294. package/src/system-prompt.ts +0 -31
  295. package/src/targets-runtime.ts +0 -180
  296. package/src/test-helpers.ts +0 -690
  297. package/src/text-runtime.test.ts +0 -162
  298. package/src/text-runtime.ts +0 -11
  299. package/src/vcard.ts +0 -84
  300. package/targets.ts +0 -5
  301. package/test-api.ts +0 -2
  302. package/tsconfig.json +0 -16
@@ -1,355 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
- import type { WhatsAppSendResult } from "../../inbound/send-result.js";
3
-
4
- // Hoisted mocks used across tests so vi.mock factories can reference them.
5
- const { resolvePolicyMock, buildContextMock, runMessageReceivedMock, trackBackgroundTaskMock } =
6
- vi.hoisted(() => ({
7
- resolvePolicyMock: vi.fn(),
8
- buildContextMock: vi.fn(),
9
- runMessageReceivedMock: vi.fn(async () => undefined),
10
- trackBackgroundTaskMock: vi.fn(),
11
- }));
12
-
13
- function acceptedSendResult(kind: "media" | "text", id: string): WhatsAppSendResult {
14
- return {
15
- kind,
16
- messageId: id,
17
- messageIds: [id],
18
- keys: [{ id }],
19
- providerAccepted: true,
20
- };
21
- }
22
-
23
- vi.mock("../../inbound-policy.js", async (importOriginal) => {
24
- const actual = await importOriginal<typeof import("../../inbound-policy.js")>();
25
- return {
26
- ...actual,
27
- resolveWhatsAppCommandAuthorized: async () => true,
28
- resolveWhatsAppInboundPolicy: resolvePolicyMock,
29
- };
30
- });
31
-
32
- vi.mock("./inbound-dispatch.js", async (importOriginal) => {
33
- const actual = await importOriginal<typeof import("./inbound-dispatch.js")>();
34
- return {
35
- ...actual,
36
- buildWhatsAppInboundContext: buildContextMock,
37
- dispatchWhatsAppBufferedReply: async () => ({
38
- queuedFinal: false,
39
- counts: { tool: 0, block: 0, final: 0 },
40
- }),
41
- resolveWhatsAppDmRouteTarget: () => null,
42
- resolveWhatsAppResponsePrefix: () => undefined,
43
- updateWhatsAppMainLastRoute: () => {},
44
- };
45
- });
46
-
47
- vi.mock("openclaw/plugin-sdk/plugin-runtime", () => ({
48
- getGlobalHookRunner: () => ({
49
- hasHooks: (hookName: string) => hookName === "message_received",
50
- runMessageReceived: runMessageReceivedMock,
51
- }),
52
- }));
53
-
54
- vi.mock("../../identity.js", async (importOriginal) => {
55
- const actual = await importOriginal<typeof import("../../identity.js")>();
56
- return {
57
- ...actual,
58
- getPrimaryIdentityId: () => null,
59
- getSelfIdentity: () => ({ e164: "+15550001111" }),
60
- getSenderIdentity: () => ({ name: "Alice", e164: "+15550002222" }),
61
- };
62
- });
63
-
64
- vi.mock("../../reconnect.js", async (importOriginal) => {
65
- const actual = await importOriginal<typeof import("../../reconnect.js")>();
66
- return { ...actual, newConnectionId: () => "test-conn-id" };
67
- });
68
-
69
- vi.mock("../../session.js", async (importOriginal) => {
70
- const actual = await importOriginal<typeof import("../../session.js")>();
71
- return { ...actual, formatError: (e: unknown) => String(e) };
72
- });
73
-
74
- vi.mock("../deliver-reply.js", async (importOriginal) => {
75
- const actual = await importOriginal<typeof import("../deliver-reply.js")>();
76
- return { ...actual, deliverWebReply: async () => {} };
77
- });
78
-
79
- vi.mock("../loggers.js", async (importOriginal) => {
80
- const actual = await importOriginal<typeof import("../loggers.js")>();
81
- return {
82
- ...actual,
83
- whatsappInboundLog: { info: () => {}, debug: () => {} },
84
- };
85
- });
86
-
87
- vi.mock("./ack-reaction.js", async (importOriginal) => {
88
- const actual = await importOriginal<typeof import("./ack-reaction.js")>();
89
- return { ...actual, maybeSendAckReaction: async () => {} };
90
- });
91
-
92
- vi.mock("./inbound-context.js", async (importOriginal) => {
93
- const actual = await importOriginal<typeof import("./inbound-context.js")>();
94
- return {
95
- ...actual,
96
- resolveVisibleWhatsAppGroupHistory: () => [],
97
- resolveVisibleWhatsAppReplyContext: () => null,
98
- };
99
- });
100
-
101
- vi.mock("./last-route.js", async (importOriginal) => {
102
- const actual = await importOriginal<typeof import("./last-route.js")>();
103
- return {
104
- ...actual,
105
- trackBackgroundTask: trackBackgroundTaskMock,
106
- updateLastRouteInBackground: () => {},
107
- };
108
- });
109
-
110
- vi.mock("./message-line.js", async (importOriginal) => {
111
- const actual = await importOriginal<typeof import("./message-line.js")>();
112
- return { ...actual, buildInboundLine: () => "hi" };
113
- });
114
-
115
- vi.mock("./runtime-api.js", async (importOriginal) => {
116
- const actual = await importOriginal<typeof import("./runtime-api.js")>();
117
- return {
118
- ...actual,
119
- buildHistoryContextFromEntries: () => "hi",
120
- createChannelReplyPipeline: () => ({ onModelSelected: () => {}, responsePrefix: undefined }),
121
- formatInboundEnvelope: () => "hi",
122
- logVerbose: () => {},
123
- normalizeE164: (v: string) => v,
124
- recordSessionMetaFromInbound: async () => {},
125
- resolveChannelContextVisibilityMode: () => "off",
126
- resolveInboundSessionEnvelopeContext: () => ({
127
- storePath: "/tmp",
128
- envelopeOptions: {},
129
- previousTimestamp: undefined,
130
- }),
131
- resolvePinnedMainDmOwnerFromAllowlist: () => null,
132
- shouldComputeCommandAuthorized: () => false,
133
- shouldLogVerbose: () => false,
134
- };
135
- });
136
-
137
- import { clearInternalHooks, registerInternalHook } from "openclaw/plugin-sdk/hook-runtime";
138
- import { processMessage } from "./process-message.js";
139
-
140
- // ---------------------------------------------------------------------------
141
- // Helpers
142
- // ---------------------------------------------------------------------------
143
-
144
- function makeAccount(groups: Record<string, { systemPrompt?: string }> = {}): {
145
- accountId: string;
146
- authDir: string;
147
- groups: Record<string, { systemPrompt?: string }>;
148
- } {
149
- return { accountId: "default", authDir: "/tmp/wa-test-auth", groups };
150
- }
151
-
152
- function makePolicy(account: ReturnType<typeof makeAccount>) {
153
- return {
154
- account,
155
- dmPolicy: "pairing",
156
- groupPolicy: "allowlist",
157
- configuredAllowFrom: [],
158
- dmAllowFrom: [],
159
- groupAllowFrom: [],
160
- isSelfChat: false,
161
- providerMissingFallbackApplied: false,
162
- shouldReadStorePairingApprovals: true,
163
- isSamePhone: () => false,
164
- isDmSenderAllowed: () => false,
165
- isGroupSenderAllowed: () => false,
166
- resolveConversationGroupPolicy: () => "allowlist",
167
- resolveConversationRequireMention: () => false,
168
- };
169
- }
170
-
171
- const GROUP_JID = "123@g.us";
172
-
173
- const baseMsg = {
174
- id: "msg1",
175
- from: GROUP_JID,
176
- to: "+15550001111",
177
- conversationId: GROUP_JID,
178
- accountId: "default",
179
- chatId: GROUP_JID,
180
- chatType: "group" as const,
181
- body: "hi",
182
- sendComposing: async () => {},
183
- reply: async () => acceptedSendResult("text", "r1"),
184
- sendMedia: async () => acceptedSendResult("media", "m1"),
185
- };
186
-
187
- const baseRoute = {
188
- agentId: "main",
189
- channel: "whatsapp",
190
- accountId: "default",
191
- sessionKey: "agent:main:whatsapp:group:123@g.us",
192
- mainSessionKey: "agent:main:whatsapp:group:123@g.us",
193
- lastRoutePolicy: "main",
194
- matchedBy: "default",
195
- };
196
-
197
- function callProcessMessage(overrides: { cfg?: unknown } = {}) {
198
- return processMessage({
199
- cfg: (overrides.cfg ?? {}) as never,
200
- msg: baseMsg as never,
201
- route: baseRoute as never,
202
- groupHistoryKey: "whatsapp:default:group:123@g.us",
203
- groupHistories: new Map(),
204
- groupMemberNames: new Map(),
205
- connectionId: "conn-1",
206
- verbose: false,
207
- maxMediaBytes: 1024,
208
- replyResolver: (async () => undefined) as never,
209
- replyLogger: { info: () => {}, warn: () => {}, error: () => {}, debug: () => {} } as never,
210
- backgroundTasks: new Set(),
211
- rememberSentText: () => {},
212
- echoHas: () => false,
213
- echoForget: () => {},
214
- buildCombinedEchoKey: ({ sessionKey }) => sessionKey,
215
- });
216
- }
217
-
218
- // ---------------------------------------------------------------------------
219
- // Tests
220
- // ---------------------------------------------------------------------------
221
-
222
- describe("processMessage group system prompt wiring", () => {
223
- beforeEach(() => {
224
- buildContextMock.mockReset();
225
- resolvePolicyMock.mockReset();
226
- runMessageReceivedMock.mockClear();
227
- trackBackgroundTaskMock.mockClear();
228
- clearInternalHooks();
229
- buildContextMock.mockImplementation(
230
- (params: { groupSystemPrompt?: string; combinedBody?: string }) => ({
231
- GroupSystemPrompt: params.groupSystemPrompt,
232
- Body: params.combinedBody ?? "",
233
- }),
234
- );
235
- });
236
-
237
- afterEach(() => {
238
- clearInternalHooks();
239
- });
240
-
241
- it("resolves group systemPrompt from account config and passes it into buildWhatsAppInboundContext", async () => {
242
- resolvePolicyMock.mockReturnValue(
243
- makePolicy(makeAccount({ [GROUP_JID]: { systemPrompt: "from config" } })),
244
- );
245
-
246
- await callProcessMessage();
247
-
248
- expect(buildContextMock.mock.calls[0][0].groupSystemPrompt).toBe("from config");
249
- });
250
-
251
- it("fires message_received hooks with canonical WhatsApp correlation fields", async () => {
252
- const internalReceived = vi.fn();
253
- registerInternalHook("message:received", internalReceived);
254
- resolvePolicyMock.mockReturnValue(makePolicy(makeAccount()));
255
- buildContextMock.mockImplementationOnce(() => ({
256
- Body: "hi",
257
- BodyForCommands: "hi",
258
- RawBody: "hi",
259
- CommandBody: "hi",
260
- From: GROUP_JID,
261
- To: "+15550001111",
262
- SessionKey: baseRoute.sessionKey,
263
- AccountId: "default",
264
- MessageSid: "msg1",
265
- SenderId: "+15550002222",
266
- SenderName: "Alice",
267
- SenderE164: "+15550002222",
268
- Timestamp: 1710000000,
269
- Provider: "whatsapp",
270
- Surface: "whatsapp",
271
- OriginatingChannel: "whatsapp",
272
- OriginatingTo: GROUP_JID,
273
- GroupSubject: "Test Group",
274
- }));
275
-
276
- await callProcessMessage({
277
- cfg: {
278
- channels: {
279
- whatsapp: {
280
- pluginHooks: {
281
- messageReceived: true,
282
- },
283
- },
284
- },
285
- },
286
- });
287
- await Promise.resolve();
288
- await Promise.resolve();
289
-
290
- expect(runMessageReceivedMock).toHaveBeenCalledTimes(1);
291
- expect(runMessageReceivedMock).toHaveBeenCalledWith(
292
- expect.objectContaining({
293
- from: GROUP_JID,
294
- content: "hi",
295
- timestamp: 1710000000,
296
- messageId: "msg1",
297
- senderId: "+15550002222",
298
- sessionKey: baseRoute.sessionKey,
299
- }),
300
- expect.objectContaining({
301
- channelId: "whatsapp",
302
- accountId: "default",
303
- conversationId: GROUP_JID,
304
- sessionKey: baseRoute.sessionKey,
305
- messageId: "msg1",
306
- senderId: "+15550002222",
307
- }),
308
- );
309
- expect(internalReceived).toHaveBeenCalledWith(
310
- expect.objectContaining({
311
- type: "message",
312
- action: "received",
313
- sessionKey: baseRoute.sessionKey,
314
- context: expect.objectContaining({
315
- from: GROUP_JID,
316
- content: "hi",
317
- timestamp: 1710000000,
318
- channelId: "whatsapp",
319
- accountId: "default",
320
- conversationId: GROUP_JID,
321
- messageId: "msg1",
322
- }),
323
- }),
324
- );
325
- });
326
-
327
- it("does not fire WhatsApp message_received hooks without explicit opt-in", async () => {
328
- const internalReceived = vi.fn();
329
- registerInternalHook("message:received", internalReceived);
330
- resolvePolicyMock.mockReturnValue(makePolicy(makeAccount()));
331
-
332
- await callProcessMessage();
333
-
334
- expect(runMessageReceivedMock).not.toHaveBeenCalled();
335
- expect(internalReceived).not.toHaveBeenCalled();
336
- });
337
-
338
- it("tracks session metadata writes as connection background tasks", async () => {
339
- resolvePolicyMock.mockReturnValue(makePolicy(makeAccount()));
340
- buildContextMock.mockImplementationOnce(() => ({
341
- Body: "hi",
342
- RawBody: "hi",
343
- CommandBody: "hi",
344
- SessionKey: baseRoute.sessionKey,
345
- Provider: "whatsapp",
346
- Surface: "whatsapp",
347
- }));
348
-
349
- await callProcessMessage();
350
-
351
- expect(trackBackgroundTaskMock).toHaveBeenCalledTimes(1);
352
- expect(trackBackgroundTaskMock.mock.calls[0]?.[0]).toBeInstanceOf(Set);
353
- expect(trackBackgroundTaskMock.mock.calls[0]?.[1]).toBeInstanceOf(Promise);
354
- });
355
- });