@0xmaxma/claude-gateway 1.8.13 → 2.0.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 (594) hide show
  1. package/README.md +28 -1605
  2. package/config.template.json +7 -1
  3. package/dist/agent/runner.d.ts +394 -0
  4. package/dist/agent/runner.d.ts.map +1 -1
  5. package/dist/agent/runner.js +867 -38
  6. package/dist/agent/runner.js.map +1 -1
  7. package/dist/agent/skill-learning/index.d.ts +6 -4
  8. package/dist/agent/skill-learning/index.d.ts.map +1 -1
  9. package/dist/agent/skill-learning/index.js +3 -3
  10. package/dist/agent/skill-learning/index.js.map +1 -1
  11. package/dist/agent/skill-learning/notifier.d.ts +3 -4
  12. package/dist/agent/skill-learning/notifier.d.ts.map +1 -1
  13. package/dist/agent/skill-learning/notifier.js +15 -13
  14. package/dist/agent/skill-learning/notifier.js.map +1 -1
  15. package/dist/agent/skill-learning/reviewer.d.ts.map +1 -1
  16. package/dist/agent/skill-learning/reviewer.js +3 -1
  17. package/dist/agent/skill-learning/reviewer.js.map +1 -1
  18. package/dist/api/connectors-router.d.ts.map +1 -1
  19. package/dist/api/connectors-router.js +110 -4
  20. package/dist/api/connectors-router.js.map +1 -1
  21. package/dist/api/gateway-router.d.ts +1 -0
  22. package/dist/api/gateway-router.d.ts.map +1 -1
  23. package/dist/api/gateway-router.js +13 -1
  24. package/dist/api/gateway-router.js.map +1 -1
  25. package/dist/api/line-webhook-router.d.ts +2 -2
  26. package/dist/api/line-webhook-router.d.ts.map +1 -1
  27. package/dist/api/line-webhook-router.js +264 -230
  28. package/dist/api/line-webhook-router.js.map +1 -1
  29. package/dist/api/router.d.ts.map +1 -1
  30. package/dist/api/router.js +372 -11
  31. package/dist/api/router.js.map +1 -1
  32. package/dist/api/share-router.d.ts.map +1 -1
  33. package/dist/api/share-router.js +29 -10
  34. package/dist/api/share-router.js.map +1 -1
  35. package/dist/api/slack-client.d.ts +2 -0
  36. package/dist/api/slack-client.d.ts.map +1 -1
  37. package/dist/api/slack-client.js +6 -2
  38. package/dist/api/slack-client.js.map +1 -1
  39. package/dist/api/slack-webhook-router.d.ts +3 -0
  40. package/dist/api/slack-webhook-router.d.ts.map +1 -1
  41. package/dist/api/slack-webhook-router.js +226 -131
  42. package/dist/api/slack-webhook-router.js.map +1 -1
  43. package/dist/api/voice-router.d.ts +21 -0
  44. package/dist/api/voice-router.d.ts.map +1 -0
  45. package/dist/api/voice-router.js +372 -0
  46. package/dist/api/voice-router.js.map +1 -0
  47. package/dist/api/voice-settings-router.d.ts +5 -0
  48. package/dist/api/voice-settings-router.d.ts.map +1 -0
  49. package/dist/api/voice-settings-router.js +318 -0
  50. package/dist/api/voice-settings-router.js.map +1 -0
  51. package/dist/api/wechat-access.d.ts +45 -0
  52. package/dist/api/wechat-access.d.ts.map +1 -0
  53. package/dist/api/wechat-access.js +48 -0
  54. package/dist/api/wechat-access.js.map +1 -0
  55. package/dist/apps/agent-container-migration.d.ts +11 -0
  56. package/dist/apps/agent-container-migration.d.ts.map +1 -0
  57. package/dist/apps/agent-container-migration.js +85 -0
  58. package/dist/apps/agent-container-migration.js.map +1 -0
  59. package/dist/apps/installer.d.ts +1 -1
  60. package/dist/apps/installer.d.ts.map +1 -1
  61. package/dist/apps/installer.js +2 -1
  62. package/dist/apps/installer.js.map +1 -1
  63. package/dist/cli/commands/tasks.d.ts +5 -0
  64. package/dist/cli/commands/tasks.d.ts.map +1 -0
  65. package/dist/cli/commands/tasks.js +92 -0
  66. package/dist/cli/commands/tasks.js.map +1 -0
  67. package/dist/cli/http-client.d.ts +2 -0
  68. package/dist/cli/http-client.d.ts.map +1 -1
  69. package/dist/cli/http-client.js +8 -3
  70. package/dist/cli/http-client.js.map +1 -1
  71. package/dist/cli/index.d.ts.map +1 -1
  72. package/dist/cli/index.js +5 -1
  73. package/dist/cli/index.js.map +1 -1
  74. package/dist/config/config-write-lock.d.ts +2 -0
  75. package/dist/config/config-write-lock.d.ts.map +1 -1
  76. package/dist/config/config-write-lock.js +5 -0
  77. package/dist/config/config-write-lock.js.map +1 -1
  78. package/dist/config/loader.d.ts.map +1 -1
  79. package/dist/config/loader.js +87 -2
  80. package/dist/config/loader.js.map +1 -1
  81. package/dist/config/migrator.d.ts.map +1 -1
  82. package/dist/config/migrator.js +12 -1
  83. package/dist/config/migrator.js.map +1 -1
  84. package/dist/config/watcher.d.ts.map +1 -1
  85. package/dist/config/watcher.js +6 -0
  86. package/dist/config/watcher.js.map +1 -1
  87. package/dist/connectors/resolve.d.ts.map +1 -1
  88. package/dist/connectors/resolve.js +3 -1
  89. package/dist/connectors/resolve.js.map +1 -1
  90. package/dist/connectors/types.d.ts +8 -0
  91. package/dist/connectors/types.d.ts.map +1 -1
  92. package/dist/cron/manager.d.ts.map +1 -1
  93. package/dist/cron/manager.js +21 -2
  94. package/dist/cron/manager.js.map +1 -1
  95. package/dist/discord/receiver.d.ts +2 -1
  96. package/dist/discord/receiver.d.ts.map +1 -1
  97. package/dist/discord/receiver.js +5 -1
  98. package/dist/discord/receiver.js.map +1 -1
  99. package/dist/history/db.d.ts +3 -0
  100. package/dist/history/db.d.ts.map +1 -1
  101. package/dist/history/db.js +21 -1
  102. package/dist/history/db.js.map +1 -1
  103. package/dist/history/types.d.ts +12 -1
  104. package/dist/history/types.d.ts.map +1 -1
  105. package/dist/history/types.js +10 -1
  106. package/dist/history/types.js.map +1 -1
  107. package/dist/index.js +48 -9
  108. package/dist/index.js.map +1 -1
  109. package/dist/orchestration/bounded-queue.d.ts +15 -0
  110. package/dist/orchestration/bounded-queue.d.ts.map +1 -0
  111. package/dist/orchestration/bounded-queue.js +58 -0
  112. package/dist/orchestration/bounded-queue.js.map +1 -0
  113. package/dist/orchestration/bridge.d.ts +55 -0
  114. package/dist/orchestration/bridge.d.ts.map +1 -0
  115. package/dist/orchestration/bridge.js +234 -0
  116. package/dist/orchestration/bridge.js.map +1 -0
  117. package/dist/orchestration/browser-routing.d.ts +7 -0
  118. package/dist/orchestration/browser-routing.d.ts.map +1 -0
  119. package/dist/orchestration/browser-routing.js +22 -0
  120. package/dist/orchestration/browser-routing.js.map +1 -0
  121. package/dist/orchestration/capabilities.d.ts +49 -0
  122. package/dist/orchestration/capabilities.d.ts.map +1 -0
  123. package/dist/orchestration/capabilities.js +417 -0
  124. package/dist/orchestration/capabilities.js.map +1 -0
  125. package/dist/orchestration/capacity.d.ts +14 -0
  126. package/dist/orchestration/capacity.d.ts.map +1 -0
  127. package/dist/orchestration/capacity.js +52 -0
  128. package/dist/orchestration/capacity.js.map +1 -0
  129. package/dist/orchestration/channel-activity.d.ts +21 -0
  130. package/dist/orchestration/channel-activity.d.ts.map +1 -0
  131. package/dist/orchestration/channel-activity.js +72 -0
  132. package/dist/orchestration/channel-activity.js.map +1 -0
  133. package/dist/orchestration/channel-controls.d.ts +32 -0
  134. package/dist/orchestration/channel-controls.d.ts.map +1 -0
  135. package/dist/orchestration/channel-controls.js +105 -0
  136. package/dist/orchestration/channel-controls.js.map +1 -0
  137. package/dist/orchestration/channel-input-media.d.ts +11 -0
  138. package/dist/orchestration/channel-input-media.d.ts.map +1 -0
  139. package/dist/orchestration/channel-input-media.js +54 -0
  140. package/dist/orchestration/channel-input-media.js.map +1 -0
  141. package/dist/orchestration/channel-media.d.ts +4 -0
  142. package/dist/orchestration/channel-media.d.ts.map +1 -0
  143. package/dist/orchestration/channel-media.js +70 -0
  144. package/dist/orchestration/channel-media.js.map +1 -0
  145. package/dist/orchestration/channel-speech.d.ts +7 -0
  146. package/dist/orchestration/channel-speech.d.ts.map +1 -0
  147. package/dist/orchestration/channel-speech.js +65 -0
  148. package/dist/orchestration/channel-speech.js.map +1 -0
  149. package/dist/orchestration/cli-skills.d.ts +12 -0
  150. package/dist/orchestration/cli-skills.d.ts.map +1 -0
  151. package/dist/orchestration/cli-skills.js +132 -0
  152. package/dist/orchestration/cli-skills.js.map +1 -0
  153. package/dist/orchestration/config.d.ts +256 -0
  154. package/dist/orchestration/config.d.ts.map +1 -0
  155. package/dist/orchestration/config.js +110 -0
  156. package/dist/orchestration/config.js.map +1 -0
  157. package/dist/orchestration/container.d.ts +21 -0
  158. package/dist/orchestration/container.d.ts.map +1 -0
  159. package/dist/orchestration/container.js +195 -0
  160. package/dist/orchestration/container.js.map +1 -0
  161. package/dist/orchestration/control-delivery.d.ts +5 -0
  162. package/dist/orchestration/control-delivery.d.ts.map +1 -0
  163. package/dist/orchestration/control-delivery.js +50 -0
  164. package/dist/orchestration/control-delivery.js.map +1 -0
  165. package/dist/orchestration/conversation-intake.d.ts +32 -0
  166. package/dist/orchestration/conversation-intake.d.ts.map +1 -0
  167. package/dist/orchestration/conversation-intake.js +92 -0
  168. package/dist/orchestration/conversation-intake.js.map +1 -0
  169. package/dist/orchestration/decisions.d.ts +27 -0
  170. package/dist/orchestration/decisions.d.ts.map +1 -0
  171. package/dist/orchestration/decisions.js +148 -0
  172. package/dist/orchestration/decisions.js.map +1 -0
  173. package/dist/orchestration/delivery.d.ts +30 -0
  174. package/dist/orchestration/delivery.d.ts.map +1 -0
  175. package/dist/orchestration/delivery.js +219 -0
  176. package/dist/orchestration/delivery.js.map +1 -0
  177. package/dist/orchestration/display-stream.d.ts +4 -0
  178. package/dist/orchestration/display-stream.d.ts.map +1 -0
  179. package/dist/orchestration/display-stream.js +77 -0
  180. package/dist/orchestration/display-stream.js.map +1 -0
  181. package/dist/orchestration/events.d.ts +30 -0
  182. package/dist/orchestration/events.d.ts.map +1 -0
  183. package/dist/orchestration/events.js +65 -0
  184. package/dist/orchestration/events.js.map +1 -0
  185. package/dist/orchestration/execution-observation.d.ts +38 -0
  186. package/dist/orchestration/execution-observation.d.ts.map +1 -0
  187. package/dist/orchestration/execution-observation.js +25 -0
  188. package/dist/orchestration/execution-observation.js.map +1 -0
  189. package/dist/orchestration/file-delivery.d.ts +16 -0
  190. package/dist/orchestration/file-delivery.d.ts.map +1 -0
  191. package/dist/orchestration/file-delivery.js +139 -0
  192. package/dist/orchestration/file-delivery.js.map +1 -0
  193. package/dist/orchestration/gateway-config.d.ts +17 -0
  194. package/dist/orchestration/gateway-config.d.ts.map +1 -0
  195. package/dist/orchestration/gateway-config.js +128 -0
  196. package/dist/orchestration/gateway-config.js.map +1 -0
  197. package/dist/orchestration/history.d.ts +13 -0
  198. package/dist/orchestration/history.d.ts.map +1 -0
  199. package/dist/orchestration/history.js +48 -0
  200. package/dist/orchestration/history.js.map +1 -0
  201. package/dist/orchestration/identity.d.ts +6 -0
  202. package/dist/orchestration/identity.d.ts.map +1 -0
  203. package/dist/orchestration/identity.js +13 -0
  204. package/dist/orchestration/identity.js.map +1 -0
  205. package/dist/orchestration/inference-errors.d.ts +3 -0
  206. package/dist/orchestration/inference-errors.d.ts.map +1 -0
  207. package/dist/orchestration/inference-errors.js +16 -0
  208. package/dist/orchestration/inference-errors.js.map +1 -0
  209. package/dist/orchestration/input-images.d.ts +12 -0
  210. package/dist/orchestration/input-images.d.ts.map +1 -0
  211. package/dist/orchestration/input-images.js +66 -0
  212. package/dist/orchestration/input-images.js.map +1 -0
  213. package/dist/orchestration/instance-lock.d.ts +5 -0
  214. package/dist/orchestration/instance-lock.d.ts.map +1 -0
  215. package/dist/orchestration/instance-lock.js +33 -0
  216. package/dist/orchestration/instance-lock.js.map +1 -0
  217. package/dist/orchestration/line-loading.d.ts +21 -0
  218. package/dist/orchestration/line-loading.d.ts.map +1 -0
  219. package/dist/orchestration/line-loading.js +89 -0
  220. package/dist/orchestration/line-loading.js.map +1 -0
  221. package/dist/orchestration/media.d.ts +3 -0
  222. package/dist/orchestration/media.d.ts.map +1 -0
  223. package/dist/orchestration/media.js +46 -0
  224. package/dist/orchestration/media.js.map +1 -0
  225. package/dist/orchestration/migrations/schema.d.ts +3 -0
  226. package/dist/orchestration/migrations/schema.d.ts.map +1 -0
  227. package/dist/orchestration/migrations/schema.js +80 -0
  228. package/dist/orchestration/migrations/schema.js.map +1 -0
  229. package/dist/orchestration/notification-mailbox.d.ts +5 -0
  230. package/dist/orchestration/notification-mailbox.d.ts.map +1 -0
  231. package/dist/orchestration/notification-mailbox.js +29 -0
  232. package/dist/orchestration/notification-mailbox.js.map +1 -0
  233. package/dist/orchestration/process-activity.d.ts +23 -0
  234. package/dist/orchestration/process-activity.d.ts.map +1 -0
  235. package/dist/orchestration/process-activity.js +95 -0
  236. package/dist/orchestration/process-activity.js.map +1 -0
  237. package/dist/orchestration/process-supervisor.d.ts +15 -0
  238. package/dist/orchestration/process-supervisor.d.ts.map +1 -0
  239. package/dist/orchestration/process-supervisor.js +92 -0
  240. package/dist/orchestration/process-supervisor.js.map +1 -0
  241. package/dist/orchestration/process-turn.d.ts +35 -0
  242. package/dist/orchestration/process-turn.d.ts.map +1 -0
  243. package/dist/orchestration/process-turn.js +246 -0
  244. package/dist/orchestration/process-turn.js.map +1 -0
  245. package/dist/orchestration/progress-review.d.ts +28 -0
  246. package/dist/orchestration/progress-review.d.ts.map +1 -0
  247. package/dist/orchestration/progress-review.js +48 -0
  248. package/dist/orchestration/progress-review.js.map +1 -0
  249. package/dist/orchestration/recovery.d.ts +8 -0
  250. package/dist/orchestration/recovery.d.ts.map +1 -0
  251. package/dist/orchestration/recovery.js +35 -0
  252. package/dist/orchestration/recovery.js.map +1 -0
  253. package/dist/orchestration/reply-context.d.ts +7 -0
  254. package/dist/orchestration/reply-context.d.ts.map +1 -0
  255. package/dist/orchestration/reply-context.js +54 -0
  256. package/dist/orchestration/reply-context.js.map +1 -0
  257. package/dist/orchestration/runtime.d.ts +232 -0
  258. package/dist/orchestration/runtime.d.ts.map +1 -0
  259. package/dist/orchestration/runtime.js +962 -0
  260. package/dist/orchestration/runtime.js.map +1 -0
  261. package/dist/orchestration/skills.d.ts +17 -0
  262. package/dist/orchestration/skills.d.ts.map +1 -0
  263. package/dist/orchestration/skills.js +32 -0
  264. package/dist/orchestration/skills.js.map +1 -0
  265. package/dist/orchestration/source-policy.d.ts +6 -0
  266. package/dist/orchestration/source-policy.d.ts.map +1 -0
  267. package/dist/orchestration/source-policy.js +16 -0
  268. package/dist/orchestration/source-policy.js.map +1 -0
  269. package/dist/orchestration/speech.d.ts +24 -0
  270. package/dist/orchestration/speech.d.ts.map +1 -0
  271. package/dist/orchestration/speech.js +61 -0
  272. package/dist/orchestration/speech.js.map +1 -0
  273. package/dist/orchestration/stop-controls.d.ts +30 -0
  274. package/dist/orchestration/stop-controls.d.ts.map +1 -0
  275. package/dist/orchestration/stop-controls.js +79 -0
  276. package/dist/orchestration/stop-controls.js.map +1 -0
  277. package/dist/orchestration/store.d.ts +86 -0
  278. package/dist/orchestration/store.d.ts.map +1 -0
  279. package/dist/orchestration/store.js +275 -0
  280. package/dist/orchestration/store.js.map +1 -0
  281. package/dist/orchestration/task-controls.d.ts +130 -0
  282. package/dist/orchestration/task-controls.d.ts.map +1 -0
  283. package/dist/orchestration/task-controls.js +55 -0
  284. package/dist/orchestration/task-controls.js.map +1 -0
  285. package/dist/orchestration/task-files.d.ts +29 -0
  286. package/dist/orchestration/task-files.d.ts.map +1 -0
  287. package/dist/orchestration/task-files.js +200 -0
  288. package/dist/orchestration/task-files.js.map +1 -0
  289. package/dist/orchestration/task-report.d.ts +7 -0
  290. package/dist/orchestration/task-report.d.ts.map +1 -0
  291. package/dist/orchestration/task-report.js +33 -0
  292. package/dist/orchestration/task-report.js.map +1 -0
  293. package/dist/orchestration/tasks/checkpoint-hook.d.ts +19 -0
  294. package/dist/orchestration/tasks/checkpoint-hook.d.ts.map +1 -0
  295. package/dist/orchestration/tasks/checkpoint-hook.js +49 -0
  296. package/dist/orchestration/tasks/checkpoint-hook.js.map +1 -0
  297. package/dist/orchestration/tasks/cleanup.d.ts +18 -0
  298. package/dist/orchestration/tasks/cleanup.d.ts.map +1 -0
  299. package/dist/orchestration/tasks/cleanup.js +113 -0
  300. package/dist/orchestration/tasks/cleanup.js.map +1 -0
  301. package/dist/orchestration/tasks/driver.d.ts +23 -0
  302. package/dist/orchestration/tasks/driver.d.ts.map +1 -0
  303. package/dist/orchestration/tasks/driver.js +209 -0
  304. package/dist/orchestration/tasks/driver.js.map +1 -0
  305. package/dist/orchestration/tasks/failure.d.ts +5 -0
  306. package/dist/orchestration/tasks/failure.d.ts.map +1 -0
  307. package/dist/orchestration/tasks/failure.js +17 -0
  308. package/dist/orchestration/tasks/failure.js.map +1 -0
  309. package/dist/orchestration/tasks/pool.d.ts +18 -0
  310. package/dist/orchestration/tasks/pool.d.ts.map +1 -0
  311. package/dist/orchestration/tasks/pool.js +73 -0
  312. package/dist/orchestration/tasks/pool.js.map +1 -0
  313. package/dist/orchestration/tasks/scheduler.d.ts +38 -0
  314. package/dist/orchestration/tasks/scheduler.d.ts.map +1 -0
  315. package/dist/orchestration/tasks/scheduler.js +160 -0
  316. package/dist/orchestration/tasks/scheduler.js.map +1 -0
  317. package/dist/orchestration/tasks/service.d.ts +109 -0
  318. package/dist/orchestration/tasks/service.d.ts.map +1 -0
  319. package/dist/orchestration/tasks/service.js +697 -0
  320. package/dist/orchestration/tasks/service.js.map +1 -0
  321. package/dist/orchestration/tasks/shared-workspace.d.ts +25 -0
  322. package/dist/orchestration/tasks/shared-workspace.d.ts.map +1 -0
  323. package/dist/orchestration/tasks/shared-workspace.js +162 -0
  324. package/dist/orchestration/tasks/shared-workspace.js.map +1 -0
  325. package/dist/orchestration/tasks/task-directive.d.ts +6 -0
  326. package/dist/orchestration/tasks/task-directive.d.ts.map +1 -0
  327. package/dist/orchestration/tasks/task-directive.js +41 -0
  328. package/dist/orchestration/tasks/task-directive.js.map +1 -0
  329. package/dist/orchestration/tasks/timing.d.ts +15 -0
  330. package/dist/orchestration/tasks/timing.d.ts.map +1 -0
  331. package/dist/orchestration/tasks/timing.js +48 -0
  332. package/dist/orchestration/tasks/timing.js.map +1 -0
  333. package/dist/orchestration/tasks/tool-repetition.d.ts +3 -0
  334. package/dist/orchestration/tasks/tool-repetition.d.ts.map +1 -0
  335. package/dist/orchestration/tasks/tool-repetition.js +30 -0
  336. package/dist/orchestration/tasks/tool-repetition.js.map +1 -0
  337. package/dist/orchestration/tasks/workspace.d.ts +24 -0
  338. package/dist/orchestration/tasks/workspace.d.ts.map +1 -0
  339. package/dist/orchestration/tasks/workspace.js +147 -0
  340. package/dist/orchestration/tasks/workspace.js.map +1 -0
  341. package/dist/orchestration/telegram-speech.d.ts +17 -0
  342. package/dist/orchestration/telegram-speech.d.ts.map +1 -0
  343. package/dist/orchestration/telegram-speech.js +55 -0
  344. package/dist/orchestration/telegram-speech.js.map +1 -0
  345. package/dist/orchestration/telegram-tool-status.d.ts +23 -0
  346. package/dist/orchestration/telegram-tool-status.d.ts.map +1 -0
  347. package/dist/orchestration/telegram-tool-status.js +207 -0
  348. package/dist/orchestration/telegram-tool-status.js.map +1 -0
  349. package/dist/orchestration/telegram-voices.d.ts +42 -0
  350. package/dist/orchestration/telegram-voices.d.ts.map +1 -0
  351. package/dist/orchestration/telegram-voices.js +70 -0
  352. package/dist/orchestration/telegram-voices.js.map +1 -0
  353. package/dist/orchestration/tool-activity.d.ts +10 -0
  354. package/dist/orchestration/tool-activity.d.ts.map +1 -0
  355. package/dist/orchestration/tool-activity.js +38 -0
  356. package/dist/orchestration/tool-activity.js.map +1 -0
  357. package/dist/orchestration/types.d.ts +177 -0
  358. package/dist/orchestration/types.d.ts.map +1 -0
  359. package/dist/orchestration/types.js +13 -0
  360. package/dist/orchestration/types.js.map +1 -0
  361. package/dist/orchestration/voice-reply-policy.d.ts +8 -0
  362. package/dist/orchestration/voice-reply-policy.d.ts.map +1 -0
  363. package/dist/orchestration/voice-reply-policy.js +46 -0
  364. package/dist/orchestration/voice-reply-policy.js.map +1 -0
  365. package/dist/orchestration/worker-shares.d.ts +8 -0
  366. package/dist/orchestration/worker-shares.d.ts.map +1 -0
  367. package/dist/orchestration/worker-shares.js +59 -0
  368. package/dist/orchestration/worker-shares.js.map +1 -0
  369. package/dist/orchestration/workflow.d.ts +121 -0
  370. package/dist/orchestration/workflow.d.ts.map +1 -0
  371. package/dist/orchestration/workflow.js +69 -0
  372. package/dist/orchestration/workflow.js.map +1 -0
  373. package/dist/session/input-image.d.ts +10 -0
  374. package/dist/session/input-image.d.ts.map +1 -0
  375. package/dist/session/input-image.js +3 -0
  376. package/dist/session/input-image.js.map +1 -0
  377. package/dist/session/process.d.ts +15 -3
  378. package/dist/session/process.d.ts.map +1 -1
  379. package/dist/session/process.js +144 -35
  380. package/dist/session/process.js.map +1 -1
  381. package/dist/session/runtime-profile.d.ts +36 -0
  382. package/dist/session/runtime-profile.d.ts.map +1 -0
  383. package/dist/session/runtime-profile.js +63 -0
  384. package/dist/session/runtime-profile.js.map +1 -0
  385. package/dist/session/store.d.ts.map +1 -1
  386. package/dist/session/store.js +23 -1
  387. package/dist/session/store.js.map +1 -1
  388. package/dist/share/share-store.d.ts +3 -1
  389. package/dist/share/share-store.d.ts.map +1 -1
  390. package/dist/share/share-store.js +13 -2
  391. package/dist/share/share-store.js.map +1 -1
  392. package/dist/shared/line-request-order.d.ts +2 -0
  393. package/dist/shared/line-request-order.d.ts.map +1 -0
  394. package/dist/shared/line-request-order.js +16 -0
  395. package/dist/shared/line-request-order.js.map +1 -0
  396. package/dist/shared/task-elapsed.d.ts +3 -0
  397. package/dist/shared/task-elapsed.d.ts.map +1 -0
  398. package/dist/shared/task-elapsed.js +12 -0
  399. package/dist/shared/task-elapsed.js.map +1 -0
  400. package/dist/shared/task-updated-time.d.ts +3 -0
  401. package/dist/shared/task-updated-time.d.ts.map +1 -0
  402. package/dist/shared/task-updated-time.js +15 -0
  403. package/dist/shared/task-updated-time.js.map +1 -0
  404. package/dist/skills/loader.d.ts +2 -0
  405. package/dist/skills/loader.d.ts.map +1 -1
  406. package/dist/skills/loader.js.map +1 -1
  407. package/dist/telegram/chunks.d.ts +19 -0
  408. package/dist/telegram/chunks.d.ts.map +1 -0
  409. package/dist/telegram/chunks.js +129 -0
  410. package/dist/telegram/chunks.js.map +1 -0
  411. package/dist/telegram/markdown.d.ts.map +1 -1
  412. package/dist/telegram/markdown.js +18 -3
  413. package/dist/telegram/markdown.js.map +1 -1
  414. package/dist/telegram/receiver.d.ts +2 -1
  415. package/dist/telegram/receiver.d.ts.map +1 -1
  416. package/dist/telegram/receiver.js +6 -1
  417. package/dist/telegram/receiver.js.map +1 -1
  418. package/dist/types.d.ts +54 -0
  419. package/dist/types.d.ts.map +1 -1
  420. package/dist/ui/web-ui.d.ts.map +1 -1
  421. package/dist/ui/web-ui.js +31 -5
  422. package/dist/ui/web-ui.js.map +1 -1
  423. package/dist/voice/diagnostics.d.ts +29 -0
  424. package/dist/voice/diagnostics.d.ts.map +1 -0
  425. package/dist/voice/diagnostics.js +37 -0
  426. package/dist/voice/diagnostics.js.map +1 -0
  427. package/dist/voice/errors.d.ts +19 -0
  428. package/dist/voice/errors.d.ts.map +1 -0
  429. package/dist/voice/errors.js +133 -0
  430. package/dist/voice/errors.js.map +1 -0
  431. package/dist/voice/line-audio.d.ts +4 -0
  432. package/dist/voice/line-audio.d.ts.map +1 -0
  433. package/dist/voice/line-audio.js +27 -0
  434. package/dist/voice/line-audio.js.map +1 -0
  435. package/dist/voice/managed-quota.d.ts +5 -0
  436. package/dist/voice/managed-quota.d.ts.map +1 -0
  437. package/dist/voice/managed-quota.js +35 -0
  438. package/dist/voice/managed-quota.js.map +1 -0
  439. package/dist/voice/mp3.d.ts +3 -0
  440. package/dist/voice/mp3.d.ts.map +1 -0
  441. package/dist/voice/mp3.js +30 -0
  442. package/dist/voice/mp3.js.map +1 -0
  443. package/dist/voice/notes.d.ts +9 -0
  444. package/dist/voice/notes.d.ts.map +1 -0
  445. package/dist/voice/notes.js +68 -0
  446. package/dist/voice/notes.js.map +1 -0
  447. package/dist/voice/playback.d.ts +22 -0
  448. package/dist/voice/playback.d.ts.map +1 -0
  449. package/dist/voice/playback.js +52 -0
  450. package/dist/voice/playback.js.map +1 -0
  451. package/dist/voice/preview.d.ts +6 -0
  452. package/dist/voice/preview.d.ts.map +1 -0
  453. package/dist/voice/preview.js +44 -0
  454. package/dist/voice/preview.js.map +1 -0
  455. package/dist/voice/protocol.d.ts +10 -0
  456. package/dist/voice/protocol.d.ts.map +1 -0
  457. package/dist/voice/protocol.js +30 -0
  458. package/dist/voice/protocol.js.map +1 -0
  459. package/dist/voice/providers/cartesia-tts.d.ts +26 -0
  460. package/dist/voice/providers/cartesia-tts.d.ts.map +1 -0
  461. package/dist/voice/providers/cartesia-tts.js +95 -0
  462. package/dist/voice/providers/cartesia-tts.js.map +1 -0
  463. package/dist/voice/providers/deepgram-stt.d.ts +20 -0
  464. package/dist/voice/providers/deepgram-stt.d.ts.map +1 -0
  465. package/dist/voice/providers/deepgram-stt.js +66 -0
  466. package/dist/voice/providers/deepgram-stt.js.map +1 -0
  467. package/dist/voice/providers/elevenlabs-stt.d.ts +20 -0
  468. package/dist/voice/providers/elevenlabs-stt.d.ts.map +1 -0
  469. package/dist/voice/providers/elevenlabs-stt.js +92 -0
  470. package/dist/voice/providers/elevenlabs-stt.js.map +1 -0
  471. package/dist/voice/providers/elevenlabs-tts.d.ts +26 -0
  472. package/dist/voice/providers/elevenlabs-tts.d.ts.map +1 -0
  473. package/dist/voice/providers/elevenlabs-tts.js +82 -0
  474. package/dist/voice/providers/elevenlabs-tts.js.map +1 -0
  475. package/dist/voice/providers/encoded-audio-tts.d.ts +21 -0
  476. package/dist/voice/providers/encoded-audio-tts.d.ts.map +1 -0
  477. package/dist/voice/providers/encoded-audio-tts.js +175 -0
  478. package/dist/voice/providers/encoded-audio-tts.js.map +1 -0
  479. package/dist/voice/providers/fake.d.ts +39 -0
  480. package/dist/voice/providers/fake.d.ts.map +1 -0
  481. package/dist/voice/providers/fake.js +41 -0
  482. package/dist/voice/providers/fake.js.map +1 -0
  483. package/dist/voice/providers/gemini-live-stt.d.ts +21 -0
  484. package/dist/voice/providers/gemini-live-stt.d.ts.map +1 -0
  485. package/dist/voice/providers/gemini-live-stt.js +158 -0
  486. package/dist/voice/providers/gemini-live-stt.js.map +1 -0
  487. package/dist/voice/providers/gemini.d.ts +60 -0
  488. package/dist/voice/providers/gemini.d.ts.map +1 -0
  489. package/dist/voice/providers/gemini.js +124 -0
  490. package/dist/voice/providers/gemini.js.map +1 -0
  491. package/dist/voice/providers/model-ref.d.ts +9 -0
  492. package/dist/voice/providers/model-ref.d.ts.map +1 -0
  493. package/dist/voice/providers/model-ref.js +31 -0
  494. package/dist/voice/providers/model-ref.js.map +1 -0
  495. package/dist/voice/providers/openrouter.d.ts +39 -0
  496. package/dist/voice/providers/openrouter.d.ts.map +1 -0
  497. package/dist/voice/providers/openrouter.js +154 -0
  498. package/dist/voice/providers/openrouter.js.map +1 -0
  499. package/dist/voice/providers/paxalabs-stt.d.ts +12 -0
  500. package/dist/voice/providers/paxalabs-stt.d.ts.map +1 -0
  501. package/dist/voice/providers/paxalabs-stt.js +41 -0
  502. package/dist/voice/providers/paxalabs-stt.js.map +1 -0
  503. package/dist/voice/providers/paxalabs-tts.d.ts +23 -0
  504. package/dist/voice/providers/paxalabs-tts.d.ts.map +1 -0
  505. package/dist/voice/providers/paxalabs-tts.js +80 -0
  506. package/dist/voice/providers/paxalabs-tts.js.map +1 -0
  507. package/dist/voice/providers/recorded-stt.d.ts +34 -0
  508. package/dist/voice/providers/recorded-stt.d.ts.map +1 -0
  509. package/dist/voice/providers/recorded-stt.js +59 -0
  510. package/dist/voice/providers/recorded-stt.js.map +1 -0
  511. package/dist/voice/providers/registry.d.ts +10 -0
  512. package/dist/voice/providers/registry.d.ts.map +1 -0
  513. package/dist/voice/providers/registry.js +77 -0
  514. package/dist/voice/providers/registry.js.map +1 -0
  515. package/dist/voice/providers/socket.d.ts +10 -0
  516. package/dist/voice/providers/socket.d.ts.map +1 -0
  517. package/dist/voice/providers/socket.js +91 -0
  518. package/dist/voice/providers/socket.js.map +1 -0
  519. package/dist/voice/providers/upstream.d.ts +9 -0
  520. package/dist/voice/providers/upstream.d.ts.map +1 -0
  521. package/dist/voice/providers/upstream.js +51 -0
  522. package/dist/voice/providers/upstream.js.map +1 -0
  523. package/dist/voice/providers/voice-catalog.d.ts +17 -0
  524. package/dist/voice/providers/voice-catalog.d.ts.map +1 -0
  525. package/dist/voice/providers/voice-catalog.js +167 -0
  526. package/dist/voice/providers/voice-catalog.js.map +1 -0
  527. package/dist/voice/queue.d.ts +2 -0
  528. package/dist/voice/queue.d.ts.map +1 -0
  529. package/dist/voice/queue.js +6 -0
  530. package/dist/voice/queue.js.map +1 -0
  531. package/dist/voice/session.d.ts +86 -0
  532. package/dist/voice/session.d.ts.map +1 -0
  533. package/dist/voice/session.js +464 -0
  534. package/dist/voice/session.js.map +1 -0
  535. package/dist/voice/turn-manager.d.ts +27 -0
  536. package/dist/voice/turn-manager.d.ts.map +1 -0
  537. package/dist/voice/turn-manager.js +75 -0
  538. package/dist/voice/turn-manager.js.map +1 -0
  539. package/dist/voice/types.d.ts +78 -0
  540. package/dist/voice/types.d.ts.map +1 -0
  541. package/dist/voice/types.js +18 -0
  542. package/dist/voice/types.js.map +1 -0
  543. package/dist/voice/wav.d.ts +2 -0
  544. package/dist/voice/wav.d.ts.map +1 -0
  545. package/dist/voice/wav.js +21 -0
  546. package/dist/voice/wav.js.map +1 -0
  547. package/dist/wechat/ilink-client.d.ts +207 -0
  548. package/dist/wechat/ilink-client.d.ts.map +1 -0
  549. package/dist/wechat/ilink-client.js +660 -0
  550. package/dist/wechat/ilink-client.js.map +1 -0
  551. package/dist/wechat/manager.d.ts +93 -0
  552. package/dist/wechat/manager.d.ts.map +1 -0
  553. package/dist/wechat/manager.js +409 -0
  554. package/dist/wechat/manager.js.map +1 -0
  555. package/dist/whatsapp/manager.d.ts.map +1 -1
  556. package/dist/whatsapp/manager.js +51 -1
  557. package/dist/whatsapp/manager.js.map +1 -1
  558. package/mcp/capability-catalog.ts +206 -0
  559. package/mcp/modules.ts +56 -0
  560. package/mcp/server.ts +18 -35
  561. package/mcp/tools/browser/module.ts +1 -1
  562. package/mcp/tools/browser/skills/open-browser/SKILL.md +5 -3
  563. package/mcp/tools/discord/commands.ts +17 -1
  564. package/mcp/tools/discord/inbound.ts +11 -0
  565. package/mcp/tools/discord/module.ts +42 -2
  566. package/mcp/tools/discord/receiver-server.ts +10 -0
  567. package/mcp/tools/discord/types.ts +4 -1
  568. package/mcp/tools/image/module.ts +3 -1
  569. package/mcp/tools/receiver-spool.test.ts +28 -0
  570. package/mcp/tools/receiver-spool.ts +56 -0
  571. package/mcp/tools/share-file/module.ts +9 -1
  572. package/mcp/tools/shared/share-client.ts +19 -0
  573. package/mcp/tools/tasks/module.ts +35 -0
  574. package/mcp/tools/telegram/media-group.ts +21 -0
  575. package/mcp/tools/telegram/receiver-server.ts +232 -11
  576. package/mcp/tools/telegram/selection-confirmation.ts +20 -0
  577. package/mcp/tools/telegram/task-browser.ts +117 -0
  578. package/mcp/tools/telegram/task-detail.ts +36 -0
  579. package/mcp/tools/telegram/task-elapsed.ts +1 -0
  580. package/mcp/tools/telegram/typing.ts +6 -116
  581. package/mcp/tools/video/module.ts +1 -1
  582. package/mcp/tools/wechat/client.ts +49 -0
  583. package/mcp/tools/wechat/module.ts +88 -0
  584. package/mcp/types.ts +5 -0
  585. package/package.json +2 -1
  586. package/resource/claude_gateway.jpeg +0 -0
  587. package/scripts/orchestration/bench-store.cjs +30 -0
  588. package/scripts/orchestration/inspect.cjs +16 -0
  589. package/scripts/orchestration/probe-profile.cjs +67 -0
  590. package/scripts/orchestration/reconcile.cjs +21 -0
  591. package/scripts/orchestration/smoke-elevenlabs.cjs +90 -0
  592. package/scripts/orchestration/smoke-media.cjs +70 -0
  593. package/scripts/orchestration/smoke-text.cjs +101 -0
  594. package/scripts/orchestration/smoke-vision.cjs +49 -0
@@ -24,127 +24,15 @@ import {
24
24
  type TurnIncidentEvidence,
25
25
  } from '../../../dist/agent/turn-trace.js'
26
26
 
27
- export const TELEGRAM_MAX_CHARS = 4096
28
-
29
- /**
30
- * Telegram rejects a message whose HTML entities are unbalanced, so a chunk cut
31
- * that falls inside a <pre><code>…</code></pre> block must close the open tags
32
- * at the end of the chunk and reopen them at the start of the next one.
33
- * Reserve room for that worst-case suffix (</a></code></pre></b></i>) plus the
34
- * mirrored reopening prefix so balancing never pushes a chunk past the limit.
35
- */
36
- const HTML_BALANCE_HEADROOM = 64
37
-
38
- /** Tags toTelegramHtml() emits — the only ones balancing needs to understand. */
39
- const BALANCED_TAGS = ['b', 'i', 'code', 'pre', 'a'] as const
40
-
41
- /**
42
- * Scan an HTML fragment (as produced by toTelegramHtml — no attributes except
43
- * <a href>, no self-closing forms) and return the stack of tags still open at
44
- * the end, as full opening-tag strings in opening order.
45
- */
46
- export function openTagStack(html: string): string[] {
47
- const stack: string[] = []
48
- // Attribute part tolerates '>' inside quoted values (<a href="a>b">).
49
- const re = /<(\/?)([a-z]+)((?:\s(?:"[^"]*"|[^>])*)?)>/g
50
- let m: RegExpExecArray | null
51
- while ((m = re.exec(html)) !== null) {
52
- const closing = m[1] === '/'
53
- const name = m[2]
54
- if (!(BALANCED_TAGS as readonly string[]).includes(name)) continue
55
- if (closing) {
56
- // toTelegramHtml emits well-nested pairs, so the match is always the top.
57
- const top = stack.length - 1
58
- if (top >= 0 && /^<([a-z]+)/.exec(stack[top])?.[1] === name) stack.pop()
59
- } else {
60
- stack.push(`<${name}${m[3] ?? ''}>`)
61
- }
62
- }
63
- return stack
64
- }
65
-
66
- /** Strip Telegram-HTML tags and unescape entities → plain-text equivalent. */
67
- export function htmlToPlain(html: string): string {
68
- return html
69
- .replace(/&lt;br\s*\/?&gt;/gi, '\n')
70
- .replace(/<[^>]+>/g, '')
71
- .replace(/&lt;/g, '<')
72
- .replace(/&gt;/g, '>')
73
- .replace(/&quot;/g, '"')
74
- .replace(/&amp;/g, '&')
75
- }
76
-
77
- /**
78
- * Split text into chunks that fit within Telegram's message size limit.
79
- * Prefers paragraph → line → space boundaries over hard cuts.
80
- * When htmlSafe=true, avoids cutting inside an HTML tag (e.g. <code>, <b>) AND
81
- * keeps every chunk entity-balanced: tags left open at a cut are closed at the
82
- * chunk's end and reopened at the next chunk's start, so no chunk is ever
83
- * rejected by Telegram's HTML parser for an unclosed <pre>/<code>/<b>.
84
- */
85
- export function chunkText(text: string, limit = TELEGRAM_MAX_CHARS, htmlSafe = false): string[] {
86
- if (text.length <= limit) return [text]
87
- const out: string[] = []
88
- let rest = text
89
- const effLimit = htmlSafe ? limit - HTML_BALANCE_HEADROOM : limit
90
- // If cut lands inside an open tag (<...>), move cut to before the '<'
91
- const avoidMidTag = (cut: number): number => {
92
- const tagStart = rest.lastIndexOf('<', cut)
93
- const tagEnd = rest.lastIndexOf('>', cut)
94
- return tagStart > tagEnd ? tagStart : cut
95
- }
96
- const closersFor = (open: string[]): string =>
97
- open.map((t) => `</${/^<([a-z]+)/.exec(t)![1]}>`).reverse().join('')
98
- // Cut at `cut`, balancing tags across the boundary when htmlSafe.
99
- const splitAt = (cut: number): { head: string; tail: string } => {
100
- let head = rest.slice(0, cut)
101
- let tail = rest.slice(cut).replace(/^\n+/, '')
102
- if (htmlSafe) {
103
- const open = openTagStack(head)
104
- if (open.length) {
105
- head += closersFor(open)
106
- tail = open.join('') + tail
107
- }
108
- }
109
- return { head, tail }
110
- }
111
- while (rest.length > effLimit) {
112
- const para = rest.lastIndexOf('\n\n', effLimit)
113
- const line = rest.lastIndexOf('\n', effLimit)
114
- const space = rest.lastIndexOf(' ', effLimit)
115
- let cut = para > effLimit / 2 ? para : line > effLimit / 2 ? line : space > 0 ? space : effLimit
116
- if (htmlSafe) cut = avoidMidTag(cut)
117
- let { head, tail } = splitAt(cut)
118
- // Forward-progress guard: when the chosen boundary sits right after an
119
- // opening tag (e.g. "<b> " + one unbroken >limit token), the reopened tag
120
- // prefix can re-add as much as the cut removed and `rest` never shrinks —
121
- // an infinite loop that would hang the whole receiver. Retry with a hard
122
- // cut at effLimit; if even that cannot shrink (degenerate tag-heavy input,
123
- // e.g. a single huge <a href>), emit the remainder as one oversized chunk
124
- // and stop — Telegram rejects it and the plain-text retry rescues the
125
- // content, which beats hanging the process.
126
- if (tail.length >= rest.length) {
127
- cut = htmlSafe ? avoidMidTag(effLimit) : effLimit
128
- ;({ head, tail } = splitAt(cut))
129
- if (tail.length >= rest.length) {
130
- out.push(rest)
131
- rest = ''
132
- break
133
- }
134
- }
135
- out.push(head)
136
- rest = tail
137
- }
138
- if (rest) out.push(rest)
139
- return out
140
- }
27
+ import { TELEGRAM_MAX_CHARS, htmlToPlain, chunkText } from '../../../dist/telegram/chunks.js'
28
+ export { TELEGRAM_MAX_CHARS, openTagStack, htmlToPlain, chunkText } from '../../../dist/telegram/chunks.js'
141
29
 
142
30
  export const STATUS_MESSAGES = [
143
31
  '⏳ Thinking...',
144
32
  '🔍 Analyzing your request...',
145
33
  '⚙️ Working on it...',
146
34
  '📝 Preparing a response...',
147
- '🧠 Processing, please wait...',
35
+ '🧠 Thinking...',
148
36
  ]
149
37
 
150
38
  export const STALLED_TIMEOUT_MS = 300_000 // 5 minutes without heartbeat → warn + stop
@@ -429,6 +317,7 @@ export function createWorkingStateManager(
429
317
  botApi: BotApi,
430
318
  fsApi: FsApi,
431
319
  onIncident?: TurnIncidentSink,
320
+ mode: 'legacy' | 'orchestration' = 'legacy',
432
321
  ) {
433
322
  const states = new Map<string, WorkingState>()
434
323
 
@@ -645,7 +534,8 @@ export function createWorkingStateManager(
645
534
  }
646
535
 
647
536
  function start(chatId: string): void {
648
- if (states.has(chatId)) return
537
+ // Managed turns use durable orchestration activity, not legacy file heartbeats.
538
+ if (mode === 'orchestration' || states.has(chatId)) return
649
539
 
650
540
  fsApi.mkdirSync(typingDir, { recursive: true })
651
541
  fsApi.writeFileSync(typingFilePath(chatId), String(Date.now()))
@@ -553,7 +553,7 @@ export class VideoModule implements ToolModule {
553
553
  byok: job.byok ?? false,
554
554
  cost: job.cost ?? 0,
555
555
  files: [filePath],
556
- note: 'Video saved. Deliver it to the user with your channel delivery tool — api_reply/reply (files: [...]). Do NOT open/Read the file to inspect it first; attach it and answer briefly.'
556
+ note: (process.env.GATEWAY_ORCHESTRATION_ROLE === 'worker' ? 'Video saved. Call task_stage_file with this file path, then report completion. Orchestration handles delivery.' : 'Video saved. Deliver it to the user with your channel delivery tool — api_reply/reply (files: [...]). Do NOT open/Read the file to inspect it first; attach it and answer briefly.')
557
557
  + (model ? ` Mention which model made it (${model}).` : ''),
558
558
  }),
559
559
  }],
@@ -0,0 +1,49 @@
1
+ /**
2
+ * HTTP client for the gateway's own WeChat REST API — never a direct iLink
3
+ * call from inside the agent's sandbox. Mirrors `mcp/tools/cron/client.ts`'s
4
+ * shape: this subprocess has no route to the live long-poll session the main
5
+ * gateway process holds in memory (per agent), so sending has to go through
6
+ * that process's own `/wechat/send` route, the same way WhatsApp's Baileys
7
+ * socket is reached (see src/api/router.ts's `/whatsapp/send` doc comment
8
+ * for the same reasoning, once that channel lands).
9
+ */
10
+
11
+ export class WeChatClient {
12
+ private readonly baseUrl: string;
13
+ private readonly agentId: string;
14
+ private readonly apiKey: string;
15
+
16
+ constructor(apiUrl: string, agentId: string, apiKey?: string) {
17
+ this.baseUrl = apiUrl.replace(/\/$/, '');
18
+ this.agentId = agentId;
19
+ this.apiKey = apiKey ?? '';
20
+ }
21
+
22
+ private url(path: string): string {
23
+ return `${this.baseUrl}/api/v1/agents/${this.agentId}/wechat${path}`;
24
+ }
25
+
26
+ private async request(method: string, path: string, body?: unknown): Promise<unknown> {
27
+ const headers: Record<string, string> = {};
28
+ if (body) headers['Content-Type'] = 'application/json';
29
+ if (this.apiKey) headers['X-Api-Key'] = this.apiKey;
30
+
31
+ const res = await fetch(this.url(path), {
32
+ method,
33
+ headers,
34
+ body: body ? JSON.stringify(body) : undefined,
35
+ });
36
+
37
+ if (!res.ok) {
38
+ const text = await res.text().catch(() => '');
39
+ throw new Error(`WeChat API ${method} ${path} failed: HTTP ${res.status} ${text}`);
40
+ }
41
+
42
+ const contentType = res.headers.get('content-type') ?? '';
43
+ return contentType.includes('application/json') ? res.json() : res.text();
44
+ }
45
+
46
+ async send(toId: string, text: string): Promise<void> {
47
+ await this.request('POST', '/send', { to_id: toId, text });
48
+ }
49
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * WeChat outbound tool module — exposes `wechat_reply` to the Claude session.
3
+ *
4
+ * WeChat is a ToolModule (reply-only): inbound arrives via the gateway's own
5
+ * WeChatManager long-poll loop (src/wechat/manager.ts), not here. Unlike
6
+ * Slack (`mcp/tools/slack/module.ts`), this module cannot talk to the
7
+ * third-party API directly — the live iLink session (credentials, per-
8
+ * recipient context tokens) only exists inside the main gateway process, so
9
+ * every send is proxied through that process's own `/wechat/send` route,
10
+ * the same reasoning WhatsApp's Baileys socket needs (see
11
+ * src/api/router.ts's `/whatsapp/send` route once that channel lands, and
12
+ * `mcp/tools/cron/module.ts` for the same "call back into our own gateway
13
+ * API" shape this module follows).
14
+ */
15
+ import type { ToolModule, McpToolDefinition, McpToolResult, ToolVisibility } from '../../types';
16
+ import { WeChatClient } from './client';
17
+
18
+ export class WeChatModule implements ToolModule {
19
+ id = 'wechat';
20
+ toolVisibility: ToolVisibility = 'current-channel';
21
+
22
+ private client: WeChatClient | null = null;
23
+
24
+ isEnabled(): boolean {
25
+ return (
26
+ process.env.GATEWAY_ORIGIN_CHANNEL === 'wechat' &&
27
+ Boolean(process.env.GATEWAY_API_URL && process.env.GATEWAY_AGENT_ID)
28
+ );
29
+ }
30
+
31
+ private getClient(): WeChatClient {
32
+ if (!this.client) {
33
+ const apiUrl = process.env.GATEWAY_API_URL!;
34
+ const agentId = process.env.GATEWAY_AGENT_ID!;
35
+ const apiKey = process.env.GATEWAY_API_KEY;
36
+ this.client = new WeChatClient(apiUrl, agentId, apiKey);
37
+ }
38
+ return this.client;
39
+ }
40
+
41
+ getTools(): McpToolDefinition[] {
42
+ return [
43
+ {
44
+ name: 'wechat_reply',
45
+ description:
46
+ 'Send a reply to the current WeChat conversation. ' +
47
+ 'Pass chat_id (the WeChat sender id shown in the <channel> tag) and text. ' +
48
+ 'Text-only for now — WeChat media sending is not yet supported.',
49
+ inputSchema: {
50
+ type: 'object',
51
+ properties: {
52
+ chat_id: {
53
+ type: 'string',
54
+ description: 'WeChat sender id to send to (the chat_id from the channel turn).',
55
+ },
56
+ text: {
57
+ type: 'string',
58
+ description: 'Message text.',
59
+ },
60
+ },
61
+ required: ['chat_id', 'text'],
62
+ additionalProperties: false,
63
+ },
64
+ },
65
+ ];
66
+ }
67
+
68
+ async handleTool(name: string, args: Record<string, unknown>): Promise<McpToolResult> {
69
+ if (name !== 'wechat_reply') {
70
+ return { content: [{ type: 'text', text: `unknown tool: ${name}` }], isError: true };
71
+ }
72
+ const chatId = args.chat_id as string | undefined;
73
+ const text = args.text as string | undefined;
74
+ if (!chatId || !text) {
75
+ return {
76
+ content: [{ type: 'text', text: 'wechat_reply failed: chat_id and text are required' }],
77
+ isError: true,
78
+ };
79
+ }
80
+ try {
81
+ await this.getClient().send(chatId, text);
82
+ return { content: [{ type: 'text', text: 'sent' }] };
83
+ } catch (err) {
84
+ const msg = err instanceof Error ? err.message : String(err);
85
+ return { content: [{ type: 'text', text: `wechat_reply failed: ${msg}` }], isError: true };
86
+ }
87
+ }
88
+ }
package/mcp/types.ts CHANGED
@@ -14,8 +14,13 @@ export type InboundMessage = {
14
14
  text: string;
15
15
  messageId: string;
16
16
  replyToMessageId?: string;
17
+ repliedText?: string;
18
+ repliedSender?: string;
19
+ attachments?: Array<{url:string;name?:string;kind?:string;quoted?:boolean}>;
17
20
  threadId?: string;
18
21
  attachmentFileId?: string;
22
+ attachmentKind?: 'voice' | 'file';
23
+ controlMessageId?: string;
19
24
  ts: number;
20
25
  };
21
26
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0xmaxma/claude-gateway",
3
- "version": "1.8.13",
3
+ "version": "2.0.0",
4
4
  "description": "Multi-agent gateway for Claude",
5
5
  "repository": {
6
6
  "type": "git",
@@ -21,6 +21,7 @@
21
21
  "!mcp/node_modules",
22
22
  "!mcp/node_modules/**",
23
23
  "README.md",
24
+ "scripts/orchestration/",
24
25
  "config.template.json"
25
26
  ],
26
27
  "publishConfig": {
Binary file
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env node
2
+ // Local durability latency, not a provider/model/network performance claim.
3
+ const { mkdtempSync, rmSync } = require('node:fs');
4
+ const { tmpdir } = require('node:os');
5
+ const { join } = require('node:path');
6
+ const { performance } = require('node:perf_hooks');
7
+ const { OrchestrationStore } = require('../../dist/orchestration/store');
8
+ const { DecisionService } = require('../../dist/orchestration/decisions');
9
+ const { TaskService } = require('../../dist/orchestration/tasks/service');
10
+ const root = mkdtempSync(join(tmpdir(), 'orchestration-bench-'));
11
+ const store = new OrchestrationStore(join(root, 'orchestration.db'), 'fixture');
12
+ const decisions = new DecisionService(store), tasks = new TaskService(store, { tasks: { maxQueuedPerAgent: 1000, maxQueuedPerConversation: 1000 } });
13
+ const inputTimes = [], commandTimes = [];
14
+ const scope = { agentId: 'fixture', agentSessionId: 'agentSession', source: 'api', accountId: 'key', chatId: 'chat', threadKey: '', principalId: 'owner' };
15
+ try {
16
+ for (let i = 0; i < 200; i++) {
17
+ let start = performance.now();
18
+ const receipt = store.acceptInput({ scope, text: `Task ${i}`, ingressKey: String(i) });
19
+ inputTimes.push(performance.now() - start);
20
+ const decision = decisions.begin(receipt.conversationId, 'owner', [receipt.inputId]);
21
+ start = performance.now();
22
+ tasks.spawn({ ...receipt, ...decision, principalId: 'owner', actionId: `action-${i}`, execute: true, writeMemory: false }, { title: `Task ${i}`, targetProfile: 'default-worker', instructions: 'Do the fixture task' });
23
+ commandTimes.push(performance.now() - start);
24
+ decisions.finish(decision, 'Queued.');
25
+ }
26
+ const summarize = values => { values.sort((a,b) => a-b); return { n: values.length, p50Ms: values[Math.floor(values.length * .50)], p95Ms: values[Math.floor(values.length * .95)], maxMs: values.at(-1) }; };
27
+ const input = summarize(inputTimes), command = summarize(commandTimes);
28
+ console.log(JSON.stringify({ node: process.version, platform: process.platform, sqlite: 'WAL, synchronous=FULL', input, command, pass: input.p95Ms <= 250 && command.p95Ms <= 250 }, null, 2));
29
+ process.exitCode = input.p95Ms <= 250 && command.p95Ms <= 250 ? 0 : 1;
30
+ } finally { store.close(); rmSync(root, { recursive: true, force: true }); }
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ // Read-only operator inspection. Never print tickets, prompts or credentials.
3
+ const { DatabaseSync } = require('node:sqlite');
4
+ if (process.argv.length !== 3) { console.error('Usage: node scripts/orchestration/inspect.cjs /path/to/agent/orchestration.db'); process.exit(2); }
5
+ const db = new DatabaseSync(process.argv[2], { readOnly: true });
6
+ try {
7
+ const all = sql => db.prepare(sql).all();
8
+ console.log(JSON.stringify({
9
+ conversations: all('SELECT status,COUNT(*) count FROM conversations GROUP BY status'),
10
+ inputs: all('SELECT status,COUNT(*) count FROM conversation_inputs GROUP BY status'),
11
+ tasks: all('SELECT state,COUNT(*) count FROM tasks GROUP BY state'),
12
+ outbox: all('SELECT kind,state,COUNT(*) count FROM outbox GROUP BY kind,state'),
13
+ resources: all('SELECT mode,lifecycle_state,COUNT(*) count FROM task_resources GROUP BY mode,lifecycle_state'),
14
+ reconcile: all("SELECT t.id,t.state,t.active_attempt_id,r.worktree_path FROM tasks t LEFT JOIN task_resources r ON r.task_id=t.id WHERE t.state='needs_reconciliation'"),
15
+ }, null, 2));
16
+ } finally { db.close(); }
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env node
2
+ // Opt-in live P0 probe. Only disposable workspace data enters the prompt.
3
+ const { mkdtempSync, writeFileSync, mkdirSync } = require('node:fs');
4
+ const { tmpdir } = require('node:os');
5
+ const { join, resolve } = require('node:path');
6
+ const { spawn, execFileSync } = require('node:child_process');
7
+ const { randomUUID } = require('node:crypto');
8
+ const { loadWorkspace } = require('../../dist/agent/workspace-loader');
9
+ const { SessionStore } = require('../../dist/session/store');
10
+ const { runtimeProfileArgs, AGENT_OVERLAY } = require('../../dist/session/runtime-profile');
11
+ (async () => {
12
+ const root = mkdtempSync(join(tmpdir(), 'gateway-orchestration-probe-'));
13
+ const workspace = join(root, 'probe', 'workspace');
14
+ mkdirSync(workspace, { recursive: true });
15
+ for (const [file, content] of Object.entries({
16
+ 'AGENTS.md': 'You are a disposable conversation profile test fixture.',
17
+ 'IDENTITY.md': 'Your fixture identity is CitrineHeron.',
18
+ 'SOUL.md': 'Be concise and truthful.',
19
+ 'USER.md': 'The fixture user prefers Thai.',
20
+ 'MEMORY.md': 'The fixture project codeword is cobalt-orchid.',
21
+ })) writeFileSync(join(workspace, file), content);
22
+ const loaded = await loadWorkspace(workspace);
23
+ mkdirSync(join(workspace, 'memory'));
24
+ writeFileSync(join(workspace, 'memory', 'fixture.md'), 'Archived marker: silver-pine.');
25
+ writeFileSync(join(workspace, 'CLAUDE.md'), loaded.systemPrompt);
26
+ const sessionId = randomUUID();
27
+ const store = new SessionStore(root);
28
+ await store.appendMessage('probe', sessionId, { role: 'user', content: 'Our previous fixture choice was amber-bridge.', ts: Date.now() });
29
+ const history = await store.loadSession('probe', sessionId);
30
+ const mcpConfigPath = join(root, 'mcp.json');
31
+ writeFileSync(mcpConfigPath, JSON.stringify({ mcpServers: { gateway: { command: 'bun',
32
+ args: [resolve(__dirname, '../../mcp/server.ts')],
33
+ env: { GATEWAY_ORCHESTRATION_ROLE: 'agent', GATEWAY_WORKSPACE_DIR: workspace, GATEWAY_ORCHESTRATION_TICKET_FILE: join(root, 'unused-ticket.json') },
34
+ } } }));
35
+ const args = ['--print', '--verbose', '--input-format', 'stream-json', '--output-format', 'stream-json',
36
+ '--include-partial-messages', '--session-id', sessionId, '--dangerously-skip-permissions',
37
+ ...runtimeProfileArgs({ role: 'agent', mcpConfigPath, overlay: AGENT_OVERLAY, context: loaded.systemPrompt }, [])];
38
+ const child = spawn('claude', args, { cwd: workspace, env: { ...process.env }, stdio: ['pipe', 'pipe', 'pipe'] });
39
+ let buffer = '', stderr = '', inventory, result;
40
+ const timer = setTimeout(() => child.kill('SIGTERM'), 45000);
41
+ child.stdout.on('data', chunk => {
42
+ buffer += chunk;
43
+ let end;
44
+ while ((end = buffer.indexOf('\n')) >= 0) {
45
+ const line = buffer.slice(0, end); buffer = buffer.slice(end + 1);
46
+ try {
47
+ const event = JSON.parse(line);
48
+ if (event.type === 'system' && event.subtype === 'init') inventory = { tools: event.tools, mcp_servers: event.mcp_servers, session_id: event.session_id };
49
+ if (event.type === 'result') { result = { subtype: event.subtype, result: event.result, is_error: event.is_error }; child.stdin.end(); }
50
+ } catch {}
51
+ }
52
+ });
53
+ child.stderr.on('data', chunk => { stderr += chunk; });
54
+ child.stdin.write(JSON.stringify({ type: 'user', message: { role: 'user', content: `Fixture history: ${JSON.stringify(history)}\nWhat are your fixture identity, project codeword and previous choice? Use memory_get to retrieve memory/fixture.md and report its archived marker. State whether Read or Bash tools are available; do not create any tasks.` } }) + '\n');
55
+ child.stdin.end();
56
+ child.on('close', (code, signal) => {
57
+ clearTimeout(timer);
58
+ const report = { cli: execFileSync('claude', ['--version'], { encoding: 'utf8' }).trim(), backend: 'headless', workspace, sessionId,
59
+ inventory, result, exitCode: code, signal, stderrPresent: Boolean(stderr),
60
+ contextPassed: Boolean(result?.result && ['CitrineHeron', 'cobalt-orchid', 'amber-bridge', 'silver-pine'].every(s => result.result.includes(s))),
61
+ inventoryPassed: Array.isArray(inventory?.tools) && inventory.tools.length === 7 && inventory.tools.every(name => /^mcp__gateway__(task_(spawn|status|cancel|update|answer)|memory_(search|get))$/.test(name)) };
62
+ const target = process.argv[2];
63
+ if (target) writeFileSync(resolve(target), JSON.stringify(report, null, 2) + '\n');
64
+ console.log(JSON.stringify(report, null, 2));
65
+ process.exitCode = report.contextPassed && report.inventoryPassed && code === 0 ? 0 : 1;
66
+ });
67
+ })().catch(error => { console.error(error.message); process.exitCode = 1; });
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ // Explicit offline operator resolution; no automatic liveness/side-effect guess.
3
+ const { dirname, join } = require('node:path');
4
+ const { readFileSync } = require('node:fs');
5
+ const { OrchestrationStore } = require('../../dist/orchestration/store');
6
+ const { TaskService } = require('../../dist/orchestration/tasks/service');
7
+ const { acquireInstanceLock } = require('../../dist/orchestration/instance-lock');
8
+ const [database, agentId, taskId, state, evidenceFile] = process.argv.slice(2);
9
+ if (!evidenceFile || !['queued', 'failed', 'cancelled'].includes(state)) {
10
+ console.error('Usage: node scripts/orchestration/reconcile.cjs ORCHESTRATION_DB AGENT_ID TASK_ID queued|failed|cancelled EVIDENCE_FILE');
11
+ console.error('Stop the gateway and verify process liveness and side effects first. queued explicitly authorizes another attempt.');
12
+ process.exit(2);
13
+ }
14
+ let release, store;
15
+ try {
16
+ release = acquireInstanceLock(join(dirname(database), 'orchestration-instance.lock'));
17
+ store = new OrchestrationStore(database, agentId);
18
+ const result = new TaskService(store).reconcile(taskId, state, readFileSync(evidenceFile, 'utf8'));
19
+ console.log(JSON.stringify({ taskId: result.taskId, state: result.state, stateVersion: result.stateVersion }));
20
+ } catch (error) { console.error(error.code || error.message); process.exitCode = 1; }
21
+ finally { store?.close(); release?.(); }
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env node
2
+ // Paid, bounded provider smoke: two short TTS requests, one file STT, one voice turn.
3
+ // npm run build && node scripts/orchestration/smoke-elevenlabs.cjs /path/to/elevenlabs.env [voice-id]
4
+ // Uses a synthetic summary fixture; does not run agent inference or test hardware.
5
+ const assert = require('node:assert/strict');
6
+ const fs = require('node:fs');
7
+ const { join } = require('node:path');
8
+ const { tmpdir } = require('node:os');
9
+ const { ElevenLabsTts } = require('../../dist/voice/providers/elevenlabs-tts');
10
+ const { ElevenLabsStt } = require('../../dist/voice/providers/elevenlabs-stt');
11
+ const { transcribeVoiceNote } = require('../../dist/voice/notes');
12
+ const { VoiceSession } = require('../../dist/voice/session');
13
+ const { decodeVoiceFrame } = require('../../dist/voice/protocol');
14
+ const { splitSpeechResponse } = require('../../dist/orchestration/speech');
15
+ const { PCM16 } = require('../../dist/voice/types');
16
+ const voiceSurfaces = {
17
+ display: 'ตัวอย่างผลทดสอบ: แก้ฟังก์ชันจากลบเป็นบวกสำเร็จ และทดสอบผ่านแล้ว รายละเอียดนี้เป็นข้อมูลจำลองสำหรับตรวจการสรุปเสียงเท่านั้น '.repeat(4),
18
+ spoken: 'ทดสอบสำเร็จแล้ว แก้ฟังก์ชันจากลบเป็นบวก และรันเทสต์ผ่านครับ',
19
+ };
20
+ const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
21
+ function wav(pcm) {
22
+ const h = Buffer.alloc(44); h.write('RIFF'); h.writeUInt32LE(36 + pcm.length, 4); h.write('WAVEfmt ', 8);
23
+ h.writeUInt32LE(16, 16); h.writeUInt16LE(1, 20); h.writeUInt16LE(1, 22); h.writeUInt32LE(16000, 24);
24
+ h.writeUInt32LE(32000, 28); h.writeUInt16LE(2, 32); h.writeUInt16LE(16, 34); h.write('data', 36); h.writeUInt32LE(pcm.length, 40);
25
+ return Buffer.concat([h, pcm]);
26
+ }
27
+ (async () => {
28
+ if (process.argv[2]) process.loadEnvFile(process.argv[2]);
29
+ const key = process.env.ELEVENLABS_API_KEY; assert(key, 'ELEVENLABS_API_KEY required');
30
+ const voiceId = process.argv[3] || 'JBFqnCBsd6RMkjVDRZzb';
31
+ const root = fs.mkdtempSync(join(tmpdir(), 'orchestration-elevenlabs-'));
32
+ const report = { date: new Date().toISOString(), voiceId, root, pass: false,
33
+ limits: ['Synthetic microphone; no hardware, echo or platform-account delivery tested.', 'Synthetic summary fixture, not a fresh agent inference.', 'No quota exhaustion or outage injected.'] };
34
+ let session;
35
+ const watchdog = setTimeout(() => { console.error('SMOKE_DEADLINE'); process.exit(1); }, 120000);
36
+ try {
37
+ const surfaces = splitSpeechResponse(JSON.stringify({ display_text: voiceSurfaces.display, spoken_text: voiceSurfaces.spoken }));
38
+ assert(surfaces.spoken && surfaces.spoken.length <= 600 && surfaces.display.length > surfaces.spoken.length);
39
+ const tts = new ElevenLabsTts(key), stt = new ElevenLabsStt(key);
40
+ const started = Date.now(), chunks = [];
41
+ report.tts = { model: 'eleven_v3_conversational', characters: surfaces.spoken.length };
42
+ for await (const chunk of tts.synthesize({ text: (async function* () { yield surfaces.spoken; })(), voiceId, language: 'th', outputFormat: PCM16, signal: AbortSignal.timeout(40000) })) {
43
+ if (!chunks.length) report.tts.firstAudioMs = Date.now() - started;
44
+ chunks.push(chunk.bytes); assert(chunks.reduce((n, c) => n + c.length, 0) <= 960000, 'Audio exceeds 30-second bound');
45
+ }
46
+ const pcm = Buffer.concat(chunks); assert(pcm.length > 3200 && pcm.some(b => b));
47
+ Object.assign(report.tts, { durationMs: Date.now() - started, audioSeconds: pcm.length / 32000, chunks: chunks.length });
48
+ const path = join(root, 'summary.wav'); fs.writeFileSync(path, wav(pcm), { mode: 0o600 });
49
+ console.log(JSON.stringify({ stage: 'tts', ...report.tts }));
50
+ const noteStart = Date.now();
51
+ const transcript = await transcribeVoiceNote(path, { provider: 'elevenlabs', model: 'scribe_v2', language: 'th' });
52
+ assert(/สำเร็จ/.test(transcript) && /บวก/.test(transcript), 'Thai file transcript lost key summary facts');
53
+ report.note = { model: 'scribe_v2', transcript, durationMs: Date.now() - noteStart };
54
+ console.log(JSON.stringify({ stage: 'file-stt', ...report.note }));
55
+ const controls = [], spokenInputs = [], output = []; let listening, played = 0, submittedText;
56
+ const tracedTts = { id: tts.id, capabilities: tts.capabilities, synthesize: options => tts.synthesize({ ...options, text: (async function* () {
57
+ for await (const text of options.text) { spokenInputs.push(text); assert.equal(text, surfaces.spoken); yield text; }
58
+ })() }) };
59
+ session = new VoiceSession(stt, tracedTts, voiceId, {
60
+ control: c => { controls.push(c); if (c.type === 'voice.state' && c.state === 'listening') listening = c; },
61
+ audio: bytes => { const frame = decodeVoiceFrame(bytes); output.push(frame.audio); played += frame.audio.length / 2; session.progress(frame.epoch, played); },
62
+ bufferedBytes: () => 0,
63
+ }, async text => {
64
+ submittedText = text;
65
+ assert(/สำเร็จ/.test(text) && /บวก/.test(text), 'Realtime transcript lost key summary facts');
66
+ return { inputId: 'live-summary-proof', response: Promise.resolve(surfaces.display), responseId: () => 'summary-proof',
67
+ stream: (async function* () { yield { responseId: 'summary-proof', text: surfaces.spoken }; })() };
68
+ }, () => {}, { language: 'th', silenceCommitMs: 650, finalizationTimeoutMs: 15000, maxUtteranceMs: 60000, maxBufferedAudioMs: 1500 });
69
+ await session.start(); const turn = listening; let sequence = 0;
70
+ const mic = Buffer.concat([pcm, Buffer.alloc(16000)]);
71
+ for (let offset = 0; offset < mic.length; offset += 3200) {
72
+ await session.audio({ generation: turn.generation, epoch: turn.epoch, sequence: ++sequence, segmentId: turn.utterance_id, audio: mic.subarray(offset, offset + 3200) });
73
+ await sleep(100);
74
+ }
75
+ const commitStart = Date.now(); await session.commit(sequence);
76
+ const deadline = Date.now() + 40000;
77
+ while (!controls.some(c => c.type === 'playback.end' || c.type === 'voice.error') && Date.now() < deadline) await sleep(20);
78
+ assert.deepEqual(controls.filter(c => c.type === 'voice.error'), []);
79
+ assert(controls.some(c => c.type === 'playback.end'), 'Missing final audio');
80
+ assert(controls.some(c => c.type === 'response.text' && c.text === surfaces.display && c.final));
81
+ assert.deepEqual(spokenInputs, [surfaces.spoken]); assert(output.length > 0);
82
+ report.voiceSession = { transcript: submittedText, partials: controls.filter(c => c.type === 'stt.partial').length,
83
+ displayCharacters: surfaces.display.length, ttsCharacters: spokenInputs.join('').length, audioSeconds: played / 16000,
84
+ commitToPlaybackEndMs: Date.now() - commitStart, nextTurnListening: listening.utterance_id !== turn.utterance_id, fullReportExcludedFromTts: true };
85
+ fs.writeFileSync(join(root, 'playback.wav'), wav(Buffer.concat(output)), { mode: 0o600 });
86
+ assert(report.voiceSession.nextTurnListening); report.pass = true;
87
+ } catch (error) { report.error = { code: error.code, message: String(error.message).replaceAll(key, '[redacted]') }; }
88
+ finally { await session?.close(); clearTimeout(watchdog); fs.writeFileSync(join(root, 'report.json'), JSON.stringify(report, null, 2), { mode: 0o600 }); console.log(JSON.stringify(report, null, 2)); }
89
+ process.exitCode = report.pass ? 0 : 1;
90
+ })().catch(error => { console.error(error.code || error.name); process.exitCode = 1; });
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env node
2
+ // Real Claude CLI with a local image-service fixture; no live image-provider claim.
3
+ const { mkdtempSync, mkdirSync, writeFileSync, readFileSync } = require('node:fs');
4
+ const { tmpdir } = require('node:os');
5
+ const { join } = require('node:path');
6
+ const { execFileSync } = require('node:child_process');
7
+ const { randomUUID } = require('node:crypto');
8
+ const { createServer } = require('node:http');
9
+ const { once } = require('node:events');
10
+ const { loadWorkspace } = require('../../dist/agent/workspace-loader');
11
+ const { SessionStore } = require('../../dist/session/store');
12
+ const { SessionProcess } = require('../../dist/session/process');
13
+ const { HistoryDB } = require('../../dist/history/db');
14
+ const { AgentOrchestrationRuntime } = require('../../dist/orchestration/runtime');
15
+ (async () => {
16
+ const root = mkdtempSync(join(tmpdir(), 'gateway-orchestration-media-'));
17
+ const agentDir = join(root, 'agents', 'probe'), workspace = join(agentDir, 'workspace'), project = join(root, 'fixture-project');
18
+ mkdirSync(workspace, { recursive: true }); mkdirSync(project);
19
+ for (const [file, value] of Object.entries({ 'AGENTS.md': 'You are an engineering assistant. Follow the agent role.',
20
+ 'IDENTITY.md': 'Name: CitrineHeron', 'SOUL.md': 'Be concise.', 'MEMORY.md': 'Project codeword: cobalt-orchid.' })) writeFileSync(join(workspace, file), value);
21
+ const loaded = await loadWorkspace(workspace); writeFileSync(join(workspace, 'CLAUDE.md'), loaded.systemPrompt);
22
+ const png = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+j3xkAAAAASUVORK5CYII=';
23
+ let generated = 0;
24
+ const imageServer = createServer(async (req, res) => {
25
+ for await (const _chunk of req) { /* consume the fixture request */ }
26
+ res.setHeader('Content-Type', 'application/json');
27
+ if (req.method === 'POST') { generated++; res.statusCode = 202; res.end(JSON.stringify({ task_id: 'fixture-job', status: 'queued' })); }
28
+ else if (req.url.includes('/jobs/')) res.end(JSON.stringify({ task_id: 'fixture-job', status: 'done', provider: 'fixture', model: 'fixture-image', images: [png] }));
29
+ else res.end(JSON.stringify({ data: [{ id: 'fixture-image', type: 'image', supports_image_ref: false }] }));
30
+ });
31
+ imageServer.listen(0, '127.0.0.1'); await once(imageServer, 'listening');
32
+ process.env.IMAGE_BASE_URL = `http://127.0.0.1:${imageServer.address().port}`;
33
+ process.env.IMAGE_API_KEY = 'fixture-only';
34
+ const agent = { id: 'probe', description: 'real CLI with fixture image provider', workspace, env: '', claude: { model: process.env.ORCHESTRATION_SMOKE_MODEL || 'sonnet', extraFlags: [] },
35
+ orchestration: { enabled: true, conversation: { decisionTimeoutMs: 45000 }, tasks: { defaultTimeoutMs: 120000 } } };
36
+ const gateway = { gateway: { orchestration: true, headless: true, logDir: join(root, 'logs'), timezone: 'UTC' }, agents: [agent] };
37
+ const sessions = new SessionStore(join(root, 'agents')), history = HistoryDB.forDir(agentDir, 'probe');
38
+ let runtime;
39
+ const host = { createAgentSession: async (sessionId, profile) => new SessionProcess(sessionId, 'api', agent, gateway, sessions, undefined, profile), releaseAgentSession: async (_, p) => p.stop() };
40
+ const report = { root, cli: execFileSync('claude', ['--version'], { encoding: 'utf8' }).trim(), events: [] };
41
+ try {
42
+ runtime = await AgentOrchestrationRuntime.open(agent, gateway, agentDir, sessions, history, host);
43
+ const scope = { agentId: 'probe', agentSessionId: randomUUID(), source: 'api', accountId: 'fixture', chatId: 'fixture', threadKey: '', principalId: 'fixture' };
44
+ const send = async text => {
45
+ const start = Date.now();
46
+ const answer = await runtime.send({ scope, text, requestId: randomUUID() }, { execute: true, writeMemory: false }, { timeoutMs: 45000 });
47
+ report.events.push({ answer, durationMs: Date.now() - start });
48
+ };
49
+ await send('Create exactly one media-worker task: use generate_image with model fixture-image and prompt a tiny red square, then task_stage_file on the generated file. Also create a document named receipt.txt containing exactly DOCUMENT_FIXTURE_OK and stage it. Do not use a project repository. Queue now and end the response.');
50
+ report.afterDispatch = runtime.store.all('SELECT state,snapshot_json FROM tasks').map(r => JSON.parse(r.snapshot_json));
51
+ await send('What is your name and our project codeword? Also report the current task status from the saved snapshot.');
52
+ report.afterFollowup = runtime.store.all('SELECT state,snapshot_json FROM tasks').map(r => JSON.parse(r.snapshot_json));
53
+ const deadline = Date.now() + 140000;
54
+ while (Date.now() < deadline) {
55
+ const task = runtime.store.all('SELECT snapshot_json FROM tasks').map(r => JSON.parse(r.snapshot_json))[0];
56
+ if (!task || ['completed', 'failed', 'needs_reconciliation', 'cancelled'].includes(task.state)) { report.task = task; break; }
57
+ await new Promise(resolve => setTimeout(resolve, 1000));
58
+ }
59
+ await send('Report the task result and actual test evidence.');
60
+ const paths = runtime.responseFiles(scope.agentSessionId);
61
+ report.attachments = paths;
62
+ report.generatedCalls = generated;
63
+ const buffers = paths.map(ref => readFileSync(join(agentDir, ref)));
64
+ report.imageBytesMatch = buffers.some(bytes => bytes.equals(Buffer.from(png, 'base64')));
65
+ report.documentBytesMatch = buffers.some(bytes => bytes.toString().trim() === 'DOCUMENT_FIXTURE_OK');
66
+ report.pass = report.task?.state === 'completed' && paths.length === 2 && report.imageBytesMatch && report.documentBytesMatch && generated === 1;
67
+ } catch (error) { report.error = { message: error.message, code: error.code }; }
68
+ finally { await runtime?.close(); await new Promise(resolve => imageServer.close(resolve)); writeFileSync(join(root, 'report.json'), JSON.stringify(report, null, 2)); console.log(JSON.stringify(report, null, 2)); }
69
+ process.exit(report.pass ? 0 : 1);
70
+ })().catch(error => { console.error(error.message); process.exit(1); });