lightclawbot 1.1.2 → 1.2.0-beta.0

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 (397) hide show
  1. package/README.md +0 -1
  2. package/dist/index.js +38 -31
  3. package/dist/setup-entry.js +32 -0
  4. package/dist/src/channel.js +301 -257
  5. package/dist/src/channel.setup.js +16 -0
  6. package/dist/src/config.js +31 -124
  7. package/dist/src/dedup.js +0 -1
  8. package/dist/src/download-tool.js +0 -1
  9. package/dist/src/file-storage.js +2 -2
  10. package/dist/src/gateway.js +226 -178
  11. package/dist/src/history/cron-utils.js +0 -1
  12. package/dist/src/history/index.js +0 -1
  13. package/dist/src/history/message-parser.js +0 -1
  14. package/dist/src/history/session-reader.js +3 -1
  15. package/dist/src/history/session-store.js +0 -1
  16. package/dist/src/history/text-processing.js +0 -1
  17. package/dist/src/history/types.js +0 -1
  18. package/dist/src/inbound.js +183 -234
  19. package/dist/src/media.js +0 -1
  20. package/dist/src/messaging.js +65 -0
  21. package/dist/src/outbound.js +131 -45
  22. package/dist/src/runtime.js +29 -11
  23. package/dist/src/setup-core.js +27 -0
  24. package/dist/src/shared.js +141 -0
  25. package/dist/src/socket/handlers.js +72 -49
  26. package/dist/src/socket/index.js +0 -1
  27. package/dist/src/socket/native-socket.js +385 -0
  28. package/dist/src/socket/registry.js +0 -1
  29. package/dist/src/socket/reliable-emitter.js +188 -50
  30. package/dist/src/streaming/delta-tracker.js +140 -0
  31. package/dist/src/streaming/index.js +12 -0
  32. package/dist/src/streaming/stream-reply-sink.js +387 -0
  33. package/dist/src/streaming/types.js +4 -0
  34. package/dist/src/tools.js +13 -0
  35. package/dist/src/types.js +23 -2
  36. package/dist/src/upload-tool.js +0 -1
  37. package/dist/src/utils/account.js +73 -0
  38. package/dist/src/utils/common.js +48 -0
  39. package/dist/src/utils/index.js +2 -0
  40. package/node_modules/ws/index.js +22 -0
  41. package/node_modules/{engine.io-client/node_modules/ws → ws}/lib/constants.js +1 -0
  42. package/node_modules/{engine.io-client/node_modules/ws → ws}/lib/permessage-deflate.js +6 -6
  43. package/node_modules/{engine.io-client/node_modules/ws → ws}/lib/websocket-server.js +10 -6
  44. package/node_modules/{engine.io-client/node_modules/ws → ws}/lib/websocket.js +19 -14
  45. package/node_modules/{engine.io-client/node_modules/ws → ws}/package.json +4 -3
  46. package/node_modules/ws/wrapper.mjs +21 -0
  47. package/openclaw.plugin.json +0 -7
  48. package/package.json +8 -5
  49. package/dist/index.d.ts +0 -24
  50. package/dist/index.d.ts.map +0 -1
  51. package/dist/index.js.map +0 -1
  52. package/dist/public/data/scripts/manifest.json +0 -11
  53. package/dist/public/data/scripts/preflight.9af62b39.sh +0 -191
  54. package/dist/public/data/scripts/preflight.sh +0 -191
  55. package/dist/src/channel.d.ts +0 -11
  56. package/dist/src/channel.d.ts.map +0 -1
  57. package/dist/src/channel.js.map +0 -1
  58. package/dist/src/config.d.ts +0 -129
  59. package/dist/src/config.d.ts.map +0 -1
  60. package/dist/src/config.js.map +0 -1
  61. package/dist/src/dedup.d.ts +0 -12
  62. package/dist/src/dedup.d.ts.map +0 -1
  63. package/dist/src/dedup.js.map +0 -1
  64. package/dist/src/download-tool.d.ts +0 -32
  65. package/dist/src/download-tool.d.ts.map +0 -1
  66. package/dist/src/download-tool.js.map +0 -1
  67. package/dist/src/file-storage.d.ts +0 -74
  68. package/dist/src/file-storage.d.ts.map +0 -1
  69. package/dist/src/file-storage.js.map +0 -1
  70. package/dist/src/format-urls.d.ts +0 -26
  71. package/dist/src/format-urls.d.ts.map +0 -1
  72. package/dist/src/format-urls.js +0 -53
  73. package/dist/src/format-urls.js.map +0 -1
  74. package/dist/src/gateway.d.ts +0 -16
  75. package/dist/src/gateway.d.ts.map +0 -1
  76. package/dist/src/gateway.js.map +0 -1
  77. package/dist/src/history/cron-utils.d.ts +0 -76
  78. package/dist/src/history/cron-utils.d.ts.map +0 -1
  79. package/dist/src/history/cron-utils.js.map +0 -1
  80. package/dist/src/history/index.d.ts +0 -20
  81. package/dist/src/history/index.d.ts.map +0 -1
  82. package/dist/src/history/index.js.map +0 -1
  83. package/dist/src/history/message-parser.d.ts +0 -52
  84. package/dist/src/history/message-parser.d.ts.map +0 -1
  85. package/dist/src/history/message-parser.js.map +0 -1
  86. package/dist/src/history/session-reader.d.ts +0 -58
  87. package/dist/src/history/session-reader.d.ts.map +0 -1
  88. package/dist/src/history/session-reader.js.map +0 -1
  89. package/dist/src/history/session-store.d.ts +0 -42
  90. package/dist/src/history/session-store.d.ts.map +0 -1
  91. package/dist/src/history/session-store.js.map +0 -1
  92. package/dist/src/history/text-processing.d.ts +0 -41
  93. package/dist/src/history/text-processing.d.ts.map +0 -1
  94. package/dist/src/history/text-processing.js.map +0 -1
  95. package/dist/src/history/types.d.ts +0 -134
  96. package/dist/src/history/types.d.ts.map +0 -1
  97. package/dist/src/history/types.js.map +0 -1
  98. package/dist/src/inbound.d.ts +0 -18
  99. package/dist/src/inbound.d.ts.map +0 -1
  100. package/dist/src/inbound.js.map +0 -1
  101. package/dist/src/media.d.ts +0 -12
  102. package/dist/src/media.d.ts.map +0 -1
  103. package/dist/src/media.js.map +0 -1
  104. package/dist/src/outbound.d.ts +0 -28
  105. package/dist/src/outbound.d.ts.map +0 -1
  106. package/dist/src/outbound.js.map +0 -1
  107. package/dist/src/runtime.d.ts +0 -4
  108. package/dist/src/runtime.d.ts.map +0 -1
  109. package/dist/src/runtime.js.map +0 -1
  110. package/dist/src/socket/handlers.d.ts +0 -26
  111. package/dist/src/socket/handlers.d.ts.map +0 -1
  112. package/dist/src/socket/handlers.js.map +0 -1
  113. package/dist/src/socket/index.d.ts +0 -11
  114. package/dist/src/socket/index.d.ts.map +0 -1
  115. package/dist/src/socket/index.js.map +0 -1
  116. package/dist/src/socket/registry.d.ts +0 -59
  117. package/dist/src/socket/registry.d.ts.map +0 -1
  118. package/dist/src/socket/registry.js.map +0 -1
  119. package/dist/src/socket/reliable-emitter.d.ts +0 -79
  120. package/dist/src/socket/reliable-emitter.d.ts.map +0 -1
  121. package/dist/src/socket/reliable-emitter.js.map +0 -1
  122. package/dist/src/types.d.ts +0 -112
  123. package/dist/src/types.d.ts.map +0 -1
  124. package/dist/src/types.js.map +0 -1
  125. package/dist/src/upload-tool.d.ts +0 -27
  126. package/dist/src/upload-tool.d.ts.map +0 -1
  127. package/dist/src/upload-tool.js.map +0 -1
  128. package/node_modules/@socket.io/component-emitter/LICENSE +0 -24
  129. package/node_modules/@socket.io/component-emitter/Readme.md +0 -79
  130. package/node_modules/@socket.io/component-emitter/lib/cjs/index.d.ts +0 -179
  131. package/node_modules/@socket.io/component-emitter/lib/cjs/index.js +0 -176
  132. package/node_modules/@socket.io/component-emitter/lib/cjs/package.json +0 -4
  133. package/node_modules/@socket.io/component-emitter/lib/esm/index.d.ts +0 -179
  134. package/node_modules/@socket.io/component-emitter/lib/esm/index.js +0 -169
  135. package/node_modules/@socket.io/component-emitter/lib/esm/package.json +0 -4
  136. package/node_modules/@socket.io/component-emitter/package.json +0 -28
  137. package/node_modules/debug/LICENSE +0 -20
  138. package/node_modules/debug/README.md +0 -481
  139. package/node_modules/debug/package.json +0 -64
  140. package/node_modules/debug/src/browser.js +0 -272
  141. package/node_modules/debug/src/common.js +0 -292
  142. package/node_modules/debug/src/index.js +0 -10
  143. package/node_modules/debug/src/node.js +0 -263
  144. package/node_modules/engine.io-client/LICENSE +0 -22
  145. package/node_modules/engine.io-client/README.md +0 -331
  146. package/node_modules/engine.io-client/build/cjs/browser-entrypoint.d.ts +0 -3
  147. package/node_modules/engine.io-client/build/cjs/browser-entrypoint.js +0 -4
  148. package/node_modules/engine.io-client/build/cjs/contrib/has-cors.d.ts +0 -1
  149. package/node_modules/engine.io-client/build/cjs/contrib/has-cors.js +0 -14
  150. package/node_modules/engine.io-client/build/cjs/contrib/parseqs.d.ts +0 -15
  151. package/node_modules/engine.io-client/build/cjs/contrib/parseqs.js +0 -38
  152. package/node_modules/engine.io-client/build/cjs/contrib/parseuri.d.ts +0 -1
  153. package/node_modules/engine.io-client/build/cjs/contrib/parseuri.js +0 -67
  154. package/node_modules/engine.io-client/build/cjs/globals.d.ts +0 -4
  155. package/node_modules/engine.io-client/build/cjs/globals.js +0 -26
  156. package/node_modules/engine.io-client/build/cjs/globals.node.d.ts +0 -21
  157. package/node_modules/engine.io-client/build/cjs/globals.node.js +0 -97
  158. package/node_modules/engine.io-client/build/cjs/index.d.ts +0 -15
  159. package/node_modules/engine.io-client/build/cjs/index.js +0 -32
  160. package/node_modules/engine.io-client/build/cjs/package.json +0 -10
  161. package/node_modules/engine.io-client/build/cjs/socket.d.ts +0 -482
  162. package/node_modules/engine.io-client/build/cjs/socket.js +0 -765
  163. package/node_modules/engine.io-client/build/cjs/transport.d.ts +0 -106
  164. package/node_modules/engine.io-client/build/cjs/transport.js +0 -153
  165. package/node_modules/engine.io-client/build/cjs/transports/index.d.ts +0 -8
  166. package/node_modules/engine.io-client/build/cjs/transports/index.js +0 -11
  167. package/node_modules/engine.io-client/build/cjs/transports/polling-fetch.d.ts +0 -15
  168. package/node_modules/engine.io-client/build/cjs/transports/polling-fetch.js +0 -60
  169. package/node_modules/engine.io-client/build/cjs/transports/polling-xhr.d.ts +0 -108
  170. package/node_modules/engine.io-client/build/cjs/transports/polling-xhr.js +0 -285
  171. package/node_modules/engine.io-client/build/cjs/transports/polling-xhr.node.d.ts +0 -11
  172. package/node_modules/engine.io-client/build/cjs/transports/polling-xhr.node.js +0 -44
  173. package/node_modules/engine.io-client/build/cjs/transports/polling.d.ts +0 -52
  174. package/node_modules/engine.io-client/build/cjs/transports/polling.js +0 -165
  175. package/node_modules/engine.io-client/build/cjs/transports/websocket.d.ts +0 -36
  176. package/node_modules/engine.io-client/build/cjs/transports/websocket.js +0 -136
  177. package/node_modules/engine.io-client/build/cjs/transports/websocket.node.d.ts +0 -14
  178. package/node_modules/engine.io-client/build/cjs/transports/websocket.node.js +0 -68
  179. package/node_modules/engine.io-client/build/cjs/transports/webtransport.d.ts +0 -18
  180. package/node_modules/engine.io-client/build/cjs/transports/webtransport.js +0 -94
  181. package/node_modules/engine.io-client/build/cjs/util.d.ts +0 -7
  182. package/node_modules/engine.io-client/build/cjs/util.js +0 -65
  183. package/node_modules/engine.io-client/build/esm/browser-entrypoint.d.ts +0 -3
  184. package/node_modules/engine.io-client/build/esm/browser-entrypoint.js +0 -2
  185. package/node_modules/engine.io-client/build/esm/contrib/has-cors.d.ts +0 -1
  186. package/node_modules/engine.io-client/build/esm/contrib/has-cors.js +0 -11
  187. package/node_modules/engine.io-client/build/esm/contrib/parseqs.d.ts +0 -15
  188. package/node_modules/engine.io-client/build/esm/contrib/parseqs.js +0 -34
  189. package/node_modules/engine.io-client/build/esm/contrib/parseuri.d.ts +0 -1
  190. package/node_modules/engine.io-client/build/esm/contrib/parseuri.js +0 -64
  191. package/node_modules/engine.io-client/build/esm/globals.d.ts +0 -4
  192. package/node_modules/engine.io-client/build/esm/globals.js +0 -22
  193. package/node_modules/engine.io-client/build/esm/globals.node.d.ts +0 -21
  194. package/node_modules/engine.io-client/build/esm/globals.node.js +0 -91
  195. package/node_modules/engine.io-client/build/esm/index.d.ts +0 -15
  196. package/node_modules/engine.io-client/build/esm/index.js +0 -15
  197. package/node_modules/engine.io-client/build/esm/package.json +0 -10
  198. package/node_modules/engine.io-client/build/esm/socket.d.ts +0 -482
  199. package/node_modules/engine.io-client/build/esm/socket.js +0 -727
  200. package/node_modules/engine.io-client/build/esm/transport.d.ts +0 -106
  201. package/node_modules/engine.io-client/build/esm/transport.js +0 -142
  202. package/node_modules/engine.io-client/build/esm/transports/index.d.ts +0 -8
  203. package/node_modules/engine.io-client/build/esm/transports/index.js +0 -8
  204. package/node_modules/engine.io-client/build/esm/transports/polling-fetch.d.ts +0 -15
  205. package/node_modules/engine.io-client/build/esm/transports/polling-fetch.js +0 -56
  206. package/node_modules/engine.io-client/build/esm/transports/polling-xhr.d.ts +0 -108
  207. package/node_modules/engine.io-client/build/esm/transports/polling-xhr.js +0 -271
  208. package/node_modules/engine.io-client/build/esm/transports/polling-xhr.node.d.ts +0 -11
  209. package/node_modules/engine.io-client/build/esm/transports/polling-xhr.node.js +0 -17
  210. package/node_modules/engine.io-client/build/esm/transports/polling.d.ts +0 -52
  211. package/node_modules/engine.io-client/build/esm/transports/polling.js +0 -145
  212. package/node_modules/engine.io-client/build/esm/transports/websocket.d.ts +0 -36
  213. package/node_modules/engine.io-client/build/esm/transports/websocket.js +0 -125
  214. package/node_modules/engine.io-client/build/esm/transports/websocket.node.d.ts +0 -14
  215. package/node_modules/engine.io-client/build/esm/transports/websocket.node.js +0 -41
  216. package/node_modules/engine.io-client/build/esm/transports/webtransport.d.ts +0 -18
  217. package/node_modules/engine.io-client/build/esm/transports/webtransport.js +0 -80
  218. package/node_modules/engine.io-client/build/esm/util.d.ts +0 -7
  219. package/node_modules/engine.io-client/build/esm/util.js +0 -59
  220. package/node_modules/engine.io-client/build/esm-debug/browser-entrypoint.d.ts +0 -3
  221. package/node_modules/engine.io-client/build/esm-debug/browser-entrypoint.js +0 -2
  222. package/node_modules/engine.io-client/build/esm-debug/contrib/has-cors.d.ts +0 -1
  223. package/node_modules/engine.io-client/build/esm-debug/contrib/has-cors.js +0 -11
  224. package/node_modules/engine.io-client/build/esm-debug/contrib/parseqs.d.ts +0 -15
  225. package/node_modules/engine.io-client/build/esm-debug/contrib/parseqs.js +0 -34
  226. package/node_modules/engine.io-client/build/esm-debug/contrib/parseuri.d.ts +0 -1
  227. package/node_modules/engine.io-client/build/esm-debug/contrib/parseuri.js +0 -64
  228. package/node_modules/engine.io-client/build/esm-debug/globals.d.ts +0 -4
  229. package/node_modules/engine.io-client/build/esm-debug/globals.js +0 -22
  230. package/node_modules/engine.io-client/build/esm-debug/globals.node.d.ts +0 -21
  231. package/node_modules/engine.io-client/build/esm-debug/globals.node.js +0 -91
  232. package/node_modules/engine.io-client/build/esm-debug/index.d.ts +0 -15
  233. package/node_modules/engine.io-client/build/esm-debug/index.js +0 -15
  234. package/node_modules/engine.io-client/build/esm-debug/package.json +0 -10
  235. package/node_modules/engine.io-client/build/esm-debug/socket.d.ts +0 -482
  236. package/node_modules/engine.io-client/build/esm-debug/socket.js +0 -756
  237. package/node_modules/engine.io-client/build/esm-debug/transport.d.ts +0 -106
  238. package/node_modules/engine.io-client/build/esm-debug/transport.js +0 -145
  239. package/node_modules/engine.io-client/build/esm-debug/transports/index.d.ts +0 -8
  240. package/node_modules/engine.io-client/build/esm-debug/transports/index.js +0 -8
  241. package/node_modules/engine.io-client/build/esm-debug/transports/polling-fetch.d.ts +0 -15
  242. package/node_modules/engine.io-client/build/esm-debug/transports/polling-fetch.js +0 -56
  243. package/node_modules/engine.io-client/build/esm-debug/transports/polling-xhr.d.ts +0 -108
  244. package/node_modules/engine.io-client/build/esm-debug/transports/polling-xhr.js +0 -276
  245. package/node_modules/engine.io-client/build/esm-debug/transports/polling-xhr.node.d.ts +0 -11
  246. package/node_modules/engine.io-client/build/esm-debug/transports/polling-xhr.node.js +0 -17
  247. package/node_modules/engine.io-client/build/esm-debug/transports/polling.d.ts +0 -52
  248. package/node_modules/engine.io-client/build/esm-debug/transports/polling.js +0 -158
  249. package/node_modules/engine.io-client/build/esm-debug/transports/websocket.d.ts +0 -36
  250. package/node_modules/engine.io-client/build/esm-debug/transports/websocket.js +0 -128
  251. package/node_modules/engine.io-client/build/esm-debug/transports/websocket.node.d.ts +0 -14
  252. package/node_modules/engine.io-client/build/esm-debug/transports/websocket.node.js +0 -41
  253. package/node_modules/engine.io-client/build/esm-debug/transports/webtransport.d.ts +0 -18
  254. package/node_modules/engine.io-client/build/esm-debug/transports/webtransport.js +0 -87
  255. package/node_modules/engine.io-client/build/esm-debug/util.d.ts +0 -7
  256. package/node_modules/engine.io-client/build/esm-debug/util.js +0 -59
  257. package/node_modules/engine.io-client/dist/engine.io.esm.min.js +0 -7
  258. package/node_modules/engine.io-client/dist/engine.io.esm.min.js.map +0 -1
  259. package/node_modules/engine.io-client/dist/engine.io.js +0 -3064
  260. package/node_modules/engine.io-client/dist/engine.io.js.map +0 -1
  261. package/node_modules/engine.io-client/dist/engine.io.min.js +0 -7
  262. package/node_modules/engine.io-client/dist/engine.io.min.js.map +0 -1
  263. package/node_modules/engine.io-client/node_modules/ws/index.js +0 -13
  264. package/node_modules/engine.io-client/node_modules/ws/wrapper.mjs +0 -8
  265. package/node_modules/engine.io-client/package.json +0 -95
  266. package/node_modules/engine.io-parser/LICENSE +0 -22
  267. package/node_modules/engine.io-parser/Readme.md +0 -158
  268. package/node_modules/engine.io-parser/build/cjs/commons.d.ts +0 -14
  269. package/node_modules/engine.io-parser/build/cjs/commons.js +0 -19
  270. package/node_modules/engine.io-parser/build/cjs/contrib/base64-arraybuffer.d.ts +0 -2
  271. package/node_modules/engine.io-parser/build/cjs/contrib/base64-arraybuffer.js +0 -48
  272. package/node_modules/engine.io-parser/build/cjs/decodePacket.browser.d.ts +0 -2
  273. package/node_modules/engine.io-parser/build/cjs/decodePacket.browser.js +0 -66
  274. package/node_modules/engine.io-parser/build/cjs/decodePacket.d.ts +0 -2
  275. package/node_modules/engine.io-parser/build/cjs/decodePacket.js +0 -59
  276. package/node_modules/engine.io-parser/build/cjs/encodePacket.browser.d.ts +0 -4
  277. package/node_modules/engine.io-parser/build/cjs/encodePacket.browser.js +0 -72
  278. package/node_modules/engine.io-parser/build/cjs/encodePacket.d.ts +0 -3
  279. package/node_modules/engine.io-parser/build/cjs/encodePacket.js +0 -38
  280. package/node_modules/engine.io-parser/build/cjs/index.d.ts +0 -9
  281. package/node_modules/engine.io-parser/build/cjs/index.js +0 -164
  282. package/node_modules/engine.io-parser/build/cjs/package.json +0 -8
  283. package/node_modules/engine.io-parser/build/esm/commons.d.ts +0 -14
  284. package/node_modules/engine.io-parser/build/esm/commons.js +0 -14
  285. package/node_modules/engine.io-parser/build/esm/contrib/base64-arraybuffer.d.ts +0 -2
  286. package/node_modules/engine.io-parser/build/esm/contrib/base64-arraybuffer.js +0 -43
  287. package/node_modules/engine.io-parser/build/esm/decodePacket.browser.d.ts +0 -2
  288. package/node_modules/engine.io-parser/build/esm/decodePacket.browser.js +0 -62
  289. package/node_modules/engine.io-parser/build/esm/decodePacket.d.ts +0 -2
  290. package/node_modules/engine.io-parser/build/esm/decodePacket.js +0 -55
  291. package/node_modules/engine.io-parser/build/esm/encodePacket.browser.d.ts +0 -4
  292. package/node_modules/engine.io-parser/build/esm/encodePacket.browser.js +0 -68
  293. package/node_modules/engine.io-parser/build/esm/encodePacket.d.ts +0 -3
  294. package/node_modules/engine.io-parser/build/esm/encodePacket.js +0 -33
  295. package/node_modules/engine.io-parser/build/esm/index.d.ts +0 -9
  296. package/node_modules/engine.io-parser/build/esm/index.js +0 -156
  297. package/node_modules/engine.io-parser/build/esm/package.json +0 -8
  298. package/node_modules/engine.io-parser/package.json +0 -46
  299. package/node_modules/ms/index.js +0 -162
  300. package/node_modules/ms/license.md +0 -21
  301. package/node_modules/ms/package.json +0 -38
  302. package/node_modules/ms/readme.md +0 -59
  303. package/node_modules/socket.io-client/LICENSE +0 -21
  304. package/node_modules/socket.io-client/README.md +0 -29
  305. package/node_modules/socket.io-client/build/cjs/browser-entrypoint.d.ts +0 -2
  306. package/node_modules/socket.io-client/build/cjs/browser-entrypoint.js +0 -4
  307. package/node_modules/socket.io-client/build/cjs/contrib/backo2.d.ts +0 -12
  308. package/node_modules/socket.io-client/build/cjs/contrib/backo2.js +0 -69
  309. package/node_modules/socket.io-client/build/cjs/index.d.ts +0 -29
  310. package/node_modules/socket.io-client/build/cjs/index.js +0 -76
  311. package/node_modules/socket.io-client/build/cjs/manager.d.ts +0 -295
  312. package/node_modules/socket.io-client/build/cjs/manager.js +0 -416
  313. package/node_modules/socket.io-client/build/cjs/on.d.ts +0 -2
  314. package/node_modules/socket.io-client/build/cjs/on.js +0 -9
  315. package/node_modules/socket.io-client/build/cjs/socket.d.ts +0 -593
  316. package/node_modules/socket.io-client/build/cjs/socket.js +0 -909
  317. package/node_modules/socket.io-client/build/cjs/url.d.ts +0 -33
  318. package/node_modules/socket.io-client/build/cjs/url.js +0 -69
  319. package/node_modules/socket.io-client/build/esm/browser-entrypoint.d.ts +0 -2
  320. package/node_modules/socket.io-client/build/esm/browser-entrypoint.js +0 -2
  321. package/node_modules/socket.io-client/build/esm/contrib/backo2.d.ts +0 -12
  322. package/node_modules/socket.io-client/build/esm/contrib/backo2.js +0 -66
  323. package/node_modules/socket.io-client/build/esm/index.d.ts +0 -29
  324. package/node_modules/socket.io-client/build/esm/index.js +0 -58
  325. package/node_modules/socket.io-client/build/esm/manager.d.ts +0 -295
  326. package/node_modules/socket.io-client/build/esm/manager.js +0 -367
  327. package/node_modules/socket.io-client/build/esm/on.d.ts +0 -2
  328. package/node_modules/socket.io-client/build/esm/on.js +0 -6
  329. package/node_modules/socket.io-client/build/esm/package.json +0 -5
  330. package/node_modules/socket.io-client/build/esm/socket.d.ts +0 -593
  331. package/node_modules/socket.io-client/build/esm/socket.js +0 -880
  332. package/node_modules/socket.io-client/build/esm/url.d.ts +0 -33
  333. package/node_modules/socket.io-client/build/esm/url.js +0 -59
  334. package/node_modules/socket.io-client/build/esm-debug/browser-entrypoint.d.ts +0 -2
  335. package/node_modules/socket.io-client/build/esm-debug/browser-entrypoint.js +0 -2
  336. package/node_modules/socket.io-client/build/esm-debug/contrib/backo2.d.ts +0 -12
  337. package/node_modules/socket.io-client/build/esm-debug/contrib/backo2.js +0 -66
  338. package/node_modules/socket.io-client/build/esm-debug/index.d.ts +0 -29
  339. package/node_modules/socket.io-client/build/esm-debug/index.js +0 -62
  340. package/node_modules/socket.io-client/build/esm-debug/manager.d.ts +0 -295
  341. package/node_modules/socket.io-client/build/esm-debug/manager.js +0 -386
  342. package/node_modules/socket.io-client/build/esm-debug/on.d.ts +0 -2
  343. package/node_modules/socket.io-client/build/esm-debug/on.js +0 -6
  344. package/node_modules/socket.io-client/build/esm-debug/package.json +0 -5
  345. package/node_modules/socket.io-client/build/esm-debug/socket.d.ts +0 -593
  346. package/node_modules/socket.io-client/build/esm-debug/socket.js +0 -902
  347. package/node_modules/socket.io-client/build/esm-debug/url.d.ts +0 -33
  348. package/node_modules/socket.io-client/build/esm-debug/url.js +0 -63
  349. package/node_modules/socket.io-client/dist/socket.io.esm.min.js +0 -7
  350. package/node_modules/socket.io-client/dist/socket.io.esm.min.js.map +0 -1
  351. package/node_modules/socket.io-client/dist/socket.io.js +0 -4955
  352. package/node_modules/socket.io-client/dist/socket.io.js.map +0 -1
  353. package/node_modules/socket.io-client/dist/socket.io.min.js +0 -7
  354. package/node_modules/socket.io-client/dist/socket.io.min.js.map +0 -1
  355. package/node_modules/socket.io-client/dist/socket.io.msgpack.min.js +0 -7
  356. package/node_modules/socket.io-client/dist/socket.io.msgpack.min.js.map +0 -1
  357. package/node_modules/socket.io-client/package.json +0 -101
  358. package/node_modules/socket.io-parser/LICENSE +0 -20
  359. package/node_modules/socket.io-parser/Readme.md +0 -81
  360. package/node_modules/socket.io-parser/build/cjs/binary.d.ts +0 -20
  361. package/node_modules/socket.io-parser/build/cjs/binary.js +0 -87
  362. package/node_modules/socket.io-parser/build/cjs/index.d.ts +0 -101
  363. package/node_modules/socket.io-parser/build/cjs/index.js +0 -367
  364. package/node_modules/socket.io-parser/build/cjs/is-binary.d.ts +0 -7
  365. package/node_modules/socket.io-parser/build/cjs/is-binary.js +0 -54
  366. package/node_modules/socket.io-parser/build/cjs/package.json +0 -3
  367. package/node_modules/socket.io-parser/build/esm/binary.d.ts +0 -20
  368. package/node_modules/socket.io-parser/build/esm/binary.js +0 -83
  369. package/node_modules/socket.io-parser/build/esm/index.d.ts +0 -101
  370. package/node_modules/socket.io-parser/build/esm/index.js +0 -356
  371. package/node_modules/socket.io-parser/build/esm/is-binary.d.ts +0 -7
  372. package/node_modules/socket.io-parser/build/esm/is-binary.js +0 -50
  373. package/node_modules/socket.io-parser/build/esm/package.json +0 -3
  374. package/node_modules/socket.io-parser/build/esm-debug/binary.d.ts +0 -20
  375. package/node_modules/socket.io-parser/build/esm-debug/binary.js +0 -83
  376. package/node_modules/socket.io-parser/build/esm-debug/index.d.ts +0 -101
  377. package/node_modules/socket.io-parser/build/esm-debug/index.js +0 -361
  378. package/node_modules/socket.io-parser/build/esm-debug/is-binary.d.ts +0 -7
  379. package/node_modules/socket.io-parser/build/esm-debug/is-binary.js +0 -50
  380. package/node_modules/socket.io-parser/build/esm-debug/package.json +0 -3
  381. package/node_modules/socket.io-parser/package.json +0 -44
  382. package/node_modules/xmlhttprequest-ssl/LICENSE +0 -22
  383. package/node_modules/xmlhttprequest-ssl/README.md +0 -67
  384. package/node_modules/xmlhttprequest-ssl/lib/XMLHttpRequest.js +0 -689
  385. package/node_modules/xmlhttprequest-ssl/package.json +0 -40
  386. /package/node_modules/{engine.io-client/node_modules/ws → ws}/LICENSE +0 -0
  387. /package/node_modules/{engine.io-client/node_modules/ws → ws}/README.md +0 -0
  388. /package/node_modules/{engine.io-client/node_modules/ws → ws}/browser.js +0 -0
  389. /package/node_modules/{engine.io-client/node_modules/ws → ws}/lib/buffer-util.js +0 -0
  390. /package/node_modules/{engine.io-client/node_modules/ws → ws}/lib/event-target.js +0 -0
  391. /package/node_modules/{engine.io-client/node_modules/ws → ws}/lib/extension.js +0 -0
  392. /package/node_modules/{engine.io-client/node_modules/ws → ws}/lib/limiter.js +0 -0
  393. /package/node_modules/{engine.io-client/node_modules/ws → ws}/lib/receiver.js +0 -0
  394. /package/node_modules/{engine.io-client/node_modules/ws → ws}/lib/sender.js +0 -0
  395. /package/node_modules/{engine.io-client/node_modules/ws → ws}/lib/stream.js +0 -0
  396. /package/node_modules/{engine.io-client/node_modules/ws → ws}/lib/subprotocol.js +0 -0
  397. /package/node_modules/{engine.io-client/node_modules/ws → ws}/lib/validation.js +0 -0
@@ -1,340 +1,274 @@
1
1
  /**
2
2
  * LightClaw — 入站消息处理
3
3
  *
4
- * 接收用户消息 → 文件处理 → 路由 → AI 分发 → 回复
5
- */
6
- import { getAssistantRuntime } from "./runtime.js";
7
- import { CHANNEL_KEY, REPLY_TIMEOUT, MEDIA_MAX_BYTES, resolveEffectiveApiKey, setSessionApiKey } from "./config.js";
8
- import { createChannelReplyPipeline } from "openclaw/plugin-sdk/channel-reply-pipeline";
9
- import { generateMsgId } from "./dedup.js";
10
- import { parseDataUrl, formatFileSize, mediaUrlsToFiles } from "./media.js";
11
- import { uploadFileToCos, downloadFileFromCos, getFileDownloadUrl } from "./file-storage.js";
12
- /**
13
- * 创建入站消息处理器
4
+ * 接收用户消息 → 文件处理 → 路由 → AI 分发 → 回复。
5
+ *
6
+ * 并发/abort 完全委托给 openclaw:
7
+ * - 并发由 session 写锁 + followup queue 保证;
8
+ * - /stop 及自然语言 abort 由 tryFastAbortFromMessage 统一处理并递归 kill subagent。
14
9
  */
10
+ import { emitSignal } from './types.js';
11
+ import { CHANNEL_KEY, MEDIA_MAX_BYTES, resolveEffectiveApiKey, setSessionApiKey, DEFAULT_AGENT_ID } from './config.js';
12
+ import { getLightclawRuntime } from './runtime.js';
13
+ import { createChannelReplyPipeline } from 'openclaw/plugin-sdk/channel-reply-pipeline';
14
+ import { generateMsgId } from './dedup.js';
15
+ import { parseDataUrl, formatFileSize } from './media.js';
16
+ import { uploadFileToCos, downloadFileFromCos, getFileDownloadUrl } from './file-storage.js';
17
+ import { createStreamReplyConfig } from './streaming/index.js';
15
18
  export function createInboundHandler(account, emitter, log) {
16
19
  return async (msg) => {
17
- const pluginRuntime = getAssistantRuntime();
20
+ // mas: {"senderId":"100013456706","text":"今天天气怎么样","messageId":"91647ae9-c123-48e4-9d80-26f2e9a91ac9","files":[],"timestamp":1776077511044}
21
+ const pluginRuntime = getLightclawRuntime();
22
+ // 每次处理消息时重新加载配置,确保使用最新的运行时配置(支持热更新)
18
23
  const currentCfg = pluginRuntime.config.loadConfig();
19
- // 根据 senderId(=uin) 获取对应的 apiKey(多 key 模式下按 uin 选 key,单 key 模式下 fallback 到主 key)
24
+ // 根据 senderId(= uin)选择对应的 apiKey
25
+ // - 多 key 模式:按 uin→apiKey 映射表查找,实现不同用户使用不同 key
26
+ // - 单 key 模式:映射表为空,fallback 到账户主 key
20
27
  const effectiveApiKey = resolveEffectiveApiKey({ senderId: msg.senderId });
21
28
  log?.info(`[${CHANNEL_KEY}] Effective API key for uin ${msg.senderId}: ${effectiveApiKey.slice(0, 8)}...`);
22
- // 1. 确定地址和会话 Key
23
- // 使用标准 user: 前缀,与 normalizeTarget 输出格式一致
29
+ // ---- 步骤 1:确定地址和会话 Key ----
30
+ // 使用标准 user: 前缀,与 normalizeTarget 输出格式保持一致,
31
+ // 确保框架路由系统能正确识别 peer kind 为 "direct"
24
32
  const fromAddress = `user:${msg.senderId}`;
25
- // 2. 路由解析
26
- const route = pluginRuntime.channel.routing.resolveAgentRoute({
33
+ // ---- 步骤 2:路由解析 ----
34
+ // 根据 channel + accountId + peer 三元组确定:
35
+ // - agentId : 处理此消息的 Agent ID
36
+ // - sessionKey : per-channel-peer 会话键(用于隔离不同用户的会话历史)
37
+ // - accountId : 实际使用的账户 ID(可能被路由规则覆盖)
38
+ // agentId 合法性校验:防止前端传入任意 agentId 访问其他 Agent 的数据
39
+ const validAgentIds = currentCfg.agents?.list?.map((a) => a.id) ?? [DEFAULT_AGENT_ID];
40
+ const resolvedAgentId = msg.agentId && validAgentIds.includes(msg.agentId) ? msg.agentId : DEFAULT_AGENT_ID; // undefined 时框架自动路由到默认 Agent
41
+ const baseRoute = pluginRuntime.channel.routing.resolveAgentRoute({
27
42
  cfg: currentCfg,
28
43
  channel: CHANNEL_KEY,
29
44
  accountId: account.accountId,
30
- peer: { kind: "direct", id: msg.senderId },
45
+ peer: { kind: 'direct', id: msg.senderId },
31
46
  });
32
- // 3. 权限检查
47
+ // route: {"agentId":"main","channel":"lightclawbot","accountId":"default","sessionKey":"agent:main:lightclawbot:direct:100013456706","mainSessionKey":"agent:main:main","lastRoutePolicy":"session","matchedBy":"default"}
48
+ // 若前端指定了合法的 agentId,则用 buildAgentSessionKey 覆盖 sessionKey 和 agentId,
49
+ // 实现 Agent 间隔离(sessionKey 含 agentId,不同 Agent 的会话历史完全独立)
50
+ const route = resolvedAgentId
51
+ ? {
52
+ ...baseRoute,
53
+ agentId: resolvedAgentId,
54
+ sessionKey: pluginRuntime.channel.routing.buildAgentSessionKey({
55
+ agentId: resolvedAgentId,
56
+ channel: CHANNEL_KEY,
57
+ accountId: baseRoute.accountId,
58
+ peer: { kind: 'direct', id: msg.senderId },
59
+ dmScope: 'per-channel-peer',
60
+ }),
61
+ mainSessionKey: `agent:${resolvedAgentId}:main`,
62
+ }
63
+ : baseRoute;
64
+ log?.info(`[CHANNEL_KEY]: route= ${JSON.stringify(route)}`);
65
+ // ---- 步骤 3:权限检查 ----
66
+ // 根据 allowFrom 白名单和 dmPolicy 策略决定是否允许此用户发送命令
33
67
  const commandAuthorized = checkAuth(account.allowFrom, account.dmPolicy, msg.senderId);
34
- // 3.5 记录 sessionKey → apiKey 映射(tool 执行时通过 ctx.sessionKey 直接获取对应 apiKey)
35
- // 注意:只写入 per-channel-peer sessionKey,不写入 mainSessionKey。
36
- // mainSessionKey(= "agent:main:main")是全局共享的,所有用户消息都会覆盖它,
37
- // 导致最后一个用户的 apiKey 覆盖前一个用户,产生并发安全问题。
68
+ // ---- 步骤 3.5:记录 sessionKey → apiKey 映射 ----
69
+ // 目的:tool 执行时通过 ctx.sessionKey 直接查找对应的 apiKey,
70
+ // 避免在 tool 层再次解析 uin。
71
+ // 重要:只写入 per-channel-peer 的 sessionKey,不写入 mainSessionKey。
72
+ // mainSessionKey(= "agent:main:main")是全局共享的,
73
+ // 若写入则最后一个用户的 apiKey 会覆盖前一个用户,产生并发安全问题。
38
74
  if (route?.sessionKey) {
39
75
  setSessionApiKey(route.sessionKey, effectiveApiKey);
40
76
  }
41
- // 4. 处理文件附件(files[] → 本地存储)
77
+ const targetId = msg.senderId;
78
+ // 2. 提前发 typing_start(作为"已读回执",减少 COS 下载/LLM TTFT 期间的无反馈感)
79
+ const replyMsgId = generateMsgId();
80
+ // 将 route.agentId 作为整条消息处理链路的绑定默认值,所有出站消息均携带此 agentId
81
+ const effectiveAgentId = route.agentId ?? resolvedAgentId ?? DEFAULT_AGENT_ID;
82
+ // 基于上层 gateway 的 emitter,构造一个绑定当前 agentId 的包装 emitter
83
+ // 所有调用 emit / sendReply / sendFiles 未显式传 agentId 时,消息体都会自动注入 effectiveAgentId
84
+ const boundEmitter = {
85
+ botClientId: emitter.botClientId,
86
+ agentId: effectiveAgentId,
87
+ emit: (data) => emitter.emit({ ...data, agentId: data.agentId ?? effectiveAgentId }),
88
+ sendReply: (tid, text, replyTo, agentId) => emitter.sendReply(tid, text, replyTo, agentId ?? effectiveAgentId),
89
+ sendFiles: (tid, text, files, replyTo, agentId) => emitter.sendFiles(tid, text, files, replyTo, agentId ?? effectiveAgentId),
90
+ };
91
+ const signalCtx = {
92
+ emitter: boundEmitter,
93
+ targetId,
94
+ replyMsgId,
95
+ originalMsgId: msg.messageId,
96
+ agentId: effectiveAgentId,
97
+ };
98
+ emitSignal(signalCtx, 'typing_start');
99
+ // 3. 处理文件附件(files[] → 本地存储 + 公网 URL)
42
100
  const localMediaPaths = [];
101
+ /** 本地文件 MIME 类型列表,与 localMediaPaths 一一对应 */
43
102
  const localMediaTypes = [];
44
- // 每个文件对应的公网可访问 URL,用于 session 历史持久化
45
103
  const publicMediaUrls = [];
104
+ /** 传递给 AI 上下文的附件列表(name + mimeType + 公网 URL) */
46
105
  const ctxAttachments = [];
47
- let attachmentDescription = "";
106
+ /** 附加到用户消息末尾的文件描述文本(告知 AI 用户发送了哪些文件) */
107
+ let attachmentDescription = '';
48
108
  for (const file of msg.files) {
49
109
  try {
50
110
  let buffer;
51
111
  let mimeType;
52
- // 记录文件的公网 URL,优先用于 session 存储
53
112
  let cosPublicUrl;
54
113
  const parsed = file.bytes ? parseDataUrl(file.bytes) : null;
55
114
  if (parsed) {
56
- // data URL 格式:直接解析
57
115
  buffer = parsed.buffer;
58
116
  mimeType = parsed.mimeType;
59
117
  }
60
118
  else if (file.uri) {
61
- // 远程 URI(下载地址),下载获取内容
62
119
  log?.info(`[${CHANNEL_KEY}] File has URI, downloading from cloud: ${file.uri}`);
63
120
  const downloaded = await downloadFileFromCos(file.uri, { apiKey: effectiveApiKey });
64
121
  buffer = downloaded.buffer;
65
122
  mimeType = file.mimeType;
66
- // 保留原始公网 URL,用于 session 历史中持久化引用
67
- cosPublicUrl = file.uri.startsWith("http")
68
- ? file.uri
69
- : getFileDownloadUrl(file.uri);
123
+ cosPublicUrl = file.uri.startsWith('http') ? file.uri : getFileDownloadUrl(file.uri);
70
124
  }
71
125
  else {
126
+ // 来源 3:既无 bytes 也无 uri,无法处理,跳过此文件
72
127
  log?.warn(`[${CHANNEL_KEY}] File has no bytes or uri: ${file.name}, skipping`);
73
128
  continue;
74
129
  }
75
- const saved = await pluginRuntime.channel.media.saveMediaBuffer(buffer, mimeType, "inbound", MEDIA_MAX_BYTES, file.name);
130
+ // 将文件内容保存到本地媒体存储(框架统一管理,支持大小限制和格式校验)
131
+ const saved = await pluginRuntime.channel.media.saveMediaBuffer(buffer, mimeType, 'inbound', MEDIA_MAX_BYTES, file.name);
76
132
  localMediaPaths.push(saved.path);
77
133
  localMediaTypes.push(mimeType);
78
- // 如果文件来自云端,使用公网 URL;否则尝试上传获取公网 URL
79
134
  if (cosPublicUrl) {
80
135
  publicMediaUrls.push(cosPublicUrl);
81
136
  }
82
137
  else {
83
- // data URL 来源的文件:上传到云端以获取公网 URL
138
+ // data URL 来源:上传到 COS 获取公网 URL,失败则 fallback 到本地路径
84
139
  try {
85
140
  const uploadResult = await uploadFileToCos(saved.path, { apiKey: effectiveApiKey });
86
141
  publicMediaUrls.push(uploadResult.url || `file://${saved.path}`);
87
- log?.info(`[${CHANNEL_KEY}] Uploaded inbound file to cloud: ${saved.path} → ${uploadResult.url}`);
142
+ log?.info(`[${CHANNEL_KEY}] Uploaded inbound file: ${saved.path} → ${uploadResult.url}`);
88
143
  }
89
144
  catch (uploadErr) {
90
- log?.warn(`[${CHANNEL_KEY}] Failed to upload inbound file, falling back to local path: ${uploadErr}`);
145
+ log?.warn(`[${CHANNEL_KEY}] Upload failed, falling back to local path: ${uploadErr}`);
91
146
  publicMediaUrls.push(`file://${saved.path}`);
92
147
  }
93
148
  }
94
- // Attachments 中使用公网 URL,确保 session 历史中的地址可被前端访问
95
149
  const attachmentUrl = publicMediaUrls[publicMediaUrls.length - 1];
96
- ctxAttachments.push({
97
- name: file.name,
98
- mimeType,
99
- url: attachmentUrl,
100
- });
150
+ ctxAttachments.push({ name: file.name, mimeType, url: attachmentUrl });
101
151
  attachmentDescription += `\n用户发送了文件: ${file.name} (${formatFileSize(saved.size)})`;
102
- log?.info(`[${CHANNEL_KEY}] File saved: ${saved.path} (${mimeType}, ${formatFileSize(saved.size)}), publicUrl: ${attachmentUrl}`);
152
+ log?.info(`[${CHANNEL_KEY}] File saved: ${saved.path} (${mimeType}, ${formatFileSize(saved.size)})`);
103
153
  }
104
154
  catch (err) {
155
+ // 单个文件处理失败不影响整条消息的处理,记录错误后继续
105
156
  log?.error(`[${CHANNEL_KEY}] File processing failed for ${file.name}: ${err}`);
106
157
  }
107
158
  }
108
- // 5. 构建消息体
159
+ // 4. 构建 AI 上下文
109
160
  const userText = msg.text + attachmentDescription;
110
- const agentBody = account.systemPrompt
111
- ? `${account.systemPrompt}\n\n${userText}`
112
- : userText;
113
- // 6. 构建入站上下文
114
- // MediaPaths 保持本地路径(AI 模型 vision 需要从本地读取文件内容)
115
- // MediaUrls 使用公网 URL(session 历史持久化,前端可直接访问)
161
+ const agentBody = account.systemPrompt ? `${account.systemPrompt}\n\n${userText}` : userText;
162
+ // MediaPaths 保留本地路径(vision 模型需读本地文件);MediaUrls 用公网 URL(session 持久化)
116
163
  const mediaFields = {};
117
164
  if (localMediaPaths.length > 0) {
118
- mediaFields.MediaPaths = localMediaPaths;
119
- mediaFields.MediaPath = localMediaPaths[0];
120
- mediaFields.MediaTypes = localMediaTypes;
121
- mediaFields.MediaType = localMediaTypes[0];
122
- mediaFields.MediaUrls = publicMediaUrls;
123
- mediaFields.MediaUrl = publicMediaUrls[0];
165
+ mediaFields.MediaPaths = localMediaPaths; // 所有本地路径(数组)
166
+ mediaFields.MediaPath = localMediaPaths[0]; // 第一个本地路径(兼容单文件场景)
167
+ mediaFields.MediaTypes = localMediaTypes; // 所有 MIME 类型(数组)
168
+ mediaFields.MediaType = localMediaTypes[0]; // 第一个 MIME 类型
169
+ mediaFields.MediaUrls = publicMediaUrls; // 所有公网 URL(数组)
170
+ mediaFields.MediaUrl = publicMediaUrls[0]; // 第一个公网 URL
124
171
  }
172
+ // finalizeInboundContext 负责将原始字段规范化为框架标准的 InboundContext 格式
125
173
  const ctxPayload = pluginRuntime.channel.reply.finalizeInboundContext({
126
- Body: userText,
127
- BodyForAgent: agentBody,
128
- RawBody: msg.text,
129
- CommandBody: msg.text,
130
- From: fromAddress,
131
- To: `${CHANNEL_KEY}:${account.accountId}`,
174
+ Body: userText, // 传给 AI 的用户消息(含文件描述)
175
+ BodyForAgent: agentBody, // 传给 Agent 的完整 body(含 systemPrompt)
176
+ RawBody: msg.text, // 用户原始文本(不含文件描述)
177
+ CommandBody: msg.text, // 命令解析用的原始文本
178
+ From: fromAddress, // 发送方地址(user:<uin>)
179
+ To: `${CHANNEL_KEY}:${account.accountId}`, // 接收方地址(通道:账户)
132
180
  Channel: CHANNEL_KEY,
133
- ChatType: "direct",
134
- SessionKey: route?.sessionKey ?? fromAddress,
135
- AccountId: route?.accountId ?? account.accountId,
136
- SenderId: msg.senderId,
137
- SenderName: msg.senderId,
181
+ ChatType: 'direct', // 私聊
182
+ SessionKey: route?.sessionKey ?? fromAddress, // 会话键(优先用路由解析结果)
183
+ AccountId: route?.accountId ?? account.accountId, // 账户 ID(路由可能覆盖)
184
+ SenderId: msg.senderId, // 发送方 uin
185
+ SenderName: msg.senderId, // 发送方显示名(暂用 uin 代替)
138
186
  Provider: CHANNEL_KEY,
139
187
  Surface: CHANNEL_KEY,
140
- MessageSid: msg.messageId,
188
+ MessageSid: msg.messageId, // 原始消息 ID(用于回复引用)
141
189
  Timestamp: msg.timestamp,
142
190
  OriginatingChannel: CHANNEL_KEY,
143
191
  OriginatingTo: fromAddress,
144
- CommandAuthorized: commandAuthorized,
192
+ CommandAuthorized: commandAuthorized, // 是否有权限执行命令
193
+ // 有权限时,将发送方加入 OwnerAllowFrom,使其可以访问 owner 级别的命令
145
194
  OwnerAllowFrom: commandAuthorized ? [msg.senderId, fromAddress] : undefined,
146
195
  AgentId: route?.agentId,
147
196
  Attachments: ctxAttachments.length > 0 ? ctxAttachments : undefined,
148
197
  ...mediaFields,
149
198
  });
150
199
  log?.info(`[${CHANNEL_KEY}] Inbound context: ${JSON.stringify(ctxPayload)}`);
151
- const targetId = msg.senderId;
152
- log?.info(`[${CHANNEL_KEY}] Processing: from=${msg.senderId} text="${(msg.text || "(仅文件)").slice(0, 60)}" files=${msg.files.length}`);
153
- // 6.5 更新 session 的 last route,使 cron 定时任务能找到 lightclawbot 的投递目标
200
+ log?.info(`[${CHANNEL_KEY}] Processing: from=${msg.senderId} text="${(msg.text || '(仅文件)').slice(0, 60)}" files=${msg.files.length}`);
201
+ // ---- 步骤 6.5:更新 session last route ----
202
+ // 目的:使 cron 定时任务能找到 lightclawbot 的投递目标(deliveryContext),
203
+ // 从而在没有用户消息触发的情况下也能主动推送消息。
154
204
  const storePath = pluginRuntime.channel.session.resolveStorePath(route.agentId);
155
205
  const deliveryCtx = {
156
206
  channel: CHANNEL_KEY,
157
207
  to: fromAddress,
158
208
  accountId: route.accountId ?? account.accountId,
159
209
  };
160
- // 写入 per-channel-peer session
210
+ // 写入 per-channel-peer session(精确匹配当前用户的会话)
161
211
  if (route?.sessionKey) {
162
- pluginRuntime.channel.session.updateLastRoute({
212
+ pluginRuntime.channel.session
213
+ .updateLastRoute({
163
214
  storePath,
164
215
  sessionKey: route.sessionKey,
165
216
  deliveryContext: deliveryCtx,
166
- }).catch((err) => {
167
- log?.error(`[${CHANNEL_KEY}] Failed to update last route (session): ${err}`);
168
- });
217
+ })
218
+ .catch((err) => log?.error(`[${CHANNEL_KEY}] updateLastRoute(session) failed: ${err}`));
169
219
  }
170
- // 写入 main session(兜底)
220
+ // 写入 main session(兜底,确保全局 cron 也能找到投递目标)
221
+ // 仅当 mainSessionKey 与 sessionKey 不同时才写入,避免重复写入
171
222
  if (route?.mainSessionKey && route.mainSessionKey !== route.sessionKey) {
172
- pluginRuntime.channel.session.updateLastRoute({
223
+ pluginRuntime.channel.session
224
+ .updateLastRoute({
173
225
  storePath,
174
226
  sessionKey: route.mainSessionKey,
175
227
  deliveryContext: deliveryCtx,
176
- }).catch((err) => {
177
- log?.error(`[${CHANNEL_KEY}] Failed to update last route (main): ${err}`);
178
- });
228
+ })
229
+ .catch((err) => log?.error(`[${CHANNEL_KEY}] updateLastRoute(main) failed: ${err}`));
179
230
  }
180
- // 7. 创建 replyPrefixOptions(使用 createChannelReplyPipeline 替代已移除的 createReplyPrefixOptions)
231
+ // ---- 步骤 7:创建 replyPrefixOptions ----
232
+ // createChannelReplyPipeline 返回:
233
+ // - onModelSelected : 模型选择回调(用于 replyOptions)
234
+ // - typingCallbacks : 打字状态回调(此处不使用,用 _tc 忽略)
235
+ // - ...prefixOptions : 传给 dispatcherOptions 的前缀配置(含 prefix、suffix 等)
181
236
  const { onModelSelected, typingCallbacks: _tc, ...prefixOptions } = createChannelReplyPipeline({
182
237
  cfg: currentCfg,
183
238
  agentId: route.agentId,
184
239
  channel: CHANNEL_KEY,
185
240
  accountId: account.accountId,
186
241
  });
187
- // 8. 分发给 AI 引擎
188
- let hasResponse = false;
189
- let idleSent = false;
190
- let timeoutId = null;
191
- let timeoutFired = false;
192
- // 超时仅记录日志,不中断 dispatch(AI 可能仍在处理中)
193
- timeoutId = setTimeout(() => {
194
- if (!hasResponse) {
195
- timeoutFired = true;
196
- log?.warn(`[${CHANNEL_KEY}] AI reply not received within ${REPLY_TIMEOUT}ms, still waiting...`);
197
- }
198
- }, REPLY_TIMEOUT);
199
- // 同一条消息的流式回复(typing_start / stream_chunk / typing_stop)共用同一个 msgId
200
- const replyMsgId = generateMsgId();
201
- const dispatchPromise = pluginRuntime.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
202
- ctx: ctxPayload,
203
- cfg: currentCfg,
204
- dispatcherOptions: {
205
- ...prefixOptions,
206
- deliver: async (payload, info) => {
207
- hasResponse = true;
208
- log?.info(`[${CHANNEL_KEY}] Deliver: ${JSON.stringify(payload)}。info: ${JSON.stringify(info)}`);
209
- if (timeoutId) {
210
- clearTimeout(timeoutId);
211
- timeoutId = null;
212
- }
213
- const replyText = payload.text ?? payload.body ?? "";
214
- const mediaList = payload.mediaUrls?.length
215
- ? payload.mediaUrls
216
- : payload.mediaUrl ? [payload.mediaUrl] : [];
217
- // 流式中间块
218
- if (info.kind === "block") {
219
- if (replyText.trim()) {
220
- emitter.emit({
221
- msgId: replyMsgId,
222
- from: emitter.botClientId,
223
- to: targetId,
224
- content: replyText,
225
- timestamp: Date.now(),
226
- replyToMsgId: msg.messageId,
227
- kind: "stream_chunk",
228
- });
229
- }
230
- return;
231
- }
232
- if (!replyText && !mediaList.length)
233
- return;
234
- // 发送媒体文件 — 同时上传到云端获取公网 URL
235
- if (mediaList.length > 0) {
236
- const files = await mediaUrlsToFiles(mediaList, log);
237
- // 尝试将文件上传获取公网链接
238
- const publicUrls = [];
239
- const storageConfig = {
240
- apiKey: effectiveApiKey,
241
- };
242
- for (const mediaUrl of mediaList) {
243
- try {
244
- // 本地文件路径(file:// 或绝对路径)
245
- const localPath = mediaUrl.startsWith("file://")
246
- ? mediaUrl.slice(7)
247
- : mediaUrl;
248
- if (localPath.startsWith("/") || localPath.match(/^[A-Za-z]:\\/)) {
249
- const { existsSync } = await import("node:fs");
250
- if (existsSync(localPath)) {
251
- const result = await uploadFileToCos(localPath, storageConfig);
252
- publicUrls.push(result.url || '');
253
- log?.info(`[${CHANNEL_KEY}] Uploaded to cloud: ${localPath} → ${result.url}`);
254
- }
255
- }
256
- }
257
- catch (uploadErr) {
258
- log?.warn(`[${CHANNEL_KEY}] Cloud upload failed for ${mediaUrl}: ${uploadErr}`);
259
- }
260
- }
261
- // 将公网 URL 追加到回复文本中(Markdown 链接格式)
262
- let enrichedText = replyText;
263
- if (publicUrls.length > 0) {
264
- const urlSection = publicUrls
265
- .map((url, i) => {
266
- // 从 URL 中提取文件名
267
- const match = url.match(/filePath=([^&]+)/);
268
- const filePath = match ? decodeURIComponent(match[1]) : "";
269
- const fileName = filePath.split("/").pop() || `file${publicUrls.length > 1 ? ` (${i + 1})` : ""}`;
270
- return `📎 [${fileName}](${url})`;
271
- })
272
- .join("\n");
273
- enrichedText = enrichedText
274
- ? `${enrichedText}\n\n${urlSection}`
275
- : urlSection;
276
- }
277
- if (files.length > 0) {
278
- emitter.sendFiles(targetId, enrichedText, files, msg.messageId);
279
- return;
280
- }
281
- // 文件无法直接发送,但有公网 URL,用文本方式发送链接
282
- if (enrichedText.trim()) {
283
- emitter.sendReply(targetId, enrichedText, msg.messageId);
284
- return;
285
- }
286
- }
287
- // 发送文本回复
288
- if (replyText.trim()) {
289
- emitter.sendReply(targetId, replyText, msg.messageId);
290
- }
291
- },
292
- onReplyStart: () => {
293
- emitter.emit({
294
- msgId: replyMsgId,
295
- from: emitter.botClientId,
296
- to: targetId,
297
- content: "",
298
- timestamp: Date.now(),
299
- kind: "typing_start",
300
- });
301
- },
302
- onIdle: () => {
303
- if (idleSent)
304
- return;
305
- idleSent = true;
306
- emitter.emit({
307
- msgId: replyMsgId,
308
- from: emitter.botClientId,
309
- to: targetId,
310
- content: "",
311
- timestamp: Date.now(),
312
- replyToMsgId: msg.messageId,
313
- kind: "typing_stop",
314
- });
315
- },
316
- onError: (err, info) => {
317
- log?.error(`[${CHANNEL_KEY}] ${info.kind} reply failed: ${String(err)}`);
318
- },
319
- },
320
- replyOptions: { onModelSelected, disableBlockStreaming: false },
321
- });
242
+ // 7. 构建流式 dispatcher
243
+ const { dispatcher, replyOptions: streamReplyOptions, hasEmittedContent, } = createStreamReplyConfig({
244
+ emitter: boundEmitter,
245
+ targetId,
246
+ replyMsgId,
247
+ originalMsgId: msg.messageId,
248
+ log,
249
+ effectiveApiKey,
250
+ typingAlreadyStarted: true,
251
+ agentId: effectiveAgentId,
252
+ }, { ...prefixOptions, onModelSelected }, signalCtx);
253
+ // 8. 分发给 AI 引擎(真流式)。abort 由 openclaw fast-abort 处理,sink 层
254
+ // 把英文回执汉化;此处仅兜底自身抛错。
322
255
  try {
323
- await dispatchPromise;
256
+ await pluginRuntime.channel.reply.withReplyDispatcher({
257
+ dispatcher,
258
+ run: () => pluginRuntime.channel.reply.dispatchReplyFromConfig({
259
+ ctx: ctxPayload,
260
+ cfg: currentCfg,
261
+ dispatcher,
262
+ replyOptions: streamReplyOptions,
263
+ }),
264
+ });
324
265
  }
325
266
  catch (err) {
326
267
  const errMsg = err instanceof Error ? err.message : String(err);
327
268
  log?.error(`[${CHANNEL_KEY}] Dispatch error: ${errMsg}`);
328
- // 只发送通用提示,不暴露内部错误细节给用户
329
- emitter.sendReply(targetId, '抱歉,处理您的消息时出现了问题,请稍后重试', msg.messageId);
330
- }
331
- finally {
332
- if (timeoutId) {
333
- clearTimeout(timeoutId);
334
- timeoutId = null;
335
- }
336
- if (timeoutFired) {
337
- log?.info(`[${CHANNEL_KEY}] Note: dispatch completed after timeout warning (${hasResponse ? 'with' : 'without'} response)`);
269
+ // 已推过可见内容时不再追加错误文案,避免打断阅读。
270
+ if (!hasEmittedContent()) {
271
+ emitter.sendReply(targetId, '抱歉,处理您的消息时出现了问题,请稍后重试', msg.messageId, effectiveAgentId);
338
272
  }
339
273
  }
340
274
  };
@@ -342,13 +276,28 @@ export function createInboundHandler(account, emitter, log) {
342
276
  // ============================================================
343
277
  // 权限检查
344
278
  // ============================================================
279
+ /**
280
+ * 检查发送方是否有权限向 Bot 发送消息(命令授权检查)。
281
+ *
282
+ * 策略优先级(从高到低):
283
+ * 1. `dmPolicy === "disabled"` → 拒绝所有消息(Bot 已关闭私聊)
284
+ * 2. `dmPolicy === "open"` → 允许所有消息(Bot 对所有人开放)
285
+ * 3. `allowFrom` 为空 → 拒绝(未配置白名单视为不允许任何人)
286
+ * 4. `allowFrom` 含 `"*"` → 允许所有人(通配符白名单)
287
+ * 5. `allowFrom` 含发送方 ID → 允许(精确匹配,大小写不敏感)
288
+ * 6. 以上均不满足 → 拒绝
289
+ *
290
+ * @param allowFrom - 允许发送消息的用户 ID 白名单(支持 "*" 通配符)
291
+ * @param dmPolicy - 私聊策略("disabled" | "open" | "allowlist")
292
+ * @param senderId - 发送方用户 ID(uin)
293
+ * @returns `true` = 有权限,`false` = 无权限
294
+ */
345
295
  function checkAuth(allowFrom, dmPolicy, senderId) {
346
- if (dmPolicy === "disabled")
296
+ if (dmPolicy === 'disabled')
347
297
  return false;
348
- if (dmPolicy === "open")
298
+ if (dmPolicy === 'open')
349
299
  return true;
350
300
  if (!allowFrom || allowFrom.length === 0)
351
301
  return false;
352
- return allowFrom.includes("*") || allowFrom.some((id) => id.toLowerCase() === senderId.toLowerCase());
302
+ return allowFrom.includes('*') || allowFrom.some((id) => id.toLowerCase() === senderId.toLowerCase());
353
303
  }
354
- //# sourceMappingURL=inbound.js.map
package/dist/src/media.js CHANGED
@@ -84,4 +84,3 @@ export async function mediaUrlsToFiles(urls, log) {
84
84
  }
85
85
  return files;
86
86
  }
87
- //# sourceMappingURL=media.js.map
@@ -0,0 +1,65 @@
1
+ import { CHANNEL_KEY } from './config.js';
2
+ /**
3
+ * 将任意格式的消息目标地址规范化为内部标准格式(`user:xxx` 或 `channel:xxx`)。
4
+ *
5
+ * 支持的输入格式:
6
+ * - `lightclawbot:dm:123` → `user:123` (带通道前缀的私聊)
7
+ * - `lightclawbot:group:456` → `channel:456` (带通道前缀的群聊)
8
+ * - `dm:123` → `user:123` (私聊简写)
9
+ * - `group:456` → `channel:456` (群聊简写)
10
+ * - `user:123` → `user:123` (已是标准格式,原样返回)
11
+ * - `channel:456` → `channel:456` (已是标准格式,原样返回)
12
+ * - `123` → `user:123` (纯数字 ID,默认视为私聊)
13
+ *
14
+ * @param target - 原始目标地址字符串
15
+ * @returns 规范化后的目标地址,若输入为空则返回 `undefined`
16
+ */
17
+ export function normalizeTarget(target) {
18
+ // 剥离通道名前缀(如 "lightclawbot:"),使后续逻辑只处理纯地址部分
19
+ const cleaned = target.replace(new RegExp(`^${CHANNEL_KEY}:`, 'i'), '');
20
+ // 输入为空或仅含通道前缀时,无法确定目标,返回 undefined
21
+ if (!cleaned)
22
+ return undefined;
23
+ // dm:xxx → user:xxx(私聊)
24
+ if (cleaned.startsWith('dm:')) {
25
+ return `user:${cleaned.slice(3)}`;
26
+ }
27
+ // group:xxx → channel:xxx(群聊)
28
+ if (cleaned.startsWith('group:')) {
29
+ return `channel:${cleaned.slice(6)}`;
30
+ }
31
+ // 已经是标准格式 user:xxx / channel:xxx,无需转换,原样返回
32
+ if (/^(user|channel):/i.test(cleaned)) {
33
+ return cleaned;
34
+ }
35
+ // 其余情况视为纯 ID(如纯数字),默认当作私聊目标
36
+ return `user:${cleaned}`;
37
+ }
38
+ /**
39
+ * 判断给定字符串是否看起来像一个合法的消息目标 ID。
40
+ *
41
+ * 优先使用已规范化的 `normalized` 值进行判断;若未提供,则直接使用原始 `id`。
42
+ *
43
+ * 以下格式均被认为是合法 ID:
44
+ * - `user:xxx` / `channel:xxx` — 内部标准前缀格式
45
+ * - `dm:123` / `group:123` — LightClaw 自有格式(纯数字部分)
46
+ * - `123` — 纯数字 ID
47
+ *
48
+ * @param id - 原始目标地址字符串
49
+ * @param normalized - 可选,已经过 `normalizeTarget` 处理的规范化地址,优先使用
50
+ * @returns 若字符串符合合法 ID 格式则返回 `true`,否则返回 `false`
51
+ */
52
+ export function looksLikeId(id, normalized) {
53
+ // 优先使用规范化值,去除首尾空白
54
+ const value = (normalized ?? id).trim();
55
+ // 空字符串不是合法 ID
56
+ if (!value)
57
+ return false;
58
+ // 匹配内部标准前缀格式:user:xxx 或 channel:xxx
59
+ if (/^(user|channel):/i.test(value))
60
+ return true;
61
+ // 剥离通道前缀后,判断是否符合 LightClaw 自有格式
62
+ const cleaned = value.replace(new RegExp(`^${CHANNEL_KEY}:`, 'i'), '');
63
+ // dm:<数字> 或 group:<数字> 格式,或纯数字 ID
64
+ return /^(dm|group):\d+/.test(cleaned) || /^\d+$/.test(cleaned);
65
+ }