agentworkshop 0.7.44 → 0.7.47

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 (1880) hide show
  1. package/.AgentWorkShop/prompts/host-tools.json +265 -6
  2. package/.AgentWorkShop/prompts/lead-supervise.md +54 -29
  3. package/.AgentWorkShop/prompts/peer-reply-optional.md +6 -2
  4. package/.AgentWorkShop/prompts/peer-reply-required.md +8 -7
  5. package/.output/.AgentWorkShop/aml-python/__pycache__/amlkit.cpython-312.pyc +0 -0
  6. package/.output/.AgentWorkShop/aml-python/amlkit.py +185 -120
  7. package/.output/.AgentWorkShop/aml-python/requirements.txt +9 -7
  8. package/.output/.AgentWorkShop/aml-python/train-hybrid-example.py +87 -0
  9. package/.output/.AgentWorkShop/prompts/host-tools.json +265 -6
  10. package/.output/.AgentWorkShop/prompts/lead-supervise.md +54 -29
  11. package/.output/.AgentWorkShop/prompts/peer-reply-optional.md +6 -2
  12. package/.output/.AgentWorkShop/prompts/peer-reply-required.md +8 -7
  13. package/.output/.AgentWorkShop/schema.json +12 -0
  14. package/.output/nitro.json +1 -1
  15. package/.output/public/_nuxt/-hB4kEmt.js +1 -0
  16. package/.output/public/_nuxt/1g9IT9Qh2.js +1 -0
  17. package/.output/public/_nuxt/74x7BOWv2.js +1 -0
  18. package/.output/public/_nuxt/9c5GOgbu.js +1 -0
  19. package/.output/public/_nuxt/9zrLAN2o2.js +1 -0
  20. package/.output/public/_nuxt/B1RT9NTO2.js +1 -0
  21. package/.output/public/_nuxt/B2x8SKRO.js +1 -0
  22. package/.output/public/_nuxt/B6Olw0Op.js +1 -0
  23. package/.output/public/_nuxt/B7jlMWsz.js +1 -0
  24. package/.output/public/_nuxt/B8cnjDtt.js +1 -0
  25. package/.output/public/_nuxt/B9rIcCX12.js +1 -0
  26. package/.output/public/_nuxt/BACBBVdw.js +1 -0
  27. package/.output/public/_nuxt/BBhLVYdM.js +1 -0
  28. package/.output/public/_nuxt/BDmNbZ252.js +1 -0
  29. package/.output/public/_nuxt/BFVf8HLR.js +1 -0
  30. package/.output/public/_nuxt/BGKUW7ra.js +1 -0
  31. package/.output/public/_nuxt/BH3obZJ42.js +1 -0
  32. package/.output/public/_nuxt/BHwG4yNs.js +1 -0
  33. package/.output/public/_nuxt/BIOq3xqe2.js +1 -0
  34. package/.output/public/_nuxt/BITZvQBK.js +1 -0
  35. package/.output/public/_nuxt/BL_dbd2v2.js +1 -0
  36. package/.output/public/_nuxt/BMMoqi94.js +1 -0
  37. package/.output/public/_nuxt/BNnnYEYh2.js +1 -0
  38. package/.output/public/_nuxt/BQXCMsXk.js +1 -0
  39. package/.output/public/_nuxt/BS9P_Ies2.js +1 -0
  40. package/.output/public/_nuxt/BWU1pvLL.js +1 -0
  41. package/.output/public/_nuxt/B_9_BM9G.js +3 -0
  42. package/.output/public/_nuxt/B_LcD7qE2.js +1 -0
  43. package/.output/public/_nuxt/BcQXL8pb.js +1 -0
  44. package/.output/public/_nuxt/BdM_Qr752.js +1 -0
  45. package/.output/public/_nuxt/BiOSWsjD.js +2 -0
  46. package/.output/public/_nuxt/BkSViqQd.js +1 -0
  47. package/.output/public/_nuxt/Bl5dYv4m.js +1 -0
  48. package/.output/public/_nuxt/BmiMC_BC.js +2 -0
  49. package/.output/public/_nuxt/BnpY_zNx.js +1 -0
  50. package/.output/public/_nuxt/BqYVLAcm.js +1 -0
  51. package/.output/public/_nuxt/Br3AySNQ.js +1 -0
  52. package/.output/public/_nuxt/Br3MggOL.js +1 -0
  53. package/.output/public/_nuxt/BrRX-l9B2.js +4108 -0
  54. package/.output/public/_nuxt/Bt2ZL5332.js +1 -0
  55. package/.output/public/_nuxt/Bub2P5me.js +28 -0
  56. package/.output/public/_nuxt/BvRk9kiK.js +0 -0
  57. package/.output/public/_nuxt/BvRk9kiK2.js +0 -0
  58. package/.output/public/_nuxt/Bwc6lt2X.js +3 -0
  59. package/.output/public/_nuxt/BxHBIVAg.js +1 -0
  60. package/.output/public/_nuxt/BxYTM0hb.js +1 -0
  61. package/.output/public/_nuxt/ByMj6e7s.js +3 -0
  62. package/.output/public/_nuxt/BzvHUfRR2.js +1 -0
  63. package/.output/public/_nuxt/C2YYOgMe.js +42 -0
  64. package/.output/public/_nuxt/C3twEwTh2.js +1 -0
  65. package/.output/public/_nuxt/C4WhK2wq.js +1 -0
  66. package/.output/public/_nuxt/C50LmoI1.js +0 -0
  67. package/.output/public/_nuxt/CAaSPBqk.js +1 -0
  68. package/.output/public/_nuxt/CBDX7p73.js +1 -0
  69. package/.output/public/_nuxt/CD9lpEz22.js +13 -0
  70. package/.output/public/_nuxt/CGZVhYJ4.js +1 -0
  71. package/.output/public/_nuxt/CJRDL4EG.js +1 -0
  72. package/.output/public/_nuxt/CKQPwwZa2.js +1 -0
  73. package/.output/public/_nuxt/CLySL7mW.js +75 -0
  74. package/.output/public/_nuxt/CMXcOb6W.js +1 -0
  75. package/.output/public/_nuxt/CN1CDAwe.js +1 -0
  76. package/.output/public/_nuxt/CP0I2l-6.js +1 -0
  77. package/.output/public/_nuxt/CP0Nep9S.js +1 -0
  78. package/.output/public/_nuxt/CPeZNE4S2.js +1 -0
  79. package/.output/public/_nuxt/CPmNRTBk2.js +21 -0
  80. package/.output/public/_nuxt/CQabB0oy.js +1 -0
  81. package/.output/public/_nuxt/CT-vTjcG.js +1 -0
  82. package/.output/public/_nuxt/CTVfcnjU.js +3 -0
  83. package/.output/public/_nuxt/CWzp2R6G.js +1 -0
  84. package/.output/public/_nuxt/C_VAXV7I2.js +7 -0
  85. package/.output/public/_nuxt/CavpkQb0.js +1 -0
  86. package/.output/public/_nuxt/CeWnOF3O.js +1 -0
  87. package/.output/public/_nuxt/CfLUvgr32.js +1 -0
  88. package/.output/public/_nuxt/Ch1P2mIf.js +1 -0
  89. package/.output/public/_nuxt/ChoLwR-s.js +1 -0
  90. package/.output/public/_nuxt/Chphw5IA2.js +1 -0
  91. package/.output/public/_nuxt/ChtjzEpK2.js +19 -0
  92. package/.output/public/_nuxt/CiTQY_n32.js +1 -0
  93. package/.output/public/_nuxt/Ck5oMvUk.js +1 -0
  94. package/.output/public/_nuxt/Ckafrjnw2.js +1 -0
  95. package/.output/public/_nuxt/Cm_PTn9t2.js +1 -0
  96. package/.output/public/_nuxt/Cmp8PMrA.js +1 -0
  97. package/.output/public/_nuxt/Cnrmlixo.js +3 -0
  98. package/.output/public/_nuxt/Cr518Gh02.js +1 -0
  99. package/.output/public/_nuxt/Crbir9cT.js +1 -0
  100. package/.output/public/_nuxt/CtPNnATm2.js +31 -0
  101. package/.output/public/_nuxt/Cu8c3oMN2.js +1 -0
  102. package/.output/public/_nuxt/CwLQAKay2.js +1 -0
  103. package/.output/public/_nuxt/CzlUIbK32.js +17 -0
  104. package/.output/public/_nuxt/D6lZftfy.js +1 -0
  105. package/.output/public/_nuxt/D83nVQPl.js +1 -0
  106. package/.output/public/_nuxt/D89BUtx6.js +1 -0
  107. package/.output/public/_nuxt/DCtk3qqr.js +1 -0
  108. package/.output/public/_nuxt/DD6Z0yPN2.js +1 -0
  109. package/.output/public/_nuxt/DGw8juu_.js +2 -0
  110. package/.output/public/_nuxt/DHSDk8Bq2.js +4 -0
  111. package/.output/public/_nuxt/DJdDFnjG2.js +1 -0
  112. package/.output/public/_nuxt/DJyNDnag.js +1 -0
  113. package/.output/public/_nuxt/DK3Fl9T5.js +1 -0
  114. package/.output/public/_nuxt/DLPuRMeG.js +19 -0
  115. package/.output/public/_nuxt/DMYYS5sK.js +1 -0
  116. package/.output/public/_nuxt/DNno23Jf2.js +1 -0
  117. package/.output/public/_nuxt/DNoEoo8t.js +1 -0
  118. package/.output/public/_nuxt/DPUXbTg92.js +1 -0
  119. package/.output/public/_nuxt/DRpFsrno.js +1 -0
  120. package/.output/public/_nuxt/DXIaadqv.js +1 -0
  121. package/.output/public/_nuxt/D_7AzAWe.js +1 -0
  122. package/.output/public/_nuxt/Dbe9TFc9.js +1 -0
  123. package/.output/public/_nuxt/DdNujZN5.js +1 -0
  124. package/.output/public/_nuxt/DdvQ7LRI.js +14 -0
  125. package/.output/public/_nuxt/DhFv8S2Z.js +1 -0
  126. package/.output/public/_nuxt/DkJVtqfc.js +1 -0
  127. package/.output/public/_nuxt/DkLCjrCk2.js +47 -0
  128. package/.output/public/_nuxt/DkpmSnHX.js +1 -0
  129. package/.output/public/_nuxt/DlUQa0wn2.js +1 -0
  130. package/.output/public/_nuxt/DoKpLEqc.js +1 -0
  131. package/.output/public/_nuxt/DpqA8D8_.js +1 -0
  132. package/.output/public/_nuxt/Dq0emNZi2.js +1 -0
  133. package/.output/public/_nuxt/DqtgGFEc.js +1 -0
  134. package/.output/public/_nuxt/DqtnqNgL2.js +1 -0
  135. package/.output/public/_nuxt/Dqz5HiXa.js +2 -0
  136. package/.output/public/_nuxt/DxagrjB8.js +1 -0
  137. package/.output/public/_nuxt/Dy3oXKdn2.js +1 -0
  138. package/.output/public/_nuxt/DzBbYWrw2.js +1 -0
  139. package/.output/public/_nuxt/EhhQmlBV2.js +1 -0
  140. package/.output/public/_nuxt/H2rNs1O82.js +1 -0
  141. package/.output/public/_nuxt/H6pPjo0l.js +1 -0
  142. package/.output/public/_nuxt/JAM4aNC_.js +1 -0
  143. package/.output/public/_nuxt/JgheoP3e.js +1 -0
  144. package/.output/public/_nuxt/LwIFGLgF.js +1 -0
  145. package/.output/public/_nuxt/Nw_6OpQZ2.js +1 -0
  146. package/.output/public/_nuxt/OXtV_ukR.js +1 -0
  147. package/.output/public/_nuxt/OmpTerminalPanel.ComMDrA8.css +1 -0
  148. package/.output/public/_nuxt/PLGqdko0.js +1 -0
  149. package/.output/public/_nuxt/PixDfCSm.js +1 -0
  150. package/.output/public/_nuxt/RAqsw632.js +1 -0
  151. package/.output/public/_nuxt/Sjjmp5OD2.js +1 -0
  152. package/.output/public/_nuxt/TOWR4WpO.js +1 -0
  153. package/.output/public/_nuxt/TownView.BvlfuLtP.css +1 -0
  154. package/.output/public/_nuxt/U8oQxruK.js +1 -0
  155. package/.output/public/_nuxt/WleoCtUX.js +1 -0
  156. package/.output/public/_nuxt/YaroNkJZ2.js +1 -0
  157. package/.output/public/_nuxt/Z-Z6EhXs.js +1 -0
  158. package/.output/public/_nuxt/ZuQtOnfI.js +1 -0
  159. package/.output/public/_nuxt/ZvXovq7N2.js +1 -0
  160. package/.output/public/_nuxt/_id_.BTrFUIHX.css +1 -0
  161. package/.output/public/_nuxt/_id_.Bossmhv1.css +1 -0
  162. package/.output/public/_nuxt/_wsId_.D-u-dbP9.css +1 -0
  163. package/.output/public/_nuxt/agents.Cgm_JG9L.css +1 -0
  164. package/.output/public/_nuxt/aml.Bi5X6_oi.css +1 -0
  165. package/.output/public/_nuxt/bg2adfck.js +1 -0
  166. package/.output/public/_nuxt/bt__BP-I.js +13 -0
  167. package/.output/public/_nuxt/builds/latest.json +1 -1
  168. package/.output/public/_nuxt/builds/meta/1b18aaf2-ccbc-45e0-b9c3-107655b226f9.json +1 -0
  169. package/.output/public/_nuxt/cBI0JqsV2.js +209 -0
  170. package/.output/public/_nuxt/cDcDztgb2.js +1 -0
  171. package/.output/public/_nuxt/cGSl2GZp.js +1 -0
  172. package/.output/public/_nuxt/csitHKnE2.js +1 -0
  173. package/.output/public/_nuxt/d-w5jR8R.js +1 -0
  174. package/.output/public/_nuxt/daq.0uieKcZk.css +1 -0
  175. package/.output/public/_nuxt/dcw.pQRVkAi_.css +1 -0
  176. package/.output/public/_nuxt/default.uao9U50c.css +1 -0
  177. package/.output/public/_nuxt/e7BBCLxr.js +1 -0
  178. package/.output/public/_nuxt/entry.6DEjPWvR.css +1 -0
  179. package/.output/public/_nuxt/eutnXI4F.js +24 -0
  180. package/.output/public/_nuxt/fxWyOzyp2.js +1 -0
  181. package/.output/public/_nuxt/hkMGMTqt.js +1 -0
  182. package/.output/public/_nuxt/ikAUnxx3.js +1 -0
  183. package/.output/public/_nuxt/lWYQbIR3.js +1 -0
  184. package/.output/public/_nuxt/logs.CD0Olr3c.css +1 -0
  185. package/.output/public/_nuxt/monitor.CI2v5Nvl.css +1 -0
  186. package/.output/public/_nuxt/pages.CMhSEhEb.css +1 -0
  187. package/.output/public/_nuxt/permissions.DxuOOIqQ.css +1 -0
  188. package/.output/public/_nuxt/plugins.C50x1qZp.css +1 -0
  189. package/.output/public/_nuxt/qOlYoGLf.js +1 -0
  190. package/.output/public/_nuxt/schedules.BXNJ9q_I.css +1 -0
  191. package/.output/public/_nuxt/settings.Bo5EYkLI.css +1 -0
  192. package/.output/public/_nuxt/teams.sGmx1AdX.css +1 -0
  193. package/.output/public/_nuxt/tokens.DFMFaCYU.css +1 -0
  194. package/.output/public/_nuxt/uI9Ki_XZ.js +9 -0
  195. package/.output/public/_nuxt/users.DBxcKnfg.css +1 -0
  196. package/.output/public/_nuxt/v55S8LnT.js +1 -0
  197. package/.output/public/_nuxt/wDPc4SSR.js +106 -0
  198. package/.output/public/_nuxt/workshop.b4YRXEe0.css +1 -0
  199. package/.output/public/_nuxt/y9kob70X.js +1 -0
  200. package/.output/public/_nuxt/zh-S_7rN.js +1 -0
  201. package/.output/server/chunks/_/LeftOutlined.mjs +1 -1
  202. package/.output/server/chunks/_/SearchOutlined.mjs +1243 -279
  203. package/.output/server/chunks/_/SearchOutlined.mjs.map +1 -1
  204. package/.output/server/chunks/_/binding-authz.mjs +1 -1
  205. package/.output/server/chunks/_/character-asset.repo.mjs +1 -1
  206. package/.output/server/chunks/_/entity.mjs +1 -1
  207. package/.output/server/chunks/_/env-manager.mjs +1 -1
  208. package/.output/server/chunks/_/host-bindings.mjs +1 -1
  209. package/.output/server/chunks/_/nitro.mjs +27006 -19064
  210. package/.output/server/chunks/_/nitro.mjs.map +1 -1
  211. package/.output/server/chunks/_/scene-layout.repo.mjs +1 -1
  212. package/.output/server/chunks/build/Checkbox-4EdGAAl_.mjs +206 -0
  213. package/.output/server/chunks/build/Checkbox-4EdGAAl_.mjs.map +1 -0
  214. package/.output/server/chunks/build/FormItemContext-4ORSzhWv.mjs +72 -0
  215. package/.output/server/chunks/build/FormItemContext-4ORSzhWv.mjs.map +1 -0
  216. package/.output/server/chunks/build/OmpTerminalPanel-EQHrOJbw.mjs +942 -0
  217. package/.output/server/chunks/build/OmpTerminalPanel-EQHrOJbw.mjs.map +1 -0
  218. package/.output/server/chunks/build/PluginSlot-BP_qedpQ.mjs +399 -0
  219. package/.output/server/chunks/build/PluginSlot-BP_qedpQ.mjs.map +1 -0
  220. package/.output/server/chunks/build/TownView-BAR8CPIZ.mjs +6373 -0
  221. package/.output/server/chunks/build/TownView-BAR8CPIZ.mjs.map +1 -0
  222. package/.output/server/chunks/build/_id_-DgMpjM3_.mjs +1354 -0
  223. package/.output/server/chunks/build/_id_-DgMpjM3_.mjs.map +1 -0
  224. package/.output/server/chunks/build/_id_-Dv3BQbYV.mjs +388 -0
  225. package/.output/server/chunks/build/_id_-Dv3BQbYV.mjs.map +1 -0
  226. package/.output/server/chunks/build/_wsId_-BKJvFmyf.mjs +13109 -0
  227. package/.output/server/chunks/build/_wsId_-BKJvFmyf.mjs.map +1 -0
  228. package/.output/server/chunks/build/agents-B2GLPmn2.mjs +1085 -0
  229. package/.output/server/chunks/build/agents-B2GLPmn2.mjs.map +1 -0
  230. package/.output/server/chunks/build/aml-DdWicH3t.mjs +806 -0
  231. package/.output/server/chunks/build/aml-DdWicH3t.mjs.map +1 -0
  232. package/.output/server/chunks/build/api-BY6ji7RC.mjs +50 -0
  233. package/.output/server/chunks/build/api-BY6ji7RC.mjs.map +1 -0
  234. package/.output/server/chunks/build/api-error-BwAQLw44.mjs +47 -0
  235. package/.output/server/chunks/build/api-error-BwAQLw44.mjs.map +1 -0
  236. package/.output/server/chunks/build/apiClient-D281qrK2.mjs +81 -0
  237. package/.output/server/chunks/build/apiClient-D281qrK2.mjs.map +1 -0
  238. package/.output/server/chunks/build/builtin-catalog-edpDcgfL.mjs +1 -1
  239. package/.output/server/chunks/build/card-CUSocE9p.mjs +953 -0
  240. package/.output/server/chunks/build/card-CUSocE9p.mjs.map +1 -0
  241. package/.output/server/chunks/build/channel-templates-RPOtkgRf.mjs +846 -0
  242. package/.output/server/chunks/build/channel-templates-RPOtkgRf.mjs.map +1 -0
  243. package/.output/server/chunks/build/checkbox-C4AKj81e.mjs +439 -0
  244. package/.output/server/chunks/build/checkbox-C4AKj81e.mjs.map +1 -0
  245. package/.output/server/chunks/build/client-only-qNA2OVV_.mjs +43 -0
  246. package/.output/server/chunks/build/client-only-qNA2OVV_.mjs.map +1 -0
  247. package/.output/server/chunks/build/constants-HPHJvjne.mjs +139 -0
  248. package/.output/server/chunks/build/constants-HPHJvjne.mjs.map +1 -0
  249. package/.output/server/chunks/build/core-CgTOPS4t.mjs +294 -0
  250. package/.output/server/chunks/build/core-CgTOPS4t.mjs.map +1 -0
  251. package/.output/server/chunks/build/daq-CPtsh0e7.mjs +1253 -0
  252. package/.output/server/chunks/build/daq-CPtsh0e7.mjs.map +1 -0
  253. package/.output/server/chunks/build/dcw-ry5Gyw6Y.mjs +478 -0
  254. package/.output/server/chunks/build/dcw-ry5Gyw6Y.mjs.map +1 -0
  255. package/.output/server/chunks/build/default-DxOE1eB0.mjs +2061 -0
  256. package/.output/server/chunks/build/default-DxOE1eB0.mjs.map +1 -0
  257. package/.output/server/chunks/build/descriptions-CFaUq4y4.mjs +406 -0
  258. package/.output/server/chunks/build/descriptions-CFaUq4y4.mjs.map +1 -0
  259. package/.output/server/chunks/build/drawer-Cfh9_zft.mjs +834 -0
  260. package/.output/server/chunks/build/drawer-Cfh9_zft.mjs.map +1 -0
  261. package/.output/server/chunks/build/dropdown-KdKWCS5K.mjs +556 -0
  262. package/.output/server/chunks/build/dropdown-KdKWCS5K.mjs.map +1 -0
  263. package/.output/server/chunks/build/dropdown-Yev6knaj.mjs +14 -0
  264. package/.output/server/chunks/build/dropdown-Yev6knaj.mjs.map +1 -0
  265. package/.output/server/chunks/build/form-uSlNqIAV.mjs +4711 -0
  266. package/.output/server/chunks/build/form-uSlNqIAV.mjs.map +1 -0
  267. package/.output/server/chunks/build/input-Cr_KFj4T.mjs +1381 -0
  268. package/.output/server/chunks/build/input-Cr_KFj4T.mjs.map +1 -0
  269. package/.output/server/chunks/build/input-number-BRVnxeiA.mjs +1119 -0
  270. package/.output/server/chunks/build/input-number-BRVnxeiA.mjs.map +1 -0
  271. package/.output/server/chunks/build/interval-DvHBIIZh.mjs +9 -0
  272. package/.output/server/chunks/build/interval-DvHBIIZh.mjs.map +1 -0
  273. package/.output/server/chunks/build/logs-CeaiO3y9.mjs +367 -0
  274. package/.output/server/chunks/build/logs-CeaiO3y9.mjs.map +1 -0
  275. package/.output/server/chunks/build/menu-BgkRSSx7.mjs +1949 -0
  276. package/.output/server/chunks/build/menu-BgkRSSx7.mjs.map +1 -0
  277. package/.output/server/chunks/build/monitor-DnuXEIi5.mjs +2245 -0
  278. package/.output/server/chunks/build/monitor-DnuXEIi5.mjs.map +1 -0
  279. package/.output/server/chunks/build/narrow-fetch-CcG-BPxc.mjs +6 -0
  280. package/.output/server/chunks/build/narrow-fetch-CcG-BPxc.mjs.map +1 -0
  281. package/.output/server/chunks/build/pages-Bn90ijKD.mjs +539 -0
  282. package/.output/server/chunks/build/pages-Bn90ijKD.mjs.map +1 -0
  283. package/.output/server/chunks/build/permissions-DL70W1YD.mjs +629 -0
  284. package/.output/server/chunks/build/permissions-DL70W1YD.mjs.map +1 -0
  285. package/.output/server/chunks/build/plugins-DrsZo--K.mjs +246 -0
  286. package/.output/server/chunks/build/plugins-DrsZo--K.mjs.map +1 -0
  287. package/.output/server/chunks/build/popconfirm-Ox-_2V8A.mjs +339 -0
  288. package/.output/server/chunks/build/popconfirm-Ox-_2V8A.mjs.map +1 -0
  289. package/.output/server/chunks/build/schedules-VLzNcjnW.mjs +7164 -0
  290. package/.output/server/chunks/build/schedules-VLzNcjnW.mjs.map +1 -0
  291. package/.output/server/chunks/build/segmented-C61yLHvo.mjs +341 -0
  292. package/.output/server/chunks/build/segmented-C61yLHvo.mjs.map +1 -0
  293. package/.output/server/chunks/build/select-rdBWytVK.mjs +3922 -0
  294. package/.output/server/chunks/build/select-rdBWytVK.mjs.map +1 -0
  295. package/.output/server/chunks/build/settings-DVAUVMsX.mjs +1089 -0
  296. package/.output/server/chunks/build/settings-DVAUVMsX.mjs.map +1 -0
  297. package/.output/server/chunks/build/space-B2uhHJG8.mjs +110 -0
  298. package/.output/server/chunks/build/space-B2uhHJG8.mjs.map +1 -0
  299. package/.output/server/chunks/build/spin-C2cuvGth.mjs +357 -0
  300. package/.output/server/chunks/build/spin-C2cuvGth.mjs.map +1 -0
  301. package/.output/server/chunks/build/switch-DZAUIbIN.mjs +377 -0
  302. package/.output/server/chunks/build/switch-DZAUIbIN.mjs.map +1 -0
  303. package/.output/server/chunks/build/table-DOFAvY-v.mjs +8881 -0
  304. package/.output/server/chunks/build/table-DOFAvY-v.mjs.map +1 -0
  305. package/.output/server/chunks/build/tabs-DTeIuZeP.mjs +1923 -0
  306. package/.output/server/chunks/build/tabs-DTeIuZeP.mjs.map +1 -0
  307. package/.output/server/chunks/build/tag-CHLGvNM6.mjs +1029 -0
  308. package/.output/server/chunks/build/tag-CHLGvNM6.mjs.map +1 -0
  309. package/.output/server/chunks/build/teams-Mc07PYO8.mjs +1195 -0
  310. package/.output/server/chunks/build/teams-Mc07PYO8.mjs.map +1 -0
  311. package/.output/server/chunks/build/tokens-DiwD5qni.mjs +1036 -0
  312. package/.output/server/chunks/build/tokens-DiwD5qni.mjs.map +1 -0
  313. package/.output/server/chunks/build/town-BIn3be5v.mjs +39 -0
  314. package/.output/server/chunks/build/town-BIn3be5v.mjs.map +1 -0
  315. package/.output/server/chunks/build/town-D8VmTCmN.mjs +128 -0
  316. package/.output/server/chunks/build/town-D8VmTCmN.mjs.map +1 -0
  317. package/.output/server/chunks/build/types-D6J7slEa.mjs +5561 -0
  318. package/.output/server/chunks/build/types-D6J7slEa.mjs.map +1 -0
  319. package/.output/server/chunks/build/useAgentHarnessOptions-CPn5dzKe.mjs +121 -0
  320. package/.output/server/chunks/build/useAgentHarnessOptions-CPn5dzKe.mjs.map +1 -0
  321. package/.output/server/chunks/build/useAgentTemplateActions-DQWzVnZ0.mjs +74 -0
  322. package/.output/server/chunks/build/useAgentTemplateActions-DQWzVnZ0.mjs.map +1 -0
  323. package/.output/server/chunks/build/useAgentTemplateDialogState-CZzpu5og.mjs +64 -0
  324. package/.output/server/chunks/build/useAgentTemplateDialogState-CZzpu5og.mjs.map +1 -0
  325. package/.output/server/chunks/build/useAgentTemplateForm-vqyiRPtt.mjs +114 -0
  326. package/.output/server/chunks/build/useAgentTemplateForm-vqyiRPtt.mjs.map +1 -0
  327. package/.output/server/chunks/build/useAgentTemplatesCatalog-DcQbsOik.mjs +130 -0
  328. package/.output/server/chunks/build/useAgentTemplatesCatalog-DcQbsOik.mjs.map +1 -0
  329. package/.output/server/chunks/build/useAmlDatasets-BM0lZu40.mjs +89 -0
  330. package/.output/server/chunks/build/useAmlDatasets-BM0lZu40.mjs.map +1 -0
  331. package/.output/server/chunks/build/useAmlEntities-BjXWvFd_.mjs +83 -0
  332. package/.output/server/chunks/build/useAmlEntities-BjXWvFd_.mjs.map +1 -0
  333. package/.output/server/chunks/build/useAmlEnv-BB7p6x_w.mjs +191 -0
  334. package/.output/server/chunks/build/useAmlEnv-BB7p6x_w.mjs.map +1 -0
  335. package/.output/server/chunks/build/useAmlExperiments-BtyW32PO.mjs +86 -0
  336. package/.output/server/chunks/build/useAmlExperiments-BtyW32PO.mjs.map +1 -0
  337. package/.output/server/chunks/build/useAmlFormat-WrKuRfw2.mjs +79 -0
  338. package/.output/server/chunks/build/useAmlFormat-WrKuRfw2.mjs.map +1 -0
  339. package/.output/server/chunks/build/useAmlJobs-DBuLvWMF.mjs +263 -0
  340. package/.output/server/chunks/build/useAmlJobs-DBuLvWMF.mjs.map +1 -0
  341. package/.output/server/chunks/build/useAmlModels-VurmkBYe.mjs +90 -0
  342. package/.output/server/chunks/build/useAmlModels-VurmkBYe.mjs.map +1 -0
  343. package/.output/server/chunks/build/useAmlNotes-BUdj3X6Y.mjs +83 -0
  344. package/.output/server/chunks/build/useAmlNotes-BUdj3X6Y.mjs.map +1 -0
  345. package/.output/server/chunks/build/useAmlPredict-DFy-Do10.mjs +127 -0
  346. package/.output/server/chunks/build/useAmlPredict-DFy-Do10.mjs.map +1 -0
  347. package/.output/server/chunks/build/useDaqAddNode-kW7uTSMQ.mjs +139 -0
  348. package/.output/server/chunks/build/useDaqAddNode-kW7uTSMQ.mjs.map +1 -0
  349. package/.output/server/chunks/build/useDaqDetailBinding-cpBz4hSL.mjs +67 -0
  350. package/.output/server/chunks/build/useDaqDetailBinding-cpBz4hSL.mjs.map +1 -0
  351. package/.output/server/chunks/build/useDaqDetailFrames-BZGtKKXW.mjs +76 -0
  352. package/.output/server/chunks/build/useDaqDetailFrames-BZGtKKXW.mjs.map +1 -0
  353. package/.output/server/chunks/build/useDaqDetailHistory-C4_hVeqZ.mjs +173 -0
  354. package/.output/server/chunks/build/useDaqDetailHistory-C4_hVeqZ.mjs.map +1 -0
  355. package/.output/server/chunks/build/useDaqDetailNode-Bwid_iA8.mjs +96 -0
  356. package/.output/server/chunks/build/useDaqDetailNode-Bwid_iA8.mjs.map +1 -0
  357. package/.output/server/chunks/build/useDaqDetailParams-JfqHvTxr.mjs +156 -0
  358. package/.output/server/chunks/build/useDaqDetailParams-JfqHvTxr.mjs.map +1 -0
  359. package/.output/server/chunks/build/useDaqFilters-C13836p-.mjs +219 -0
  360. package/.output/server/chunks/build/useDaqFilters-C13836p-.mjs.map +1 -0
  361. package/.output/server/chunks/build/useDaqNodeWindow-1DWj2H5G.mjs +87 -0
  362. package/.output/server/chunks/build/useDaqNodeWindow-1DWj2H5G.mjs.map +1 -0
  363. package/.output/server/chunks/build/useDaqOptimizations-Ct-TSXxy.mjs +133 -0
  364. package/.output/server/chunks/build/useDaqOptimizations-Ct-TSXxy.mjs.map +1 -0
  365. package/.output/server/chunks/build/useDaqStream-wOxZcMDA.mjs +395 -0
  366. package/.output/server/chunks/build/useDaqStream-wOxZcMDA.mjs.map +1 -0
  367. package/.output/server/chunks/build/useDaqTemplates-BqQRdrIm.mjs +184 -0
  368. package/.output/server/chunks/build/useDaqTemplates-BqQRdrIm.mjs.map +1 -0
  369. package/.output/server/chunks/build/useDashboardCharts-DZysNDUX.mjs +351 -0
  370. package/.output/server/chunks/build/useDashboardCharts-DZysNDUX.mjs.map +1 -0
  371. package/.output/server/chunks/build/useDashboardData-Ny_wtbo6.mjs +150 -0
  372. package/.output/server/chunks/build/useDashboardData-Ny_wtbo6.mjs.map +1 -0
  373. package/.output/server/chunks/build/useDcwAddNode-C8nE7geh.mjs +148 -0
  374. package/.output/server/chunks/build/useDcwAddNode-C8nE7geh.mjs.map +1 -0
  375. package/.output/server/chunks/build/useDcwCards-ETEsHvVy.mjs +64 -0
  376. package/.output/server/chunks/build/useDcwCards-ETEsHvVy.mjs.map +1 -0
  377. package/.output/server/chunks/build/useDcwDetailScope-BNrpDzbO.mjs +181 -0
  378. package/.output/server/chunks/build/useDcwDetailScope-BNrpDzbO.mjs.map +1 -0
  379. package/.output/server/chunks/build/useDcwDetailTemplates-IcKAJ37Y.mjs +145 -0
  380. package/.output/server/chunks/build/useDcwDetailTemplates-IcKAJ37Y.mjs.map +1 -0
  381. package/.output/server/chunks/build/useDcwFilter-FfVlDdyS.mjs +68 -0
  382. package/.output/server/chunks/build/useDcwFilter-FfVlDdyS.mjs.map +1 -0
  383. package/.output/server/chunks/build/useDcwLedger-BLoMmcu1.mjs +76 -0
  384. package/.output/server/chunks/build/useDcwLedger-BLoMmcu1.mjs.map +1 -0
  385. package/.output/server/chunks/build/useDcwLineMutations-BMC5BTWU.mjs +134 -0
  386. package/.output/server/chunks/build/useDcwLineMutations-BMC5BTWU.mjs.map +1 -0
  387. package/.output/server/chunks/build/useDcwLineRun-Bpxk4mse.mjs +101 -0
  388. package/.output/server/chunks/build/useDcwLineRun-Bpxk4mse.mjs.map +1 -0
  389. package/.output/server/chunks/build/useDcwProducts-D-zrMaeV.mjs +90 -0
  390. package/.output/server/chunks/build/useDcwProducts-D-zrMaeV.mjs.map +1 -0
  391. package/.output/server/chunks/build/useDcwQuery-1lYHOaU6.mjs +95 -0
  392. package/.output/server/chunks/build/useDcwQuery-1lYHOaU6.mjs.map +1 -0
  393. package/.output/server/chunks/build/useDcwQuickActions-C-tgcXIr.mjs +85 -0
  394. package/.output/server/chunks/build/useDcwQuickActions-C-tgcXIr.mjs.map +1 -0
  395. package/.output/server/chunks/build/useDcwRecipes-BzGOymqz.mjs +237 -0
  396. package/.output/server/chunks/build/useDcwRecipes-BzGOymqz.mjs.map +1 -0
  397. package/.output/server/chunks/build/useDcwStream-D04kCV3J.mjs +435 -0
  398. package/.output/server/chunks/build/useDcwStream-D04kCV3J.mjs.map +1 -0
  399. package/.output/server/chunks/build/useDcwTemplates-Dsjw9u6U.mjs +88 -0
  400. package/.output/server/chunks/build/useDcwTemplates-Dsjw9u6U.mjs.map +1 -0
  401. package/.output/server/chunks/build/useDcwWrites-3RxwN36I.mjs +120 -0
  402. package/.output/server/chunks/build/useDcwWrites-3RxwN36I.mjs.map +1 -0
  403. package/.output/server/chunks/build/useDeviceTwins-CbVad1M3.mjs +128 -0
  404. package/.output/server/chunks/build/useDeviceTwins-CbVad1M3.mjs.map +1 -0
  405. package/.output/server/chunks/build/useLocalTime-9a4B-aHv.mjs +1 -8
  406. package/.output/server/chunks/build/useLocalTime-9a4B-aHv.mjs.map +1 -1
  407. package/.output/server/chunks/build/useLogsFormat-BlwLpyzy.mjs +74 -0
  408. package/.output/server/chunks/build/useLogsFormat-BlwLpyzy.mjs.map +1 -0
  409. package/.output/server/chunks/build/useLogsManual-Deev2Cjk.mjs +81 -0
  410. package/.output/server/chunks/build/useLogsManual-Deev2Cjk.mjs.map +1 -0
  411. package/.output/server/chunks/build/useLogsQuery-CRAm2hmS.mjs +112 -0
  412. package/.output/server/chunks/build/useLogsQuery-CRAm2hmS.mjs.map +1 -0
  413. package/.output/server/chunks/build/useLogsScope-ClNijVj4.mjs +80 -0
  414. package/.output/server/chunks/build/useLogsScope-ClNijVj4.mjs.map +1 -0
  415. package/.output/server/chunks/build/useMonitorColumns-ylxrUNTK.mjs +212 -0
  416. package/.output/server/chunks/build/useMonitorColumns-ylxrUNTK.mjs.map +1 -0
  417. package/.output/server/chunks/build/useMonitorData-CEpKXoD4.mjs +131 -0
  418. package/.output/server/chunks/build/useMonitorData-CEpKXoD4.mjs.map +1 -0
  419. package/.output/server/chunks/build/useMonitorFormat-_7zLapf3.mjs +87 -0
  420. package/.output/server/chunks/build/useMonitorFormat-_7zLapf3.mjs.map +1 -0
  421. package/.output/server/chunks/build/useMonitorTerminal-Dj4QwRNW.mjs +68 -0
  422. package/.output/server/chunks/build/useMonitorTerminal-Dj4QwRNW.mjs.map +1 -0
  423. package/.output/server/chunks/build/useOpsLog-CgnNG7_n.mjs +137 -0
  424. package/.output/server/chunks/build/useOpsLog-CgnNG7_n.mjs.map +1 -0
  425. package/.output/server/chunks/build/useTeamActions-D6sxdpkP.mjs +76 -0
  426. package/.output/server/chunks/build/useTeamActions-D6sxdpkP.mjs.map +1 -0
  427. package/.output/server/chunks/build/useTeamAddMemberDialog-Q-ntQ6Vo.mjs +81 -0
  428. package/.output/server/chunks/build/useTeamAddMemberDialog-Q-ntQ6Vo.mjs.map +1 -0
  429. package/.output/server/chunks/build/useTeamCreateDialog-D7OMfDTM.mjs +94 -0
  430. package/.output/server/chunks/build/useTeamCreateDialog-D7OMfDTM.mjs.map +1 -0
  431. package/.output/server/chunks/build/useTeamDeployDialog-vBRqjiut.mjs +77 -0
  432. package/.output/server/chunks/build/useTeamDeployDialog-vBRqjiut.mjs.map +1 -0
  433. package/.output/server/chunks/build/useTeamDialogState-CFRUQxAf.mjs +79 -0
  434. package/.output/server/chunks/build/useTeamDialogState-CFRUQxAf.mjs.map +1 -0
  435. package/.output/server/chunks/build/useTeamPluginDialog-B8kxewpZ.mjs +100 -0
  436. package/.output/server/chunks/build/useTeamPluginDialog-B8kxewpZ.mjs.map +1 -0
  437. package/.output/server/chunks/build/useTeamsCatalog-xRhk7ezA.mjs +120 -0
  438. package/.output/server/chunks/build/useTeamsCatalog-xRhk7ezA.mjs.map +1 -0
  439. package/.output/server/chunks/build/useTokenClipboard-CwQpoFeP.mjs +69 -0
  440. package/.output/server/chunks/build/useTokenClipboard-CwQpoFeP.mjs.map +1 -0
  441. package/.output/server/chunks/build/useTokenCreate-DpDcF1Vx.mjs +112 -0
  442. package/.output/server/chunks/build/useTokenCreate-DpDcF1Vx.mjs.map +1 -0
  443. package/.output/server/chunks/build/useTokenRename-BRejFrtc.mjs +84 -0
  444. package/.output/server/chunks/build/useTokenRename-BRejFrtc.mjs.map +1 -0
  445. package/.output/server/chunks/build/useTokenReveal-DER2afAS.mjs +115 -0
  446. package/.output/server/chunks/build/useTokenReveal-DER2afAS.mjs.map +1 -0
  447. package/.output/server/chunks/build/useTokensList-DHt65IOY.mjs +89 -0
  448. package/.output/server/chunks/build/useTokensList-DHt65IOY.mjs.map +1 -0
  449. package/.output/server/chunks/build/useWorkbenchAuth-B2j-zILO.mjs +135 -0
  450. package/.output/server/chunks/build/useWorkbenchAuth-B2j-zILO.mjs.map +1 -0
  451. package/.output/server/chunks/build/useWorkbenchWorkspaces-B_2mOxN6.mjs +133 -0
  452. package/.output/server/chunks/build/useWorkbenchWorkspaces-B_2mOxN6.mjs.map +1 -0
  453. package/.output/server/chunks/build/useWorkshopApi-B1B9vd4m.mjs +102 -0
  454. package/.output/server/chunks/build/useWorkshopApi-B1B9vd4m.mjs.map +1 -0
  455. package/.output/server/chunks/build/useWorkshopWs-B-Es2Xg3.mjs +1782 -0
  456. package/.output/server/chunks/build/useWorkshopWs-B-Es2Xg3.mjs.map +1 -0
  457. package/.output/server/chunks/build/useWorkspaceAuth-tQ1ORWXo.mjs +57 -0
  458. package/.output/server/chunks/build/useWorkspaceAuth-tQ1ORWXo.mjs.map +1 -0
  459. package/.output/server/chunks/build/useWorkspaceChannels-BwB6TAWY.mjs +87 -0
  460. package/.output/server/chunks/build/useWorkspaceChannels-BwB6TAWY.mjs.map +1 -0
  461. package/.output/server/chunks/build/useWorkspacePanels-CuAmDpT5.mjs +75 -0
  462. package/.output/server/chunks/build/useWorkspacePanels-CuAmDpT5.mjs.map +1 -0
  463. package/.output/server/chunks/build/useWorkspaceShell-CcQ4JlqO.mjs +165 -0
  464. package/.output/server/chunks/build/useWorkspaceShell-CcQ4JlqO.mjs.map +1 -0
  465. package/.output/server/chunks/build/users-De2HygNt.mjs +561 -0
  466. package/.output/server/chunks/build/users-De2HygNt.mjs.map +1 -0
  467. package/.output/server/chunks/build/workshop-CmgpTwyf.mjs +1018 -0
  468. package/.output/server/chunks/build/workshop-CmgpTwyf.mjs.map +1 -0
  469. package/.output/server/chunks/build/workspaces-DVIEk1Bl.mjs +139 -0
  470. package/.output/server/chunks/build/workspaces-DVIEk1Bl.mjs.map +1 -0
  471. package/.output/server/chunks/routes/api/health.get.mjs +2 -2
  472. package/.output/server/chunks/routes/api/index.get.mjs +2 -2
  473. package/.output/server/chunks/routes/api/index.post.mjs +2 -2
  474. package/.output/server/chunks/routes/api/mcp/workshop.mjs +2 -2
  475. package/.output/server/chunks/routes/api/metrics.mjs +2 -2
  476. package/.output/server/chunks/routes/api/plugins/_name/_...path_.mjs +2 -2
  477. package/.output/server/chunks/routes/api/plugins/client/_name_.get.mjs +2 -2
  478. package/.output/server/chunks/routes/api/plugins/i18n.get.mjs +2 -2
  479. package/.output/server/chunks/routes/api/plugins/manifest.get.mjs +2 -2
  480. package/.output/server/chunks/routes/api/system/config-groups/_id_.delete.mjs +2 -2
  481. package/.output/server/chunks/routes/api/system/config-groups/_id_.patch.mjs +2 -2
  482. package/.output/server/chunks/routes/api/system/config.get.mjs +2 -2
  483. package/.output/server/chunks/routes/api/system/index.get.mjs +2 -2
  484. package/.output/server/chunks/routes/api/system/index.patch.mjs +2 -2
  485. package/.output/server/chunks/routes/api/system/index.post.mjs +2 -2
  486. package/.output/server/chunks/routes/api/system/index2.get.mjs +2 -2
  487. package/.output/server/chunks/routes/api/system/monitor/terminal/ws.mjs +35 -4
  488. package/.output/server/chunks/routes/api/system/monitor/terminal/ws.mjs.map +1 -1
  489. package/.output/server/chunks/routes/api/system/monitor/terminate.post.mjs +2 -2
  490. package/.output/server/chunks/routes/api/system/monitor.get.mjs +2 -2
  491. package/.output/server/chunks/routes/api/system/settings/events.get.mjs +2 -2
  492. package/.output/server/chunks/routes/api/system/settings/reset.post.mjs +2 -2
  493. package/.output/server/chunks/routes/api/users/_id_.delete.mjs +2 -2
  494. package/.output/server/chunks/routes/api/users/_id_.get.mjs +2 -2
  495. package/.output/server/chunks/routes/api/users/_id_.put.mjs +2 -2
  496. package/.output/server/chunks/routes/api/users/index.get.mjs +2 -2
  497. package/.output/server/chunks/routes/api/users/index.post.mjs +2 -2
  498. package/.output/server/chunks/routes/api/users/login.post.mjs +2 -2
  499. package/.output/server/chunks/routes/api/users/logout.post.mjs +2 -2
  500. package/.output/server/chunks/routes/api/users/me.get.mjs +2 -2
  501. package/.output/server/chunks/routes/api/users/register.post.mjs +2 -2
  502. package/.output/server/chunks/routes/api/users/setup-status.get.mjs +2 -2
  503. package/.output/server/chunks/routes/api/users/tokens/_id/token.get.mjs +2 -2
  504. package/.output/server/chunks/routes/api/users/tokens/_id_.delete.mjs +2 -2
  505. package/.output/server/chunks/routes/api/users/tokens/_id_.patch.mjs +2 -2
  506. package/.output/server/chunks/routes/api/workshop/_...path_.mjs +2 -2
  507. package/.output/server/chunks/routes/api/workshop/a2a/_agentId/index.get.mjs +2 -2
  508. package/.output/server/chunks/routes/api/workshop/a2a/_agentId/index.post.mjs +2 -2
  509. package/.output/server/chunks/routes/api/workshop/a2a/send.post.mjs +2 -2
  510. package/.output/server/chunks/routes/api/workshop/agent-tools/approvals/_id/decide.post.mjs +38 -6
  511. package/.output/server/chunks/routes/api/workshop/agent-tools/approvals/_id/decide.post.mjs.map +1 -1
  512. package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.delete.mjs +2 -2
  513. package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.patch.mjs +2 -2
  514. package/.output/server/chunks/routes/api/workshop/agent-tools/index.get.mjs +14 -5
  515. package/.output/server/chunks/routes/api/workshop/agent-tools/index.get.mjs.map +1 -1
  516. package/.output/server/chunks/routes/api/workshop/agent-tools/index.post.mjs +2 -2
  517. package/.output/server/chunks/routes/api/workshop/agent-tools/index2.get.mjs +2 -2
  518. package/.output/server/chunks/routes/api/workshop/agent-tools/invoke.post.mjs +2 -2
  519. package/.output/server/chunks/routes/api/workshop/agent-tools/list.get.mjs +2 -2
  520. package/.output/server/chunks/routes/api/workshop/agents/_id_.delete.mjs +2 -2
  521. package/.output/server/chunks/routes/api/workshop/agents/_id_.get.mjs +2 -2
  522. package/.output/server/chunks/routes/api/workshop/agents/_id_.patch.mjs +2 -2
  523. package/.output/server/chunks/routes/api/workshop/agents/subscribe.post.mjs +2 -2
  524. package/.output/server/chunks/routes/api/workshop/aml/datasets/_id/preview.get.mjs +1 -1
  525. package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.delete.mjs +2 -2
  526. package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.get.mjs +2 -2
  527. package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.patch.mjs +2 -2
  528. package/.output/server/chunks/routes/api/workshop/aml/entities/prune.post.mjs +2 -2
  529. package/.output/server/chunks/routes/api/workshop/aml/env/recheck.post.mjs +2 -2
  530. package/.output/server/chunks/routes/api/workshop/aml/env/uv.post.mjs +2 -2
  531. package/.output/server/chunks/routes/api/workshop/aml/env/venv.post.mjs +2 -2
  532. package/.output/server/chunks/routes/api/workshop/aml/index.get.mjs +2 -2
  533. package/.output/server/chunks/routes/api/workshop/aml/index.post.mjs +2 -2
  534. package/.output/server/chunks/routes/api/workshop/aml/index2.get.mjs +2 -2
  535. package/.output/server/chunks/routes/api/workshop/aml/index2.post.mjs +2 -2
  536. package/.output/server/chunks/routes/api/workshop/aml/index3.get.mjs +2 -2
  537. package/.output/server/chunks/routes/api/workshop/aml/index4.get.mjs +2 -2
  538. package/.output/server/chunks/routes/api/workshop/aml/index5.get.mjs +2 -2
  539. package/.output/server/chunks/routes/api/workshop/aml/index6.get.mjs +2 -2
  540. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/cancel.post.mjs +2 -2
  541. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/logs.get.mjs +2 -2
  542. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/retry.post.mjs +2 -2
  543. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id_.delete.mjs +2 -2
  544. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id_.get.mjs +2 -2
  545. package/.output/server/chunks/routes/api/workshop/aml/models/_id/predict.post.mjs +2 -2
  546. package/.output/server/chunks/routes/api/workshop/aml/models/_id/promote.post.mjs +2 -2
  547. package/.output/server/chunks/routes/api/workshop/aml/models/_id_.delete.mjs +2 -2
  548. package/.output/server/chunks/routes/api/workshop/aml/models/_id_.patch.mjs +2 -2
  549. package/.output/server/chunks/routes/api/workshop/approvals/_id/decide.post.mjs +2 -2
  550. package/.output/server/chunks/routes/api/workshop/assets/character/_id_.delete.mjs +1 -1
  551. package/.output/server/chunks/routes/api/workshop/assets/devices/_id_.delete.mjs +1 -1
  552. package/.output/server/chunks/routes/api/workshop/assets/index.get.mjs +2 -2
  553. package/.output/server/chunks/routes/api/workshop/assets/index.post.mjs +1 -1
  554. package/.output/server/chunks/routes/api/workshop/assets/index2.get.mjs +1 -1
  555. package/.output/server/chunks/routes/api/workshop/assets/index2.post.mjs +1 -1
  556. package/.output/server/chunks/routes/api/workshop/audit.get.mjs +2 -2
  557. package/.output/server/chunks/routes/api/workshop/caller.mjs +2 -2
  558. package/.output/server/chunks/routes/api/workshop/channel-templates/_id/instantiate.post.mjs +10 -5
  559. package/.output/server/chunks/routes/api/workshop/channel-templates/_id/instantiate.post.mjs.map +1 -1
  560. package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.delete.mjs +2 -2
  561. package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.get.mjs +2 -2
  562. package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.patch.mjs +2 -2
  563. package/.output/server/chunks/routes/api/workshop/channel-templates/from-channel.post.mjs +2 -2
  564. package/.output/server/chunks/routes/api/workshop/channels/_id/activate.post.mjs +2 -2
  565. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/index.get.mjs +2 -2
  566. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/index.post.mjs +2 -2
  567. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/memories/_memoryId_.delete.mjs +2 -2
  568. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/memories/search.post.mjs +2 -2
  569. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/model.patch.mjs +2 -2
  570. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/position.patch.mjs +2 -2
  571. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/range.patch.mjs +2 -2
  572. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/stop.post.mjs +2 -2
  573. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId_.delete.mjs +2 -2
  574. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId_.patch.mjs +2 -2
  575. package/.output/server/chunks/routes/api/workshop/channels/_id/chat/index.get.mjs +41 -0
  576. package/.output/server/chunks/routes/api/workshop/channels/_id/chat/index.get.mjs.map +1 -0
  577. package/.output/server/chunks/routes/api/workshop/channels/_id/chat/index.post.mjs +52 -0
  578. package/.output/server/chunks/routes/api/workshop/channels/_id/chat/index.post.mjs.map +1 -0
  579. package/.output/server/chunks/routes/api/workshop/channels/_id/chat/messages/_messageId/read.post.mjs +33 -0
  580. package/.output/server/chunks/routes/api/workshop/channels/_id/chat/messages/_messageId/read.post.mjs.map +1 -0
  581. package/.output/server/chunks/routes/api/workshop/channels/_id/chat/permissions.get.mjs +48 -0
  582. package/.output/server/chunks/routes/api/workshop/channels/_id/chat/permissions.get.mjs.map +1 -0
  583. package/.output/server/chunks/routes/api/workshop/channels/_id/events.get.mjs +2 -2
  584. package/.output/server/chunks/routes/api/workshop/channels/_id/index.get.mjs +2 -2
  585. package/.output/server/chunks/routes/api/workshop/channels/_id/index.post.mjs +2 -2
  586. package/.output/server/chunks/routes/api/workshop/channels/_id/index.put.mjs +2 -2
  587. package/.output/server/chunks/routes/api/workshop/channels/_id/index2.get.mjs +10 -14
  588. package/.output/server/chunks/routes/api/workshop/channels/_id/index2.get.mjs.map +1 -1
  589. package/.output/server/chunks/routes/api/workshop/channels/_id/index2.post.mjs +2 -2
  590. package/.output/server/chunks/routes/api/workshop/channels/_id/index3.get.mjs +15 -28
  591. package/.output/server/chunks/routes/api/workshop/channels/_id/index3.get.mjs.map +1 -1
  592. package/.output/server/chunks/routes/api/workshop/channels/_id/index3.post.mjs +3 -2
  593. package/.output/server/chunks/routes/api/workshop/channels/_id/index3.post.mjs.map +1 -1
  594. package/.output/server/chunks/routes/api/workshop/channels/_id/index4.get.mjs +29 -23
  595. package/.output/server/chunks/routes/api/workshop/channels/_id/index4.get.mjs.map +1 -1
  596. package/.output/server/chunks/routes/api/workshop/channels/_id/index4.post.mjs +9 -4
  597. package/.output/server/chunks/routes/api/workshop/channels/_id/index4.post.mjs.map +1 -1
  598. package/.output/server/chunks/routes/api/workshop/channels/_id/index5.get.mjs +22 -10
  599. package/.output/server/chunks/routes/api/workshop/channels/_id/index5.get.mjs.map +1 -1
  600. package/.output/server/chunks/routes/api/workshop/channels/_id/index6.get.mjs +34 -0
  601. package/.output/server/chunks/routes/api/workshop/channels/_id/index6.get.mjs.map +1 -0
  602. package/.output/server/chunks/routes/api/workshop/channels/_id/members/_userId/approve.post.mjs +33 -0
  603. package/.output/server/chunks/routes/api/workshop/channels/_id/members/_userId/approve.post.mjs.map +1 -0
  604. package/.output/server/chunks/routes/api/workshop/channels/_id/members/_userId_.delete.mjs +34 -0
  605. package/.output/server/chunks/routes/api/workshop/channels/_id/members/_userId_.delete.mjs.map +1 -0
  606. package/.output/server/chunks/routes/api/workshop/channels/_id/members/join.post.mjs +35 -0
  607. package/.output/server/chunks/routes/api/workshop/channels/_id/members/join.post.mjs.map +1 -0
  608. package/.output/server/chunks/routes/api/workshop/channels/_id/members/leave.post.mjs +33 -0
  609. package/.output/server/chunks/routes/api/workshop/channels/_id/members/leave.post.mjs.map +1 -0
  610. package/.output/server/chunks/routes/api/workshop/channels/_id/memories/_memoryId_.delete.mjs +2 -2
  611. package/.output/server/chunks/routes/api/workshop/channels/_id/queue.get.mjs +2 -2
  612. package/.output/server/chunks/routes/api/workshop/channels/_id/terminals.get.mjs +2 -2
  613. package/.output/server/chunks/routes/api/workshop/channels/_id_.delete.mjs +2 -2
  614. package/.output/server/chunks/routes/api/workshop/channels/index.get.mjs +2 -2
  615. package/.output/server/chunks/routes/api/workshop/channels/index.patch.mjs +22 -6
  616. package/.output/server/chunks/routes/api/workshop/channels/index.patch.mjs.map +1 -1
  617. package/.output/server/chunks/routes/api/workshop/channels.get.mjs +21 -3
  618. package/.output/server/chunks/routes/api/workshop/channels.get.mjs.map +1 -1
  619. package/.output/server/chunks/routes/api/workshop/channels.post.mjs +5 -5
  620. package/.output/server/chunks/routes/api/workshop/daq/_id/bind.post.mjs +2 -2
  621. package/.output/server/chunks/routes/api/workshop/daq/_id/bindings.put.mjs +2 -2
  622. package/.output/server/chunks/routes/api/workshop/daq/_id/frames/content.get.mjs +2 -2
  623. package/.output/server/chunks/routes/api/workshop/daq/_id/frames.get.mjs +2 -2
  624. package/.output/server/chunks/routes/api/workshop/daq/_id/samples.get.mjs +2 -2
  625. package/.output/server/chunks/routes/api/workshop/daq/_id/test.post.mjs +2 -2
  626. package/.output/server/chunks/routes/api/workshop/daq/_id_.delete.mjs +2 -2
  627. package/.output/server/chunks/routes/api/workshop/daq/_id_.patch.mjs +2 -2
  628. package/.output/server/chunks/routes/api/workshop/daq/alarms/_id/ack.post.mjs +2 -2
  629. package/.output/server/chunks/routes/api/workshop/daq/alarms.get.mjs +2 -2
  630. package/.output/server/chunks/routes/api/workshop/daq/controller.post.mjs +2 -2
  631. package/.output/server/chunks/routes/api/workshop/daq/index.post.mjs +2 -2
  632. package/.output/server/chunks/routes/api/workshop/daq/infra/reconnect.post.mjs +2 -2
  633. package/.output/server/chunks/routes/api/workshop/daq/infra.get.mjs +2 -2
  634. package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.delete.mjs +2 -2
  635. package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.patch.mjs +2 -2
  636. package/.output/server/chunks/routes/api/workshop/daq/test-driver.post.mjs +2 -2
  637. package/.output/server/chunks/routes/api/workshop/dcw/_id/bind.post.mjs +2 -2
  638. package/.output/server/chunks/routes/api/workshop/dcw/_id/bindings.put.mjs +2 -2
  639. package/.output/server/chunks/routes/api/workshop/dcw/_id/param-ledger.get.mjs +2 -2
  640. package/.output/server/chunks/routes/api/workshop/dcw/_id/read.post.mjs +2 -2
  641. package/.output/server/chunks/routes/api/workshop/dcw/_id/test.post.mjs +2 -2
  642. package/.output/server/chunks/routes/api/workshop/dcw/_id/write.post.mjs +2 -2
  643. package/.output/server/chunks/routes/api/workshop/dcw/_id_.delete.mjs +2 -2
  644. package/.output/server/chunks/routes/api/workshop/dcw/_id_.patch.mjs +2 -2
  645. package/.output/server/chunks/routes/api/workshop/dcw/controller.post.mjs +2 -2
  646. package/.output/server/chunks/routes/api/workshop/dcw/index.get.mjs +2 -2
  647. package/.output/server/chunks/routes/api/workshop/dcw/index.post.mjs +2 -2
  648. package/.output/server/chunks/routes/api/workshop/dcw/index2.get.mjs +2 -2
  649. package/.output/server/chunks/routes/api/workshop/dcw/index2.post.mjs +2 -2
  650. package/.output/server/chunks/routes/api/workshop/dcw/index3.get.mjs +2 -2
  651. package/.output/server/chunks/routes/api/workshop/dcw/index3.post.mjs +2 -2
  652. package/.output/server/chunks/routes/api/workshop/dcw/index4.get.mjs +2 -2
  653. package/.output/server/chunks/routes/api/workshop/dcw/index4.post.mjs +2 -2
  654. package/.output/server/chunks/routes/api/workshop/dcw/index5.get.mjs +2 -2
  655. package/.output/server/chunks/routes/api/workshop/dcw/index5.post.mjs +2 -2
  656. package/.output/server/chunks/routes/api/workshop/dcw/index6.get.mjs +2 -2
  657. package/.output/server/chunks/routes/api/workshop/dcw/journal/node/_nodeId/rollback.post.mjs +2 -2
  658. package/.output/server/chunks/routes/api/workshop/dcw/line/query.get.mjs +2 -2
  659. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/start.post.mjs +2 -2
  660. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/stop.post.mjs +2 -2
  661. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.delete.mjs +2 -2
  662. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.patch.mjs +2 -2
  663. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/judge.post.mjs +2 -2
  664. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/rollback.post.mjs +2 -2
  665. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/series.get.mjs +2 -2
  666. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id_.get.mjs +2 -2
  667. package/.output/server/chunks/routes/api/workshop/dcw/params/_id/read.post.mjs +2 -2
  668. package/.output/server/chunks/routes/api/workshop/dcw/params/_id/write.post.mjs +2 -2
  669. package/.output/server/chunks/routes/api/workshop/dcw/params/_id_.delete.mjs +2 -2
  670. package/.output/server/chunks/routes/api/workshop/dcw/params/_id_.patch.mjs +2 -2
  671. package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.delete.mjs +2 -2
  672. package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.patch.mjs +2 -2
  673. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/apply.post.mjs +2 -2
  674. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/mark-good.post.mjs +2 -2
  675. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/revert.post.mjs +2 -2
  676. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/rollback-good.post.mjs +2 -2
  677. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/versions.get.mjs +2 -2
  678. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id_.delete.mjs +2 -2
  679. package/.output/server/chunks/routes/api/workshop/dcw/recipes/index.patch.mjs +2 -2
  680. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/close.post.mjs +2 -2
  681. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/data.get.mjs +2 -2
  682. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/rollback.post.mjs +2 -2
  683. package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.delete.mjs +2 -2
  684. package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.patch.mjs +2 -2
  685. package/.output/server/chunks/routes/api/workshop/dcw/test-driver.post.mjs +2 -2
  686. package/.output/server/chunks/routes/api/workshop/device-twins/_id/control.post.mjs +2 -2
  687. package/.output/server/chunks/routes/api/workshop/device-twins/_id/telemetry.post.mjs +2 -2
  688. package/.output/server/chunks/routes/api/workshop/device-twins/_id_.delete.mjs +2 -2
  689. package/.output/server/chunks/routes/api/workshop/device-twins/_id_.patch.mjs +2 -2
  690. package/.output/server/chunks/routes/api/workshop/fs/dirs.get.mjs +1 -1
  691. package/.output/server/chunks/routes/api/workshop/harnesses/_id/providers.get.mjs +2 -2
  692. package/.output/server/chunks/routes/api/workshop/harnesses.get.mjs +2 -2
  693. package/.output/server/chunks/routes/api/workshop/hitl/pending.get.mjs +11 -4
  694. package/.output/server/chunks/routes/api/workshop/hitl/pending.get.mjs.map +1 -1
  695. package/.output/server/chunks/routes/api/workshop/hitl/respond.post.mjs +28 -36
  696. package/.output/server/chunks/routes/api/workshop/hitl/respond.post.mjs.map +1 -1
  697. package/.output/server/chunks/routes/api/workshop/index.get.mjs +2 -2
  698. package/.output/server/chunks/routes/api/workshop/index.post.mjs +2 -2
  699. package/.output/server/chunks/routes/api/workshop/index.put.mjs +2 -2
  700. package/.output/server/chunks/routes/api/workshop/index10.get.mjs +26 -12
  701. package/.output/server/chunks/routes/api/workshop/index10.get.mjs.map +1 -1
  702. package/.output/server/chunks/routes/api/workshop/index11.get.mjs +12 -7
  703. package/.output/server/chunks/routes/api/workshop/index11.get.mjs.map +1 -1
  704. package/.output/server/chunks/routes/api/workshop/index12.get.mjs +3 -3
  705. package/.output/server/chunks/routes/api/workshop/index12.get.mjs.map +1 -1
  706. package/.output/server/chunks/routes/api/workshop/index13.get.mjs +29 -0
  707. package/.output/server/chunks/routes/api/workshop/index13.get.mjs.map +1 -0
  708. package/.output/server/chunks/routes/api/workshop/index14.get.mjs +28 -0
  709. package/.output/server/chunks/routes/api/workshop/index14.get.mjs.map +1 -0
  710. package/.output/server/chunks/routes/api/workshop/index2.get.mjs +2 -2
  711. package/.output/server/chunks/routes/api/workshop/index2.post.mjs +2 -2
  712. package/.output/server/chunks/routes/api/workshop/index3.get.mjs +2 -2
  713. package/.output/server/chunks/routes/api/workshop/index3.post.mjs +2 -2
  714. package/.output/server/chunks/routes/api/workshop/index4.get.mjs +2 -2
  715. package/.output/server/chunks/routes/api/workshop/index4.post.mjs +2 -2
  716. package/.output/server/chunks/routes/api/workshop/index5.get.mjs +2 -2
  717. package/.output/server/chunks/routes/api/workshop/index5.post.mjs +2 -2
  718. package/.output/server/chunks/routes/api/workshop/index6.get.mjs +2 -2
  719. package/.output/server/chunks/routes/api/workshop/index6.post.mjs +2 -2
  720. package/.output/server/chunks/routes/api/workshop/index7.get.mjs +2 -2
  721. package/.output/server/chunks/routes/api/workshop/index7.post.mjs +14 -16
  722. package/.output/server/chunks/routes/api/workshop/index7.post.mjs.map +1 -1
  723. package/.output/server/chunks/routes/api/workshop/index8.get.mjs +40 -19
  724. package/.output/server/chunks/routes/api/workshop/index8.get.mjs.map +1 -1
  725. package/.output/server/chunks/routes/api/workshop/index8.post.mjs +19 -5
  726. package/.output/server/chunks/routes/api/workshop/index8.post.mjs.map +1 -1
  727. package/.output/server/chunks/routes/api/workshop/index9.get.mjs +20 -24
  728. package/.output/server/chunks/routes/api/workshop/index9.get.mjs.map +1 -1
  729. package/.output/server/chunks/routes/api/workshop/index9.post.mjs +30 -0
  730. package/.output/server/chunks/routes/api/workshop/index9.post.mjs.map +1 -0
  731. package/.output/server/chunks/routes/api/workshop/mailbox/all.get.mjs +2 -2
  732. package/.output/server/chunks/routes/api/workshop/mailbox.get.mjs +2 -2
  733. package/.output/server/chunks/routes/api/workshop/memories/maintenance.post.mjs +2 -2
  734. package/.output/server/chunks/routes/api/workshop/notifications/read.post.mjs +41 -0
  735. package/.output/server/chunks/routes/api/workshop/notifications/read.post.mjs.map +1 -0
  736. package/.output/server/chunks/routes/api/workshop/plugins/_name/disable.post.mjs +2 -2
  737. package/.output/server/chunks/routes/api/workshop/plugins/_name/enable.post.mjs +2 -2
  738. package/.output/server/chunks/routes/api/workshop/plugins/index.get.mjs +2 -2
  739. package/.output/server/chunks/routes/api/workshop/runtime.get.mjs +2 -2
  740. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.delete.mjs +2 -2
  741. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.put.mjs +2 -2
  742. package/.output/server/chunks/routes/api/workshop/scene/layouts.get.mjs +2 -2
  743. package/.output/server/chunks/routes/api/workshop/schedules/_id/run.post.mjs +29 -0
  744. package/.output/server/chunks/routes/api/workshop/schedules/_id/run.post.mjs.map +1 -0
  745. package/.output/server/chunks/routes/api/workshop/schedules/_id/runs.get.mjs +31 -0
  746. package/.output/server/chunks/routes/api/workshop/schedules/_id/runs.get.mjs.map +1 -0
  747. package/.output/server/chunks/routes/api/workshop/schedules/_id_.delete.mjs +30 -0
  748. package/.output/server/chunks/routes/api/workshop/schedules/_id_.delete.mjs.map +1 -0
  749. package/.output/server/chunks/routes/api/workshop/schedules/_id_.get.mjs +29 -0
  750. package/.output/server/chunks/routes/api/workshop/schedules/_id_.get.mjs.map +1 -0
  751. package/.output/server/chunks/routes/api/workshop/schedules/_id_.patch.mjs +40 -0
  752. package/.output/server/chunks/routes/api/workshop/schedules/_id_.patch.mjs.map +1 -0
  753. package/.output/server/chunks/routes/api/workshop/tasks/_id/complete.post.mjs +2 -2
  754. package/.output/server/chunks/routes/api/workshop/tasks/_id/dispatch.post.mjs +2 -2
  755. package/.output/server/chunks/routes/api/workshop/tasks/_id/index.post.mjs +2 -2
  756. package/.output/server/chunks/routes/api/workshop/tasks/_id/reassign.post.mjs +39 -0
  757. package/.output/server/chunks/routes/api/workshop/tasks/_id/reassign.post.mjs.map +1 -0
  758. package/.output/server/chunks/routes/api/workshop/tasks/_id/report.post.mjs +2 -2
  759. package/.output/server/chunks/routes/api/workshop/tasks/_id/retry.post.mjs +2 -2
  760. package/.output/server/chunks/routes/api/workshop/tasks/_id/update.post.mjs +44 -0
  761. package/.output/server/chunks/routes/api/workshop/tasks/_id/update.post.mjs.map +1 -0
  762. package/.output/server/chunks/routes/api/workshop/tasks/_id_.get.mjs +9 -5
  763. package/.output/server/chunks/routes/api/workshop/tasks/_id_.get.mjs.map +1 -1
  764. package/.output/server/chunks/routes/api/workshop/tasks.get.mjs +2 -2
  765. package/.output/server/chunks/routes/api/workshop/teams/_id/deploy.post.mjs +2 -2
  766. package/.output/server/chunks/routes/api/workshop/teams/_id/index.get.mjs +2 -2
  767. package/.output/server/chunks/routes/api/workshop/teams/_id/index.post.mjs +2 -2
  768. package/.output/server/chunks/routes/api/workshop/teams/_id/index.put.mjs +2 -2
  769. package/.output/server/chunks/routes/api/workshop/teams/_id/index2.get.mjs +2 -2
  770. package/.output/server/chunks/routes/api/workshop/teams/_id/members/_agentId_.delete.mjs +2 -2
  771. package/.output/server/chunks/routes/api/workshop/teams/_id_.delete.mjs +2 -2
  772. package/.output/server/chunks/routes/api/workshop/teams/_id_.get.mjs +2 -2
  773. package/.output/server/chunks/routes/api/workshop/teams/_id_.patch.mjs +2 -2
  774. package/.output/server/chunks/routes/api/workshop/users/me.get.mjs +2 -2
  775. package/.output/server/chunks/routes/api/workshop/users/register.post.mjs +2 -2
  776. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channel-templates/_tplId_.post.mjs +3 -3
  777. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channels/_channelId_.delete.mjs +2 -2
  778. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channels/_channelId_.post.mjs +2 -2
  779. package/.output/server/chunks/routes/api/workshop/workspaces/index.delete.mjs +2 -2
  780. package/.output/server/chunks/routes/renderer.mjs +3 -3
  781. package/.output/server/chunks/virtual/entry.mjs +6055 -1624
  782. package/.output/server/chunks/virtual/entry.mjs.map +1 -1
  783. package/.output/server/chunks/virtual/precomputed.mjs +1 -1
  784. package/.output/server/index.mjs +15 -5549
  785. package/.output/server/index.mjs.map +1 -1
  786. package/.output/server/package.json +1 -1
  787. package/README-zh.md +102 -48
  788. package/README.md +105 -38
  789. package/app/components/AppHeader.vue +26 -703
  790. package/app/components/aml/AmlDatasetFormModal.vue +279 -0
  791. package/app/components/aml/AmlDatasetTable.vue +319 -0
  792. package/app/components/aml/AmlEnvPanel.vue +230 -0
  793. package/app/components/aml/AmlExperimentsTable.vue +142 -0
  794. package/app/components/aml/AmlInfraBanner.vue +23 -0
  795. package/app/components/aml/AmlJobsTable.vue +248 -0
  796. package/app/components/aml/AmlModelsTable.vue +173 -0
  797. package/app/components/aml/AmlOverviewBar.vue +62 -0
  798. package/app/components/aml/AmlPageHeader.vue +47 -0
  799. package/app/components/aml/AmlPredictConsole.vue +201 -0
  800. package/app/components/app-header/HeaderTools.vue +208 -0
  801. package/app/components/app-header/HitlBell.vue +423 -0
  802. package/app/components/app-header/TrailNav.vue +261 -0
  803. package/app/components/app-header/UserChip.vue +150 -0
  804. package/app/components/daq/DaqAddNodeModal.vue +209 -0
  805. package/app/components/daq/DaqAlarmBar.vue +46 -0
  806. package/app/components/daq/DaqControlCard.vue +159 -0
  807. package/app/components/daq/DaqDetailFramesTile.vue +139 -0
  808. package/app/components/daq/DaqDetailHistoryCard.vue +128 -0
  809. package/app/components/daq/DaqDetailLiveCard.vue +92 -0
  810. package/app/components/daq/DaqDetailParamForm.vue +350 -0
  811. package/app/components/daq/DaqInfraBanner.vue +31 -0
  812. package/app/components/daq/DaqLineBanner.vue +47 -0
  813. package/app/components/daq/DaqNodePanel.vue +396 -0
  814. package/app/components/daq/DaqOptPanel.vue +197 -0
  815. package/app/components/daq/DaqTemplateModal.vue +246 -0
  816. package/app/components/dashboard/DashboardFleetPanel.vue +228 -0
  817. package/app/components/dashboard/DashboardGaugeBand.vue +78 -0
  818. package/app/components/dashboard/DashboardHarnessPanel.vue +149 -0
  819. package/app/components/dashboard/DashboardHero.vue +209 -0
  820. package/app/components/dashboard/DashboardLineStatePanel.vue +78 -0
  821. package/app/components/dashboard/DashboardNodeStatePanel.vue +46 -0
  822. package/app/components/dashboard/DashboardPipelinePanel.vue +46 -0
  823. package/app/components/dashboard/DashboardTrendPanel.vue +83 -0
  824. package/app/components/dashboard/DashboardWritePanel.vue +52 -0
  825. package/app/components/dcw/DcwAddNodeModal.vue +328 -0
  826. package/app/components/dcw/DcwAdoptCard.vue +89 -0
  827. package/app/components/dcw/DcwCreateLineModal.vue +105 -0
  828. package/app/components/dcw/DcwDeleteLineModal.vue +73 -0
  829. package/app/components/dcw/DcwDetailHead.vue +65 -0
  830. package/app/components/dcw/DcwDetailTemplateModal.vue +238 -0
  831. package/app/components/dcw/DcwEditLineModal.vue +108 -0
  832. package/app/components/dcw/DcwGatewayBar.vue +94 -0
  833. package/app/components/dcw/DcwLedgerCard.vue +160 -0
  834. package/app/components/dcw/DcwLineCard.vue +117 -0
  835. package/app/components/dcw/DcwLineRunCard.vue +158 -0
  836. package/app/components/dcw/DcwNodesTable.vue +253 -0
  837. package/app/components/dcw/DcwProductCreateModal.vue +113 -0
  838. package/app/components/dcw/DcwQueryCard.vue +251 -0
  839. package/app/components/dcw/DcwRecipeEditModal.vue +285 -0
  840. package/app/components/dcw/DcwRecipeHistoryModal.vue +165 -0
  841. package/app/components/dcw/DcwRecipePanel.vue +367 -0
  842. package/app/components/dcw/DcwRunDataModal.vue +191 -0
  843. package/app/components/dcw/DcwTemplateModal.vue +227 -0
  844. package/app/components/dcw/DcwWriteHistoryCard.vue +96 -0
  845. package/app/components/logs/LogsEventTable.vue +309 -0
  846. package/app/components/logs/LogsFilterCard.vue +234 -0
  847. package/app/components/logs/LogsManualModal.vue +231 -0
  848. package/app/components/logs/LogsPageHead.vue +71 -0
  849. package/app/components/monitor/MonitorAgentTable.vue +143 -0
  850. package/app/components/monitor/MonitorChannelTable.vue +80 -0
  851. package/app/components/monitor/MonitorLoginGate.vue +24 -0
  852. package/app/components/monitor/MonitorPageHead.vue +92 -0
  853. package/app/components/monitor/MonitorProcessTable.vue +159 -0
  854. package/app/components/monitor/MonitorStatGrid.vue +165 -0
  855. package/app/components/settings/AppearancePane.vue +282 -0
  856. package/app/components/settings/PluginsSection.vue +280 -0
  857. package/app/components/settings/RuntimeFieldRow.vue +189 -0
  858. package/app/components/settings/RuntimeGroupSection.vue +290 -0
  859. package/app/components/settings/RuntimePane.vue +235 -0
  860. package/app/components/settings/SystemPane.vue +83 -0
  861. package/app/components/tokens/TokenCreateModal.vue +42 -0
  862. package/app/components/tokens/TokenOnceModal.vue +164 -0
  863. package/app/components/tokens/TokenRenameModal.vue +40 -0
  864. package/app/components/tokens/TokensAuthGate.vue +47 -0
  865. package/app/components/tokens/TokensPageHead.vue +76 -0
  866. package/app/components/tokens/TokensTable.vue +227 -0
  867. package/app/components/workshop/AgentLanesView.vue +35 -755
  868. package/app/components/workshop/ChannelSessionList.vue +58 -493
  869. package/app/components/workshop/ChatMemberPanel.vue +555 -0
  870. package/app/components/workshop/ChatTimeline.vue +569 -0
  871. package/app/components/workshop/CommandPalette.vue +1 -0
  872. package/app/components/workshop/Composer.vue +224 -511
  873. package/app/components/workshop/DeviceTwinPanel.vue +23 -499
  874. package/app/components/workshop/EventBlock.vue +20 -408
  875. package/app/components/workshop/MemoryPanel.vue +405 -364
  876. package/app/components/workshop/MultiChannelView.vue +189 -189
  877. package/app/components/workshop/NotificationCenter.vue +325 -0
  878. package/app/components/workshop/TaskBoardView.vue +260 -686
  879. package/app/components/workshop/TaskInspectorDrawer.vue +484 -390
  880. package/app/components/workshop/TranscriptTimeline.vue +60 -438
  881. package/app/components/workshop/agents/AgentTemplateEditModal.vue +139 -0
  882. package/app/components/workshop/agents/AgentTemplateTable.vue +269 -0
  883. package/app/components/workshop/agents/AgentTemplateToolbar.vue +67 -0
  884. package/app/components/workshop/blocks/ClusterRoute.vue +1 -1
  885. package/app/components/workshop/blocks/EventBlockAvatar.vue +114 -0
  886. package/app/components/workshop/blocks/EventBlockHead.vue +232 -0
  887. package/app/components/workshop/composer/ComposerToolbar.vue +278 -0
  888. package/app/components/workshop/composer/MentionMenu.vue +135 -0
  889. package/app/components/workshop/composer/ReplyChip.vue +65 -0
  890. package/app/components/workshop/composer/StatusChip.vue +171 -0
  891. package/app/components/workshop/console/CenterPane.vue +94 -0
  892. package/app/components/workshop/console/Dock.vue +71 -0
  893. package/app/components/workshop/console/LeftPane.vue +84 -0
  894. package/app/components/workshop/console/RightPane.vue +95 -0
  895. package/app/components/workshop/console/Topbar.vue +289 -0
  896. package/app/components/workshop/device-twin/DeviceTwinCard.vue +265 -0
  897. package/app/components/workshop/device-twin/DeviceTwinDcwSection.vue +203 -0
  898. package/app/components/workshop/lanes/AddMemberModal.vue +270 -0
  899. package/app/components/workshop/lanes/EditMemberModal.vue +106 -0
  900. package/app/components/workshop/lanes/LaneHeader.vue +432 -0
  901. package/app/components/workshop/lanes/LanesToolbar.vue +97 -0
  902. package/app/components/workshop/session-list/ChannelSettingsModal.vue +329 -0
  903. package/app/components/workshop/session-list/MountChannelModal.vue +124 -0
  904. package/app/components/workshop/session-list/SaveTemplateModal.vue +93 -0
  905. package/app/components/workshop/task-board/Card.vue +172 -0
  906. package/app/components/workshop/task-board/Column.vue +151 -0
  907. package/app/components/workshop/task-board/List.vue +157 -0
  908. package/app/components/workshop/task-board/StatusMenu.vue +88 -0
  909. package/app/components/workshop/teams/TeamAddMemberModal.vue +53 -0
  910. package/app/components/workshop/teams/TeamCard.vue +183 -0
  911. package/app/components/workshop/teams/TeamCreateModal.vue +94 -0
  912. package/app/components/workshop/teams/TeamDeployModal.vue +40 -0
  913. package/app/components/workshop/teams/TeamPluginModal.vue +119 -0
  914. package/app/components/workshop/terminal/OmpTerminalPanel.vue +19 -760
  915. package/app/components/workshop/terminal/TerminalHitlCard.vue +170 -0
  916. package/app/components/workshop/town/TownScene.ts +72 -961
  917. package/app/components/workshop/town/TownScene3D.ts +357 -4045
  918. package/app/components/workshop/town/TownView.vue +461 -7405
  919. package/app/components/workshop/town/components/TownAgentBindings.vue +380 -0
  920. package/app/components/workshop/town/components/TownAgentInspector.vue +546 -0
  921. package/app/components/workshop/town/components/TownAlarmList.vue +147 -0
  922. package/app/components/workshop/town/components/TownBoundaryPanel.vue +350 -0
  923. package/app/components/workshop/town/components/TownCalloutLayer.vue +147 -0
  924. package/app/components/workshop/town/components/TownChannelDock.vue +116 -0
  925. package/app/components/workshop/town/components/TownControlDock.vue +400 -0
  926. package/app/components/workshop/town/components/TownDaqNodeInspector.vue +345 -0
  927. package/app/components/workshop/town/components/TownDaqTree.vue +366 -0
  928. package/app/components/workshop/town/components/TownDcwBindSection.vue +473 -0
  929. package/app/components/workshop/town/components/TownDcwNodeInspector.vue +185 -0
  930. package/app/components/workshop/town/components/TownDcwTree.vue +280 -0
  931. package/app/components/workshop/town/components/TownDeviceBindings.vue +394 -0
  932. package/app/components/workshop/town/components/TownDeviceTransform.vue +248 -0
  933. package/app/components/workshop/town/components/TownEventList.vue +120 -0
  934. package/app/components/workshop/town/components/TownHealthBody.vue +100 -0
  935. package/app/components/workshop/town/components/TownKpiStrip.vue +207 -0
  936. package/app/components/workshop/town/components/TownLeftRail.vue +308 -0
  937. package/app/components/workshop/town/components/TownLoadingMask.vue +61 -0
  938. package/app/components/workshop/town/components/TownNavMap.vue +154 -0
  939. package/app/components/workshop/town/components/TownRightRail.vue +540 -0
  940. package/app/components/workshop/town/components/TownStage.vue +281 -0
  941. package/app/components/workshop/town/components/TownStageTop.vue +238 -0
  942. package/app/components/workshop/town/components/TownStatusBar.vue +108 -0
  943. package/app/components/workshop/town/components/TownTopNav.vue +367 -0
  944. package/app/components/workshop/town/components/TownTrendDock.vue +178 -0
  945. package/app/components/workshop/town/scene/town-scene-agents.ts +254 -0
  946. package/app/components/workshop/town/scene/town-scene-behavior.ts +194 -0
  947. package/app/components/workshop/town/scene/town-scene-bubbles.ts +96 -0
  948. package/app/components/workshop/town/scene/town-scene-core.ts +158 -0
  949. package/app/components/workshop/town/scene/town-scene-models.ts +109 -0
  950. package/app/components/workshop/town/scene/town-scene-visuals.ts +279 -0
  951. package/app/components/workshop/town/scene/town-scene3d-agents.ts +308 -0
  952. package/app/components/workshop/town/scene/town-scene3d-blocks.ts +297 -0
  953. package/app/components/workshop/town/scene/town-scene3d-bubbles.ts +281 -0
  954. package/app/components/workshop/town/scene/town-scene3d-camera.ts +282 -0
  955. package/app/components/workshop/town/scene/town-scene3d-devices.ts +433 -0
  956. package/app/components/workshop/town/scene/town-scene3d-editing.ts +490 -0
  957. package/app/components/workshop/town/scene/town-scene3d-events.ts +173 -0
  958. package/app/components/workshop/town/scene/town-scene3d-factory.ts +412 -0
  959. package/app/components/workshop/town/scene/town-scene3d-hud.ts +110 -0
  960. package/app/components/workshop/town/scene/town-scene3d-lifecycle.ts +144 -0
  961. package/app/components/workshop/town/scene/town-scene3d-links.ts +141 -0
  962. package/app/components/workshop/town/scene/town-scene3d-loop.ts +286 -0
  963. package/app/components/workshop/town/scene/town-scene3d-models.ts +154 -0
  964. package/app/components/workshop/town/scene/town-scene3d-nodes.ts +562 -0
  965. package/app/components/workshop/town/scene/town-scene3d-ranges.ts +273 -0
  966. package/app/components/workshop/town/scene/town-scene3d-renderer.ts +320 -0
  967. package/app/components/workshop/town/scene/town-scene3d-selection.ts +257 -0
  968. package/app/components/workshop/town/scene/town-scene3d-types.ts +264 -0
  969. package/app/components/workshop/transcript/TranscriptBlockList.vue +68 -0
  970. package/app/components/workshop/transcript/TranscriptEarlierPager.vue +81 -0
  971. package/app/components/workshop/transcript/TranscriptEmptyState.vue +153 -0
  972. package/app/components/workshop/transcript/TranscriptFilterBar.vue +126 -0
  973. package/app/components/workshop/workbench/AuthGate.vue +179 -0
  974. package/app/components/workshop/workbench/CreateWorkspaceModal.vue +36 -0
  975. package/app/components/workshop/workbench/WorkbenchHead.vue +129 -0
  976. package/app/components/workshop/workbench/WorkspaceCard.vue +198 -0
  977. package/app/components/workshop/workbench/WorkspaceEmpty.vue +56 -0
  978. package/app/composables/workshop/device-twin-types.ts +29 -0
  979. package/app/composables/workshop/event-blocks/attention.ts +58 -0
  980. package/app/composables/workshop/event-blocks/classify.ts +44 -0
  981. package/app/composables/workshop/event-blocks/clusterer.ts +231 -0
  982. package/app/composables/workshop/event-blocks/constants.ts +48 -0
  983. package/app/composables/workshop/event-blocks/fold-stream.ts +45 -0
  984. package/app/composables/workshop/event-blocks/markdown.ts +81 -0
  985. package/app/composables/workshop/event-blocks/mentions.ts +49 -0
  986. package/app/composables/workshop/event-blocks/text-utils.ts +100 -0
  987. package/app/composables/workshop/event-blocks/types.ts +40 -0
  988. package/app/composables/workshop/town/town-relay-props.ts +226 -0
  989. package/app/composables/workshop/town/town-view-types.ts +145 -0
  990. package/app/composables/workshop/town/useTownAgentBindings.ts +115 -0
  991. package/app/composables/workshop/town/useTownAgentChat.ts +203 -0
  992. package/app/composables/workshop/town/useTownAlarms.ts +36 -0
  993. package/app/composables/workshop/town/useTownCallouts.ts +174 -0
  994. package/app/composables/workshop/town/useTownChannels.ts +220 -0
  995. package/app/composables/workshop/town/useTownHealth.ts +66 -0
  996. package/app/composables/workshop/town/useTownHudTickers.ts +77 -0
  997. package/app/composables/workshop/town/useTownLayout.ts +277 -0
  998. package/app/composables/workshop/town/useTownNavMap.ts +301 -0
  999. package/app/composables/workshop/town/useTownNodeBindings.ts +345 -0
  1000. package/app/composables/workshop/town/useTownPanelDrag.ts +91 -0
  1001. package/app/composables/workshop/town/useTownRailData.ts +421 -0
  1002. package/app/composables/workshop/town/useTownSceneControl.ts +92 -0
  1003. package/app/composables/workshop/town/useTownSceneInput.ts +275 -0
  1004. package/app/composables/workshop/town/useTownSceneRuntime.ts +390 -0
  1005. package/app/composables/workshop/town/useTownSheets.ts +41 -0
  1006. package/app/composables/workshop/town/useTownTrends.ts +93 -0
  1007. package/app/composables/workshop/useChannelList.ts +88 -0
  1008. package/app/composables/workshop/useChannelTerminals.ts +65 -0
  1009. package/app/composables/workshop/useComposerMentions.ts +130 -0
  1010. package/app/composables/workshop/useDeviceTwinDcwWrite.ts +77 -0
  1011. package/app/composables/workshop/useDeviceTwinPanel.ts +56 -0
  1012. package/app/composables/workshop/useEventBlockView.ts +159 -0
  1013. package/app/composables/workshop/useEventBlocks.ts +33 -662
  1014. package/app/composables/workshop/useHitlAnswer.ts +184 -0
  1015. package/app/composables/workshop/useLaneWidths.ts +27 -0
  1016. package/app/composables/workshop/useOmpTerminalSession.ts +424 -0
  1017. package/app/composables/workshop/usePluginAdmin.ts +152 -0
  1018. package/app/composables/workshop/useRuntimeConfigDraft.ts +118 -0
  1019. package/app/composables/workshop/useSettingsGroups.ts +243 -0
  1020. package/app/composables/workshop/useTaskBoardColumns.ts +47 -0
  1021. package/app/composables/workshop/useTaskBoardDrag.ts +78 -0
  1022. package/app/composables/workshop/useTaskBoardMenu.ts +60 -0
  1023. package/app/composables/workshop/useTaskBoardTasks.ts +74 -0
  1024. package/app/composables/workshop/useTerminalRenderer.ts +308 -0
  1025. package/app/composables/workshop/useTranscriptEnterStage.ts +48 -0
  1026. package/app/composables/workshop/useTranscriptHistory.ts +52 -0
  1027. package/app/composables/workshop/useTranscriptScroll.ts +113 -0
  1028. package/app/composables/workshop/useWorkshopApi.ts +85 -2
  1029. package/app/composables/workshop/useWorkshopWs.ts +265 -126
  1030. package/app/config/schema.ts +13 -0
  1031. package/app/layouts/town.vue +21 -16
  1032. package/app/pages/aml/api.ts +6 -0
  1033. package/app/pages/aml/composables/useAmlDatasets.ts +38 -0
  1034. package/app/pages/aml/composables/useAmlEntities.ts +57 -0
  1035. package/app/pages/aml/composables/useAmlEnv.ts +191 -0
  1036. package/app/pages/aml/composables/useAmlExperiments.ts +45 -0
  1037. package/app/pages/aml/composables/useAmlFormat.ts +44 -0
  1038. package/app/pages/aml/composables/useAmlJobs.ts +131 -0
  1039. package/app/pages/aml/composables/useAmlModels.ts +56 -0
  1040. package/app/pages/aml/composables/useAmlNotes.ts +47 -0
  1041. package/app/pages/aml/composables/useAmlPredict.ts +93 -0
  1042. package/app/pages/aml/constants.ts +63 -0
  1043. package/app/pages/aml/index.vue +143 -2596
  1044. package/app/pages/aml/styles.css +420 -0
  1045. package/app/pages/aml/types.ts +189 -0
  1046. package/app/pages/composables/useDashboardCharts.ts +192 -0
  1047. package/app/pages/composables/useDashboardData.ts +144 -0
  1048. package/app/pages/daq/[id].vue +59 -929
  1049. package/app/pages/daq/composables/useDaqAddNode.ts +126 -0
  1050. package/app/pages/daq/composables/useDaqDetailBinding.ts +29 -0
  1051. package/app/pages/daq/composables/useDaqDetailFrames.ts +42 -0
  1052. package/app/pages/daq/composables/useDaqDetailHistory.ts +199 -0
  1053. package/app/pages/daq/composables/useDaqDetailNode.ts +53 -0
  1054. package/app/pages/daq/composables/useDaqDetailParams.ts +138 -0
  1055. package/app/pages/daq/composables/useDaqFilters.ts +187 -0
  1056. package/app/pages/daq/composables/useDaqNodeWindow.ts +86 -0
  1057. package/app/pages/daq/composables/useDaqOptimizations.ts +99 -0
  1058. package/app/pages/daq/composables/useDaqTemplates.ts +152 -0
  1059. package/app/pages/daq/daq-page.css +681 -0
  1060. package/app/pages/daq/index.vue +132 -2188
  1061. package/app/pages/dcw/[id].vue +297 -2615
  1062. package/app/pages/dcw/composables/useDcwAddNode.ts +121 -0
  1063. package/app/pages/dcw/composables/useDcwCards.ts +27 -0
  1064. package/app/pages/dcw/composables/useDcwDetailScope.ts +145 -0
  1065. package/app/pages/dcw/composables/useDcwDetailTemplates.ts +94 -0
  1066. package/app/pages/dcw/composables/useDcwFilter.ts +29 -0
  1067. package/app/pages/dcw/composables/useDcwLedger.ts +34 -0
  1068. package/app/pages/dcw/composables/useDcwLineMutations.ts +115 -0
  1069. package/app/pages/dcw/composables/useDcwLineRun.ts +60 -0
  1070. package/app/pages/dcw/composables/useDcwProducts.ts +54 -0
  1071. package/app/pages/dcw/composables/useDcwQuery.ts +68 -0
  1072. package/app/pages/dcw/composables/useDcwQuickActions.ts +47 -0
  1073. package/app/pages/dcw/composables/useDcwRecipes.ts +239 -0
  1074. package/app/pages/dcw/composables/useDcwTemplates.ts +50 -0
  1075. package/app/pages/dcw/composables/useDcwWrites.ts +81 -0
  1076. package/app/pages/dcw/dcw-page.css +344 -0
  1077. package/app/pages/dcw/index.vue +64 -986
  1078. package/app/pages/dcw/types.ts +9 -0
  1079. package/app/pages/index.vue +64 -925
  1080. package/app/pages/logs/composables/useLogsFormat.ts +43 -0
  1081. package/app/pages/logs/composables/useLogsManual.ts +63 -0
  1082. package/app/pages/logs/composables/useLogsQuery.ts +52 -0
  1083. package/app/pages/logs/composables/useLogsScope.ts +39 -0
  1084. package/app/pages/logs/index.vue +57 -728
  1085. package/app/pages/monitor/composables/useMonitorColumns.ts +69 -0
  1086. package/app/pages/monitor/composables/useMonitorData.ts +124 -0
  1087. package/app/pages/monitor/composables/useMonitorFormat.ts +39 -0
  1088. package/app/pages/monitor/composables/useMonitorTerminal.ts +28 -0
  1089. package/app/pages/monitor/types.ts +61 -0
  1090. package/app/pages/monitor.vue +88 -658
  1091. package/app/pages/permissions/index.vue +3 -2
  1092. package/app/pages/plugins/index.vue +3 -2
  1093. package/app/pages/settings.vue +7 -1403
  1094. package/app/pages/tokens/composables/useTokenClipboard.ts +33 -0
  1095. package/app/pages/tokens/composables/useTokenCreate.ts +93 -0
  1096. package/app/pages/tokens/composables/useTokenRename.ts +54 -0
  1097. package/app/pages/tokens/composables/useTokenReveal.ts +84 -0
  1098. package/app/pages/tokens/composables/useTokensList.ts +60 -0
  1099. package/app/pages/tokens.vue +79 -597
  1100. package/app/pages/users.vue +5 -4
  1101. package/app/pages/workshop/agents.vue +47 -529
  1102. package/app/pages/workshop/composables/useAgentHarnessOptions.ts +59 -0
  1103. package/app/pages/workshop/composables/useAgentTemplateActions.ts +42 -0
  1104. package/app/pages/workshop/composables/useAgentTemplateDialogState.ts +24 -0
  1105. package/app/pages/workshop/composables/useAgentTemplateForm.ts +88 -0
  1106. package/app/pages/workshop/composables/useAgentTemplatesCatalog.ts +92 -0
  1107. package/app/pages/workshop/composables/useTeamActions.ts +44 -0
  1108. package/app/pages/workshop/composables/useTeamAddMemberDialog.ts +49 -0
  1109. package/app/pages/workshop/composables/useTeamCreateDialog.ts +67 -0
  1110. package/app/pages/workshop/composables/useTeamDeployDialog.ts +49 -0
  1111. package/app/pages/workshop/composables/useTeamDialogState.ts +46 -0
  1112. package/app/pages/workshop/composables/useTeamPluginDialog.ts +72 -0
  1113. package/app/pages/workshop/composables/useTeamsCatalog.ts +100 -0
  1114. package/app/pages/workshop/composables/useWorkbenchAuth.ts +125 -0
  1115. package/app/pages/workshop/composables/useWorkbenchWorkspaces.ts +123 -0
  1116. package/app/pages/workshop/composables/useWorkspaceAuth.ts +31 -0
  1117. package/app/pages/workshop/composables/useWorkspaceChannels.ts +62 -0
  1118. package/app/pages/workshop/composables/useWorkspacePanels.ts +56 -0
  1119. package/app/pages/workshop/composables/useWorkspaceShell.ts +136 -0
  1120. package/app/pages/workshop/index.vue +68 -620
  1121. package/app/pages/workshop/schedules.vue +553 -0
  1122. package/app/pages/workshop/teams.vue +58 -568
  1123. package/app/pages/workshop/w/[wsId].vue +113 -596
  1124. package/app/stores/workshop/chat.ts +434 -0
  1125. package/app/stores/workshop/entities.ts +385 -283
  1126. package/app/stores/workshop/events.ts +5 -4
  1127. package/app/stores/workshop/hitl.ts +110 -7
  1128. package/app/stores/workshop/narrow-fetch.ts +23 -0
  1129. package/app/stores/workshop/notifications.ts +288 -0
  1130. package/app/stores/workshop/user.ts +23 -10
  1131. package/app/stores/workshop/workspaces.ts +12 -2
  1132. package/config.yml +7 -1
  1133. package/docs/aml.md +11 -0
  1134. package/docs/cli.en.md +5 -5
  1135. package/docs/cli.md +5 -5
  1136. package/docs/full-test-plan.md +15 -1
  1137. package/docs/plugins.en.md +1 -1
  1138. package/docs/plugins.md +1 -1
  1139. package/docs/sdk.en.md +1 -1
  1140. package/docs/sdk.md +1 -1
  1141. package/i18n/dicts/dcwDetail.json +2 -0
  1142. package/i18n/locales/en.ts +71 -0
  1143. package/i18n/locales/zh-CN.ts +71 -0
  1144. package/package.json +2 -3
  1145. package/scripts/_audit/detached-instance.mjs +112 -0
  1146. package/scripts/_audit/schedules-ui/schedules-page.png +0 -0
  1147. package/scripts/_audit/schedules-ui/workspace-channel-tag.png +0 -0
  1148. package/scripts/_audit/stubs/nuxt-imports.mjs +67 -0
  1149. package/scripts/_audit/ts-register-hook.mjs +12 -0
  1150. package/scripts/_audit/ts-resolve-hook.mjs +25 -5
  1151. package/scripts/_audit/watchdog-recovery-test.mjs +24 -2
  1152. package/scripts/_aw-packaged-start.cjs +22 -0
  1153. package/scripts/_aw0746-stage12.mjs +94 -0
  1154. package/scripts/_aw0746-stage34.mjs +134 -0
  1155. package/scripts/_aw0746-stage5.mjs +106 -0
  1156. package/scripts/_aw0746-stage6-aml.mjs +177 -0
  1157. package/scripts/_aw0746-stage6b-train-sweep.mjs +142 -0
  1158. package/scripts/_aw0746-stage7-twin.mjs +259 -0
  1159. package/scripts/_aw0746-train-strong.py +142 -0
  1160. package/scripts/_dbg-comm-verify.mjs +188 -0
  1161. package/scripts/_dbg-full-feature-e2e.mjs +19 -11
  1162. package/scripts/_dbg-im-e2e.mjs +169 -0
  1163. package/scripts/_dbg-opt2-run.mjs +114 -0
  1164. package/scripts/_dbg-opt2-setup.mjs +95 -0
  1165. package/scripts/_dbg-param-map-e2e.ts +1 -1
  1166. package/scripts/_dbg-param-map-rest-smoke.mjs +1 -1
  1167. package/scripts/_dbg-real-scenario-e2e.mjs +246 -0
  1168. package/scripts/_dbg-schedule-e2e.mjs +262 -0
  1169. package/scripts/_dbg-schedule-ui-verify.mjs +115 -0
  1170. package/scripts/_dbg-team-matrix.mjs +148 -0
  1171. package/scripts/_dbg-ui-fullcrawl.mjs +91 -0
  1172. package/scripts/_dbg-ui-static-audit.mjs +65 -0
  1173. package/scripts/_dbg-write-lock-e2e.mjs +131 -0
  1174. package/scripts/_plc-sim-detached.cjs +22 -0
  1175. package/scripts/_probe-daq-omp-task.mjs +100 -0
  1176. package/scripts/_probe-daq-scope-default.mjs +123 -0
  1177. package/scripts/_probe-density.cjs +15 -0
  1178. package/scripts/_probe-gate-model.mjs +34 -0
  1179. package/scripts/_probe-model-eligibility.cjs +13 -0
  1180. package/scripts/_probe-recipe-switch.mjs +92 -0
  1181. package/scripts/_provision-injection-line.mjs +39 -0
  1182. package/scripts/_run-matrix.ps1 +53 -0
  1183. package/scripts/_run-real-injection-fifo-goals.mjs +367 -0
  1184. package/scripts/acceptance-aml-db.ts +23 -0
  1185. package/scripts/acceptance-aml-hybrid-live.mjs +94 -0
  1186. package/scripts/acceptance-aml-hybrid-twin.ts +93 -0
  1187. package/scripts/acceptance-hybrid-python.py +51 -0
  1188. package/scripts/aml-ui-smoke.mjs +2 -0
  1189. package/scripts/api-live-e2e.mjs +32 -7
  1190. package/scripts/demo-group-chat-all-real.ts +279 -0
  1191. package/scripts/demo-group-chat-omp-cases.ts +210 -0
  1192. package/scripts/demo-group-chat-omp.ts +184 -0
  1193. package/scripts/demo-group-chat-order.ts +197 -0
  1194. package/scripts/e2e-agent-team.mjs +6 -4
  1195. package/scripts/e2e-agentteam-chat.mjs +473 -0
  1196. package/scripts/e2e-agentteam-real-triage.mjs +421 -0
  1197. package/scripts/e2e-agentteam-task-flow-real.ts +443 -0
  1198. package/scripts/e2e-aw-tui-global.mjs +8 -8
  1199. package/scripts/e2e-channel-isolation.ts +5 -1
  1200. package/scripts/e2e-closedloop/cleanup.mjs +27 -0
  1201. package/scripts/e2e-closedloop/lib.mjs +109 -0
  1202. package/scripts/e2e-closedloop/main.mjs +59 -0
  1203. package/scripts/e2e-closedloop/scenarios-accounts.mjs +208 -0
  1204. package/scripts/e2e-closedloop/scenarios-authz.mjs +190 -0
  1205. package/scripts/e2e-closedloop/scenarios-daq-dcw.mjs +219 -0
  1206. package/scripts/e2e-closedloop/scenarios-plugins.mjs +169 -0
  1207. package/scripts/e2e-closedloop/state.mjs +10 -0
  1208. package/scripts/e2e-crash-cycle.mjs +108 -0
  1209. package/scripts/e2e-full-closedloop.mjs +6 -919
  1210. package/scripts/e2e-hil-multi-user.mjs +307 -0
  1211. package/scripts/e2e-hil-restart.mjs +339 -0
  1212. package/scripts/e2e-hitl-live.mjs +336 -323
  1213. package/scripts/e2e-lead-team-mgmt.ts +1 -1
  1214. package/scripts/e2e-memory-system.ts +70 -89
  1215. package/scripts/e2e-multiharness-team.mjs +32 -15
  1216. package/scripts/e2e-omp-workspace.ts +21 -6
  1217. package/scripts/e2e-parallel-execution.mjs +20 -6
  1218. package/scripts/e2e-plc-plugin-closedloop.mjs +96 -65
  1219. package/scripts/e2e-rest-memory.mjs +26 -11
  1220. package/scripts/e2e-resume-crash.mjs +22 -7
  1221. package/scripts/e2e-task-queue.ts +8 -8
  1222. package/scripts/e2e-template-isolation.mjs +4 -2
  1223. package/scripts/proof-omp-real.ts +189 -0
  1224. package/scripts/real-injection-closed-loop.mjs +383 -0
  1225. package/scripts/test-agent-runtime.ts +5 -1
  1226. package/scripts/test-agentteam-guardrails.ts +113 -0
  1227. package/scripts/test-agentteam-task-chat-flow.ts +420 -0
  1228. package/scripts/test-agentteam-workflow.ts +472 -0
  1229. package/scripts/test-collab-e2e.mjs +17 -3
  1230. package/scripts/test-dcw-read.ts +9 -2
  1231. package/scripts/test-event-persistence.mjs +10 -2
  1232. package/scripts/test-full-system.ts +16 -3
  1233. package/scripts/test-group-chat-hardening.ts +265 -0
  1234. package/scripts/test-group-chat-unit/lib.ts +186 -0
  1235. package/scripts/test-group-chat-unit/main.ts +45 -0
  1236. package/scripts/test-group-chat-unit/section-a-migration.ts +75 -0
  1237. package/scripts/test-group-chat-unit/section-b-permission-matrix.ts +88 -0
  1238. package/scripts/test-group-chat-unit/section-c-member-lifecycle.ts +64 -0
  1239. package/scripts/test-group-chat-unit/section-d-mention-resolution.ts +36 -0
  1240. package/scripts/test-group-chat-unit/section-e-chat-facts.ts +97 -0
  1241. package/scripts/test-group-chat-unit/section-f-user-notifications.ts +52 -0
  1242. package/scripts/test-group-chat-unit/section-g-member-projection.ts +44 -0
  1243. package/scripts/test-group-chat-unit/section-h-outbox-consistency.ts +30 -0
  1244. package/scripts/test-group-chat-unit/section-i-read-idempotency.ts +24 -0
  1245. package/scripts/test-group-chat-unit/section-j-permission-scope.ts +150 -0
  1246. package/scripts/test-group-chat-unit.ts +35 -0
  1247. package/scripts/test-hitl-decision.ts +526 -0
  1248. package/scripts/test-hitl-legacy-channel-auth.ts +143 -0
  1249. package/scripts/test-lane-history-live.mjs +30 -7
  1250. package/scripts/test-memory-vector.ts +10 -0
  1251. package/scripts/test-orchestration.ts +7 -2
  1252. package/scripts/test-persistence-lazy.ts +7 -1
  1253. package/scripts/test-prompt-system.mjs +46 -20
  1254. package/scripts/test-route-reason.mjs +9 -2
  1255. package/scripts/test-schedule-runtime.ts +309 -0
  1256. package/scripts/test-scheduler-loop/lib.ts +321 -0
  1257. package/scripts/test-scheduler-loop/main.ts +40 -0
  1258. package/scripts/test-scheduler-loop/scenarios-modes.ts +95 -0
  1259. package/scripts/test-scheduler-loop/scenarios-runtime.ts +58 -0
  1260. package/scripts/test-scheduler-loop/scenarios-supervise.ts +183 -0
  1261. package/scripts/test-scheduler-loop/scenarios-triage.ts +102 -0
  1262. package/scripts/test-scheduler-loop.ts +5 -460
  1263. package/scripts/test-supervision-watchdog.ts +105 -0
  1264. package/scripts/test-task-engine.ts +27 -5
  1265. package/scripts/test-task-lease-fencing.ts +154 -0
  1266. package/scripts/test-terminal-e2e.mjs +9 -3
  1267. package/scripts/three-system-e2e/lib.mjs +79 -0
  1268. package/scripts/three-system-e2e/main.mjs +40 -0
  1269. package/scripts/three-system-e2e/phases/phase-0-user-token.mjs +42 -0
  1270. package/scripts/three-system-e2e/phases/phase-0a2-line-autoselect.mjs +35 -0
  1271. package/scripts/three-system-e2e/phases/phase-0b-fixture-grants.mjs +39 -0
  1272. package/scripts/three-system-e2e/phases/phase-0c-plugin-outbound-auth.mjs +95 -0
  1273. package/scripts/three-system-e2e/phases/stage-1-health.mjs +47 -0
  1274. package/scripts/three-system-e2e/phases/stage-2-5-team-plugins.mjs +84 -0
  1275. package/scripts/three-system-e2e/phases/stage-2-teams-tools-hitl.mjs +184 -0
  1276. package/scripts/three-system-e2e/phases/stage-3-diag.mjs +73 -0
  1277. package/scripts/three-system-e2e/phases/stage-4-plugin-toggle.mjs +53 -0
  1278. package/scripts/three-system-e2e/state.mjs +87 -0
  1279. package/scripts/three-system-e2e.mjs +24 -646
  1280. package/scripts/typecheck.mjs +75 -0
  1281. package/scripts/ui/lib.mjs +14 -2
  1282. package/scripts/ui/smoke-refactor.mjs +258 -0
  1283. package/scripts/verify-a2a-live.mjs +15 -1
  1284. package/scripts/verify-ws-events.mjs +19 -1
  1285. package/server/api/system/monitor/terminal/ws.ts +51 -1
  1286. package/server/api/workshop/agent-tools/approvals/[id]/decide.post.ts +59 -5
  1287. package/server/api/workshop/agent-tools/approvals/index.get.ts +28 -3
  1288. package/server/api/workshop/channel-templates/[id]/instantiate.post.ts +6 -1
  1289. package/server/api/workshop/channels/[id]/chat/messages/[messageId]/read.post.ts +22 -0
  1290. package/server/api/workshop/channels/[id]/chat/messages/index.get.ts +29 -0
  1291. package/server/api/workshop/channels/[id]/chat/messages/index.post.ts +51 -0
  1292. package/server/api/workshop/channels/[id]/chat/permissions.get.ts +35 -0
  1293. package/server/api/workshop/channels/[id]/index.patch.ts +34 -8
  1294. package/server/api/workshop/channels/[id]/members/[userId]/approve.post.ts +20 -0
  1295. package/server/api/workshop/channels/[id]/members/[userId].delete.ts +21 -0
  1296. package/server/api/workshop/channels/[id]/members/index.get.ts +23 -0
  1297. package/server/api/workshop/channels/[id]/members/join.post.ts +30 -0
  1298. package/server/api/workshop/channels/[id]/members/leave.post.ts +20 -0
  1299. package/server/api/workshop/channels/[id]/messages/index.post.ts +3 -0
  1300. package/server/api/workshop/channels/[id]/tasks/index.post.ts +8 -0
  1301. package/server/api/workshop/channels.get.ts +21 -1
  1302. package/server/api/workshop/hitl/pending.get.ts +27 -7
  1303. package/server/api/workshop/hitl/respond.post.ts +86 -89
  1304. package/server/api/workshop/notifications/index.get.ts +60 -0
  1305. package/server/api/workshop/notifications/read.post.ts +31 -0
  1306. package/server/api/workshop/schedules/[id]/run.post.ts +15 -0
  1307. package/server/api/workshop/schedules/[id]/runs.get.ts +15 -0
  1308. package/server/api/workshop/schedules/[id].delete.ts +14 -0
  1309. package/server/api/workshop/schedules/[id].get.ts +13 -0
  1310. package/server/api/workshop/schedules/[id].patch.ts +29 -0
  1311. package/server/api/workshop/schedules/index.get.ts +12 -0
  1312. package/server/api/workshop/schedules/index.post.ts +32 -0
  1313. package/server/api/workshop/tasks/[id]/reassign.post.ts +32 -0
  1314. package/server/api/workshop/tasks/[id]/update.post.ts +35 -0
  1315. package/server/api/workshop/tasks/[id].get.ts +15 -6
  1316. package/server/api/workshop/ws/audience.ts +56 -0
  1317. package/server/api/workshop/ws/db-buffer.ts +68 -0
  1318. package/server/api/workshop/ws/event-mapping.ts +47 -0
  1319. package/server/api/workshop/ws/handlers.ts +132 -0
  1320. package/server/api/workshop/ws/hub.ts +133 -0
  1321. package/server/api/workshop/ws/index.ts +23 -0
  1322. package/server/api/workshop/ws/notification-uplink.ts +77 -0
  1323. package/server/api/workshop/ws/peer-sub.ts +128 -0
  1324. package/server/api/workshop/ws/publish.ts +122 -0
  1325. package/server/api/workshop/ws/shared.ts +94 -0
  1326. package/server/api/workshop/ws/streams.ts +146 -0
  1327. package/server/api/workshop/ws/subscriptions.ts +137 -0
  1328. package/server/plugins/workshop.ts +30 -0
  1329. package/server/plugins-builtin/diag-bridge/host/constants.mjs +25 -0
  1330. package/server/plugins-builtin/diag-bridge/host/diagnosis.mjs +56 -0
  1331. package/server/plugins-builtin/diag-bridge/host/helpers.mjs +126 -0
  1332. package/server/plugins-builtin/diag-bridge/host/index.mjs +15 -0
  1333. package/server/plugins-builtin/diag-bridge/host/plugin.mjs +296 -0
  1334. package/server/plugins-builtin/diag-bridge/host/snapshot.mjs +93 -0
  1335. package/server/plugins-builtin/diag-bridge/host/sweep.mjs +51 -0
  1336. package/server/plugins-builtin/diag-bridge/index.mjs +6 -605
  1337. package/server/repositories/user.repository.ts +13 -0
  1338. package/server/services/system-config/contracts.ts +29 -0
  1339. package/server/services/system-config/dispose.ts +19 -0
  1340. package/server/services/system-config/facade.ts +26 -0
  1341. package/server/services/system-config/groups.ts +108 -0
  1342. package/server/services/system-config/helpers.ts +41 -0
  1343. package/server/services/system-config/index.ts +21 -0
  1344. package/server/services/system-config/init.ts +26 -0
  1345. package/server/services/system-config/mutate.ts +103 -0
  1346. package/server/services/system-config/plugins.ts +104 -0
  1347. package/server/services/system-config/recompute.ts +66 -0
  1348. package/server/services/system-config/snapshot.ts +59 -0
  1349. package/server/services/system-config/state.ts +79 -0
  1350. package/server/services/system-config/types.ts +58 -0
  1351. package/server/services/workshop/agents/adapters/line-spawn.ts +2 -2
  1352. package/server/services/workshop/agents/adapters/omp-rpc-client/api.ts +111 -0
  1353. package/server/services/workshop/agents/adapters/omp-rpc-client/contracts.ts +22 -0
  1354. package/server/services/workshop/agents/adapters/omp-rpc-client/facade.ts +7 -0
  1355. package/server/services/workshop/agents/adapters/omp-rpc-client/frames.ts +111 -0
  1356. package/server/services/workshop/agents/adapters/omp-rpc-client/helpers.ts +38 -0
  1357. package/server/services/workshop/agents/adapters/omp-rpc-client/index.ts +25 -0
  1358. package/server/services/workshop/agents/adapters/omp-rpc-client/start.ts +70 -0
  1359. package/server/services/workshop/agents/adapters/omp-rpc-client/state.ts +65 -0
  1360. package/server/services/workshop/agents/adapters/omp-rpc-client/stdout.ts +92 -0
  1361. package/server/services/workshop/agents/adapters/omp-rpc-client/types.ts +115 -0
  1362. package/server/services/workshop/agents/adapters/omp-rpc-client/usage.ts +47 -0
  1363. package/server/services/workshop/agents/agent-interface.ts +52 -4
  1364. package/server/services/workshop/agents/base-agent.ts +36 -8
  1365. package/server/services/workshop/agents/claude-agent.ts +5 -0
  1366. package/server/services/workshop/agents/codex-agent/client.ts +170 -0
  1367. package/server/services/workshop/agents/codex-agent/core.ts +119 -0
  1368. package/server/services/workshop/agents/codex-agent/facade.ts +8 -0
  1369. package/server/services/workshop/agents/codex-agent/helpers.ts +13 -0
  1370. package/server/services/workshop/agents/codex-agent/hitl.ts +138 -0
  1371. package/server/services/workshop/agents/codex-agent/index.ts +14 -0
  1372. package/server/services/workshop/agents/codex-agent/turn.ts +367 -0
  1373. package/server/services/workshop/agents/codex-agent/types.ts +42 -0
  1374. package/server/services/workshop/agents/dsh-agent.ts +5 -0
  1375. package/server/services/workshop/agents/harness-availability.ts +127 -127
  1376. package/server/services/workshop/agents/harness-terminal/api.ts +197 -0
  1377. package/server/services/workshop/agents/harness-terminal/index.ts +17 -0
  1378. package/server/services/workshop/agents/harness-terminal/io.ts +120 -0
  1379. package/server/services/workshop/agents/harness-terminal/park.ts +55 -0
  1380. package/server/services/workshop/agents/harness-terminal/sanitize.ts +98 -0
  1381. package/server/services/workshop/agents/harness-terminal/session.ts +124 -0
  1382. package/server/services/workshop/agents/harness-terminal/shared.ts +74 -0
  1383. package/server/services/workshop/agents/hermes-agent.ts +5 -0
  1384. package/server/services/workshop/agents/hitl-capabilities.ts +312 -0
  1385. package/server/services/workshop/agents/hitl-decision/answers.ts +27 -0
  1386. package/server/services/workshop/agents/hitl-decision/decide.ts +268 -0
  1387. package/server/services/workshop/agents/hitl-decision/dispatcher.ts +81 -0
  1388. package/server/services/workshop/agents/hitl-decision/index.ts +24 -0
  1389. package/server/services/workshop/agents/hitl-decision/payload.ts +45 -0
  1390. package/server/services/workshop/agents/hitl-decision/reconcile.ts +70 -0
  1391. package/server/services/workshop/agents/hitl-decision/shared.ts +106 -0
  1392. package/server/services/workshop/agents/hitl-decision/visibility.ts +94 -0
  1393. package/server/services/workshop/agents/hitl-registry.ts +403 -7
  1394. package/server/services/workshop/agents/host-tool-bridge/catalog.ts +78 -0
  1395. package/server/services/workshop/agents/host-tool-bridge/dispatch.ts +167 -0
  1396. package/server/services/workshop/agents/host-tool-bridge/index.ts +15 -0
  1397. package/server/services/workshop/agents/host-tool-bridge/session.ts +22 -0
  1398. package/server/services/workshop/agents/host-tool-bridge/tools/industrial.ts +64 -0
  1399. package/server/services/workshop/agents/host-tool-bridge/tools/memory.ts +44 -0
  1400. package/server/services/workshop/agents/host-tool-bridge/tools/messaging.ts +182 -0
  1401. package/server/services/workshop/agents/host-tool-bridge/tools/progress.ts +84 -0
  1402. package/server/services/workshop/agents/host-tool-bridge/tools/tasks.ts +120 -0
  1403. package/server/services/workshop/agents/host-tool-bridge/tools/team.ts +70 -0
  1404. package/server/services/workshop/agents/host-tool-bridge/types.ts +31 -0
  1405. package/server/services/workshop/agents/industrial/aml-dataset-tools.ts +276 -0
  1406. package/server/services/workshop/agents/industrial/aml-job-tools.ts +363 -0
  1407. package/server/services/workshop/agents/industrial/daq-tools.ts +251 -0
  1408. package/server/services/workshop/agents/industrial/dcw-judge-tools.ts +153 -0
  1409. package/server/services/workshop/agents/industrial/dcw-tools.ts +213 -0
  1410. package/server/services/workshop/agents/industrial/index.ts +24 -0
  1411. package/server/services/workshop/agents/industrial/ops-tools.ts +382 -0
  1412. package/server/services/workshop/agents/industrial/param-tools.ts +172 -0
  1413. package/server/services/workshop/agents/industrial/twin-tools.ts +250 -0
  1414. package/server/services/workshop/agents/mock-agent.ts +136 -12
  1415. package/server/services/workshop/agents/omp-agent/client.ts +116 -0
  1416. package/server/services/workshop/agents/omp-agent/context-governance.ts +204 -0
  1417. package/server/services/workshop/agents/omp-agent/core.ts +146 -0
  1418. package/server/services/workshop/agents/omp-agent/event-mapping.ts +142 -0
  1419. package/server/services/workshop/agents/omp-agent/facade.ts +8 -0
  1420. package/server/services/workshop/agents/omp-agent/helpers.ts +37 -0
  1421. package/server/services/workshop/agents/omp-agent/index.ts +16 -0
  1422. package/server/services/workshop/agents/omp-agent/lifecycle.ts +80 -0
  1423. package/server/services/workshop/agents/omp-agent/tools-steer.ts +487 -0
  1424. package/server/services/workshop/agents/omp-agent/types.ts +45 -0
  1425. package/server/services/workshop/agents/opencode-agent/core.ts +77 -0
  1426. package/server/services/workshop/agents/opencode-agent/engine-agnostic.ts +274 -0
  1427. package/server/services/workshop/agents/opencode-agent/facade.ts +8 -0
  1428. package/server/services/workshop/agents/opencode-agent/helpers.ts +29 -0
  1429. package/server/services/workshop/agents/opencode-agent/hitl.ts +113 -0
  1430. package/server/services/workshop/agents/opencode-agent/index.ts +16 -0
  1431. package/server/services/workshop/agents/opencode-agent/lifecycle.ts +44 -0
  1432. package/server/services/workshop/agents/opencode-agent/server.ts +244 -0
  1433. package/server/services/workshop/agents/opencode-agent/turn.ts +278 -0
  1434. package/server/services/workshop/agents/opencode-agent/types.ts +54 -0
  1435. package/server/services/workshop/agents/prompt-builder.ts +16 -6
  1436. package/server/services/workshop/agents/qwen-agent.ts +6 -2
  1437. package/server/services/workshop/agents/registry.ts +32 -2
  1438. package/server/services/workshop/aml/job-orchestrator/broadcast.ts +37 -0
  1439. package/server/services/workshop/aml/job-orchestrator/control.ts +94 -0
  1440. package/server/services/workshop/aml/job-orchestrator/failure.ts +77 -0
  1441. package/server/services/workshop/aml/job-orchestrator/index.ts +22 -0
  1442. package/server/services/workshop/aml/job-orchestrator/process.ts +100 -0
  1443. package/server/services/workshop/aml/job-orchestrator/shared.ts +51 -0
  1444. package/server/services/workshop/aml/job-orchestrator/stages.ts +96 -0
  1445. package/server/services/workshop/aml/job-orchestrator/start-job.ts +140 -0
  1446. package/server/services/workshop/aml/job-orchestrator/status.ts +20 -0
  1447. package/server/services/workshop/aml/job-orchestrator/submit.ts +120 -0
  1448. package/server/services/workshop/aml/job-orchestrator/tick.ts +37 -0
  1449. package/server/services/workshop/aml/python/__pycache__/amlkit.cpython-312.pyc +0 -0
  1450. package/server/services/workshop/aml/python/amlkit.py +185 -120
  1451. package/server/services/workshop/aml/python/requirements.txt +9 -7
  1452. package/server/services/workshop/aml/python/train-hybrid-example.py +87 -0
  1453. package/server/services/workshop/aml/twin/acceptance.ts +68 -0
  1454. package/server/services/workshop/aml/twin/calibration-scheduler.ts +48 -0
  1455. package/server/services/workshop/aml/twin/channel-profile.ts +43 -0
  1456. package/server/services/workshop/aml/twin/contracts.ts +215 -0
  1457. package/server/services/workshop/aml/twin/physics-runtime.ts +165 -0
  1458. package/server/services/workshop/aml/twin/repo.ts +31 -0
  1459. package/server/services/workshop/aml/twin/snapshot-service.ts +81 -0
  1460. package/server/services/workshop/aml/twin/trial-service.ts +89 -0
  1461. package/server/services/workshop/aml/twin/uq-ood.ts +66 -0
  1462. package/server/services/workshop/daq/daq-controller/contracts.ts +39 -0
  1463. package/server/services/workshop/daq/daq-controller/crud.ts +202 -0
  1464. package/server/services/workshop/daq/daq-controller/driver-probe.ts +64 -0
  1465. package/server/services/workshop/daq/daq-controller/facade.ts +28 -0
  1466. package/server/services/workshop/daq/daq-controller/frames.ts +137 -0
  1467. package/server/services/workshop/daq/daq-controller/helpers.ts +52 -0
  1468. package/server/services/workshop/daq/daq-controller/index.ts +22 -0
  1469. package/server/services/workshop/daq/daq-controller/ingest.ts +189 -0
  1470. package/server/services/workshop/daq/daq-controller/runtime-control.ts +72 -0
  1471. package/server/services/workshop/daq/daq-controller/state.ts +194 -0
  1472. package/server/services/workshop/daq/daq-controller/sweep-alarms.ts +164 -0
  1473. package/server/services/workshop/daq/daq-controller/tsdb-twin.ts +138 -0
  1474. package/server/services/workshop/daq/daq-controller/types.ts +68 -0
  1475. package/server/services/workshop/daq/daq-controller/views.ts +84 -0
  1476. package/server/services/workshop/daq/drivers/http.ts +95 -0
  1477. package/server/services/workshop/daq/drivers/index.ts +29 -0
  1478. package/server/services/workshop/daq/drivers/mock.ts +130 -0
  1479. package/server/services/workshop/daq/drivers/modbus-rtu.ts +67 -0
  1480. package/server/services/workshop/daq/drivers/modbus-tcp.ts +307 -0
  1481. package/server/services/workshop/daq/drivers/mqtt.ts +182 -0
  1482. package/server/services/workshop/daq/drivers/opcua.ts +227 -0
  1483. package/server/services/workshop/daq/drivers/registry.ts +144 -0
  1484. package/server/services/workshop/daq/drivers/s7-stub.ts +29 -0
  1485. package/server/services/workshop/daq/drivers/shared.ts +60 -0
  1486. package/server/services/workshop/db/channel-member.repo.ts +122 -0
  1487. package/server/services/workshop/db/channel.repo.ts +93 -8
  1488. package/server/services/workshop/db/chat-message.repo.ts +233 -0
  1489. package/server/services/workshop/db/database/index.ts +18 -0
  1490. package/server/services/workshop/db/database/json.ts +14 -0
  1491. package/server/services/workshop/db/database/migrations.ts +367 -0
  1492. package/server/services/workshop/db/database/open.ts +76 -0
  1493. package/server/services/workshop/db/database/rows.ts +374 -0
  1494. package/server/services/workshop/db/database/schema.ts +651 -0
  1495. package/server/services/workshop/db/database/seed-data.ts +60 -0
  1496. package/server/services/workshop/db/database/seed.ts +145 -0
  1497. package/server/services/workshop/db/hitl-request.repo.ts +221 -0
  1498. package/server/services/workshop/db/notification.repo.ts +199 -0
  1499. package/server/services/workshop/db/outbox.repo.ts +127 -0
  1500. package/server/services/workshop/db/scheduled-task.repo.ts +235 -0
  1501. package/server/services/workshop/db/schema.sql +185 -0
  1502. package/server/services/workshop/db/task.repo.ts +185 -69
  1503. package/server/services/workshop/db/transaction.ts +72 -0
  1504. package/server/services/workshop/dcw/dcw-controller/actuation.ts +127 -0
  1505. package/server/services/workshop/dcw/dcw-controller/bindings.ts +83 -0
  1506. package/server/services/workshop/dcw/dcw-controller/contracts.ts +16 -0
  1507. package/server/services/workshop/dcw/dcw-controller/control.ts +78 -0
  1508. package/server/services/workshop/dcw/dcw-controller/crud.ts +152 -0
  1509. package/server/services/workshop/dcw/dcw-controller/facade.ts +19 -0
  1510. package/server/services/workshop/dcw/dcw-controller/helpers.ts +57 -0
  1511. package/server/services/workshop/dcw/dcw-controller/index.ts +22 -0
  1512. package/server/services/workshop/dcw/dcw-controller/lines.ts +213 -0
  1513. package/server/services/workshop/dcw/dcw-controller/params.ts +97 -0
  1514. package/server/services/workshop/dcw/dcw-controller/products.ts +103 -0
  1515. package/server/services/workshop/dcw/dcw-controller/recipes.ts +137 -0
  1516. package/server/services/workshop/dcw/dcw-controller/state.ts +66 -0
  1517. package/server/services/workshop/dcw/dcw-controller/types.ts +57 -0
  1518. package/server/services/workshop/dcw/dcw-controller/write.ts +147 -0
  1519. package/server/services/workshop/dcw/dcw-node.ts +8 -0
  1520. package/server/services/workshop/dcw/drivers/http.ts +66 -0
  1521. package/server/services/workshop/dcw/drivers/index.ts +26 -0
  1522. package/server/services/workshop/dcw/drivers/mock.ts +44 -0
  1523. package/server/services/workshop/dcw/drivers/modbus-rtu.ts +93 -0
  1524. package/server/services/workshop/dcw/drivers/modbus.ts +139 -0
  1525. package/server/services/workshop/dcw/drivers/mqtt.ts +108 -0
  1526. package/server/services/workshop/dcw/drivers/opcua.ts +110 -0
  1527. package/server/services/workshop/dcw/drivers/registry.ts +118 -0
  1528. package/server/services/workshop/dcw/drivers/shared.ts +113 -0
  1529. package/server/services/workshop/dcw/recipe-rollback-manager/contracts.ts +26 -0
  1530. package/server/services/workshop/dcw/recipe-rollback-manager/facade.ts +13 -0
  1531. package/server/services/workshop/dcw/recipe-rollback-manager/helpers.ts +30 -0
  1532. package/server/services/workshop/dcw/recipe-rollback-manager/index.ts +17 -0
  1533. package/server/services/workshop/dcw/recipe-rollback-manager/internal.ts +33 -0
  1534. package/server/services/workshop/dcw/recipe-rollback-manager/judge.ts +52 -0
  1535. package/server/services/workshop/dcw/recipe-rollback-manager/lock.ts +137 -0
  1536. package/server/services/workshop/dcw/recipe-rollback-manager/rollback.ts +190 -0
  1537. package/server/services/workshop/dcw/recipe-rollback-manager/state.ts +21 -0
  1538. package/server/services/workshop/dcw/recipe-rollback-manager/sweep.ts +77 -0
  1539. package/server/services/workshop/dcw/recipe-rollback-manager/types.ts +3 -0
  1540. package/server/services/workshop/dcw/recipe-rollback-manager/views.ts +214 -0
  1541. package/server/services/workshop/plugins/host/api.mjs +90 -0
  1542. package/server/services/workshop/plugins/host/config.mjs +135 -0
  1543. package/server/services/workshop/plugins/host/index.mjs +23 -0
  1544. package/server/services/workshop/plugins/host/init.mjs +101 -0
  1545. package/server/services/workshop/plugins/host/load.mjs +321 -0
  1546. package/server/services/workshop/plugins/host/reload.mjs +94 -0
  1547. package/server/services/workshop/plugins/host/rollback.mjs +72 -0
  1548. package/server/services/workshop/plugins/host/services.mjs +58 -0
  1549. package/server/services/workshop/plugins/host/state.mjs +54 -0
  1550. package/server/services/workshop/plugins/host/toggle.mjs +64 -0
  1551. package/server/services/workshop/plugins/host.mjs +6 -890
  1552. package/server/services/workshop/runtime/agent-runtime/contracts.ts +25 -0
  1553. package/server/services/workshop/runtime/agent-runtime/facade.ts +7 -0
  1554. package/server/services/workshop/runtime/agent-runtime/helpers.ts +18 -0
  1555. package/server/services/workshop/runtime/agent-runtime/index.ts +19 -0
  1556. package/server/services/workshop/runtime/agent-runtime/lifecycle.ts +119 -0
  1557. package/server/services/workshop/runtime/agent-runtime/message.ts +409 -0
  1558. package/server/services/workshop/runtime/agent-runtime/state.ts +371 -0
  1559. package/server/services/workshop/runtime/agent-runtime/supervise.ts +188 -0
  1560. package/server/services/workshop/runtime/agent-runtime/types.ts +186 -0
  1561. package/server/services/workshop/runtime/channel-runtime.ts +7 -0
  1562. package/server/services/workshop/runtime/chat-mention.ts +164 -0
  1563. package/server/services/workshop/runtime/chat-projection.ts +246 -0
  1564. package/server/services/workshop/runtime/execution-mode.ts +11 -2
  1565. package/server/services/workshop/runtime/manager/a2a.ts +283 -0
  1566. package/server/services/workshop/runtime/manager/access.ts +483 -0
  1567. package/server/services/workshop/runtime/manager/admin-agents.ts +268 -0
  1568. package/server/services/workshop/runtime/manager/admin-channel.ts +276 -0
  1569. package/server/services/workshop/runtime/manager/bus.ts +182 -0
  1570. package/server/services/workshop/runtime/manager/channel-templates.ts +171 -0
  1571. package/server/services/workshop/runtime/manager/chat-reply.ts +181 -0
  1572. package/server/services/workshop/runtime/manager/chat.ts +384 -0
  1573. package/server/services/workshop/runtime/manager/contracts.ts +210 -0
  1574. package/server/services/workshop/runtime/manager/facade.ts +24 -0
  1575. package/server/services/workshop/runtime/manager/helpers.ts +119 -0
  1576. package/server/services/workshop/runtime/manager/host-tools.ts +249 -0
  1577. package/server/services/workshop/runtime/manager/index.ts +42 -0
  1578. package/server/services/workshop/runtime/manager/internal.ts +73 -0
  1579. package/server/services/workshop/runtime/manager/lead-team.ts +161 -0
  1580. package/server/services/workshop/runtime/manager/notifications.ts +108 -0
  1581. package/server/services/workshop/runtime/manager/runtime-observe.ts +300 -0
  1582. package/server/services/workshop/runtime/manager/runtime-wiring.ts +307 -0
  1583. package/server/services/workshop/runtime/manager/schedules.ts +302 -0
  1584. package/server/services/workshop/runtime/manager/state.ts +644 -0
  1585. package/server/services/workshop/runtime/manager/tasks.ts +518 -0
  1586. package/server/services/workshop/runtime/manager/teams.ts +148 -0
  1587. package/server/services/workshop/runtime/manager/types.ts +245 -0
  1588. package/server/services/workshop/runtime/manager/workspace.ts +136 -0
  1589. package/server/services/workshop/runtime/memory/contracts.ts +18 -0
  1590. package/server/services/workshop/runtime/memory/facade.ts +10 -0
  1591. package/server/services/workshop/runtime/memory/governance.ts +184 -0
  1592. package/server/services/workshop/runtime/memory/helpers.ts +196 -0
  1593. package/server/services/workshop/runtime/memory/index.ts +27 -0
  1594. package/server/services/workshop/runtime/memory/recall.ts +216 -0
  1595. package/server/services/workshop/runtime/memory/score.ts +33 -0
  1596. package/server/services/workshop/runtime/memory/state.ts +40 -0
  1597. package/server/services/workshop/runtime/memory/types.ts +44 -0
  1598. package/server/services/workshop/runtime/memory/write.ts +93 -0
  1599. package/server/services/workshop/runtime/permission-scope.ts +81 -0
  1600. package/server/services/workshop/runtime/schedule-runtime.ts +320 -0
  1601. package/server/services/workshop/runtime/scheduler-loop/contracts.ts +29 -0
  1602. package/server/services/workshop/runtime/scheduler-loop/execute.ts +295 -0
  1603. package/server/services/workshop/runtime/scheduler-loop/facade.ts +7 -0
  1604. package/server/services/workshop/runtime/scheduler-loop/helpers.ts +14 -0
  1605. package/server/services/workshop/runtime/scheduler-loop/index.ts +16 -0
  1606. package/server/services/workshop/runtime/scheduler-loop/rules.ts +131 -0
  1607. package/server/services/workshop/runtime/scheduler-loop/snapshot.ts +99 -0
  1608. package/server/services/workshop/runtime/scheduler-loop/state.ts +150 -0
  1609. package/server/services/workshop/runtime/scheduler-loop/tick.ts +157 -0
  1610. package/server/services/workshop/runtime/scheduler-loop/types.ts +50 -0
  1611. package/server/services/workshop/runtime/task-engine/contracts.ts +16 -0
  1612. package/server/services/workshop/runtime/task-engine/create.ts +145 -0
  1613. package/server/services/workshop/runtime/task-engine/facade.ts +7 -0
  1614. package/server/services/workshop/runtime/task-engine/helpers.ts +87 -0
  1615. package/server/services/workshop/runtime/task-engine/index.ts +15 -0
  1616. package/server/services/workshop/runtime/task-engine/lease.ts +79 -0
  1617. package/server/services/workshop/runtime/task-engine/lifecycle.ts +308 -0
  1618. package/server/services/workshop/runtime/task-engine/policy.ts +113 -0
  1619. package/server/services/workshop/runtime/task-engine/transition.ts +146 -0
  1620. package/server/services/workshop/runtime/task-engine/types.ts +3 -0
  1621. package/server/services/workshop/runtime/task-engine/update.ts +116 -0
  1622. package/server/services/workshop/runtime/task-engine/views.ts +169 -0
  1623. package/server/services/workshop/runtime/user-notification-hub.ts +192 -0
  1624. package/server/services/workshop/settings.ts +32 -0
  1625. package/server/services/workshop/types/task.ts +85 -0
  1626. package/server/utils/errors.ts +2 -0
  1627. package/server/utils/mojibake-guard.ts +29 -0
  1628. package/shared/config/schema.json +12 -0
  1629. package/shared/dcw-protocol/catalog.ts +203 -0
  1630. package/shared/dcw-protocol/closed-loop.ts +137 -0
  1631. package/shared/dcw-protocol/index.ts +19 -0
  1632. package/shared/dcw-protocol/line.ts +131 -0
  1633. package/shared/dcw-protocol/recipe.ts +301 -0
  1634. package/shared/workshop-protocol.ts +327 -5
  1635. package/tui/aw-tui.mjs +27 -6
  1636. package/tui/lib/pickers.mjs +21 -2
  1637. package/.output/public/_nuxt/4sIEbgcl.js +0 -42
  1638. package/.output/public/_nuxt/B7gZokg82.js +0 -209
  1639. package/.output/public/_nuxt/B8uy9iRW.js +0 -1
  1640. package/.output/public/_nuxt/BC9wjTJK2.js +0 -4
  1641. package/.output/public/_nuxt/BCGafdXT.js +0 -2
  1642. package/.output/public/_nuxt/BDmh31hl.js +0 -1
  1643. package/.output/public/_nuxt/BFjGV-RV2.js +0 -4108
  1644. package/.output/public/_nuxt/BGTYYQH-.js +0 -1
  1645. package/.output/public/_nuxt/BHA40aHa.js +0 -1
  1646. package/.output/public/_nuxt/BJHKLJJU.js +0 -1
  1647. package/.output/public/_nuxt/BN6iuJEg2.js +0 -1
  1648. package/.output/public/_nuxt/BU83-NnX.js +0 -106
  1649. package/.output/public/_nuxt/BUmHEJ77.js +0 -2
  1650. package/.output/public/_nuxt/BY7YrV_D.js +0 -1
  1651. package/.output/public/_nuxt/BYhEUx8t.js +0 -17
  1652. package/.output/public/_nuxt/BneN7fbu.js +0 -75
  1653. package/.output/public/_nuxt/Bqcgz95s.js +0 -18
  1654. package/.output/public/_nuxt/C3J6FYKa.js +0 -1
  1655. package/.output/public/_nuxt/C3gwHTz0.js +0 -1
  1656. package/.output/public/_nuxt/C4DWUZ6d2.js +0 -1
  1657. package/.output/public/_nuxt/C7UlqPeD.js +0 -1
  1658. package/.output/public/_nuxt/CClOy-Hz2.js +0 -1
  1659. package/.output/public/_nuxt/CFxtLwjp.js +0 -1
  1660. package/.output/public/_nuxt/CS50LB_l.js +0 -1
  1661. package/.output/public/_nuxt/CSkxz2NX.js +0 -3
  1662. package/.output/public/_nuxt/CTmDn-YP.js +0 -1
  1663. package/.output/public/_nuxt/CWoJjWmZ.js +0 -1
  1664. package/.output/public/_nuxt/CYWVXZTS2.js +0 -7
  1665. package/.output/public/_nuxt/C__m4EhR.js +0 -1
  1666. package/.output/public/_nuxt/CoNpEq5X.js +0 -1
  1667. package/.output/public/_nuxt/Crod5z2f.js +0 -1
  1668. package/.output/public/_nuxt/Cs8pVeVG.js +0 -1
  1669. package/.output/public/_nuxt/CssgYAAL2.js +0 -1
  1670. package/.output/public/_nuxt/CzlMDL5H.js +0 -13
  1671. package/.output/public/_nuxt/D0ZBQrN_2.js +0 -1
  1672. package/.output/public/_nuxt/D6uzXueg.js +0 -2
  1673. package/.output/public/_nuxt/D98NH8kG.js +0 -1
  1674. package/.output/public/_nuxt/D9Oidm5I.js +0 -1
  1675. package/.output/public/_nuxt/DBHNsT1Y.js +0 -23
  1676. package/.output/public/_nuxt/DDgJcSET.js +0 -19
  1677. package/.output/public/_nuxt/DGIuvyRN2.js +0 -1
  1678. package/.output/public/_nuxt/DGj-WEBg.js +0 -1
  1679. package/.output/public/_nuxt/DHFrCUxA2.js +0 -13
  1680. package/.output/public/_nuxt/DIaZ2PTo2.js +0 -1
  1681. package/.output/public/_nuxt/DKySmNPI.js +0 -14
  1682. package/.output/public/_nuxt/DPnwL14Y.js +0 -1
  1683. package/.output/public/_nuxt/DR12_WCA.js +0 -3
  1684. package/.output/public/_nuxt/DTFCy6h-.js +0 -1
  1685. package/.output/public/_nuxt/DYr1VMiQ.js +0 -6
  1686. package/.output/public/_nuxt/DZtm4l-P2.js +0 -1
  1687. package/.output/public/_nuxt/DdD9mCHM.js +0 -1
  1688. package/.output/public/_nuxt/DeyBFhKH2.js +0 -4
  1689. package/.output/public/_nuxt/Di0NY_ht.js +0 -1
  1690. package/.output/public/_nuxt/DkGQ7lnb2.js +0 -1
  1691. package/.output/public/_nuxt/DtYHUi5Z.js +0 -1
  1692. package/.output/public/_nuxt/Dz_Q3Lpw2.js +0 -1
  1693. package/.output/public/_nuxt/DzbFpZRk.js +0 -3
  1694. package/.output/public/_nuxt/EHlEMRii.js +0 -1
  1695. package/.output/public/_nuxt/Eke1fs-U.js +0 -1
  1696. package/.output/public/_nuxt/H0BcqZtT.js +0 -9
  1697. package/.output/public/_nuxt/HSYEkkce.js +0 -1
  1698. package/.output/public/_nuxt/IREZ1eC2.js +0 -1
  1699. package/.output/public/_nuxt/J9oU00D1.js +0 -1
  1700. package/.output/public/_nuxt/JCoYF4IJ.js +0 -31
  1701. package/.output/public/_nuxt/JTLM-kqr2.js +0 -1
  1702. package/.output/public/_nuxt/KZQX7xoM.js +0 -3
  1703. package/.output/public/_nuxt/OmpTerminalPanel.BxR5-lvi.css +0 -1
  1704. package/.output/public/_nuxt/RYFtK4qZ2.js +0 -1
  1705. package/.output/public/_nuxt/SSyAPaHc.js +0 -1
  1706. package/.output/public/_nuxt/TownView.li4EMQxK.css +0 -1
  1707. package/.output/public/_nuxt/VdLk4jLE2.js +0 -1
  1708. package/.output/public/_nuxt/YnQxK3eG.js +0 -1
  1709. package/.output/public/_nuxt/_id_.BhsXoEuk.css +0 -1
  1710. package/.output/public/_nuxt/_id_.DQyj-WKN.css +0 -1
  1711. package/.output/public/_nuxt/_wsId_.CTx-BlfF.css +0 -1
  1712. package/.output/public/_nuxt/aLLjF2K-2.js +0 -1
  1713. package/.output/public/_nuxt/aShsv_rG.js +0 -19
  1714. package/.output/public/_nuxt/aWWIh8YL.js +0 -24
  1715. package/.output/public/_nuxt/aesgXKSr.js +0 -4
  1716. package/.output/public/_nuxt/agents.B21nUEUX.css +0 -1
  1717. package/.output/public/_nuxt/aml.ekTjxFkf.css +0 -1
  1718. package/.output/public/_nuxt/builds/meta/b5506ef0-f48e-4f14-a6c0-d65e505d0b09.json +0 -1
  1719. package/.output/public/_nuxt/ca4TJ3Op.js +0 -1
  1720. package/.output/public/_nuxt/daq.BdVmoIfe.css +0 -1
  1721. package/.output/public/_nuxt/dcw.DCgyzpWV.css +0 -1
  1722. package/.output/public/_nuxt/default.Bh3L2HU8.css +0 -1
  1723. package/.output/public/_nuxt/entry.bdm0tv6M.css +0 -1
  1724. package/.output/public/_nuxt/jZsY8yYz.js +0 -1
  1725. package/.output/public/_nuxt/lHAxdSsj.js +0 -1
  1726. package/.output/public/_nuxt/logs.BpKzmKsh.css +0 -1
  1727. package/.output/public/_nuxt/monitor.D9pe7qN6.css +0 -1
  1728. package/.output/public/_nuxt/pages.j9rzRocr.css +0 -1
  1729. package/.output/public/_nuxt/pdk8jLGT.js +0 -1
  1730. package/.output/public/_nuxt/permissions.DwTVlFe6.css +0 -1
  1731. package/.output/public/_nuxt/plugins.DhiZbHU8.css +0 -1
  1732. package/.output/public/_nuxt/settings.BRx9rIDg.css +0 -1
  1733. package/.output/public/_nuxt/teams.BLlOPB_Z.css +0 -1
  1734. package/.output/public/_nuxt/tokens.De8xzszn.css +0 -1
  1735. package/.output/public/_nuxt/town.BLrD9-WH.css +0 -1
  1736. package/.output/public/_nuxt/users.DLgZ1D0h.css +0 -1
  1737. package/.output/public/_nuxt/vRTjoWqd.js +0 -1
  1738. package/.output/public/_nuxt/workshop.D1jFNkrn.css +0 -1
  1739. package/.output/public/_nuxt/xh3_vYcu.js +0 -1
  1740. package/.output/public/_nuxt/zq5t1vyX.js +0 -1
  1741. package/.output/server/chunks/build/Checkbox-eax2M3o-.mjs +0 -207
  1742. package/.output/server/chunks/build/Checkbox-eax2M3o-.mjs.map +0 -1
  1743. package/.output/server/chunks/build/OmpTerminalPanel-CVvxpsF7.mjs +0 -915
  1744. package/.output/server/chunks/build/OmpTerminalPanel-CVvxpsF7.mjs.map +0 -1
  1745. package/.output/server/chunks/build/PluginSlot-CcR4Ys3T.mjs +0 -400
  1746. package/.output/server/chunks/build/PluginSlot-CcR4Ys3T.mjs.map +0 -1
  1747. package/.output/server/chunks/build/TownView-CJ6IsDCc.mjs +0 -2791
  1748. package/.output/server/chunks/build/TownView-CJ6IsDCc.mjs.map +0 -1
  1749. package/.output/server/chunks/build/_id_-CVD_H0ir.mjs +0 -804
  1750. package/.output/server/chunks/build/_id_-CVD_H0ir.mjs.map +0 -1
  1751. package/.output/server/chunks/build/_id_-CtxMb3qp.mjs +0 -381
  1752. package/.output/server/chunks/build/_id_-CtxMb3qp.mjs.map +0 -1
  1753. package/.output/server/chunks/build/_wsId_-DpY3T-md.mjs +0 -10136
  1754. package/.output/server/chunks/build/_wsId_-DpY3T-md.mjs.map +0 -1
  1755. package/.output/server/chunks/build/agents-DsCkuXDV.mjs +0 -1114
  1756. package/.output/server/chunks/build/agents-DsCkuXDV.mjs.map +0 -1
  1757. package/.output/server/chunks/build/aml-CT0xKGKI.mjs +0 -605
  1758. package/.output/server/chunks/build/aml-CT0xKGKI.mjs.map +0 -1
  1759. package/.output/server/chunks/build/api-error-dul30BYQ.mjs +0 -47
  1760. package/.output/server/chunks/build/api-error-dul30BYQ.mjs.map +0 -1
  1761. package/.output/server/chunks/build/apiClient-BwnfOQU8.mjs +0 -81
  1762. package/.output/server/chunks/build/apiClient-BwnfOQU8.mjs.map +0 -1
  1763. package/.output/server/chunks/build/button-DEcZFcqN.mjs +0 -1938
  1764. package/.output/server/chunks/build/button-DEcZFcqN.mjs.map +0 -1
  1765. package/.output/server/chunks/build/card-Dipvaykh.mjs +0 -955
  1766. package/.output/server/chunks/build/card-Dipvaykh.mjs.map +0 -1
  1767. package/.output/server/chunks/build/channel-templates-Dla9FbYa.mjs +0 -847
  1768. package/.output/server/chunks/build/channel-templates-Dla9FbYa.mjs.map +0 -1
  1769. package/.output/server/chunks/build/checkbox-8fB-wI-T.mjs +0 -439
  1770. package/.output/server/chunks/build/checkbox-8fB-wI-T.mjs.map +0 -1
  1771. package/.output/server/chunks/build/client-only-D5BzSQc6.mjs +0 -43
  1772. package/.output/server/chunks/build/client-only-D5BzSQc6.mjs.map +0 -1
  1773. package/.output/server/chunks/build/daq-DWWSKGAV.mjs +0 -1059
  1774. package/.output/server/chunks/build/daq-DWWSKGAV.mjs.map +0 -1
  1775. package/.output/server/chunks/build/dcw-CT8k17_E.mjs +0 -250
  1776. package/.output/server/chunks/build/dcw-CT8k17_E.mjs.map +0 -1
  1777. package/.output/server/chunks/build/default-D3525UFX.mjs +0 -1487
  1778. package/.output/server/chunks/build/default-D3525UFX.mjs.map +0 -1
  1779. package/.output/server/chunks/build/drawer-Cmh90erI.mjs +0 -836
  1780. package/.output/server/chunks/build/drawer-Cmh90erI.mjs.map +0 -1
  1781. package/.output/server/chunks/build/dropdown-CGQ0KAzA.mjs +0 -14
  1782. package/.output/server/chunks/build/dropdown-CGQ0KAzA.mjs.map +0 -1
  1783. package/.output/server/chunks/build/dropdown-vhn1NPFs.mjs +0 -558
  1784. package/.output/server/chunks/build/dropdown-vhn1NPFs.mjs.map +0 -1
  1785. package/.output/server/chunks/build/initDefaultProps-DIbWwP4R.mjs +0 -21
  1786. package/.output/server/chunks/build/initDefaultProps-DIbWwP4R.mjs.map +0 -1
  1787. package/.output/server/chunks/build/input-number-DzpyYB99.mjs +0 -1521
  1788. package/.output/server/chunks/build/input-number-DzpyYB99.mjs.map +0 -1
  1789. package/.output/server/chunks/build/input-sf_BT6o6.mjs +0 -2617
  1790. package/.output/server/chunks/build/input-sf_BT6o6.mjs.map +0 -1
  1791. package/.output/server/chunks/build/logs--dByNyhw.mjs +0 -198
  1792. package/.output/server/chunks/build/logs--dByNyhw.mjs.map +0 -1
  1793. package/.output/server/chunks/build/menu-WCrlpYVh.mjs +0 -1950
  1794. package/.output/server/chunks/build/menu-WCrlpYVh.mjs.map +0 -1
  1795. package/.output/server/chunks/build/modal-yvUquPj5.mjs +0 -1272
  1796. package/.output/server/chunks/build/modal-yvUquPj5.mjs.map +0 -1
  1797. package/.output/server/chunks/build/monitor-Dh2Kvaq5.mjs +0 -2212
  1798. package/.output/server/chunks/build/monitor-Dh2Kvaq5.mjs.map +0 -1
  1799. package/.output/server/chunks/build/pages-BHcSBM2D.mjs +0 -518
  1800. package/.output/server/chunks/build/pages-BHcSBM2D.mjs.map +0 -1
  1801. package/.output/server/chunks/build/permissions-68SsNjex.mjs +0 -629
  1802. package/.output/server/chunks/build/permissions-68SsNjex.mjs.map +0 -1
  1803. package/.output/server/chunks/build/plugins-BNgIi61W.mjs +0 -246
  1804. package/.output/server/chunks/build/plugins-BNgIi61W.mjs.map +0 -1
  1805. package/.output/server/chunks/build/popconfirm-CRaHcz5O.mjs +0 -342
  1806. package/.output/server/chunks/build/popconfirm-CRaHcz5O.mjs.map +0 -1
  1807. package/.output/server/chunks/build/segmented-3TrWo0lS.mjs +0 -5047
  1808. package/.output/server/chunks/build/segmented-3TrWo0lS.mjs.map +0 -1
  1809. package/.output/server/chunks/build/select-D-CeE5vY.mjs +0 -3923
  1810. package/.output/server/chunks/build/select-D-CeE5vY.mjs.map +0 -1
  1811. package/.output/server/chunks/build/settings-ipYBDWdn.mjs +0 -1175
  1812. package/.output/server/chunks/build/settings-ipYBDWdn.mjs.map +0 -1
  1813. package/.output/server/chunks/build/space-CCBYAkXt.mjs +0 -197
  1814. package/.output/server/chunks/build/space-CCBYAkXt.mjs.map +0 -1
  1815. package/.output/server/chunks/build/spin-HVY81X_L.mjs +0 -358
  1816. package/.output/server/chunks/build/spin-HVY81X_L.mjs.map +0 -1
  1817. package/.output/server/chunks/build/switch-CelRXpcy.mjs +0 -377
  1818. package/.output/server/chunks/build/switch-CelRXpcy.mjs.map +0 -1
  1819. package/.output/server/chunks/build/table-BjSWwmic.mjs +0 -8883
  1820. package/.output/server/chunks/build/table-BjSWwmic.mjs.map +0 -1
  1821. package/.output/server/chunks/build/tabs-BM3tAh_J.mjs +0 -1925
  1822. package/.output/server/chunks/build/tabs-BM3tAh_J.mjs.map +0 -1
  1823. package/.output/server/chunks/build/tag-DNE9vXc0.mjs +0 -1029
  1824. package/.output/server/chunks/build/tag-DNE9vXc0.mjs.map +0 -1
  1825. package/.output/server/chunks/build/teams-5lx-CwFa.mjs +0 -1218
  1826. package/.output/server/chunks/build/teams-5lx-CwFa.mjs.map +0 -1
  1827. package/.output/server/chunks/build/tokens-q-IDT8Io.mjs +0 -908
  1828. package/.output/server/chunks/build/tokens-q-IDT8Io.mjs.map +0 -1
  1829. package/.output/server/chunks/build/town-BUqRobze.mjs +0 -52
  1830. package/.output/server/chunks/build/town-BUqRobze.mjs.map +0 -1
  1831. package/.output/server/chunks/build/town-QJWB5wng.mjs +0 -125
  1832. package/.output/server/chunks/build/town-QJWB5wng.mjs.map +0 -1
  1833. package/.output/server/chunks/build/useDaqStream-DfCFpb3p.mjs +0 -395
  1834. package/.output/server/chunks/build/useDaqStream-DfCFpb3p.mjs.map +0 -1
  1835. package/.output/server/chunks/build/useDcwStream-UPiX-3iO.mjs +0 -435
  1836. package/.output/server/chunks/build/useDcwStream-UPiX-3iO.mjs.map +0 -1
  1837. package/.output/server/chunks/build/useDeviceTwins-Yko6nNPF.mjs +0 -128
  1838. package/.output/server/chunks/build/useDeviceTwins-Yko6nNPF.mjs.map +0 -1
  1839. package/.output/server/chunks/build/useOpsLog-CO_VWh7t.mjs +0 -137
  1840. package/.output/server/chunks/build/useOpsLog-CO_VWh7t.mjs.map +0 -1
  1841. package/.output/server/chunks/build/useWorkshopApi-NyjL0L3j.mjs +0 -90
  1842. package/.output/server/chunks/build/useWorkshopApi-NyjL0L3j.mjs.map +0 -1
  1843. package/.output/server/chunks/build/useWorkshopWs-C_I7q9As.mjs +0 -1319
  1844. package/.output/server/chunks/build/useWorkshopWs-C_I7q9As.mjs.map +0 -1
  1845. package/.output/server/chunks/build/users-Cfd5-l2-.mjs +0 -561
  1846. package/.output/server/chunks/build/users-Cfd5-l2-.mjs.map +0 -1
  1847. package/.output/server/chunks/build/workshop-BIlCj_ZP.mjs +0 -931
  1848. package/.output/server/chunks/build/workshop-BIlCj_ZP.mjs.map +0 -1
  1849. package/.output/server/chunks/build/workspaces-Bgz5Ekwp.mjs +0 -139
  1850. package/.output/server/chunks/build/workspaces-Bgz5Ekwp.mjs.map +0 -1
  1851. package/scripts/test-agent-brain.ts +0 -135
  1852. package/scripts/test-game-session.ts +0 -160
  1853. package/scripts/test-protocol.ts +0 -156
  1854. package/scripts/verify-game.mjs +0 -477
  1855. package/server/api/workshop/ws.ts +0 -763
  1856. package/server/services/system-config.ts +0 -629
  1857. package/server/services/workshop/agents/adapters/omp-rpc-client.ts +0 -604
  1858. package/server/services/workshop/agents/codex-agent.ts +0 -743
  1859. package/server/services/workshop/agents/harness-terminal.ts +0 -625
  1860. package/server/services/workshop/agents/host-tool-bridge.ts +0 -714
  1861. package/server/services/workshop/agents/industrial-tools.ts +0 -1680
  1862. package/server/services/workshop/agents/omp-agent.ts +0 -1199
  1863. package/server/services/workshop/agents/opencode-agent.ts +0 -960
  1864. package/server/services/workshop/aml/job-orchestrator.ts +0 -639
  1865. package/server/services/workshop/daq/daq-controller.ts +0 -1284
  1866. package/server/services/workshop/daq/drivers.ts +0 -1196
  1867. package/server/services/workshop/db/database.ts +0 -1044
  1868. package/server/services/workshop/dcw/dcw-controller.ts +0 -1176
  1869. package/server/services/workshop/dcw/drivers.ts +0 -731
  1870. package/server/services/workshop/dcw/recipe-rollback-manager.ts +0 -713
  1871. package/server/services/workshop/runtime/agent-runtime.ts +0 -821
  1872. package/server/services/workshop/runtime/manager.ts +0 -3050
  1873. package/server/services/workshop/runtime/memory.ts +0 -681
  1874. package/server/services/workshop/runtime/scheduler-loop.ts +0 -799
  1875. package/server/services/workshop/runtime/task-engine.ts +0 -574
  1876. package/shared/dcw-protocol.ts +0 -747
  1877. /package/.output/public/_nuxt/{BrIJiJSN.js → BrIJiJSN2.js} +0 -0
  1878. /package/.output/public/_nuxt/{CNs_Ozdc2.js → CNs_Ozdc.js} +0 -0
  1879. /package/.output/public/_nuxt/{DIOBYJe3.js → DIOBYJe32.js} +0 -0
  1880. /package/.output/public/_nuxt/{lO5tpDZ5.js → lO5tpDZ52.js} +0 -0
@@ -1,3050 +0,0 @@
1
- /**
2
- * AgentChannelManager — 统一管理(对象化)。
3
- * Channel / Agent 模板 / Channel Agent 实例 全是对象;所有作业方法做权限校验(lead/assignee/channel 作用域)。
4
- *
5
- * v3:Agent 模板与 Channel 实例分离:
6
- * - Agent 模板(agents):全局可复用数据结构(name/harness/config/enabled)
7
- * - Channel 实例(channel_agents):每次把模板放入 channel 都克隆出独立身份 id 的新实例
8
- * (name/harness/config 复制自模板,另含独立 role + token)
9
- * - 每个实例在各自 channel 独立装配 AgentRuntime(独立 mailbox/impl 子进程/状态)
10
- * 权威契约见 docs/superpowers/plans/2026-08-13-agent-workshop-multi-agent.md 核心契约块 T3。
11
- */
12
- import { createLogger } from '../logger'
13
- import { mkdirSync } from 'node:fs'
14
- import { resolve } from 'node:path'
15
- import { randomUUID } from 'node:crypto'
16
- import type { DatabaseSync } from 'node:sqlite'
17
- import { AppError } from '../../../utils/errors'
18
- import { userRepository } from '../../../repositories/user.repository'
19
- import type { A2AMessage, A2AArtifact, ChannelMail, Part } from '../types/a2a'
20
- import type { AgentStatusView, AgentTaskQueueView, TaskState, WorkspaceTask } from '../types/task'
21
- import { TERMINAL_TASK_STATES } from '../types/task'
22
- import type { AgentInfo, AgentInterface, AgentWorkspace, AgentEvent, ExecutionMode } from '../agents/agent-interface'
23
- import type { ModeConfig } from './execution-mode'
24
- import { encodeTaskMode, isGoalSummaryArtifact } from './execution-mode'
25
- import type { ChannelRepo } from '../db/channel.repo'
26
- import type { AgentRepo } from '../db/agent.repo'
27
- import type { TeamRepo } from '../db/team.repo'
28
- import type { TeamMemberRepo } from '../db/team-member.repo'
29
- import type { ChannelAgentRepo } from '../db/channel-agent.repo'
30
- import type { MessageRepo } from '../db/message.repo'
31
- import type { SubscriptionRepo } from '../db/subscription.repo'
32
- import type { TaskRepo, TaskPatch } from '../db/task.repo'
33
- import { parseJson, type AgentRow, type ChannelAgentRow, type ChannelRow, type ChannelTemplateRow, type MemoryRow, type MessageRow, type TaskRow, type TeamRow, type UserRow, type WorkspaceRow } from '../db/database'
34
- import { Mailbox, rowToMessage } from './mailbox'
35
- import { AgentRuntime } from './agent-runtime'
36
- import type { ChannelBus, MemberChangeEvent, TaskEngine, TaskEventTask } from './agent-runtime'
37
- import { ChannelRuntime } from './channel-runtime'
38
- import { SchedulerLoop, type SchedulerLoopOptions } from './scheduler-loop'
39
- import { TaskEngine as TaskEngineImpl } from './task-engine'
40
- import { AgentMemory, runMemoryMaintenance, segmentCJK, unsegmentCJK, vectorizeMemory, type MaintenanceResult, type MemorySnippet } from './memory'
41
- import { memorySettings, workshopSettings } from '../settings'
42
- import { createEnvEmbeddingProvider } from './embedding-provider'
43
- import { listHarnessProcesses, listAliveHarnessProcessesByAgent, sweepHarnessProcesses, killHarnessProcess } from '../agents/harness-process'
44
- import { hasTerminalSession, sweepTerminalSessions } from '../agents/harness-terminal'
45
- import { knownHarnesses } from '../agents/registry'
46
- import { assertHarnessUsable } from '../agents/harness-availability'
47
- import { hostToolsForRole } from '../agents/host-tool-bridge'
48
- import { listPluginTools, pluginOfTool } from '../agents/plugin-tools'
49
- import { TEAM_AGENT_ID, type MemoryRepo } from '../db/memory.repo'
50
- import type { UserRepo } from '../db/user.repo'
51
- import type { ChannelEventRepo } from '../db/channel-event.repo'
52
- import type { ChannelTemplateRepo, ChannelTemplateMember } from '../db/channel-template.repo'
53
- import { getChannelPluginsRepo, type ChannelPluginToggle } from '../db/channel-plugins.repo'
54
-
55
- const log = createLogger('workshop.manager')
56
-
57
- /** 全部仓储(依赖注入) */
58
- export interface AllRepos {
59
- users: UserRepo
60
- channelEvents: ChannelEventRepo
61
- channels: ChannelRepo
62
- agents: AgentRepo
63
- teams: TeamRepo
64
- teamMembers: TeamMemberRepo
65
- channelTemplates: ChannelTemplateRepo
66
- channelAgents: ChannelAgentRepo
67
- messages: MessageRepo
68
- subscriptions: SubscriptionRepo
69
- tasks: TaskRepo
70
- memories: MemoryRepo
71
- }
72
-
73
- /** Manager 依赖 */
74
- export interface ManagerDeps {
75
- repos: AllRepos
76
- implFactory: (agent: AgentInfo) => AgentInterface
77
- taskEngineFactory?: (repos: { tasks: TaskRepo, messages: MessageRepo }) => TaskEngine
78
- db: DatabaseSync
79
- }
80
-
81
- /** 权限主体(路由层 ResolvedUser 的子集;role 供 admin 判定) */
82
- export interface ActingUser {
83
- id: string
84
- role?: string
85
- }
86
-
87
- /** Agent 模板详情(全局;含其克隆出的全部实例) */
88
- export interface AgentTemplateDetail {
89
- id: string
90
- name: string
91
- harness: string
92
- config: Record<string, unknown>
93
- enabled: number
94
- /** 可见性:'private' | 'public' */
95
- visibility: string
96
- /** 内置模板(owner NULL;公开只读,任何人含 admin 不可修改删除) */
97
- isBuiltin: boolean
98
- /** 归属用户(null = 内置公共) */
99
- ownerUserId: string | null
100
- /** 该模板克隆出的全部实例(跨 channel) */
101
- instances: Array<{ id: string, channelId: string, role: 'lead' | 'worker', token: string }>
102
- createdAt: string
103
- updatedAt: string
104
- }
105
-
106
- /** AgentTeam 详情(含成员模板快照) */
107
- export interface AgentTeamDetail {
108
- id: string
109
- name: string
110
- description: string
111
- /** 可见性:'private' | 'public' */
112
- visibility: string
113
- /** 内置编组(owner NULL;公开只读,任何人含 admin 不可修改删除) */
114
- isBuiltin: boolean
115
- /** 归属用户(null = 内置公共) */
116
- ownerUserId: string | null
117
- /** 成员(按加入顺序;快照含模板当前 name/harness,便于前端展示) */
118
- members: Array<{
119
- templateId: string
120
- name: string
121
- harness: string
122
- role: 'lead' | 'worker'
123
- addedAt: string
124
- }>
125
- createdAt: string
126
- updatedAt: string
127
- }
128
-
129
- /** Channel 模板详情(场景 + 工作目录 + 成员组合;lead/members 已反序列化) */
130
- export interface ChannelTemplateDetail {
131
- id: string
132
- name: string
133
- description: string
134
- scenarioPrompt: string
135
- workspace: string
136
- /** 内联 lead 定义(空 = 无 lead) */
137
- lead: { name: string, harness: string, config?: Record<string, unknown> } | null
138
- /** 成员组合:引用 Agent 模板或内联定义 */
139
- members: ChannelTemplateMember[]
140
- visibility: string
141
- isBuiltin: boolean
142
- ownerUserId: string | null
143
- createdAt: string
144
- updatedAt: string
145
- }
146
-
147
- /** ChannelAgentRow → AgentInfo(实例视图:实例 id + 本 channel 的 role/token + 复制的 name/harness/config) */
148
- function instanceToAgentInfo(m: ChannelAgentRow): AgentInfo {
149
- return {
150
- id: m.id,
151
- channelId: m.channelId,
152
- name: m.name,
153
- harness: m.harness,
154
- role: m.role as 'lead' | 'worker',
155
- config: parseJson<Record<string, unknown>>(m.configJson, {}),
156
- token: m.token,
157
- enabled: m.enabled,
158
- /** 来源 Agent 模板 id(手工成员为 null)。
159
- * 外部调用方需要它把「模板 → 已部署实例」对上 —— Agent↔节点绑定必须落到实例 id,
160
- * 而绑定接口只回一个实例 id;不暴露这个字段时调用方只能靠名字猜(实测踩过)。 */
161
- templateId: m.templateId ?? null,
162
- }
163
- }
164
-
165
- /** TaskRow → WorkspaceTask(artifacts/history 反序列化) */
166
- function rowToTask(row: TaskRow): WorkspaceTask {
167
- return {
168
- id: row.id,
169
- channelId: row.channelId,
170
- parentId: row.parentId ?? undefined,
171
- assigneeId: row.assigneeId,
172
- creatorId: row.creatorId ?? '',
173
- title: row.title,
174
- description: row.description ?? undefined,
175
- state: row.state as TaskState,
176
- progress: row.progress,
177
- retryCount: row.retryCount,
178
- artifacts: parseJson<A2AArtifact[]>(row.artifactsJson, []),
179
- history: parseJson<A2AMessage[]>(row.historyJson, []),
180
- routeReason: row.routeReason || undefined,
181
- createdAt: row.createdAt,
182
- updatedAt: row.updatedAt,
183
- }
184
- }
185
-
186
- /** MessageRow → ChannelMail(parts/metadata 反序列化;渠道邮件公开投影) */
187
- function rowToChannelMail(row: MessageRow): ChannelMail {
188
- return {
189
- messageId: row.id,
190
- taskId: row.taskId,
191
- fromAgentId: row.fromAgentId,
192
- toAgentId: row.toAgentId,
193
- role: row.role as 'ROLE_USER' | 'ROLE_AGENT',
194
- parts: parseJson<Part[]>(row.partsJson, []),
195
- metadata: parseJson<Record<string, unknown>>(row.metadataJson, {}),
196
- state: row.state,
197
- createdAt: row.createdAt,
198
- consumedAt: row.consumedAt,
199
- }
200
- }
201
-
202
- /** 构造 A2AMessage(统一入口) */
203
- function buildMessage(
204
- channelId: string,
205
- role: 'ROLE_USER' | 'ROLE_AGENT',
206
- parts: Part[],
207
- metadata: Record<string, unknown>,
208
- ): A2AMessage {
209
- return { messageId: randomUUID(), contextId: channelId, role, parts, metadata }
210
- }
211
-
212
- /** 运行时实例复合键(channel, 实例) */
213
- /** channel llm_json 解析(容错;空/坏 JSON 返回 null) */
214
- function parseChannelLlm(json: string | undefined): { provider?: string, model?: string, effort?: string } | null {
215
- if (!json) return null
216
- try {
217
- const v = JSON.parse(json) as { provider?: string, model?: string, effort?: string }
218
- if (!v || typeof v !== 'object') return null
219
- return v
220
- }
221
- catch {
222
- return null
223
- }
224
- }
225
-
226
- function runtimeKey(channelId: string, agentId: string): string {
227
- return `${channelId}\u0000${agentId}`
228
- }
229
-
230
- /** factory 支持的 harness 集(registry 单一事实源;lead 建成员时校验) */
231
- const KNOWN_HARNESSES = new Set(knownHarnesses())
232
-
233
- /** 全局用户名解析(带 60s 缓存;owner 归属呈现用,解析失败返回 null) */
234
- const ownerNameCache = new Map<string, { name: string | null, at: number }>()
235
- export function resolveOwnerName(userId: string): string | null {
236
- const hit = ownerNameCache.get(userId)
237
- if (hit && Date.now() - hit.at < 60_000) return hit.name
238
- let name: string | null
239
- try {
240
- name = userRepository.findById(userId)?.name ?? null
241
- }
242
- catch {
243
- name = null
244
- }
245
- ownerNameCache.set(userId, { name, at: Date.now() })
246
- return name
247
- }
248
-
249
- /** 运行时资源监控:单个 ChannelRuntime 视图 */
250
- export interface RuntimeChannelView {
251
- channelId: string
252
- /** 已装配(wired)的 AgentRuntime 数 */
253
- wiredAgentCount: number
254
- /** channel 内成员总数(含未装配;来自 DB) */
255
- memberCount: number
256
- /** 是否为 lead 装配并启动了 SchedulerLoop */
257
- hasScheduler: boolean
258
- leadAgentId: string | null
259
- /** 归属用户(admin 全量视图附带;普通用户视图为自身) */
260
- ownerUserId?: string | null
261
- /** 归属用户名(admin 视角呈现创建者) */
262
- ownerName?: string | null
263
- }
264
-
265
- /** 运行时资源监控:单个 AgentRuntime 视图 */
266
- export interface RuntimeAgentView {
267
- channelId: string
268
- agentId: string
269
- name: string
270
- role: 'lead' | 'worker'
271
- harness: string
272
- state: 'idle' | 'busy' | 'stopped'
273
- currentTaskId: string | null
274
- queuedCount: number
275
- completedCount: number
276
- /** harness 进程(进程内 harness 为 null) */
277
- process: { pid: number, alive: boolean, command: string } | null
278
- /** 归属用户(admin 全量视图附带;普通用户视图为自身) */
279
- ownerUserId?: string | null
280
- ownerName?: string | null
281
- }
282
-
283
- /** 运行时资源监控:harnest 进程视图(注册表,含孤儿) */
284
- export interface RuntimeProcessView {
285
- pid: number
286
- harness: string
287
- command: string
288
- args: string[]
289
- agentId: string | null
290
- channelId: string | null
291
- name: string | null
292
- role: 'lead' | 'worker' | null
293
- startedAt: number
294
- alive: boolean
295
- exitCode: number | null
296
- /** 是否被某个已装配 runtime 引用(否则为孤儿进程) */
297
- bound: boolean
298
- /** 终端镜像是否可接入(harness-terminal tap 已挂载;/monitor 终端按钮依据) */
299
- terminal: boolean
300
- }
301
-
302
- /** 运行时资源监控:全量快照 */
303
- export interface RuntimeMonitorSnapshot {
304
- generatedAt: string
305
- /** 服务端(宿主)进程 pid */
306
- serverPid: number
307
- uptimeMs: number
308
- channels: RuntimeChannelView[]
309
- agents: RuntimeAgentView[]
310
- processes: RuntimeProcessView[]
311
- counts: {
312
- channels: number
313
- agents: number
314
- processes: number
315
- aliveProcesses: number
316
- orphanProcesses: number
317
- }
318
- }
319
-
320
- export class AgentChannelManager {
321
- private channels = new Map<string, ChannelRuntime>()
322
- /** 键 = runtimeKey(channelId, 实例 id);每个实例一个独立运行时 */
323
- private agentIndex = new Map<string, AgentRuntime>()
324
- private buses = new Map<string, ChannelBus>()
325
- private taskEngine: TaskEngine | null = null
326
- private idleSweeperTimer: NodeJS.Timeout | null = null
327
- private memoryTimer: NodeJS.Timeout | null = null
328
- /** 全 manager 共享的 env 向量 provider(未配置 → null 纯 FTS;熔断/维度全体实例共享) */
329
- private readonly memoryEmbedder = createEnvEmbeddingProvider()
330
- /** 反思游标:每 agent 上次聚合的当月任务数(月度幂等增量判定) */
331
- private readonly reflectCounts = new Map<string, number>()
332
- /** agent 最近一次工具 invoke 时刻(调度器停滞看门狗的活性源;工具调用即健康推进) */
333
- private readonly lastToolInvokeAt = new Map<string, number>()
334
-
335
- /** 依赖集(repos/implFactory/db)。
336
- * API 作业面(ws/agent-tools/a2a card/…)需要直接读 repo —— 原先只能靠
337
- * `(manager as unknown as { deps })` 断言绕过 private。这里改成 public readonly:
338
- * TS 的 private 是纯类型层(擦除后运行时无差异),readonly 保证不可重绑定,
339
- * 既去掉断言又保持封装语义(依赖注入本身就是本类的构造契约)。 */
340
- constructor(readonly deps: ManagerDeps) {
341
- // 记忆衰减清理定时器(失败只记日志,绝不抛出;unref 不阻进程退出;非法/非正 env 回退默认)
342
- this.memoryTimer = setInterval(() => {
343
- try {
344
- runMemoryMaintenance(this.deps.repos.memories)
345
- }
346
- catch (err) {
347
- log.error('[memory] 维护任务异常', err)
348
- }
349
- // 空闲反思(sleep-time compute):busy runtime 存在即整轮跳过,绝不与作业争抢
350
- try {
351
- this.reflectIdleMemories()
352
- }
353
- catch (err) {
354
- log.error('[memory] 反思任务异常', err)
355
- }
356
- }, memorySettings().maintenance_ms)
357
- this.memoryTimer.unref?.()
358
- }
359
-
360
- // ===== 运行时装配 =====
361
-
362
- private getTaskEngine(): TaskEngine {
363
- if (!this.taskEngine) {
364
- const factory = this.deps.taskEngineFactory ?? (r => new TaskEngineImpl(r, {
365
- onTaskChange: (e) => {
366
- // 全字段转发(含 progress):TaskEngine 内部进度变化(applyEvent 分块折算 /
367
- // complete 置 100)须经总线 → WS task.progress 实时同步,否则前端实体进度滞后
368
- this.buses.get(e.channelId)?.notifyTask({
369
- taskId: e.taskId,
370
- state: e.state,
371
- progress: e.progress,
372
- agentId: e.agentId,
373
- task: e.task,
374
- })
375
- // 事件驱动调度:任务状态变化即唤醒该频道调度循环(空闲退避即刻恢复快节奏)
376
- this.channels.get(e.channelId)?.scheduler?.wake()
377
- },
378
- }))
379
- this.taskEngine = factory({ tasks: this.deps.repos.tasks, messages: this.deps.repos.messages })
380
- }
381
- return this.taskEngine
382
- }
383
-
384
- private ensureChannelRuntime(channelId: string): ChannelRuntime {
385
- let cr = this.channels.get(channelId)
386
- if (!cr) {
387
- cr = new ChannelRuntime(channelId, {
388
- taskEngine: this.getTaskEngine(),
389
- subscriptionRepo: this.deps.repos.subscriptions,
390
- channelAgents: this.deps.repos.channelAgents,
391
- // 路由成功 → 总线通知(a2a.message 帧):经 runtime 回调统一收口,
392
- // 调度器直呼 channelRuntime.route 的消息同样可见
393
- }, msg => this.buses.get(channelId)?.notifyMessage(msg))
394
- cr.setLoader(id => this.ensureAgentRuntime(channelId, id))
395
- this.channels.set(channelId, cr)
396
- this.buses.set(channelId, this.buildBus(cr))
397
- // 团队记忆沉淀(任务终态事件单点收口):team-task 共享行 + 编年史滚动重写。
398
- // 事件总线保证每次状态迁移恰好一次通知——worker/lead 各自私有域 harvest 之外
399
- // 的团队域写入不存在双写;失败仅记日志,绝不影响任务流。
400
- this.buses.get(channelId)!.onTaskEvent(e => this.recordTeamTaskTerminal(channelId, e))
401
- }
402
- return cr
403
- }
404
-
405
- /**
406
- * 团队历史沉淀(任务终态):① team-task 共享行(成果/失败原因,全员可检索);
407
- * ② 团队编年史滚动重写(最近 12 条终态任务轨迹)。
408
- */
409
- private recordTeamTaskTerminal(channelId: string, e: { taskId: string, state?: TaskState, task?: TaskEventTask }): void {
410
- if (!e.state || !TERMINAL_TASK_STATES[e.state]) return
411
- try {
412
- const completed = e.state === 'COMPLETED'
413
- const task = e.task
414
- const title = task?.title ?? `任务 ${e.taskId.slice(0, 8)}`
415
- // 成果提取与 AgentMemory.recordTaskOutcome 同口径(deliverable/summary 优先)
416
- const artifacts = (task?.artifacts ?? []) as A2AArtifact[]
417
- const preferred = artifacts.filter(a => a.name === 'deliverable' || a.name === 'summary')
418
- const source = preferred.length > 0 ? preferred : artifacts
419
- const deliverable = source
420
- .flatMap(a => a.parts)
421
- .map(p => ('text' in p ? p.text : ''))
422
- .join(' ')
423
- .trim()
424
- const content = completed
425
- ? (deliverable || title)
426
- : `任务「${title}」${e.state === 'CANCELED' ? '已取消' : '未完成'}${deliverable ? `;已有进展: ${deliverable.slice(0, 200)}` : ''}`
427
- const mem = new AgentMemory(this.deps.repos.memories, { channelId, agentId: TEAM_AGENT_ID, embedder: this.memoryEmbedder ?? undefined })
428
- void mem.appendTeamTaskRecord({
429
- taskId: e.taskId,
430
- title,
431
- content,
432
- importance: completed ? 0.8 : 0.55,
433
- }).catch((err) => { log.error('[memory] team-task 沉淀失败:', err) })
434
- this.refreshChronicle(channelId)
435
- }
436
- catch (err) {
437
- log.error('[memory] 团队任务沉淀异常:', err)
438
- }
439
- }
440
-
441
- /** 团队编年史滚动重写(最近 12 条终态任务;chronicle:<channelId> 幂等单行;免向量化) */
442
- private refreshChronicle(channelId: string): void {
443
- try {
444
- const terminal = this.getTaskEngine().list(channelId)
445
- .filter(t => TERMINAL_TASK_STATES[t.state])
446
- .sort((a, b) => (a.updatedAt < b.updatedAt ? 1 : -1))
447
- .slice(0, 12)
448
- if (terminal.length === 0) return
449
- const entries = terminal.map((t) => {
450
- const stamp = t.updatedAt.slice(5, 16).replace('T', ' ')
451
- const deliverable = t.artifacts
452
- .flatMap(a => a.parts)
453
- .map(p => ('text' in p ? p.text : ''))
454
- .join(' ')
455
- .replace(/\s+/g, ' ')
456
- .trim()
457
- .slice(0, 60)
458
- const state = t.state === 'COMPLETED' ? '完成' : t.state === 'FAILED' ? '失败' : '取消'
459
- return `${stamp} [${state}] ${t.title} — ${t.assigneeId.slice(0, 8)}${deliverable ? `(${deliverable})` : ''}`
460
- })
461
- new AgentMemory(this.deps.repos.memories, { channelId, agentId: TEAM_AGENT_ID })
462
- .upsertChronicle(entries.join('\n'))
463
- }
464
- catch (err) {
465
- log.error('[memory] 编年史刷新失败:', err)
466
- }
467
- }
468
-
469
- /**
470
- * 空闲反思(sleep-time compute,零 LLM):当月 episodic-task 增量 ≥ 阈值时,
471
- * 聚合标题+结论成 semantic 反思行(月度 dedupKey 幂等;FTS 可检索,免向量化)。
472
- */
473
- private reflectIdleMemories(): void {
474
- for (const rt of this.agentIndex.values()) {
475
- if (rt.getState() === 'busy') return
476
- }
477
- const trigger = memorySettings().reflect_trigger
478
- const month = new Date().toISOString().slice(0, 7)
479
- const memories = this.deps.repos.memories
480
- for (const agentId of memories.listMemoryAgentIds()) {
481
- // 条件下推到 SQL:原先拉 limit=1_000_000 全量再 JS filter,代价随记忆总量无上限增长。
482
- // 这里按 (agent, kind, 当月) 精确取行 —— 返回量与实际增量同阶,且内存不随历史膨胀。
483
- const rows = memories.listByAgentKindMonth(agentId, 'episodic-task', month)
484
- const prev = this.reflectCounts.get(agentId) ?? 0
485
- if (rows.length < trigger || rows.length <= prev) continue
486
- // 行可能跨 channel(历史迁移):按 channel 分组,各组建反思
487
- const byChannel = new Map<string, typeof rows>()
488
- for (const r of rows) {
489
- const list = byChannel.get(r.channelId) ?? []
490
- list.push(r)
491
- byChannel.set(r.channelId, list)
492
- }
493
- for (const [channelId, list] of byChannel) {
494
- const lines = list.slice(0, 20).map(r => `- ${r.title}:${unsegmentCJK(r.content).slice(0, 60)}`)
495
- new AgentMemory(this.deps.repos.memories, { channelId, agentId })
496
- .upsertReflection({ month, content: [`当月 ${list.length} 项任务经验聚合:`, ...lines].join('\n') })
497
- }
498
- this.reflectCounts.set(agentId, rows.length)
499
- log.info(`[memory] 反思蒸馏:agent=${agentId.slice(0, 8)} 当月 ${rows.length} 项任务已聚合`)
500
- }
501
- }
502
-
503
- private buildBus(cr: ChannelRuntime): ChannelBus {
504
- const eventListeners = new Set<(event: AgentEvent, source: A2AMessage) => void>()
505
- const taskListeners = new Set<(e: { taskId: string, state?: TaskState, progress?: number }) => void>()
506
- const agentListeners = new Set<(e: { agentId: string, state: 'idle' | 'busy' | 'stopped' }) => void>()
507
- const messageListeners = new Set<(message: A2AMessage) => void>()
508
- const memoryListeners = new Set<(e: { agentId: string, scope: 'private' | 'shared', title: string, dedupKey: string }) => void>()
509
- const memberListeners = new Set<(e: MemberChangeEvent) => void>()
510
- return {
511
- emit: (event, source) => {
512
- for (const fn of eventListeners) {
513
- try {
514
- fn(event, source)
515
- }
516
- catch (err) {
517
- log.error('[ChannelBus] event listener error:', err)
518
- }
519
- }
520
- cr.wakeScheduler()
521
- },
522
- onEvent: (fn) => {
523
- eventListeners.add(fn)
524
- return () => eventListeners.delete(fn)
525
- },
526
- notifyTask: (e: { taskId: string, state?: TaskState, progress?: number, agentId?: string, task?: TaskEventTask }) => {
527
- for (const fn of taskListeners) {
528
- try {
529
- fn(e)
530
- }
531
- catch (err) {
532
- log.error('[ChannelBus] task listener error:', err)
533
- }
534
- }
535
- },
536
- onTaskEvent: (fn) => {
537
- taskListeners.add(fn)
538
- return () => taskListeners.delete(fn)
539
- },
540
- notifyAgent: (e) => {
541
- for (const fn of agentListeners) {
542
- try {
543
- fn(e)
544
- }
545
- catch (err) {
546
- log.error('[ChannelBus] agent listener error:', err)
547
- }
548
- }
549
- },
550
- onAgentStatus: (fn) => {
551
- agentListeners.add(fn)
552
- return () => agentListeners.delete(fn)
553
- },
554
- notifyMessage: (message) => {
555
- for (const fn of messageListeners) {
556
- try {
557
- fn(message)
558
- }
559
- catch (err) {
560
- log.error('[ChannelBus] message listener error:', err)
561
- }
562
- }
563
- },
564
- onMessage: (fn) => {
565
- messageListeners.add(fn)
566
- return () => messageListeners.delete(fn)
567
- },
568
- notifyMemory: (e) => {
569
- for (const fn of memoryListeners) {
570
- try {
571
- fn(e)
572
- }
573
- catch (err) {
574
- log.error('[ChannelBus] memory listener error:', err)
575
- }
576
- }
577
- },
578
- onMemoryEvent: (fn) => {
579
- memoryListeners.add(fn)
580
- return () => memoryListeners.delete(fn)
581
- },
582
- notifyMember: (e) => {
583
- for (const fn of memberListeners) {
584
- try {
585
- fn(e)
586
- }
587
- catch (err) {
588
- log.error('[ChannelBus] member listener error:', err)
589
- }
590
- }
591
- },
592
- onMemberEvent: (fn) => {
593
- memberListeners.add(fn)
594
- return () => memberListeners.delete(fn)
595
- },
596
- wakeScheduler: () => {
597
- cr.wakeScheduler()
598
- },
599
- }
600
- }
601
-
602
- subscribeAgentStatus(channelId: string, fn: (e: Parameters<ChannelBus['notifyAgent']>[0]) => void): () => void {
603
- // 先确保 bus 存在:channel 尚未激活时订阅会被静默丢弃(monitor 先订阅后提交任务的场景)
604
- // 返回 bus 的真实退订函数:stream 重绑时必须可退订,否则同一 bus 上订阅两份 → 事件双发
605
- this.ensureChannelRuntime(channelId)
606
- return this.buses.get(channelId)?.onAgentStatus(fn) ?? (() => {})
607
- }
608
-
609
- subscribeChannelEvents(channelId: string, fn: (event: AgentEvent, source: A2AMessage) => void): () => void {
610
- this.ensureChannelRuntime(channelId)
611
- return this.buses.get(channelId)?.onEvent(fn) ?? (() => {})
612
- }
613
-
614
- subscribeTaskEvents(channelId: string, fn: (e: { taskId: string, state?: TaskState, progress?: number, agentId?: string, task?: TaskEventTask }) => void): () => void {
615
- // 真实退订(同上:防 stream 重绑泄漏导致 task.status 双发落库)
616
- this.ensureChannelRuntime(channelId)
617
- return this.buses.get(channelId)?.onTaskEvent(fn) ?? (() => {})
618
- }
619
-
620
- /** 订阅 channel 内消息投递(AEP a2a.message 事件源;route 汇流点触发) */
621
- subscribeChannelMessages(channelId: string, fn: (message: A2AMessage) => void): () => void {
622
- this.ensureChannelRuntime(channelId)
623
- return this.buses.get(channelId)?.onMessage(fn) ?? (() => {})
624
- }
625
-
626
- /** 订阅 channel 内记忆写入(AEP memory.saved 事件源) */
627
- subscribeMemoryEvents(channelId: string, fn: (e: { agentId: string, scope: 'private' | 'shared', title: string, dedupKey: string }) => void): () => void {
628
- this.ensureChannelRuntime(channelId)
629
- return this.buses.get(channelId)?.onMemoryEvent(fn) ?? (() => {})
630
- }
631
-
632
- /** 订阅 channel 内团队成员增/改/删(AEP agent.member 事件源;lead 工具桥与 REST 入口共用汇流点) */
633
- subscribeMemberEvents(channelId: string, fn: (e: MemberChangeEvent) => void): () => void {
634
- this.ensureChannelRuntime(channelId)
635
- return this.buses.get(channelId)?.onMemberEvent(fn) ?? (() => {})
636
- }
637
-
638
- private notifyTask(
639
- channelId: string,
640
- e: { taskId: string, state?: TaskState, progress?: number, agentId?: string, task?: TaskEventTask },
641
- ): void {
642
- this.buses.get(channelId)?.notifyTask(e)
643
- }
644
-
645
- /** 团队成员变更广播(AEP agent.member 事件源;lead 工具桥与 REST 入口共用) */
646
- private notifyMember(channelId: string, e: MemberChangeEvent): void {
647
- this.buses.get(channelId)?.notifyMember(e)
648
- }
649
-
650
- /** 按实例装配 AgentRuntime(每个实例一个独立运行时) */
651
- private wireMember(m: ChannelAgentRow): AgentRuntime {
652
- const agent = instanceToAgentInfo(m)
653
- const cr = this.ensureChannelRuntime(m.channelId)
654
- const bus = this.buses.get(m.channelId)!
655
- const mailbox = new Mailbox(this.deps.repos.messages, m.channelId, agent.id, () => cr.wakeScheduler())
656
- const memory = new AgentMemory(this.deps.repos.memories, { channelId: m.channelId, agentId: agent.id, embedder: this.memoryEmbedder ?? undefined })
657
- const workspace = this.buildWorkspace(agent, memory)
658
- const chWorkspace = this.channelWorkspace(m.channelId)
659
- // channel 级作业场景 prompt 注入 harness config(用户场景 × 系统设计组合的入口;
660
- // 变更经 updateChannel 回收成员运行时,下次装配拿到新场景)
661
- const scenarioPrompt = this.deps.repos.channels.findById(m.channelId)?.scenarioPrompt ?? ''
662
- const configWithCtx: Record<string, unknown> = { ...agent.config }
663
- if (scenarioPrompt) configWithCtx.scenarioPrompt = scenarioPrompt
664
- if (chWorkspace.length > 0) configWithCtx.cwd = chWorkspace
665
- // channel 级默认 LLM(v11):成员 config 未显式指定 model/provider 时按引擎注入;
666
- // effort 语义按引擎映射(omp thinkingLevel / opencode variant / codex effort / dsh 暂不支持)
667
- const chRow = this.deps.repos.channels.findById(m.channelId)
668
- const chLlm = parseChannelLlm(chRow?.llmJson)
669
- if (chLlm) {
670
- if (!configWithCtx.model && chLlm.model) configWithCtx.model = chLlm.model
671
- if (!configWithCtx.provider && chLlm.provider) configWithCtx.provider = chLlm.provider
672
- if (!configWithCtx.effort && chLlm.effort) configWithCtx.effort = chLlm.effort
673
- }
674
- const agentWithCtx: AgentInfo = { ...agent, config: configWithCtx }
675
- const runtime = new AgentRuntime(agent, this.deps.implFactory(agentWithCtx), {
676
- mailbox,
677
- taskEngine: this.getTaskEngine(),
678
- bus,
679
- workspace,
680
- memory,
681
- })
682
- cr.addAgent(runtime)
683
- this.agentIndex.set(runtimeKey(m.channelId, agent.id), runtime)
684
- runtime.start()
685
- return runtime
686
- }
687
-
688
- /** 按需装配实例运行时(幂等):已装配返回缓存,否则从实例行 wire;禁用/不存在返回 undefined */
689
- private ensureAgentRuntime(channelId: string, agentId: string): AgentRuntime | undefined {
690
- const key = runtimeKey(channelId, agentId)
691
- const existing = this.agentIndex.get(key)
692
- if (existing) return existing
693
- const m = this.deps.repos.channelAgents.findByChannelAgent(channelId, agentId)
694
- if (!m || m.enabled !== 1) return undefined
695
- return this.wireMember(m)
696
- }
697
-
698
- private runtimeOf(channelId: string, agentId: string): AgentRuntime | undefined {
699
- return this.agentIndex.get(runtimeKey(channelId, agentId))
700
- }
701
-
702
- /** 激活 channel:装配 lead 运行时 + 装配并启动 SchedulerLoop(幂等) */
703
- ensureChannelActive(channelId: string, options?: SchedulerLoopOptions): void {
704
- const channel = this.deps.repos.channels.findById(channelId)
705
- if (!channel || channel.enabled !== 1 || !channel.leadAgentId) return
706
- const cr = this.ensureChannelRuntime(channelId)
707
- if (cr.scheduler) return
708
- const lead = this.ensureAgentRuntime(channelId, channel.leadAgentId)
709
- if (!lead) return
710
- const loop = new SchedulerLoop(cr, lead, {
711
- // 停滞窗口默认取 workshop.stall_ms(默认 5 分钟,可经设置调整):
712
- // 它决定"多久算停滞"以及"多久之后收口",是运维最需要按现场调的一个值;
713
- // 以前写死在 SchedulerLoop 构造默认值里,mock/规则引擎路径上最长要 10 分钟才可见。
714
- ...(Number.isFinite(workshopSettings().stall_ms) ? { stallMs: workshopSettings().stall_ms } : {}),
715
- ...options,
716
- // 停滞看门狗活性源:agent 最近一次工具 invoke 时刻(工具调用即健康推进)
717
- toolActivityOf: (agentId: string) => this.lastToolInvokeAt.get(agentId) ?? null,
718
- // 调度快照的邮件上下文(lead 观察 worker 间通信的唯一来源;DB 为事实源)
719
- supervisionMail: limit => this.deps.repos.messages
720
- .listRecentByChannel(channelId, limit)
721
- .map(rowToChannelMail),
722
- })
723
- loop.setLoopResubmitCallback((title, description) => {
724
- this.submitChannelTask({ channelId, title, description }).catch((err) => {
725
- // 清理竞态:channel 已删除/lead 已卸载时的到期重放 → 静默(NOT_FOUND 为预期)
726
- const code = (err as { code?: string }).code
727
- if (code === 'NOT_FOUND' || code === 'NO_LEAD_AGENT') return
728
- log.error(`[AgentChannelManager:${channelId}] loop 重新提交失败:`, err)
729
- })
730
- })
731
- cr.scheduler = loop
732
- loop.start()
733
- }
734
-
735
- /** 停止并卸载某实例运行时(强制;删除实例/channel 时用) */
736
- private async stopAndDetach(channelId: string, agentId: string): Promise<void> {
737
- const key = runtimeKey(channelId, agentId)
738
- const runtime = this.agentIndex.get(key)
739
- if (!runtime) return
740
- const cr = this.channels.get(channelId)
741
- if (runtime.role === 'lead' && cr) {
742
- cr.scheduler?.stop()
743
- cr.scheduler = null
744
- }
745
- // 先摘除再停机:runtime.stop() 会关闭 mailbox,若成员仍在 route 视野内,
746
- // 停机窗口内到达的消息会被 closed mailbox 静默吞掉但 delivered 照常上报
747
- // (发送方收到成功假象);先 detach 让 route 立即按"成员不存在"如实失败
748
- cr?.detachAgent(agentId)
749
- await runtime.stop()
750
- this.agentIndex.delete(key)
751
- if (cr && cr.getAgents().length === 0 && !cr.scheduler) {
752
- this.channels.delete(channelId)
753
- this.buses.delete(channelId)
754
- }
755
- }
756
-
757
- /** 卸载实例运行时(空闲后释放内存,杀 omp 子进程);busy/有 pending/lead 有活跃任务 → 跳过 */
758
- async unloadAgent(channelId: string, agentId: string): Promise<void> {
759
- const runtime = this.runtimeOf(channelId, agentId)
760
- if (!runtime) return
761
- if (runtime.getState() !== 'idle') return
762
- if (this.deps.repos.messages.listPendingByChannelAgent(channelId, agentId).length > 0) return
763
- if (runtime.role === 'lead') {
764
- const tasks = this.getTaskEngine().list(runtime.channelId)
765
- const hasActive = tasks.some(t => t.state !== 'COMPLETED' && t.state !== 'CANCELED' && t.state !== 'FAILED')
766
- if (hasActive) return
767
- }
768
- await this.stopAndDetach(channelId, agentId)
769
- }
770
-
771
- async unloadIdleAgents(): Promise<void> {
772
- for (const rt of [...this.agentIndex.values()]) {
773
- await this.unloadAgent(rt.channelId, rt.agentId)
774
- }
775
- }
776
-
777
- startIdleSweeper(options?: { intervalMs?: number, graceMs?: number }): () => void {
778
- const intervalMs = options?.intervalMs ?? 60_000
779
- const graceMs = options?.graceMs ?? 120_000
780
- const idleSince = new Map<string, number>()
781
- this.idleSweeperTimer = setInterval(() => {
782
- const now = Date.now()
783
- for (const rt of [...this.agentIndex.values()]) {
784
- // 存活校准优先:休眠/强杀后子进程 exit 事件可能不达,周期探 OS 实际存在性,
785
- // 死进程收敛为已退出(在途回合归位,下一回合自动重生),避免 stuck busy/死客户端空转
786
- try {
787
- rt.reconcileProcess()
788
- }
789
- catch (err) {
790
- log.error(`[AgentChannelManager] 校准 ${rt.channelId}/${rt.agentId} 进程存活失败:`, err)
791
- }
792
- const key = runtimeKey(rt.channelId, rt.agentId)
793
- if (rt.getState() === 'idle') {
794
- const since = idleSince.get(key) ?? now
795
- idleSince.set(key, since)
796
- if (now - since >= graceMs) {
797
- idleSince.delete(key)
798
- this.unloadAgent(rt.channelId, rt.agentId).catch((err) => {
799
- log.error(`[AgentChannelManager] 卸载 ${rt.channelId}/${rt.agentId} 失败:`, err)
800
- })
801
- }
802
- }
803
- else {
804
- idleSince.delete(key)
805
- }
806
- }
807
- }, intervalMs)
808
- return () => {
809
- if (this.idleSweeperTimer) {
810
- clearInterval(this.idleSweeperTimer)
811
- this.idleSweeperTimer = null
812
- }
813
- }
814
- }
815
-
816
- runtimeStatus(): { wiredAgents: string[], activeChannels: string[] } {
817
- return {
818
- wiredAgents: [...this.agentIndex.values()].map(rt => rt.agentId),
819
- activeChannels: [...this.channels.keys()],
820
- }
821
- }
822
-
823
- /**
824
- * 运行时资源监控快照:已装配的 ChannelRuntime / AgentRuntime
825
- * + 全部已启动的 harness 进程(注册表,含已脱离 runtimes 的孤儿进程)。
826
- */
827
- monitorRuntime(): RuntimeMonitorSnapshot {
828
- sweepHarnessProcesses()
829
- sweepTerminalSessions()
830
- const channels: RuntimeChannelView[] = [...this.channels.values()].map((cr) => {
831
- const channel = this.deps.repos.channels.findById(cr.channelId)
832
- return {
833
- channelId: cr.channelId,
834
- wiredAgentCount: cr.getAgents().length,
835
- memberCount: this.deps.repos.channelAgents.listByChannel(cr.channelId).length,
836
- hasScheduler: cr.scheduler !== null,
837
- leadAgentId: channel?.leadAgentId ?? null,
838
- ownerUserId: channel?.ownerUserId ?? null,
839
- }
840
- })
841
- const agents: RuntimeAgentView[] = [...this.agentIndex.values()].map((rt) => {
842
- const status = rt.getStatus()
843
- const row = this.deps.repos.channelAgents.findByChannelAgent(rt.channelId, rt.agentId)
844
- return {
845
- channelId: rt.channelId,
846
- agentId: rt.agentId,
847
- name: rt.name,
848
- role: rt.role,
849
- harness: row?.harness ?? '?',
850
- state: status.state,
851
- currentTaskId: status.currentTaskId,
852
- queuedCount: status.queuedCount,
853
- completedCount: status.completedCount,
854
- process: rt.getProcessInfo(),
855
- }
856
- })
857
- const channelOwner = new Map(channels.map(c => [c.channelId, c.ownerUserId ?? null]))
858
- const boundPids = new Set(
859
- agents.map(a => a.process?.pid).filter((p): p is number => typeof p === 'number'),
860
- )
861
- const processes: RuntimeProcessView[] = listHarnessProcesses().map(p => ({
862
- pid: p.pid,
863
- harness: p.harness,
864
- command: p.command,
865
- args: p.args,
866
- agentId: p.agentId,
867
- channelId: p.channelId,
868
- name: p.name,
869
- role: p.role,
870
- startedAt: p.startedAt,
871
- alive: p.alive,
872
- exitCode: p.exitCode,
873
- bound: boundPids.has(p.pid),
874
- terminal: hasTerminalSession(p.pid),
875
- }))
876
- for (const a of agents) {
877
- a.ownerUserId = channelOwner.get(a.channelId) ?? null
878
- }
879
- for (const p of processes) {
880
- ;(p as RuntimeProcessView & { ownerUserId?: string | null }).ownerUserId = p.channelId
881
- ? channelOwner.get(p.channelId) ?? null
882
- : null
883
- }
884
- return {
885
- generatedAt: new Date().toISOString(),
886
- serverPid: process.pid,
887
- uptimeMs: Math.round(process.uptime() * 1000),
888
- channels,
889
- agents,
890
- processes,
891
- counts: {
892
- channels: channels.length,
893
- agents: agents.length,
894
- processes: processes.length,
895
- aliveProcesses: processes.filter(p => p.alive).length,
896
- orphanProcesses: processes.filter(p => p.alive && !p.bound).length,
897
- },
898
- }
899
- }
900
-
901
- /**
902
- * 用户级监控快照(v10 用户隔离):
903
- * - 普通用户:仅本人 channel 的 runtime/agent,以及绑定到本人 channel 的进程;
904
- * 未绑定/孤儿进程与遗留无主 channel 一律不可见。
905
- * - admin:全量视图,每个 channel/agent/process 附带 ownerUserId(ownerName 由路由层补注)。
906
- */
907
- monitorRuntimeForUser(user: ActingUser): RuntimeMonitorSnapshot & { scope: 'user' | 'admin', ownerNames?: Record<string, string> } {
908
- const snap = this.monitorRuntime()
909
- if (user.role === 'admin') {
910
- const ownerIds = new Set<string>()
911
- for (const c of snap.channels) {
912
- if (c.ownerUserId) ownerIds.add(c.ownerUserId)
913
- }
914
- const ownerNames: Record<string, string> = {}
915
- for (const id of ownerIds) {
916
- const name = resolveOwnerName(id)
917
- if (name) ownerNames[id] = name
918
- }
919
- for (const c of snap.channels) c.ownerName = c.ownerUserId ? ownerNames[c.ownerUserId] ?? null : null
920
- for (const a of snap.agents) a.ownerName = a.ownerUserId ? ownerNames[a.ownerUserId] ?? null : null
921
- return { ...snap, scope: 'admin', ownerNames }
922
- }
923
- const visibleChannels = new Set(snap.channels.filter(c => c.ownerUserId === user.id).map(c => c.channelId))
924
- // 本人有主但当前未装配 runtime 的 channel 也计入 channels 视图(成员数来自 DB,装配为 0)
925
- for (const row of this.deps.repos.channels.list()) {
926
- if (row.ownerUserId === user.id) visibleChannels.add(row.id)
927
- }
928
- const channels = snap.channels.filter(c => visibleChannels.has(c.channelId))
929
- for (const row of this.deps.repos.channels.list()) {
930
- if (visibleChannels.has(row.id) && !channels.some(c => c.channelId === row.id)) {
931
- channels.push({
932
- channelId: row.id,
933
- wiredAgentCount: 0,
934
- memberCount: this.deps.repos.channelAgents.listByChannel(row.id).length,
935
- hasScheduler: false,
936
- leadAgentId: row.leadAgentId,
937
- ownerUserId: row.ownerUserId,
938
- })
939
- }
940
- }
941
- const agents = snap.agents.filter(a => visibleChannels.has(a.channelId))
942
- const processes = snap.processes.filter(p => p.channelId !== null && visibleChannels.has(p.channelId))
943
- return {
944
- generatedAt: snap.generatedAt,
945
- serverPid: snap.serverPid,
946
- uptimeMs: snap.uptimeMs,
947
- channels,
948
- agents,
949
- processes,
950
- counts: {
951
- channels: channels.length,
952
- agents: agents.length,
953
- processes: processes.length,
954
- aliveProcesses: processes.filter(p => p.alive).length,
955
- orphanProcesses: processes.filter(p => p.alive && !p.bound).length,
956
- },
957
- scope: 'user',
958
- }
959
- }
960
-
961
- /**
962
- * 终止指定 runtime 的 harness 进程 → 对应 AgentRuntime 随之 stop 并卸载。
963
- * 语义比 HITL stopAgentRuntime 更强:先强杀进程(进程树),再走 stopAndDetach
964
- * (停 SchedulerLoop / 中断当前 run / dispose impl / 移出索引)。成员行保留,
965
- * 后续任务投递按需重新装配。
966
- * runtime 未装配(如已被空闲卸载)但进程残留 → 按 agentId 兜底强杀进程,防资源浪费。
967
- */
968
- async terminateRuntimeProcess(channelId: string, agentId: string): Promise<{ agentId: string, stopped: boolean }> {
969
- const m = this.deps.repos.channelAgents.findByChannelAgent(channelId, agentId)
970
- if (!m) throw new AppError(404, 'NOT_FOUND', `成员不存在: ${agentId}`)
971
- const runtime = this.runtimeOf(channelId, agentId)
972
- if (runtime) {
973
- try {
974
- runtime.killProcess()
975
- }
976
- catch (err) {
977
- log.error(`[AgentChannelManager] 终止进程失败 ${channelId}/${agentId}:`, err)
978
- }
979
- await this.stopAndDetach(channelId, agentId)
980
- return { agentId, stopped: true }
981
- }
982
- const leftover = listAliveHarnessProcessesByAgent(agentId)
983
- for (const p of leftover) killHarnessProcess(p.pid)
984
- return { agentId, stopped: leftover.length > 0 }
985
- }
986
-
987
- /** 按 PID 终止 harness 进程(孤儿进程专用;已绑定 runtime 的请走 terminateRuntimeProcess) */
988
- killHarnessProcessByPid(pid: number): { pid: number, killed: boolean } {
989
- return { pid, killed: killHarnessProcess(pid) }
990
- }
991
-
992
- async shutdown(): Promise<void> {
993
- if (this.idleSweeperTimer) {
994
- clearInterval(this.idleSweeperTimer)
995
- this.idleSweeperTimer = null
996
- }
997
- if (this.memoryTimer) {
998
- clearInterval(this.memoryTimer)
999
- this.memoryTimer = null
1000
- }
1001
- for (const cr of this.channels.values()) {
1002
- cr.scheduler?.stop()
1003
- cr.scheduler = null
1004
- }
1005
- await Promise.all([...this.agentIndex.values()].map(a => a.stop()))
1006
- this.agentIndex.clear()
1007
- this.channels.clear()
1008
- this.buses.clear()
1009
- }
1010
-
1011
- /** Agent 自主作业能力面(绑定本实例身份与 channel,委托 manager 作业方法) */
1012
- private buildWorkspace(agent: AgentInfo, memory: AgentMemory): AgentWorkspace {
1013
- const channelId = agent.channelId
1014
- return {
1015
- listAgents: () => this.listChannelAgents(channelId),
1016
- dispatchTask: input => this.dispatchTask(channelId, agent.id, input),
1017
- listTasks: () => this.listTasks(channelId, agent.id),
1018
- getTask: taskId => this.getTask(channelId, agent.id, taskId),
1019
- reportTask: input => this.reportTask(channelId, agent.id, input),
1020
- completeTask: (taskId, artifacts) => this.completeTask(channelId, agent.id, { taskId, artifacts }),
1021
- cancelTask: taskId => this.cancelTask(channelId, agent.id, { taskId }),
1022
- myQueue: () => this.myQueue(channelId, agent.id),
1023
- queueOverview: () => this.queueOverview(channelId, agent.id),
1024
- updateTask: (taskId, patch) => this.updateTask(channelId, agent.id, taskId, patch),
1025
- reassignTask: (taskId, toAgentId) => this.reassignTask(channelId, agent.id, taskId, toAgentId),
1026
- sendMessage: input => this.sendA2A(channelId, agent.id, input),
1027
- sendCrossChannelMessage: input => this.sendCrossChannelMessage(channelId, agent.id, input),
1028
- listOtherTeams: () => this.listOtherTeamsOverview(channelId, agent.id),
1029
- searchOtherTeamsMemory: input => this.recallOtherTeamsMemory(channelId, agent.id, input),
1030
- refuseTask: (taskId, reason) => this.refuseTask(channelId, agent.id, taskId, reason),
1031
- pollMailbox: limit => this.pollMailbox(channelId, agent.id, limit),
1032
- waitMailbox: (limit, waitMs) => this.waitMailbox(channelId, agent.id, limit ?? 10, waitMs ?? 0),
1033
- ackMailbox: ids => Promise.resolve(this.ackMailbox(channelId, agent.id, ids)),
1034
- listMail: opts => this.listChannelMail(channelId, agent.id, opts),
1035
- subscribe: input => this.subscribe(channelId, agent.id, input),
1036
- // 记忆按需抓取/主动沉淀(成员校验 + 委托本实例 AgentMemory;shared 写入即 Channel 公共域)
1037
- recallMemory: async (input) => {
1038
- this.requireMember(channelId, agent.id)
1039
- return memory.recallRows(input.query, { scope: input.scope, limit: input.limit })
1040
- },
1041
- saveMemory: async (input) => {
1042
- this.requireMember(channelId, agent.id)
1043
- const saved = await memory.save(input)
1044
- this.buses.get(channelId)?.notifyMemory({ agentId: agent.id, scope: input.scope, title: input.title, dedupKey: saved.dedupKey })
1045
- return saved
1046
- },
1047
- // 会话压缩摘要入库(harvest 桥):omp 压缩产出 → 本成员 episodic-session 记忆
1048
- recordSessionMemory: async (input) => {
1049
- const saved = await memory.recordSessionCompaction(input)
1050
- this.buses.get(channelId)?.notifyMemory({ agentId: agent.id, scope: 'private', title: `会话压缩摘要(${input.summary.length}字)`, dedupKey: saved.dedupKey })
1051
- },
1052
- // 团队成员管理(仅 lead;manager 内二次校验角色,工具面与决策面共用)
1053
- createTeamMember: input => this.createTeamMember(channelId, agent.id, input),
1054
- updateTeamMember: (agentId, patch) => this.updateTeamMember(channelId, agent.id, agentId, patch),
1055
- removeTeamMember: (agentId, reason) => this.removeTeamMember(channelId, agent.id, agentId, reason),
1056
- }
1057
- }
1058
-
1059
- // ===== 用户面(用户级隔离;管理 API 凭证 = 用户 token)=====
1060
-
1061
- /** 注册用户(name 唯一 → 409;token 仅此一次返回) */
1062
- registerUser(name: string): UserRow {
1063
- const trimmed = name.trim()
1064
- if (!trimmed) throw new AppError(400, 'BAD_REQUEST', '用户名不能为空')
1065
- if (this.deps.repos.users.getByName(trimmed)) {
1066
- throw new AppError(409, 'USER_EXISTS', `用户名已存在: ${trimmed}`)
1067
- }
1068
- return this.deps.repos.users.create(trimmed)
1069
- }
1070
-
1071
- /** 用户 token → 用户(无效 → 401;REST resolveUser / WS sub 共用) */
1072
- getUserByToken(token: string): UserRow | null {
1073
- return this.deps.repos.users.getByToken(token)
1074
- }
1075
-
1076
- /**
1077
- * 资源 owner 守卫:owner 匹配放行;NULL owner(遗留公共数据)只读——
1078
- * 写操作一律拒绝(FORBIDDEN_LEGACY,提示归属缺失);他人资源 → 403。
1079
- */
1080
- requireOwned(ownerUserId: string | null | undefined, userId: string, what: string): void {
1081
- if (ownerUserId === null || ownerUserId === undefined) {
1082
- throw new AppError(403, 'FORBIDDEN_LEGACY', `${what} 为遗留公共数据(无归属),禁止变更`)
1083
- }
1084
- if (ownerUserId !== userId) {
1085
- throw new AppError(403, 'SCOPE_VIOLATION', `${what} 不属于当前用户`)
1086
- }
1087
- }
1088
-
1089
- /**
1090
- * 模板/资源可写守卫(v10 权限系统):
1091
- * - 内置模板(owner NULL)→ 任何人(含 admin)不可修改删除(TEMPLATE_BUILTIN);
1092
- * - 属主 → 放行;
1093
- * - admin → 越权放行(最高管理权限);
1094
- * - 其余 → 403 SCOPE_VIOLATION。
1095
- */
1096
- requireWritable(ownerUserId: string | null | undefined, user: ActingUser, what: string): void {
1097
- if (ownerUserId === null || ownerUserId === undefined) {
1098
- throw new AppError(403, 'TEMPLATE_BUILTIN', `${what} 为内置公共模板,不可修改或删除`)
1099
- }
1100
- if (ownerUserId === user.id) return
1101
- if (user.role === 'admin') return
1102
- throw new AppError(403, 'SCOPE_VIOLATION', `${what} 不属于当前用户`)
1103
- }
1104
-
1105
- /**
1106
- * 模板可读守卫:属主 / public / admin 放行;他人 private → 403(不存在语义由调用方先判)。
1107
- */
1108
- requireTemplateReadable(tpl: { ownerUserId: string | null, visibility: string }, user: ActingUser, what: string): void {
1109
- if (tpl.ownerUserId === null || tpl.ownerUserId === user.id) return
1110
- if (tpl.visibility === 'public') return
1111
- if (user.role === 'admin') return
1112
- throw new AppError(403, 'SCOPE_VIOLATION', `${what} 不属于当前用户且未公开`)
1113
- }
1114
-
1115
- /** channel 读取(已认证用户可见本人 + 遗留公共;不存在 → 404) */
1116
- getChannelForUser(channelId: string, userId: string): ChannelRow {
1117
- const channel = this.deps.repos.channels.findById(channelId)
1118
- if (!channel) throw new AppError(404, 'NOT_FOUND', `channel 不存在: ${channelId}`)
1119
- if (channel.ownerUserId !== null && channel.ownerUserId !== userId) {
1120
- throw new AppError(403, 'SCOPE_VIOLATION', 'channel 不属于当前用户')
1121
- }
1122
- return channel
1123
- }
1124
-
1125
- /** 用户视角 channel 列表(本人 + 遗留公共) */
1126
- listChannelsForUser(userId: string): ChannelRow[] {
1127
- return this.deps.repos.channels.listForOwner(userId)
1128
- }
1129
-
1130
- // ===== Workspace(服务端持久化;按 owner 隔离)=====
1131
-
1132
- listWorkspaces(userId: string): Array<WorkspaceRow & { channelIds: string[] }> {
1133
- // 纯读:挂载引用的失效清理已下沉到 removeChannel 的级联
1134
- // (unmountChannelEverywhere)。早先这里在 .filter() 回调里 DELETE 挂载行,
1135
- // 使 GET /api/workshop/workspaces 与 GET /users/me 成为**有副作用的读** ——
1136
- // 读路径必须可重放、可缓存、可并发,不写库。
1137
- return this.deps.repos.users.listWorkspaces(userId).map(ws => ({
1138
- ...ws,
1139
- channelIds: this.deps.repos.users.listMountedChannels(ws.id),
1140
- }))
1141
- }
1142
-
1143
- createWorkspace(userId: string, name: string): WorkspaceRow & { channelIds: string[] } {
1144
- const trimmed = name.trim()
1145
- if (!trimmed) throw new AppError(400, 'BAD_REQUEST', 'Workspace 名称不能为空')
1146
- const ws = this.deps.repos.users.createWorkspace(userId, trimmed)
1147
- return { ...ws, channelIds: [] }
1148
- }
1149
-
1150
- deleteWorkspace(userId: string, workspaceId: string): void {
1151
- const ws = this.deps.repos.users.getWorkspace(workspaceId)
1152
- if (!ws) throw new AppError(404, 'NOT_FOUND', `workspace 不存在: ${workspaceId}`)
1153
- this.requireOwned(ws.ownerUserId, userId, 'workspace')
1154
- this.deps.repos.users.deleteWorkspace(workspaceId)
1155
- }
1156
-
1157
- /** 挂载 channel(须为本人的 channel;遗留公共不可挂载) */
1158
- mountChannelToWorkspace(userId: string, workspaceId: string, channelId: string): void {
1159
- const ws = this.deps.repos.users.getWorkspace(workspaceId)
1160
- if (!ws) throw new AppError(404, 'NOT_FOUND', `workspace 不存在: ${workspaceId}`)
1161
- this.requireOwned(ws.ownerUserId, userId, 'workspace')
1162
- const channel = this.deps.repos.channels.findById(channelId)
1163
- if (!channel) throw new AppError(404, 'NOT_FOUND', `channel 不存在: ${channelId}`)
1164
- this.requireOwned(channel.ownerUserId, userId, 'channel')
1165
- this.deps.repos.users.mountChannel(workspaceId, channelId)
1166
- }
1167
-
1168
- unmountChannelFromWorkspace(userId: string, workspaceId: string, channelId: string): void {
1169
- const ws = this.deps.repos.users.getWorkspace(workspaceId)
1170
- if (!ws) throw new AppError(404, 'NOT_FOUND', `workspace 不存在: ${workspaceId}`)
1171
- this.requireOwned(ws.ownerUserId, userId, 'workspace')
1172
- this.deps.repos.users.unmountChannel(workspaceId, channelId)
1173
- }
1174
-
1175
- // ===== Channel 管理面 =====
1176
-
1177
- async createChannel(input: {
1178
- name: string
1179
- description?: string
1180
- scenarioPrompt?: string
1181
- workspace?: string
1182
- leadAgent?: { name: string, harness: string, config?: Record<string, unknown> }
1183
- ownerUserId?: string | null
1184
- }): Promise<{ channelId: string, leadAgentId?: string, workspace: string }> {
1185
- const channel = this.deps.repos.channels.create({ name: input.name, description: input.description, scenarioPrompt: input.scenarioPrompt, ownerUserId: input.ownerUserId ?? null })
1186
- const workspace = input.workspace && input.workspace.length > 0
1187
- ? input.workspace
1188
- : resolve(process.cwd(), 'data', 'workspaces', channel.id)
1189
- this.deps.repos.channels.update(channel.id, { workspace })
1190
- this.ensureWorkspaceDir(workspace)
1191
-
1192
- let leadAgentId: string | undefined
1193
- if (input.leadAgent) {
1194
- // lead 内联模板归属 channel 属主(private;避免落成无主内置模板)
1195
- const tpl = this.deps.repos.agents.create({
1196
- name: input.leadAgent.name,
1197
- harness: input.leadAgent.harness,
1198
- config: input.leadAgent.config,
1199
- ownerUserId: input.ownerUserId ?? null,
1200
- })
1201
- const inst = this.deps.repos.channelAgents.create({
1202
- channelId: channel.id,
1203
- templateId: tpl.id,
1204
- name: tpl.name,
1205
- harness: tpl.harness,
1206
- config: parseJson<Record<string, unknown>>(tpl.configJson, {}),
1207
- role: 'lead',
1208
- })
1209
- this.deps.repos.channels.update(channel.id, { leadAgentId: inst.id })
1210
- leadAgentId = inst.id
1211
- // 懒加载:仅持久化,不装配运行时;首次任务提交时 ensureChannelActive 触发装配
1212
- }
1213
- return { channelId: channel.id, leadAgentId, workspace }
1214
- }
1215
-
1216
- async getChannel(channelId: string): Promise<ChannelRow & { agents: AgentInfo[] }> {
1217
- const channel = this.deps.repos.channels.findById(channelId)
1218
- if (!channel) throw new AppError(404, 'NOT_FOUND', `channel 不存在: ${channelId}`)
1219
- const agents = await this.listChannelAgents(channelId)
1220
- return { ...channel, agents }
1221
- }
1222
-
1223
- async updateChannel(channelId: string, patch: { name?: string, description?: string, scenarioPrompt?: string, workspace?: string, enabled?: number, llm?: { provider?: string, model?: string, effort?: string } | null }): Promise<ChannelRow> {
1224
- const channel = this.deps.repos.channels.findById(channelId)
1225
- if (!channel) throw new AppError(404, 'NOT_FOUND', `channel 不存在: ${channelId}`)
1226
- if (patch.workspace !== undefined && patch.workspace !== channel.workspace) {
1227
- this.ensureWorkspaceDir(patch.workspace)
1228
- await this.unloadChannelAgents(channelId)
1229
- }
1230
- if (patch.enabled === 0 && channel.enabled !== 0) {
1231
- await this.unloadChannelAgents(channelId)
1232
- }
1233
- // 场景 prompt 变更 → 回收成员运行时(下次装配注入新场景;进度任务不受影响,
1234
- // 排队任务在成员重新装配后按需恢复)
1235
- if (patch.scenarioPrompt !== undefined && patch.scenarioPrompt !== channel.scenarioPrompt) {
1236
- await this.unloadChannelAgents(channelId)
1237
- }
1238
- // channel 默认 LLM 变更 → 同样回收成员运行时(下次装配注入新默认;成员 config
1239
- // 显式指定的 model/provider 优先,不受影响)
1240
- const prevLlm = channel.llmJson
1241
- const nextLlm = patch.llm !== undefined ? JSON.stringify(patch.llm) : undefined
1242
- if (nextLlm !== undefined && nextLlm !== prevLlm) {
1243
- await this.unloadChannelAgents(channelId)
1244
- }
1245
- const updated = this.deps.repos.channels.update(channelId, patch)
1246
- // 卸载后 channel 需重新激活(懒装配 lead + 恢复调度驱动)
1247
- if (updated && updated.leadAgentId && (patch.scenarioPrompt !== undefined || patch.workspace !== undefined || (nextLlm !== undefined && nextLlm !== prevLlm))) {
1248
- this.ensureChannelActive(channelId)
1249
- }
1250
- return updated!
1251
- }
1252
-
1253
- private async unloadChannelAgents(channelId: string): Promise<void> {
1254
- const cr = this.channels.get(channelId)
1255
- if (cr) {
1256
- cr.scheduler?.stop()
1257
- cr.scheduler = null
1258
- for (const agent of [...cr.getAgents()]) {
1259
- await agent.stop()
1260
- cr.detachAgent(agent.agentId)
1261
- this.agentIndex.delete(runtimeKey(channelId, agent.agentId))
1262
- }
1263
- if (cr.getAgents().length === 0) {
1264
- this.channels.delete(channelId)
1265
- this.buses.delete(channelId)
1266
- }
1267
- }
1268
- }
1269
-
1270
- async updateChannelWorkspace(channelId: string, workspace: string): Promise<ChannelRow> {
1271
- return this.updateChannel(channelId, { workspace })
1272
- }
1273
-
1274
- private ensureWorkspaceDir(workspace: string): void {
1275
- mkdirSync(workspace, { recursive: true })
1276
- }
1277
-
1278
- private channelWorkspace(channelId: string): string {
1279
- return this.deps.repos.channels.findById(channelId)?.workspace ?? ''
1280
- }
1281
-
1282
- async listChannels(): Promise<ChannelRow[]> {
1283
- return this.deps.repos.channels.list()
1284
- }
1285
-
1286
- async removeChannel(channelId: string): Promise<void> {
1287
- const cr = this.channels.get(channelId)
1288
- if (cr) {
1289
- cr.scheduler?.stop()
1290
- cr.scheduler = null
1291
- for (const agent of [...cr.getAgents()]) {
1292
- await agent.stop()
1293
- this.agentIndex.delete(runtimeKey(channelId, agent.agentId))
1294
- }
1295
- this.channels.delete(channelId)
1296
- this.buses.delete(channelId)
1297
- }
1298
- // 记忆级联清理:成员私有行 + team 公共行(防残留行污染他 channel 的 FTS/team 检索域)
1299
- this.deps.repos.memories.deleteByChannel(channelId)
1300
- // workspace 挂载级联:不清理会留下"幽灵频道"(左栏有条目、右栏永空)——
1301
- // 这是 listWorkspaces 读路径兜底要解决的问题,现在在删除侧一次性收敛
1302
- this.deps.repos.users.unmountChannelEverywhere(channelId)
1303
- this.deps.repos.channels.remove(channelId)
1304
- }
1305
-
1306
- // ===== Agent 模板管理面(全局,可复用;v10 可见性隔离) =====
1307
-
1308
- /** 创建 Agent 模板(可复用数据结构;visibility 缺省 private) */
1309
- async createAgent(input: {
1310
- name: string
1311
- harness: string
1312
- config?: Record<string, unknown>
1313
- visibility?: string
1314
- ownerUserId?: string | null
1315
- }): Promise<AgentTemplateDetail> {
1316
- // 执行前强校验:引擎未安装的模板不允许落库(前端下拉已禁用未安装项,此处兜底)
1317
- assertHarnessUsable(input.harness, input.config)
1318
- const row = this.deps.repos.agents.create({ name: input.name, harness: input.harness, config: input.config, visibility: input.visibility, ownerUserId: input.ownerUserId ?? null })
1319
- return this.templateDetailOf(row)
1320
- }
1321
-
1322
- /** 列出全部 Agent 模板(全局) */
1323
- async listAgents(): Promise<AgentTemplateDetail[]> {
1324
- return this.deps.repos.agents.list().map(row => this.templateDetailOf(row))
1325
- }
1326
-
1327
- /** 用户视角模板列表(本人 + 遗留公共) */
1328
- async listAgentsForUser(userId: string): Promise<AgentTemplateDetail[]> {
1329
- return this.deps.repos.agents.listForOwner(userId).map(row => this.templateDetailOf(row))
1330
- }
1331
-
1332
- /** 可见性感知列表:普通用户 = 本人(任意可见性)+ 全部 public(含内置);admin = 全量 */
1333
- async listAgentsVisibleTo(user: ActingUser): Promise<AgentTemplateDetail[]> {
1334
- const rows = user.role === 'admin'
1335
- ? this.deps.repos.agents.list()
1336
- : this.deps.repos.agents.listVisible(user.id)
1337
- return rows.map(row => this.templateDetailOf(row))
1338
- }
1339
-
1340
- /** Agent 模板详情(含其克隆出的全部实例) */
1341
- getAgent(agentId: string): AgentTemplateDetail | undefined {
1342
- const row = this.deps.repos.agents.findById(agentId)
1343
- if (!row) return undefined
1344
- return this.templateDetailOf(row)
1345
- }
1346
-
1347
- /** 更新 Agent 模板(name/harness/config/enabled/visibility);不影响已克隆实例(复制语义) */
1348
- async updateAgent(agentId: string, patch: { name?: string, harness?: string, config?: Record<string, unknown>, enabled?: number, visibility?: string }): Promise<AgentTemplateDetail> {
1349
- const row = this.deps.repos.agents.findById(agentId)
1350
- if (!row) throw new AppError(404, 'NOT_FOUND', `Agent 模板不存在: ${agentId}`)
1351
- if (patch.harness) assertHarnessUsable(patch.harness, patch.config ?? parseJson<Record<string, unknown>>(row.configJson, {}))
1352
- const updated = this.deps.repos.agents.update(agentId, patch)
1353
- if (!updated) throw new AppError(404, 'NOT_FOUND', `Agent 模板不存在: ${agentId}`)
1354
- return this.templateDetailOf(updated)
1355
- }
1356
-
1357
- /** 删除 Agent 模板(实例保留,template_id 置空) */
1358
- async removeAgent(agentId: string): Promise<void> {
1359
- if (!this.deps.repos.agents.findById(agentId)) return
1360
- this.deps.repos.agents.remove(agentId)
1361
- }
1362
-
1363
- private templateDetailOf(row: AgentRow): AgentTemplateDetail {
1364
- const instances = this.deps.repos.channelAgents.listByTemplate(row.id)
1365
- return {
1366
- id: row.id,
1367
- name: row.name,
1368
- harness: row.harness,
1369
- config: parseJson<Record<string, unknown>>(row.configJson, {}),
1370
- enabled: row.enabled,
1371
- visibility: row.ownerUserId === null ? 'public' : row.visibility,
1372
- isBuiltin: row.ownerUserId === null,
1373
- ownerUserId: row.ownerUserId ?? null,
1374
- instances: instances.map(i => ({ id: i.id, channelId: i.channelId, role: i.role as 'lead' | 'worker', token: i.token })),
1375
- createdAt: row.createdAt,
1376
- updatedAt: row.updatedAt,
1377
- }
1378
- }
1379
-
1380
- // ===== Channel 实例管理面 =====
1381
-
1382
- /** 把 Agent 模板放入 channel → 克隆出独立身份 id 的新实例(复制 name/harness/config) */
1383
- async addAgentToChannel(input: {
1384
- channelId: string
1385
- agentId: string
1386
- role: 'lead' | 'worker'
1387
- /** 模板 config 覆盖项(浅合并;用于注入/覆盖 systemPromptPrefix 等场景配置) */
1388
- configOverride?: Record<string, unknown>
1389
- /** 操作发起方(AEP agent.member 的 by;缺省 'user') */
1390
- by?: string
1391
- reason?: string
1392
- }): Promise<AgentInfo> {
1393
- const tpl = this.deps.repos.agents.findById(input.agentId)
1394
- if (!tpl) throw new AppError(404, 'NOT_FOUND', `Agent 模板不存在: ${input.agentId}`)
1395
- const instConfig = { ...parseJson<Record<string, unknown>>(tpl.configJson, {}), ...input.configOverride }
1396
- // 绑定即执行入口:引擎未安装的模板不许入 channel(deploy/加成员在此失败,不产生半成品实例)
1397
- assertHarnessUsable(tpl.harness, instConfig)
1398
- if (input.role === 'lead') {
1399
- const channel = this.deps.repos.channels.findById(input.channelId)
1400
- if (channel && channel.leadAgentId) {
1401
- throw new AppError(409, 'LEAD_EXISTS', `channel ${input.channelId} 已存在 lead`)
1402
- }
1403
- }
1404
- const inst = this.deps.repos.channelAgents.create({
1405
- channelId: input.channelId,
1406
- templateId: tpl.id,
1407
- name: tpl.name,
1408
- harness: tpl.harness,
1409
- config: instConfig,
1410
- role: input.role,
1411
- })
1412
- if (input.role === 'lead') {
1413
- this.deps.repos.channels.update(input.channelId, { leadAgentId: inst.id })
1414
- }
1415
- this.notifyMember(input.channelId, {
1416
- op: 'added',
1417
- agentId: inst.id,
1418
- name: inst.name,
1419
- role: inst.role as 'lead' | 'worker',
1420
- harness: inst.harness,
1421
- enabled: inst.enabled,
1422
- config: parseJson<Record<string, unknown>>(inst.configJson, {}),
1423
- by: input.by ?? 'user',
1424
- reason: input.reason,
1425
- })
1426
- return instanceToAgentInfo(inst)
1427
- }
1428
-
1429
- async listChannelAgents(channelId: string): Promise<AgentInfo[]> {
1430
- return this.deps.repos.channelAgents.listByChannel(channelId).map(instanceToAgentInfo)
1431
- }
1432
-
1433
- /** Agent 记忆列表(私有观察面;content 还原为未切分原文,客户端可读):实例须存在于本 channel */
1434
- listMemories(channelId: string, agentId: string, limit = 50): MemoryRow[] {
1435
- const m = this.deps.repos.channelAgents.findByChannelAgent(channelId, agentId)
1436
- if (!m) throw new AppError(404, 'NOT_FOUND', `实例不存在: ${agentId}`)
1437
- return this.deps.repos.memories.listByAgent(agentId, limit)
1438
- .map(r => ({ ...r, content: unsegmentCJK(r.content) }))
1439
- }
1440
-
1441
- /**
1442
- * 记忆混合检索(REST/客户端观察面;与 agent 运行时 search_memory 工具同源算法):
1443
- * 以 targetAgent 视角召回(私有域 + 本 channel 公共域),scope 过滤同 recallRows。
1444
- * caller 须为本 channel 成员;返回结构化片段(综合分排序,content 未切分原文)。
1445
- */
1446
- async searchAgentMemories(
1447
- channelId: string,
1448
- callerAgentId: string,
1449
- targetAgentId: string,
1450
- input: { query: string, scope?: 'auto' | 'private' | 'shared', limit?: number },
1451
- opts: { byOwner?: boolean } = {},
1452
- ): Promise<MemorySnippet[]> {
1453
- // byOwner:人类 owner(channel 属主)经控制台检索,跳过 agent 成员校验
1454
- if (!opts.byOwner) this.requireMember(channelId, callerAgentId)
1455
- if (!this.deps.repos.channelAgents.findByChannelAgent(channelId, targetAgentId)) {
1456
- throw new AppError(404, 'NOT_FOUND', `Agent 实例不存在: ${targetAgentId}`)
1457
- }
1458
- const mem = new AgentMemory(this.deps.repos.memories, { channelId, agentId: targetAgentId, embedder: this.memoryEmbedder ?? undefined })
1459
- return mem.recallRows(input.query, { scope: input.scope, limit: input.limit })
1460
- }
1461
-
1462
- // ===== 团队共享记忆域(agent_id='__team__' 哨兵;lead 策展,channel 内全员 recall 可见)=====
1463
-
1464
- /** 团队共享记忆列表(channel 级;任意本 channel 成员可读;content 还原为未切分原文) */
1465
- listTeamMemories(channelId: string, limit = 50): MemoryRow[] {
1466
- if (!this.deps.repos.channels.findById(channelId)) throw new AppError(404, 'NOT_FOUND', `channel 不存在: ${channelId}`)
1467
- return this.deps.repos.memories.listByAgentChannel(channelId, TEAM_AGENT_ID, limit)
1468
- .map(r => ({ ...r, content: unsegmentCJK(r.content) }))
1469
- }
1470
-
1471
- /** 写/更新团队记忆(仅 lead;稳定 dedupKey 幂等刷新;成功后 fire-and-forget 向量化) */
1472
- addTeamMemory(channelId: string, callerAgentId: string, input: { title: string, content: string, importance?: number, dedupKey?: string }, opts: { byOwner?: boolean } = {}): MemoryRow[] {
1473
- // byOwner:人类 owner 策展(与 lead 同权;curator 身份以 __team__ 哨兵入事件)
1474
- if (!opts.byOwner) {
1475
- const caller = this.deps.repos.channelAgents.findByChannelAgent(channelId, callerAgentId)
1476
- if (!caller || caller.role !== 'lead') throw new AppError(403, 'SCOPE_VIOLATION', '仅 lead 可写团队记忆')
1477
- }
1478
- const dedupKey = input.dedupKey ?? `manual:${randomUUID()}`
1479
- this.deps.repos.memories.upsert({
1480
- channelId,
1481
- agentId: TEAM_AGENT_ID,
1482
- kind: 'semantic',
1483
- title: input.title,
1484
- titleFts: segmentCJK(input.title),
1485
- content: segmentCJK(input.content).slice(0, 800),
1486
- importance: input.importance ?? 0.9,
1487
- taskId: null,
1488
- dedupKey,
1489
- })
1490
- // 策展行同样入向量域(未切分原文;provider 未配置/失败 → 静默留 FTS)
1491
- void vectorizeMemory(this.deps.repos.memories, this.memoryEmbedder, channelId, TEAM_AGENT_ID, dedupKey, input.content).catch(() => {})
1492
- this.buses.get(channelId)?.notifyMemory({ agentId: callerAgentId, scope: 'shared', title: input.title, dedupKey })
1493
- return this.listTeamMemories(channelId)
1494
- }
1495
-
1496
- /** 删团队记忆(仅 lead;vec 行残留由维护任务统一清理) */
1497
- deleteTeamMemory(channelId: string, callerAgentId: string, memoryId: string, opts: { byOwner?: boolean } = {}): void {
1498
- if (!opts.byOwner) {
1499
- const caller = this.deps.repos.channelAgents.findByChannelAgent(channelId, callerAgentId)
1500
- if (!caller || caller.role !== 'lead') throw new AppError(403, 'SCOPE_VIOLATION', '仅 lead 可删团队记忆')
1501
- }
1502
- const row = this.deps.repos.memories.listByAgentChannel(channelId, TEAM_AGENT_ID, 1_000_000).find(r => r.id === memoryId)
1503
- if (!row) throw new AppError(404, 'NOT_FOUND', `团队记忆不存在: ${memoryId}`)
1504
- this.deps.repos.memories.delete(memoryId)
1505
- }
1506
-
1507
- /** 手动触发记忆衰减清理(REST 透传;策略与定时器同一函数) */
1508
- runMemoryMaintenanceNow(): MaintenanceResult {
1509
- return runMemoryMaintenance(this.deps.repos.memories)
1510
- }
1511
-
1512
- // ===== Agent 私有记忆策展(本人或 lead 写/删;kind='semantic' 人工策展)=====
1513
-
1514
- /** 写/更新 Agent 私有记忆(caller 须为本人或 lead;稳定 dedupKey 幂等刷新)。
1515
- * scope='shared'(caller 任意成员)→ 落 Channel 公共域(agent:<caller>:<key> 命名空间,全员可检索)。 */
1516
- addAgentMemory(channelId: string, callerAgentId: string, targetAgentId: string, input: { title: string, content: string, importance?: number, dedupKey?: string, scope?: 'private' | 'shared' }, opts: { byOwner?: boolean } = {}): void {
1517
- // byOwner:人类 owner 策展任意成员记忆(本人/lead 校验旁路;curator 以目标成员入事件)
1518
- if (!opts.byOwner) {
1519
- const caller = this.deps.repos.channelAgents.findByChannelAgent(channelId, callerAgentId)
1520
- if (!caller) throw new AppError(403, 'SCOPE_VIOLATION', '调用方 Agent 不在本 channel')
1521
- if (input.scope !== 'shared' && callerAgentId !== targetAgentId && caller.role !== 'lead') {
1522
- throw new AppError(403, 'SCOPE_VIOLATION', '仅本人或 lead 可策展 Agent 记忆')
1523
- }
1524
- }
1525
- if (input.scope === 'shared') {
1526
- // 共享域:走 AgentMemory.save 同源路径(命名空间 dedup + 自动向量化)
1527
- const mem = new AgentMemory(this.deps.repos.memories, { channelId, agentId: callerAgentId, embedder: this.memoryEmbedder ?? undefined })
1528
- void mem.save({
1529
- title: input.title,
1530
- content: input.content,
1531
- importance: input.importance,
1532
- scope: 'shared',
1533
- dedupKey: input.dedupKey,
1534
- }).then(saved => this.buses.get(channelId)?.notifyMemory({ agentId: callerAgentId, scope: 'shared', title: input.title, dedupKey: saved.dedupKey })).catch(() => {})
1535
- return
1536
- }
1537
- if (!this.deps.repos.channelAgents.findByChannelAgent(channelId, targetAgentId)) {
1538
- throw new AppError(404, 'NOT_FOUND', `Agent 实例不存在: ${targetAgentId}`)
1539
- }
1540
- const dedupKey = input.dedupKey ?? `manual:${randomUUID()}`
1541
- this.deps.repos.memories.upsert({
1542
- channelId,
1543
- agentId: targetAgentId,
1544
- kind: 'semantic',
1545
- title: input.title,
1546
- titleFts: segmentCJK(input.title),
1547
- content: segmentCJK(input.content).slice(0, 800),
1548
- importance: input.importance ?? 0.9,
1549
- taskId: null,
1550
- dedupKey,
1551
- })
1552
- // 策展行同样入向量域(未切分原文;provider 未配置/失败 → 静默留 FTS)
1553
- void vectorizeMemory(this.deps.repos.memories, this.memoryEmbedder, channelId, targetAgentId, dedupKey, input.content).catch(() => {})
1554
- this.buses.get(channelId)?.notifyMemory({ agentId: targetAgentId, scope: 'private', title: input.title, dedupKey })
1555
- }
1556
-
1557
- /** 删 Agent 私有记忆(caller 须为本人或 lead;行须属该 agent) */
1558
- deleteAgentMemory(channelId: string, callerAgentId: string, targetAgentId: string, memoryId: string, opts: { byOwner?: boolean } = {}): void {
1559
- if (!opts.byOwner) {
1560
- const caller = this.deps.repos.channelAgents.findByChannelAgent(channelId, callerAgentId)
1561
- if (!caller || (callerAgentId !== targetAgentId && caller.role !== 'lead')) {
1562
- throw new AppError(403, 'SCOPE_VIOLATION', '仅本人或 lead 可删除 Agent 记忆')
1563
- }
1564
- }
1565
- const row = this.deps.repos.memories.listByAgent(targetAgentId, 10_000)
1566
- .find(r => r.id === memoryId && r.channelId === channelId && r.agentId === targetAgentId)
1567
- if (!row) throw new AppError(404, 'NOT_FOUND', `记忆不存在: ${memoryId}`)
1568
- this.deps.repos.memories.delete(memoryId)
1569
- }
1570
-
1571
- /** 实例详情(含运行时装配状态) */
1572
- getChannelAgent(instanceId: string): (AgentInfo & { wired: boolean, runtimeState: 'idle' | 'busy' | 'stopped' | null }) | undefined {
1573
- const m = this.deps.repos.channelAgents.findById(instanceId)
1574
- if (!m) return undefined
1575
- const rt = this.runtimeOf(m.channelId, instanceId)
1576
- return {
1577
- ...instanceToAgentInfo(m),
1578
- wired: rt !== undefined,
1579
- runtimeState: rt ? rt.getState() : null,
1580
- }
1581
- }
1582
-
1583
- /** 更新实例(name/harness/config/enabled);变更后卸载已装配运行时以重载 */
1584
- async updateChannelAgent(
1585
- instanceId: string,
1586
- patch: { name?: string, harness?: string, config?: Record<string, unknown>, enabled?: number },
1587
- meta?: { channelId?: string, by?: string, reason?: string },
1588
- ): Promise<AgentInfo> {
1589
- const m = this.deps.repos.channelAgents.findById(instanceId)
1590
- if (!m) throw new AppError(404, 'NOT_FOUND', `实例不存在: ${instanceId}`)
1591
- if (patch.harness) assertHarnessUsable(patch.harness, patch.config ?? parseJson<Record<string, unknown>>(m.configJson, {}))
1592
- const updated = this.deps.repos.channelAgents.update(instanceId, patch)
1593
- if (!updated) throw new AppError(404, 'NOT_FOUND', `实例不存在: ${instanceId}`)
1594
- await this.unloadAgent(updated.channelId, instanceId)
1595
- this.notifyMember(updated.channelId, {
1596
- op: 'updated',
1597
- agentId: instanceId,
1598
- name: updated.name,
1599
- role: updated.role as 'lead' | 'worker',
1600
- harness: updated.harness,
1601
- enabled: updated.enabled,
1602
- config: parseJson<Record<string, unknown>>(updated.configJson, {}),
1603
- by: meta?.by ?? 'user',
1604
- reason: meta?.reason,
1605
- })
1606
- return instanceToAgentInfo(updated)
1607
- }
1608
-
1609
- /** 从 channel 移除实例(仅删实例,不删模板) */
1610
- async removeAgentFromChannel(channelId: string, instanceId: string, meta?: { by?: string, reason?: string }): Promise<void> {
1611
- const m = this.deps.repos.channelAgents.findByChannelAgent(channelId, instanceId)
1612
- if (!m) return
1613
- await this.stopAndDetach(channelId, instanceId)
1614
- if (m.role === 'lead') {
1615
- this.deps.repos.channels.update(channelId, { leadAgentId: null })
1616
- }
1617
- this.deps.repos.subscriptions.removeByAgent(channelId, instanceId)
1618
- this.deps.repos.channelAgents.remove(channelId, instanceId)
1619
- this.notifyMember(channelId, {
1620
- op: 'removed',
1621
- agentId: instanceId,
1622
- name: m.name,
1623
- role: m.role as 'lead' | 'worker',
1624
- harness: m.harness,
1625
- enabled: m.enabled,
1626
- by: meta?.by ?? 'user',
1627
- reason: meta?.reason,
1628
- })
1629
- }
1630
-
1631
- // ===== Lead 自主团队管理面(执行中扩容/调参/裁撤;工具桥 + 调度决策共用) =====
1632
-
1633
- /** lead 在本 channel 新建团队成员(worker):按需落模板(owner=channel 属主)并克隆为独立实例 */
1634
- async createTeamMember(
1635
- channelId: string,
1636
- callerAgentId: string,
1637
- input: { name: string, harness?: string, config?: Record<string, unknown>, templateId?: string, reason?: string },
1638
- ): Promise<AgentInfo> {
1639
- const caller = this.requireMember(channelId, callerAgentId)
1640
- if (caller.role !== 'lead') throw new AppError(403, 'SCOPE_VIOLATION', '仅 lead 可管理团队成员')
1641
- const channel = this.deps.repos.channels.findById(channelId)
1642
- if (!channel) throw new AppError(404, 'NOT_FOUND', `channel 不存在: ${channelId}`)
1643
- const name = input.name.trim()
1644
- if (!name) throw new AppError(400, 'BAD_REQUEST', '成员名不能为空')
1645
- let templateId = input.templateId
1646
- if (templateId) {
1647
- if (!this.deps.repos.agents.findById(templateId)) {
1648
- throw new AppError(404, 'NOT_FOUND', `Agent 模板不存在: ${templateId}`)
1649
- }
1650
- }
1651
- else {
1652
- const harness = input.harness ?? 'omp'
1653
- if (!KNOWN_HARNESSES.has(harness)) {
1654
- throw new AppError(400, 'UNKNOWN_HARNESS', `未知 harness: ${harness}(可选 ${[...KNOWN_HARNESSES].join('/')})`)
1655
- }
1656
- // 先校验引擎可用再落模板,防断言失败遗留孤儿模板行
1657
- assertHarnessUsable(harness, input.config)
1658
- const tpl = this.deps.repos.agents.create({
1659
- name,
1660
- harness,
1661
- config: input.config,
1662
- ownerUserId: channel.ownerUserId ?? null,
1663
- })
1664
- templateId = tpl.id
1665
- }
1666
- // 新成员立即装配:lead 建员即进入 channel 运行时(前端/调度立即可见,
1667
- // 无需等首次任务投递的懒加载;DB 已由 addAgentToChannel 同步落库)
1668
- const member = await this.addAgentToChannel({
1669
- channelId,
1670
- agentId: templateId,
1671
- role: 'worker',
1672
- by: `lead:${callerAgentId}`,
1673
- reason: input.reason,
1674
- })
1675
- this.ensureAgentRuntime(channelId, member.id)
1676
- return member
1677
- }
1678
-
1679
- /** lead 更新团队成员(改名/改配置/启停;不能改自己);变更后卸载运行时,下次消费按新配置重载 */
1680
- async updateTeamMember(
1681
- channelId: string,
1682
- callerAgentId: string,
1683
- agentId: string,
1684
- patch: { name?: string, config?: Record<string, unknown>, enabled?: number, reason?: string },
1685
- ): Promise<AgentInfo> {
1686
- const caller = this.requireMember(channelId, callerAgentId)
1687
- if (caller.role !== 'lead') throw new AppError(403, 'SCOPE_VIOLATION', '仅 lead 可管理团队成员')
1688
- if (agentId === callerAgentId) {
1689
- throw new AppError(400, 'BAD_REQUEST', 'lead 不能在执行中更新自己(避免自毁调度循环)')
1690
- }
1691
- const target = this.deps.repos.channelAgents.findByChannelAgent(channelId, agentId)
1692
- if (!target) throw new AppError(404, 'NOT_FOUND', `团队成员不存在: ${agentId}`)
1693
- return this.updateChannelAgent(agentId, patch, { channelId, by: `lead:${callerAgentId}`, reason: patch.reason })
1694
- }
1695
-
1696
- /**
1697
- * lead 移除团队成员(worker;不能移除自己)。
1698
- * 孤儿任务回收(成员移除后其任务不能悬死):
1699
- * - SUBMITTED/ASSIGNED(排队中)→ 重派给剩余队列最短的 worker;无接收者 → 取消
1700
- * - WORKING/WAITING(执行中)→ 中止运行时并置 FAILED,交调度循环按重试策略重派
1701
- */
1702
- async removeTeamMember(
1703
- channelId: string,
1704
- callerAgentId: string,
1705
- agentId: string,
1706
- reason?: string,
1707
- ): Promise<{ recycledTasks: string[] }> {
1708
- const caller = this.requireMember(channelId, callerAgentId)
1709
- if (caller.role !== 'lead') throw new AppError(403, 'SCOPE_VIOLATION', '仅 lead 可管理团队成员')
1710
- if (agentId === callerAgentId) {
1711
- throw new AppError(400, 'BAD_REQUEST', 'lead 不能移除自己(移除 lead 请用 REST 删除)')
1712
- }
1713
- const target = this.deps.repos.channelAgents.findByChannelAgent(channelId, agentId)
1714
- if (!target) throw new AppError(404, 'NOT_FOUND', `团队成员不存在: ${agentId}`)
1715
-
1716
- const recycledTasks: string[] = []
1717
- const orphans = this.deps.repos.tasks
1718
- .listByChannelAssignee(channelId, agentId)
1719
- .map(rowToTask)
1720
- .filter(t => !TERMINAL_TASK_STATES[t.state])
1721
- for (const task of orphans) {
1722
- if (task.state === 'SUBMITTED' || task.state === 'ASSIGNED') {
1723
- const receiver = this.pickReceiverWorker(channelId, agentId)
1724
- if (receiver) {
1725
- this.getTaskEngine().reassign(task.id, receiver)
1726
- this.wakeAgent(channelId, receiver)
1727
- }
1728
- else {
1729
- this.getTaskEngine().cancel(task.id, callerAgentId)
1730
- }
1731
- }
1732
- else {
1733
- // WORKING/WAITING:先中止在跑回合,再走 FAILED(调度循环 retry/reassign 兜底)
1734
- this.runtimeOf(channelId, agentId)?.abortCurrent()
1735
- if (task.state === 'WAITING') {
1736
- this.getTaskEngine().transition(task.id, 'WORKING', callerAgentId)
1737
- }
1738
- this.getTaskEngine().transition(task.id, 'FAILED', callerAgentId)
1739
- }
1740
- recycledTasks.push(task.id)
1741
- }
1742
-
1743
- await this.removeAgentFromChannel(channelId, agentId, { by: `lead:${callerAgentId}`, reason })
1744
- // lead 现场创建的一次性模板:无任何 channel 实例、未被编组引用 → 连模板一并删除
1745
- // (数据库信息彻底清理;有外部引用则保留模板,仅删实例行)
1746
- if (target.templateId) {
1747
- const instances = this.deps.repos.channelAgents.listByTemplate(target.templateId)
1748
- const teamRefs = this.deps.repos.teamMembers.listByTemplate(target.templateId)
1749
- if (instances.length === 0 && teamRefs.length === 0) {
1750
- this.deps.repos.agents.remove(target.templateId)
1751
- }
1752
- }
1753
- return { recycledTasks }
1754
- }
1755
-
1756
- /** 剩余可用 worker 里选队列最短者(成员移除重派接收者) */
1757
- private pickReceiverWorker(channelId: string, excludeAgentId: string): string | null {
1758
- const candidates = this.deps.repos.channelAgents
1759
- .listByChannel(channelId)
1760
- .filter(m => m.enabled === 1 && m.role === 'worker' && m.id !== excludeAgentId)
1761
- let best: string | null = null
1762
- let bestLen = Number.POSITIVE_INFINITY
1763
- for (const m of candidates) {
1764
- const len = this.getTaskEngine().queueViewOf(channelId, m.id).queued.length
1765
- if (len < bestLen) {
1766
- best = m.id
1767
- bestLen = len
1768
- }
1769
- }
1770
- return best
1771
- }
1772
-
1773
- // ===== AgentTeam 管理面(模板编组 + 批量部署;v10 可见性隔离) =====
1774
-
1775
- /** 创建 AgentTeam */
1776
- async createTeam(input: { name: string, description?: string, visibility?: string, ownerUserId?: string | null, plugins?: ChannelPluginToggle[] }): Promise<AgentTeamDetail> {
1777
- const row = this.deps.repos.teams.create({ name: input.name, description: input.description, visibility: input.visibility, ownerUserId: input.ownerUserId ?? null })
1778
- // 建队时的插件勾选:以 team id 为键落 channel_plugins(team 作用域偏好),
1779
- // 部署 deployTeamToChannel 时传导到目标 channel(未配置 = 全启用,向后兼容)
1780
- if (input.plugins?.length) getChannelPluginsRepo().setMany(row.id, input.plugins)
1781
- return this.teamDetailOf(row)
1782
- }
1783
-
1784
- /** 全部 AgentTeam */
1785
- async listTeams(): Promise<AgentTeamDetail[]> {
1786
- return this.deps.repos.teams.list().map(row => this.teamDetailOf(row))
1787
- }
1788
-
1789
- /** 用户视角编组列表(本人 + 遗留公共) */
1790
- async listTeamsForUser(userId: string): Promise<AgentTeamDetail[]> {
1791
- return this.deps.repos.teams.listForOwner(userId).map(row => this.teamDetailOf(row))
1792
- }
1793
-
1794
- /** 可见性感知列表:普通用户 = 本人(任意可见性)+ 全部 public(含内置);admin = 全量 */
1795
- async listTeamsVisibleTo(user: ActingUser): Promise<AgentTeamDetail[]> {
1796
- const rows = user.role === 'admin'
1797
- ? this.deps.repos.teams.list()
1798
- : this.deps.repos.teams.listVisible(user.id)
1799
- return rows.map(row => this.teamDetailOf(row))
1800
- }
1801
-
1802
- /** AgentTeam 详情(含成员模板快照);不存在返回 undefined */
1803
- getTeam(teamId: string): AgentTeamDetail | undefined {
1804
- const row = this.deps.repos.teams.findById(teamId)
1805
- if (!row) return undefined
1806
- return this.teamDetailOf(row)
1807
- }
1808
-
1809
- /** 更新 AgentTeam(name/description/visibility) */
1810
- async updateTeam(teamId: string, patch: { name?: string, description?: string, visibility?: string }): Promise<AgentTeamDetail> {
1811
- const updated = this.deps.repos.teams.update(teamId, patch)
1812
- if (!updated) throw new AppError(404, 'NOT_FOUND', `AgentTeam 不存在: ${teamId}`)
1813
- return this.teamDetailOf(updated)
1814
- }
1815
-
1816
- /** 删除 AgentTeam(仅删编组关系,不动模板与其已部署实例) */
1817
- async removeTeam(teamId: string): Promise<void> {
1818
- this.deps.repos.teams.remove(teamId)
1819
- }
1820
-
1821
- /** 把 Agent 模板加入 AgentTeam(同 team 内模板唯一;至多一个 lead) */
1822
- async addTemplateToTeam(input: { teamId: string, templateId: string, role?: 'lead' | 'worker' }): Promise<AgentTeamDetail> {
1823
- const team = this.deps.repos.teams.findById(input.teamId)
1824
- if (!team) throw new AppError(404, 'NOT_FOUND', `AgentTeam 不存在: ${input.teamId}`)
1825
- const tpl = this.deps.repos.agents.findById(input.templateId)
1826
- if (!tpl) throw new AppError(404, 'NOT_FOUND', `Agent 模板不存在: ${input.templateId}`)
1827
- const role = input.role ?? 'worker'
1828
- if (this.deps.repos.teamMembers.findByTeamTemplate(input.teamId, input.templateId)) {
1829
- throw new AppError(409, 'ALREADY_MEMBER', `模板 ${input.templateId} 已在 team ${input.teamId} 中`)
1830
- }
1831
- if (role === 'lead' && this.deps.repos.teamMembers.countLead(input.teamId) > 0) {
1832
- throw new AppError(409, 'LEAD_EXISTS', `team ${input.teamId} 已存在 lead`)
1833
- }
1834
- this.deps.repos.teamMembers.add({ teamId: input.teamId, templateId: input.templateId, role })
1835
- return this.teamDetailOf(team)
1836
- }
1837
-
1838
- /** 从 AgentTeam 移除 Agent 模板(仅删编组关系) */
1839
- async removeTemplateFromTeam(teamId: string, templateId: string): Promise<AgentTeamDetail> {
1840
- const team = this.deps.repos.teams.findById(teamId)
1841
- if (!team) throw new AppError(404, 'NOT_FOUND', `AgentTeam 不存在: ${teamId}`)
1842
- const member = this.deps.repos.teamMembers.findByTeamTemplate(teamId, templateId)
1843
- if (!member) throw new AppError(404, 'NOT_FOUND', `模板 ${templateId} 不在 team ${teamId} 中`)
1844
- this.deps.repos.teamMembers.remove(teamId, templateId)
1845
- return this.teamDetailOf(team)
1846
- }
1847
-
1848
- /**
1849
- * 批量部署 AgentTeam → Channel:对每个成员模板调用 addAgentToChannel 克隆出独立实例。
1850
- * - channel 已有 lead 且 team 成员含 lead → 该成员 409 LEAD_EXISTS,默认整体失败(事务性语义)。
1851
- * 实际上为简化:逐个克隆,失败时抛错(已克隆实例保留,调用方可 remove 重试)。
1852
- * - 返回每个成员的部署结果(实例 AgentInfo)。
1853
- */
1854
- async deployTeamToChannel(input: {
1855
- channelId: string
1856
- teamId: string
1857
- }): Promise<{ channelId: string, teamId: string, agents: AgentInfo[] }> {
1858
- const channel = this.deps.repos.channels.findById(input.channelId)
1859
- if (!channel) throw new AppError(404, 'NOT_FOUND', `channel 不存在: ${input.channelId}`)
1860
- const team = this.deps.repos.teams.findById(input.teamId)
1861
- if (!team) throw new AppError(404, 'NOT_FOUND', `AgentTeam 不存在: ${input.teamId}`)
1862
- const members = this.deps.repos.teamMembers.listByTeam(input.teamId)
1863
- if (members.length === 0) {
1864
- throw new AppError(400, 'TEAM_EMPTY', `team ${input.teamId} 无成员,先添加 Agent 模板`)
1865
- }
1866
- const agents: AgentInfo[] = []
1867
- for (const m of members) {
1868
- const inst = await this.addAgentToChannel({
1869
- channelId: input.channelId,
1870
- agentId: m.templateId,
1871
- role: m.role === 'lead' ? 'lead' : 'worker',
1872
- })
1873
- agents.push(inst)
1874
- }
1875
- // 团队插件开关传导:建队/团队设置显式配置过的开关随部署落到目标 channel
1876
- // (以 team id 为键的偏好 → 以 channel id 为键;工具注入与 dispatch 同源过滤)
1877
- const teamPlugins = getChannelPluginsRepo().explicitFor(input.teamId)
1878
- if (teamPlugins && teamPlugins.size) {
1879
- getChannelPluginsRepo().setMany(input.channelId, [...teamPlugins].map(([name, enabled]) => ({ name, enabled })))
1880
- }
1881
- return { channelId: input.channelId, teamId: input.teamId, agents }
1882
- }
1883
-
1884
- private teamDetailOf(row: TeamRow): AgentTeamDetail {
1885
- const members = this.deps.repos.teamMembers.listByTeam(row.id)
1886
- return {
1887
- id: row.id,
1888
- name: row.name,
1889
- description: row.description,
1890
- visibility: row.ownerUserId === null ? 'public' : row.visibility,
1891
- isBuiltin: row.ownerUserId === null,
1892
- ownerUserId: row.ownerUserId ?? null,
1893
- members: members.map((m) => {
1894
- const tpl = this.deps.repos.agents.findById(m.templateId)
1895
- return {
1896
- templateId: m.templateId,
1897
- name: tpl?.name ?? '(deleted)',
1898
- harness: tpl?.harness ?? '',
1899
- role: m.role === 'lead' ? 'lead' : 'worker',
1900
- addedAt: m.createdAt,
1901
- }
1902
- }),
1903
- createdAt: row.createdAt,
1904
- updatedAt: row.updatedAt,
1905
- }
1906
- }
1907
-
1908
- // ===== Channel 模板管理面(v10:场景 + 工作目录 + 成员组合;实例化一键建 channel) =====
1909
-
1910
- /** 可见性感知 Channel 模板列表:普通用户 = 本人 + public(含内置);admin = 全量 */
1911
- listChannelTemplatesVisibleTo(user: ActingUser): ChannelTemplateDetail[] {
1912
- const rows = user.role === 'admin'
1913
- ? this.deps.repos.channelTemplates.list()
1914
- : this.deps.repos.channelTemplates.listVisible(user.id)
1915
- return rows.map(row => this.channelTemplateDetailOf(row))
1916
- }
1917
-
1918
- /** Channel 模板详情;不存在返回 undefined */
1919
- getChannelTemplate(templateId: string): ChannelTemplateDetail | undefined {
1920
- const row = this.deps.repos.channelTemplates.findById(templateId)
1921
- if (!row) return undefined
1922
- return this.channelTemplateDetailOf(row)
1923
- }
1924
-
1925
- /** 创建 Channel 模板 */
1926
- createChannelTemplate(input: {
1927
- name: string
1928
- description?: string
1929
- scenarioPrompt?: string
1930
- workspace?: string
1931
- lead?: { name: string, harness: string, config?: Record<string, unknown> } | null
1932
- members?: ChannelTemplateMember[]
1933
- visibility?: string
1934
- ownerUserId: string
1935
- }): ChannelTemplateDetail {
1936
- this.assertHarness(input.lead?.harness)
1937
- const row = this.deps.repos.channelTemplates.create({
1938
- name: input.name,
1939
- description: input.description,
1940
- scenarioPrompt: input.scenarioPrompt,
1941
- workspace: input.workspace,
1942
- lead: input.lead ?? null,
1943
- members: input.members ?? [],
1944
- visibility: input.visibility,
1945
- ownerUserId: input.ownerUserId,
1946
- })
1947
- return this.channelTemplateDetailOf(row)
1948
- }
1949
-
1950
- /** 从既有 Channel 实例捕获模板:场景 + 工作目录 + lead(内联)+ 成员(有模板引用则引用,否则内联快照) */
1951
- createChannelTemplateFromChannel(channelId: string, input: { name: string, description?: string, visibility?: string }, ownerUserId: string): ChannelTemplateDetail {
1952
- const channel = this.deps.repos.channels.findById(channelId)
1953
- if (!channel) throw new AppError(404, 'NOT_FOUND', `channel 不存在: ${channelId}`)
1954
- const members = this.deps.repos.channelAgents.listByChannel(channelId)
1955
- .filter(m => m.id !== channel.leadAgentId)
1956
- .map((m): ChannelTemplateMember => m.templateId
1957
- ? { templateId: m.templateId, role: m.role === 'lead' ? 'lead' : 'worker' }
1958
- : { inline: { name: m.name, harness: m.harness, config: parseJson<Record<string, unknown>>(m.configJson, {}) }, role: m.role === 'lead' ? 'lead' : 'worker' })
1959
- const leadInst = channel.leadAgentId
1960
- ? this.deps.repos.channelAgents.findById(channel.leadAgentId)
1961
- : undefined
1962
- const lead = leadInst
1963
- ? {
1964
- name: leadInst.name,
1965
- harness: leadInst.harness,
1966
- config: parseJson<Record<string, unknown>>(leadInst.configJson, {}),
1967
- }
1968
- : null
1969
- const row = this.deps.repos.channelTemplates.create({
1970
- name: input.name,
1971
- description: input.description,
1972
- scenarioPrompt: channel.scenarioPrompt,
1973
- workspace: channel.workspace,
1974
- lead,
1975
- members,
1976
- visibility: input.visibility,
1977
- ownerUserId,
1978
- })
1979
- return this.channelTemplateDetailOf(row)
1980
- }
1981
-
1982
- /** 更新 Channel 模板(属主/admin;内置拒绝) */
1983
- updateChannelTemplate(templateId: string, patch: Parameters<ChannelTemplateRepo['update']>[1]): ChannelTemplateDetail {
1984
- const updated = this.deps.repos.channelTemplates.update(templateId, patch)
1985
- if (!updated) throw new AppError(404, 'NOT_FOUND', `Channel 模板不存在: ${templateId}`)
1986
- return this.channelTemplateDetailOf(updated)
1987
- }
1988
-
1989
- /** 删除 Channel 模板(属主/admin;内置拒绝) */
1990
- removeChannelTemplate(templateId: string): void {
1991
- this.deps.repos.channelTemplates.remove(templateId)
1992
- }
1993
-
1994
- /**
1995
- * 实例化 Channel 模板 → 新 channel(属主 = 操作用户):
1996
- * 场景/工作目录照搬;lead 内联创建;成员逐个克隆(引用模板时校验操作者可读)。
1997
- * 返回 createChannel 同构结果 + 成员实例数。
1998
- */
1999
- async instantiateChannelTemplate(templateId: string, user: ActingUser, nameOverride?: string): Promise<{ channelId: string, workspace: string, agentCount: number, leadAgentId?: string }> {
2000
- const tpl = this.deps.repos.channelTemplates.findById(templateId)
2001
- if (!tpl) throw new AppError(404, 'NOT_FOUND', `Channel 模板不存在: ${templateId}`)
2002
- this.requireTemplateReadable(tpl, user, 'Channel 模板')
2003
- const lead = tpl.leadJson
2004
- ? parseJson<{ name: string, harness: string, config?: Record<string, unknown> } | null>(tpl.leadJson, null)
2005
- : null
2006
- const created = await this.createChannel({
2007
- name: (nameOverride && nameOverride.trim()) || tpl.name,
2008
- description: tpl.description,
2009
- scenarioPrompt: tpl.scenarioPrompt,
2010
- workspace: tpl.workspace || undefined,
2011
- leadAgent: lead ? { name: lead.name, harness: lead.harness, config: lead.config } : undefined,
2012
- ownerUserId: user.id,
2013
- })
2014
- const members = parseJson<ChannelTemplateMember[]>(tpl.membersJson, [])
2015
- let agentCount = lead ? 1 : 0
2016
- for (const m of members) {
2017
- if ('templateId' in m) {
2018
- const tplRow = this.deps.repos.agents.findById(m.templateId)
2019
- if (!tplRow) throw new AppError(404, 'NOT_FOUND', `成员 Agent 模板不存在: ${m.templateId}`)
2020
- this.requireTemplateReadable(tplRow, user, '成员 Agent 模板')
2021
- await this.addAgentToChannel({ channelId: created.channelId, agentId: m.templateId, role: m.role, by: 'template' })
2022
- }
2023
- else {
2024
- this.assertHarness(m.inline.harness)
2025
- const inlineTpl = await this.createAgent({ name: m.inline.name, harness: m.inline.harness, config: m.inline.config, ownerUserId: user.id })
2026
- await this.addAgentToChannel({ channelId: created.channelId, agentId: inlineTpl.id, role: m.role, by: 'template' })
2027
- }
2028
- agentCount += 1
2029
- }
2030
- return { channelId: created.channelId, workspace: created.workspace, agentCount, leadAgentId: created.leadAgentId }
2031
- }
2032
-
2033
- private assertHarness(harness: string | undefined): void {
2034
- if (harness && !KNOWN_HARNESSES.has(harness)) {
2035
- throw new AppError(400, 'BAD_REQUEST', `未知 harness: ${harness}`)
2036
- }
2037
- }
2038
-
2039
- private channelTemplateDetailOf(row: ChannelTemplateRow): ChannelTemplateDetail {
2040
- return {
2041
- id: row.id,
2042
- name: row.name,
2043
- description: row.description,
2044
- scenarioPrompt: row.scenarioPrompt,
2045
- workspace: row.workspace,
2046
- lead: row.leadJson ? parseJson<ChannelTemplateDetail['lead']>(row.leadJson, null) : null,
2047
- members: parseJson<ChannelTemplateMember[]>(row.membersJson, []),
2048
- visibility: row.ownerUserId === null ? 'public' : row.visibility,
2049
- isBuiltin: row.ownerUserId === null,
2050
- ownerUserId: row.ownerUserId ?? null,
2051
- createdAt: row.createdAt,
2052
- updatedAt: row.updatedAt,
2053
- }
2054
- }
2055
-
2056
- // ===== 任务作业面 =====
2057
-
2058
- /**
2059
- * 人类向 channel 提交任务(HITL 控制面入口):
2060
- * - 缺省 assigneeId → 自动路由 lead(原行为);
2061
- * - 指定 assigneeId(Composer @ 某成员)→ 直发该成员:任务 create→ASSIGNED,
2062
- * assign 消息直投其信箱(不经 lead 调度,人类即此刻的调度者);
2063
- * - fromLabel(登录用户名)盖章 x-aw-from-label → 时间线以"用户章"渲染发送者。
2064
- */
2065
- async submitChannelTask(input: {
2066
- channelId: string
2067
- title: string
2068
- description?: string
2069
- parts?: Part[]
2070
- mode?: ExecutionMode
2071
- modeConfig?: ModeConfig
2072
- /** HITL 直发目标(缺省 lead);须为本 channel 启用成员 */
2073
- assigneeId?: string
2074
- /** 人类发送者显示名(时间线归属) */
2075
- fromLabel?: string
2076
- }): Promise<WorkspaceTask> {
2077
- const channel = this.deps.repos.channels.findById(input.channelId)
2078
- if (!channel || !channel.leadAgentId) {
2079
- throw new AppError(400, 'NO_LEAD_AGENT', `channel ${input.channelId} 无 lead,请先创建 lead`)
2080
- }
2081
- if (channel.enabled !== 1) {
2082
- throw new AppError(403, 'CHANNEL_DISABLED', `channel ${input.channelId} 已禁用`)
2083
- }
2084
- this.ensureChannelActive(input.channelId)
2085
- // 入口幂等(数据状态驱动):同 channel 同标题且**非终态**的任务已存在 → 409。
2086
- // 挡住 HITL 双击/客户端重试造成的重复执行;前一轮已 COMPLETED 的 loop 重放
2087
- // (LoopController → 本方法)不受影响 —— 终态不参与判定
2088
- const duplicate = this.getTaskEngine().list(input.channelId).find(t =>
2089
- t.title === input.title
2090
- && t.state !== 'COMPLETED' && t.state !== 'FAILED' && t.state !== 'CANCELED')
2091
- if (duplicate) {
2092
- throw new AppError(409, 'TASK_DUPLICATE', `同标题任务已在途:「${input.title}」(${duplicate.id.slice(0, 8)},${duplicate.state}),请等待其完成或取消后再提交`)
2093
- }
2094
- // HITL 直发目标校验 + 容错寻址(id/名字/唯一前缀;人类输入名字即可直发)
2095
- let assigneeId = channel.leadAgentId
2096
- if (input.assigneeId && input.assigneeId !== channel.leadAgentId) {
2097
- assigneeId = this.resolveMemberRef(input.channelId, input.assigneeId).id
2098
- }
2099
- // 任务执行前强校验:收件引擎不可用直接 409(不留「已创建即失败」的幽灵任务)
2100
- const assigneeRow = this.deps.repos.channelAgents.findByChannelAgent(input.channelId, assigneeId)
2101
- if (assigneeRow) assertHarnessUsable(assigneeRow.harness, parseJson<Record<string, unknown>>(assigneeRow.configJson, {}))
2102
- const description = input.mode
2103
- ? encodeTaskMode(input.mode, input.modeConfig ?? {}, input.description ?? '')
2104
- : input.description
2105
- let task = this.getTaskEngine().create({
2106
- channelId: input.channelId,
2107
- creatorId: '',
2108
- assigneeId,
2109
- title: input.title,
2110
- description,
2111
- parts: input.parts,
2112
- })
2113
- // 直发 worker:补 ASSIGNED 迁移(与 dispatchTask 独立任务同构,worker 消费循环按 assign 起回合)
2114
- if (assigneeId !== channel.leadAgentId) {
2115
- task = this.getTaskEngine().transition(task.id, 'ASSIGNED', 'system')
2116
- }
2117
- const messageMetadata: Record<string, unknown> = {
2118
- 'x-aw-task-kind': 'assign',
2119
- 'x-aw-task-id': task.id,
2120
- }
2121
- if (input.fromLabel) messageMetadata['x-aw-from-label'] = input.fromLabel
2122
- const message = buildMessage(input.channelId, 'ROLE_USER', input.parts ?? [], messageMetadata)
2123
- message.taskId = task.id
2124
- const delivered = this.route(input.channelId, message)
2125
- if (!delivered.includes(assigneeId)) {
2126
- // 投递失败补偿:任务回收终态(不留幽灵任务,用户重试不再累积重复任务)
2127
- this.getTaskEngine().transition(task.id, 'CANCELED', 'system')
2128
- throw new AppError(502, 'DELIVERY_FAILED', `任务指派未能投递到 ${assigneeId.slice(0, 8)} 的信箱,请重试`)
2129
- }
2130
- if (assigneeId !== channel.leadAgentId) this.wakeAgent(input.channelId, assigneeId)
2131
- this.ensureChannelRuntime(input.channelId).wakeScheduler()
2132
- return task
2133
- }
2134
-
2135
- async dispatchTask(
2136
- channelId: string,
2137
- callerAgentId: string,
2138
- input: {
2139
- parentTaskId?: string
2140
- assigneeId: string
2141
- title: string
2142
- description?: string
2143
- parts?: Part[]
2144
- routeReason?: string
2145
- },
2146
- ): Promise<WorkspaceTask> {
2147
- const caller = this.requireMember(channelId, callerAgentId)
2148
- if (caller.role !== 'lead') {
2149
- throw new AppError(403, 'SCOPE_VIOLATION', '仅 lead 可 dispatch 任务')
2150
- }
2151
- const assignee = this.deps.repos.channelAgents.findByChannelAgent(channelId, input.assigneeId)
2152
- if (!assignee) {
2153
- throw new AppError(403, 'SCOPE_VIOLATION', 'assignee 不在本 channel')
2154
- }
2155
- // 执行前强校验:worker 引擎未安装 → 报错回 lead(可改派),不产生必败子任务
2156
- assertHarnessUsable(assignee.harness, parseJson<Record<string, unknown>>(assignee.configJson, {}))
2157
- let task: WorkspaceTask
2158
- if (input.parentTaskId) {
2159
- const parent = this.getTaskEngine().get(input.parentTaskId)
2160
- if (!parent) throw new AppError(404, 'NOT_FOUND', `父任务不存在: ${input.parentTaskId}`)
2161
- if (parent.channelId !== channelId) {
2162
- throw new AppError(403, 'SCOPE_VIOLATION', '父任务不在本 channel')
2163
- }
2164
- // 防重复派发守卫(确定性,不依赖 LLM 纪律):同父任务下同标题子任务
2165
- // - 在途(非终态)→ 拒绝,告知等待现有执行(省 token 不重跑)
2166
- // - 已完成且有交付 → 拒绝,直接附上既有成果预览(lead 可引用,不必重做)
2167
- const norm = (s: string): string => s.replace(/\s+/g, ' ').trim().toLowerCase()
2168
- const siblings = this.getTaskEngine().list(channelId).filter(t => t.parentId === input.parentTaskId)
2169
- const dupTitle = (t: WorkspaceTask): boolean => norm(t.title) === norm(input.title)
2170
- const inFlight = siblings.find(t => dupTitle(t) && !['COMPLETED', 'CANCELED', 'FAILED'].includes(t.state))
2171
- if (inFlight) {
2172
- throw new AppError(409, 'DUPLICATE_DISPATCH', `子任务 "${input.title}" 已在执行中(状态 ${inFlight.state},指派 ${inFlight.assigneeId?.slice(0, 8) ?? '?'})。不要重复派发——等待其完成;若内容有差异请换一个能区分意图的标题。`)
2173
- }
2174
- const done = siblings.find(t => dupTitle(t) && t.state === 'COMPLETED' && t.artifacts.length > 0)
2175
- if (done) {
2176
- const preview = done.artifacts[0]?.parts
2177
- ?.map(p => ('text' in p ? p.text : ''))
2178
- .join(' ')
2179
- .replace(/\s+/g, ' ')
2180
- .trim()
2181
- .slice(0, 300) ?? ''
2182
- throw new AppError(409, 'DUPLICATE_DISPATCH', `子任务 "${input.title}" 已完成并交付(任务 ${done.id})。已有成果:${preview || '(见任务详情)'}。直接引用该成果即可,不要重复派发相同工作。`)
2183
- }
2184
- task = this.getTaskEngine().dispatch(parent, {
2185
- assigneeId: input.assigneeId,
2186
- title: input.title,
2187
- description: input.description,
2188
- parts: input.parts,
2189
- routeReason: input.routeReason,
2190
- })
2191
- this.wakeAgent(channelId, input.assigneeId)
2192
- }
2193
- else {
2194
- task = this.getTaskEngine().create({
2195
- channelId,
2196
- creatorId: callerAgentId,
2197
- assigneeId: input.assigneeId,
2198
- title: input.title,
2199
- description: input.description,
2200
- parts: input.parts,
2201
- })
2202
- task = this.getTaskEngine().transition(task.id, 'ASSIGNED', callerAgentId)
2203
- const message = buildMessage(channelId, 'ROLE_USER', input.parts ?? [], {
2204
- 'x-aw-task-kind': 'assign',
2205
- 'x-aw-task-id': task.id,
2206
- 'x-aw-from-agent': callerAgentId,
2207
- })
2208
- message.taskId = task.id
2209
- const delivered = this.route(channelId, message)
2210
- if (!delivered.includes(input.assigneeId)) {
2211
- // 投递失败补偿:子任务回收终态(父任务等全部子任务终态后由调度器重新决策)
2212
- this.getTaskEngine().transition(task.id, 'CANCELED', callerAgentId)
2213
- throw new AppError(502, 'DELIVERY_FAILED', `子任务指派未能投递到 ${input.assigneeId.slice(0, 8)} 的信箱,请重试或改派`)
2214
- }
2215
- }
2216
- return task
2217
- }
2218
-
2219
- /**
2220
- * 任务拒绝(assignee 认为任务超出自己能力/作业范畴时主动退回):
2221
- * - 任务置 FAILED(调度器将按重试规则改派他人,而非本 Agent 硬扛或静默搁置);
2222
- * - 回执拒绝通知:优先发任务创建者(本 channel 成员),否则 channel lead ——
2223
- * 有发送人就必须让对方知道"为什么被拒",防止错发任务石沉大海。
2224
- */
2225
- async refuseTask(
2226
- channelId: string,
2227
- refuserId: string,
2228
- taskId: string,
2229
- reason: string,
2230
- ): Promise<{ task: WorkspaceTask, notifiedTo: string | null }> {
2231
- this.requireMember(channelId, refuserId)
2232
- const engine = this.getTaskEngine()
2233
- const task = engine.get(taskId)
2234
- if (!task || task.channelId !== channelId) {
2235
- throw new AppError(404, 'NOT_FOUND', `任务不存在或不在本 channel: ${taskId}`)
2236
- }
2237
- if (task.assigneeId !== refuserId) {
2238
- throw new AppError(403, 'SCOPE_VIOLATION', `只能拒绝指派给自己的任务(assignee=${task.assigneeId.slice(0, 8)})`)
2239
- }
2240
- if (task.state === 'WAITING') {
2241
- throw new AppError(400, 'INVALID_TRANSITION', 'WAITING 父任务(有子任务/阶段在执行)不可整体拒绝;请拒绝对应的子任务,父任务会按子任务结果汇总')
2242
- }
2243
- const trimmedReason = reason.trim()
2244
- if (!trimmedReason) throw new AppError(400, 'BAD_REQUEST', '拒绝必须说明原因(reason)')
2245
-
2246
- let current = task
2247
- if (!TERMINAL_TASK_STATES[current.state]) {
2248
- // 状态机需经 WORKING 到 FAILED(SUBMITTED/ASSIGNED 直达 FAILED 非法)
2249
- if (current.state === 'SUBMITTED' || current.state === 'ASSIGNED') {
2250
- current = engine.transition(taskId, 'WORKING', refuserId)
2251
- }
2252
- if (current.state !== 'FAILED') {
2253
- current = engine.transition(taskId, 'FAILED', refuserId)
2254
- }
2255
- // 拒绝理由进任务历史(审计留痕)
2256
- this.deps.repos.tasks.update(taskId, {
2257
- history: [...current.history, {
2258
- messageId: randomUUID(),
2259
- contextId: channelId,
2260
- role: 'ROLE_AGENT' as const,
2261
- parts: [{ text: `[任务拒绝] ${refuserId.slice(0, 8)}:${trimmedReason}` }],
2262
- }],
2263
- })
2264
- }
2265
-
2266
- // 回执对象:任务创建者(仍为本 channel 在册成员)优先,fallback channel lead
2267
- const members = this.deps.repos.channelAgents.listByChannel(channelId).filter(m => m.enabled === 1)
2268
- const notifyTo = members.find(m => m.id === task.creatorId)?.id
2269
- ?? members.find(m => m.role === 'lead')?.id
2270
- ?? null
2271
- if (notifyTo && notifyTo !== refuserId) {
2272
- const message = buildMessage(channelId, 'ROLE_AGENT', [{
2273
- text: `【任务拒绝回执】任务「${task.title}」(${taskId.slice(0, 8)}) 已被 ${refuserId.slice(0, 8)} 拒绝。原因:${trimmedReason}。请改派给能力匹配的成员,或取消该任务。`,
2274
- }], {
2275
- 'x-aw-target-agent': notifyTo,
2276
- 'x-aw-from-agent': refuserId,
2277
- 'x-aw-msg-priority': 'immediate',
2278
- })
2279
- const delivered = this.route(channelId, message)
2280
- return { task: engine.get(taskId) ?? current, notifiedTo: delivered.includes(notifyTo) ? notifyTo : null }
2281
- }
2282
- return { task: engine.get(taskId) ?? current, notifiedTo: null }
2283
- }
2284
-
2285
- async reportTask(
2286
- channelId: string,
2287
- callerAgentId: string,
2288
- input: { taskId: string, progress?: number, artifact?: A2AArtifact, message?: string },
2289
- ): Promise<WorkspaceTask> {
2290
- const task = this.requireTaskInScope(channelId, callerAgentId, input.taskId)
2291
- if (task.assigneeId !== callerAgentId) {
2292
- throw new AppError(403, 'SCOPE_VIOLATION', '仅 assignee 可上报任务')
2293
- }
2294
- // 终态设防:进度/交付物/历史是任务活性信号,终态任务(COMPLETED/FAILED/CANCELED)
2295
- // 不得再写 —— 否则状态数据被污染(如 cancel 后迟到回合继续长出"新进度"),
2296
- // 破坏"所有执行都标记 state"的数据状态驱动不变量
2297
- if (task.state === 'COMPLETED' || task.state === 'FAILED' || task.state === 'CANCELED') {
2298
- return task
2299
- }
2300
- const patch: TaskPatch = {}
2301
- if (input.progress !== undefined) patch.progress = input.progress
2302
- if (input.artifact) patch.artifacts = [...task.artifacts, input.artifact]
2303
- if (input.message) {
2304
- patch.history = [
2305
- ...task.history,
2306
- { messageId: randomUUID(), contextId: task.channelId, role: 'ROLE_AGENT' as const, parts: [{ text: input.message }] },
2307
- ].slice(-200)
2308
- }
2309
- const updated = this.deps.repos.tasks.update(input.taskId, patch)
2310
- const next = rowToTask(updated!)
2311
- this.notifyTask(task.channelId, { taskId: task.id, progress: next.progress, agentId: callerAgentId })
2312
- return next
2313
- }
2314
-
2315
- async completeTask(
2316
- channelId: string,
2317
- callerAgentId: string,
2318
- input: { taskId: string, artifacts?: A2AArtifact[] },
2319
- ): Promise<WorkspaceTask> {
2320
- const task = this.requireTaskInScope(channelId, callerAgentId, input.taskId)
2321
- if (task.assigneeId !== callerAgentId) {
2322
- throw new AppError(403, 'SCOPE_VIOLATION', '仅 assignee 可完成任务')
2323
- }
2324
- // 终态幂等:已完成 → 原样返回(重复 complete 不炸);
2325
- // 已取消/失败 → 语义化错误(非裸状态机异常),调用方可据此引导继续下一项
2326
- if (task.state === 'COMPLETED') return task
2327
- if (task.state === 'CANCELED' || task.state === 'FAILED') {
2328
- throw new AppError(409, 'TASK_TERMINAL', `任务 ${input.taskId.slice(0, 8)} 已被平台${task.state === 'CANCELED' ? '取消' : '判定失败'},不能再标记完成;请继续处理队列下一项`)
2329
- }
2330
- const completed = this.getTaskEngine().complete(input.taskId, input.artifacts)
2331
- // goal 保底合成产物广播(goal 模式父任务且 lead 未自带总结时,taskEngine 追加了
2332
- // 平台合成的 goal-summary;以 goal-summary 语义 + artifactId 差集识别,幂等不重复广播)
2333
- const knownIds = new Set([
2334
- ...task.artifacts.map(a => a.artifactId),
2335
- ...(input.artifacts ?? []).map(a => a.artifactId),
2336
- ])
2337
- for (const artifact of completed.artifacts) {
2338
- if (isGoalSummaryArtifact(artifact) && !knownIds.has(artifact.artifactId)) {
2339
- this.runtimeOf(channelId, callerAgentId)?.emitExternal({ kind: 'artifact', artifact }, callerAgentId)
2340
- }
2341
- }
2342
- if (completed.parentId) {
2343
- this.getTaskEngine().onChildCompleted(completed)
2344
- const parent = this.getTaskEngine().get(completed.parentId)
2345
- if (parent) this.wakeAgent(completed.channelId, parent.assigneeId)
2346
- }
2347
- return completed
2348
- }
2349
-
2350
- async cancelTask(
2351
- channelId: string,
2352
- callerAgentId: string,
2353
- input: { taskId: string },
2354
- ): Promise<WorkspaceTask> {
2355
- const task = this.requireTaskInScope(channelId, callerAgentId, input.taskId)
2356
- const caller = this.requireMember(channelId, callerAgentId)
2357
- const isLead = caller.role === 'lead'
2358
- const isCreator = task.creatorId === callerAgentId
2359
- if (!isLead && !isCreator) {
2360
- throw new AppError(403, 'SCOPE_VIOLATION', '仅 lead/creator 可取消任务')
2361
- }
2362
- const canceled = this.getTaskEngine().cancel(input.taskId, callerAgentId)
2363
- this.runtimeOf(channelId, canceled.assigneeId)?.abortCurrent()
2364
- this.wakeAgent(channelId, canceled.assigneeId)
2365
- return canceled
2366
- }
2367
-
2368
- /**
2369
- * HITL:前端独立中断指定成员运行时(worker 或 lead)。
2370
- * - worker:强制 stop + detach(中断当前 run/杀子进程),成员行保留 enabled=1,
2371
- * 后续任务投递按需重新装配(interrupt 语义,不删成员)。
2372
- * - lead:stopAndDetach 内部同时停 SchedulerLoop;channel 恢复活跃由
2373
- * 下次任务提交(ensureChannelActive)自动重装配 lead + 调度器。
2374
- * 变更经 AEP agent.member(op=updated) 广播回流前端。
2375
- */
2376
- async stopAgentRuntime(channelId: string, agentId: string, by = 'user'): Promise<{ agentId: string, stopped: boolean }> {
2377
- const m = this.deps.repos.channelAgents.findByChannelAgent(channelId, agentId)
2378
- if (!m) throw new AppError(404, 'NOT_FOUND', `成员不存在: ${agentId}`)
2379
- await this.stopAndDetach(channelId, agentId)
2380
- this.notifyMember(channelId, {
2381
- op: 'updated',
2382
- agentId,
2383
- name: m.name,
2384
- role: m.role as 'lead' | 'worker',
2385
- harness: m.harness,
2386
- enabled: m.enabled,
2387
- by,
2388
- reason: 'HITL stop',
2389
- })
2390
- return { agentId, stopped: true }
2391
- }
2392
-
2393
- /**
2394
- * HITL:用户重试 FAILED 任务(lead/worker 任务均可)。
2395
- * 优先原 assignee(仍在本 channel 且启用),否则选队列最短的空闲 worker;
2396
- * 无可用承接者 → 400 NO_WORKER。重试后经调度循环重新投递执行。
2397
- */
2398
- async retryTask(channelId: string, callerAgentId: string, taskId: string): Promise<WorkspaceTask> {
2399
- const task = this.requireTaskInScope(channelId, callerAgentId, taskId)
2400
- if (task.state !== 'FAILED') {
2401
- throw new AppError(400, 'INVALID_STATE', `仅 FAILED 任务可重试(当前 ${task.state})`)
2402
- }
2403
- let target = this.deps.repos.channelAgents.findByChannelAgent(channelId, task.assigneeId)
2404
- if (!target || target.enabled !== 1) {
2405
- const receiver = this.pickReceiverWorker(channelId, '')
2406
- if (!receiver) throw new AppError(400, 'NO_WORKER', '无可用 worker 承接重试任务')
2407
- target = this.deps.repos.channelAgents.findByChannelAgent(channelId, receiver)!
2408
- }
2409
- const updated = this.getTaskEngine().reassign(taskId, target.id)
2410
- this.wakeAgent(channelId, target.id)
2411
- return updated
2412
- }
2413
-
2414
- async listTasks(channelId: string, callerAgentId: string): Promise<WorkspaceTask[]> {
2415
- this.requireMember(channelId, callerAgentId)
2416
- return this.deps.repos.tasks.listByChannel(channelId).map(rowToTask)
2417
- }
2418
-
2419
- async getTask(channelId: string, callerAgentId: string, taskId: string): Promise<WorkspaceTask> {
2420
- return this.requireTaskInScope(channelId, callerAgentId, taskId)
2421
- }
2422
-
2423
- /** 自己的任务队列视图(待执行 FIFO / 执行中 / 已完成)——每个 agent 的任务管理系统入口 */
2424
- async myQueue(channelId: string, callerAgentId: string): Promise<AgentTaskQueueView> {
2425
- this.requireMember(channelId, callerAgentId)
2426
- return this.getTaskEngine().queueViewOf(channelId, callerAgentId)
2427
- }
2428
-
2429
- /** 全员实时状态 + 队列总览(lead 统一调度/最优调配的观察面) */
2430
- async queueOverview(channelId: string, callerAgentId: string): Promise<AgentStatusView[]> {
2431
- this.requireMember(channelId, callerAgentId)
2432
- const cr = this.channels.get(channelId)
2433
- const wired = new Map((cr?.getAgents() ?? []).map(a => [a.agentId, a]))
2434
- return this.deps.repos.channelAgents.listByChannel(channelId)
2435
- .filter(m => m.enabled === 1)
2436
- .map((m) => {
2437
- const runtime = wired.get(m.id)
2438
- if (runtime) return runtime.getStatus()
2439
- // 未装配(懒加载)成员:状态按 idle,队列视图仍来自 tasks 表
2440
- const view = this.getTaskEngine().queueViewOf(channelId, m.id)
2441
- return {
2442
- agentId: m.id,
2443
- channelId,
2444
- role: m.role as 'lead' | 'worker',
2445
- name: m.name,
2446
- state: 'idle' as const,
2447
- currentTaskId: view.current?.id ?? null,
2448
- currentTaskTitle: view.current?.title ?? null,
2449
- currentTaskProgress: view.current?.progress != null ? view.current.progress : null,
2450
- queuedCount: view.queued.length,
2451
- completedCount: view.completed.length,
2452
- }
2453
- })
2454
- }
2455
-
2456
- /** 修改待执行任务(lead 对 worker 队列的"改";仅待执行态可改)+ 唤醒 assignee 消费新投递 */
2457
- async updateTask(
2458
- channelId: string,
2459
- callerAgentId: string,
2460
- taskId: string,
2461
- patch: { title?: string, description?: string },
2462
- ): Promise<WorkspaceTask> {
2463
- const task = this.requireTaskInScope(channelId, callerAgentId, taskId)
2464
- const caller = this.requireMember(channelId, callerAgentId)
2465
- if (caller.role !== 'lead' && task.creatorId !== callerAgentId) {
2466
- throw new AppError(403, 'SCOPE_VIOLATION', '仅 lead/创建者可修改任务')
2467
- }
2468
- const updated = this.getTaskEngine().updateTask(taskId, patch, callerAgentId)
2469
- this.wakeAgent(channelId, updated.assigneeId)
2470
- return updated
2471
- }
2472
-
2473
- /** 重新指派(lead 的"调配":待执行/失败任务迁移到其他 worker)+ 唤醒新 assignee */
2474
- async reassignTask(
2475
- channelId: string,
2476
- callerAgentId: string,
2477
- taskId: string,
2478
- toAgentId: string,
2479
- ): Promise<WorkspaceTask> {
2480
- this.requireTaskInScope(channelId, callerAgentId, taskId) // 校验任务在调用方作用域内
2481
- const caller = this.requireMember(channelId, callerAgentId)
2482
- if (caller.role !== 'lead') {
2483
- throw new AppError(403, 'SCOPE_VIOLATION', '仅 lead 可调配任务')
2484
- }
2485
- const target = this.resolveMemberRef(channelId, toAgentId)
2486
- const updated = this.getTaskEngine().reassign(taskId, target.id)
2487
- this.wakeAgent(channelId, target.id)
2488
- return updated
2489
- }
2490
-
2491
- async sendA2A(
2492
- channelId: string,
2493
- callerAgentId: string,
2494
- input: { toAgentId: string, parts: Part[], metadata?: Record<string, unknown> },
2495
- ): Promise<A2AMessage> {
2496
- this.requireMember(channelId, callerAgentId)
2497
- // 容错寻址:id/模板 id/名字/唯一前缀;失败错误携带当前名册(LLM 自我纠正)
2498
- const target = this.resolveMemberRef(channelId, input.toAgentId)
2499
- const message = buildMessage(channelId, 'ROLE_AGENT', input.parts, {
2500
- ...(input.metadata ?? {}),
2501
- 'x-aw-target-agent': target.id,
2502
- 'x-aw-from-agent': callerAgentId,
2503
- })
2504
- // 真送达契约:route 回执必须包含目标(落库 enqueue 同步完成),否则向上抛错 ——
2505
- // 消息绝不允许"报告已发送"却没进对方信箱
2506
- const delivered = this.route(channelId, message)
2507
- if (!delivered.includes(target.id)) {
2508
- throw new AppError(502, 'DELIVERY_FAILED', `消息未能投递到 ${target.name} 的信箱(成员装配失败),请重试或改投其他成员`)
2509
- }
2510
- return message
2511
- }
2512
-
2513
- /**
2514
- * 按主键查 Channel 成员实例(跨频道)。
2515
- * 用途:校验「Agent ↔ 工业节点绑定」的主体 —— 运行时持绑定做鉴权的是**成员实例**,
2516
- * 不是 Agent 模板;绑到模板 id 上会得到一条永远不生效的静默绑定(实测踩过)。
2517
- */
2518
- findChannelAgentById(channelAgentId: string): { id: string, channelId: string, templateId: string | null } | undefined {
2519
- const row = this.deps.repos.channelAgents.findById(channelAgentId)
2520
- return row ? { id: row.id, channelId: row.channelId, templateId: row.templateId } : undefined
2521
- }
2522
-
2523
- /** 某 Agent 模板已部署到哪些频道(用于把"绑错主体"的报错变成可执行提示) */
2524
- listChannelAgentInstances(templateId: string): Array<{ id: string, channelId: string, name: string }> {
2525
- return this.deps.repos.channelAgents.listByTemplate(templateId).map(r => ({
2526
- id: r.id,
2527
- channelId: r.channelId,
2528
- name: this.deps.repos.channels.findById(r.channelId)?.name ?? r.channelId,
2529
- }))
2530
- }
2531
-
2532
- /**
2533
- * 实时消息(外部/系统注入):priority=immediate → busy 时 steer 注入运行中的 omp 会话。
2534
- * 触发器 requireReply=true → 接收方须回执(执行结果+所需内容,in_reply_to 关联)。
2535
- */
2536
- async sendImmediateMessage(input: {
2537
- channelId: string
2538
- fromAgentId?: string
2539
- toAgentId: string
2540
- parts: Part[]
2541
- requireReply?: boolean
2542
- /** 人类发送者显示名(REST 注入时的时间线归属;进入 x-aw-from-label 元数据) */
2543
- fromLabel?: string
2544
- }): Promise<A2AMessage> {
2545
- // 无主消息拦截:发送方必须可追溯(agent 成员或人类显示名),否则拒绝发送
2546
- const hasFromAgent = !!input.fromAgentId && this.deps.repos.channelAgents.findByChannelAgent(input.channelId, input.fromAgentId) != null
2547
- if (!hasFromAgent && !input.fromLabel) {
2548
- throw new AppError(400, 'NO_SENDER', '消息缺少可追溯发送人(fromAgentId 须为本 channel 成员,或提供 fromLabel 人类显示名)')
2549
- }
2550
- const metadata: Record<string, unknown> = {
2551
- 'x-aw-target-agent': input.toAgentId,
2552
- 'x-aw-msg-priority': 'immediate',
2553
- }
2554
- if (hasFromAgent) metadata['x-aw-from-agent'] = input.fromAgentId
2555
- if (input.fromLabel) metadata['x-aw-from-label'] = input.fromLabel
2556
- if (input.requireReply) metadata['x-aw-require-reply'] = 'true'
2557
- const message = buildMessage(input.channelId, 'ROLE_AGENT', input.parts, metadata)
2558
- const delivered = this.route(input.channelId, message)
2559
- if (!delivered.includes(input.toAgentId)) {
2560
- throw new AppError(502, 'DELIVERY_FAILED', `消息未能投递到 ${input.toAgentId} 的信箱,请重试`)
2561
- }
2562
- return message
2563
- }
2564
-
2565
- /**
2566
- * 跨 Channel 点对点通信(仅 lead):把消息直投目标 channel 的 lead mailbox。
2567
- * 沿用既有 mailbox/route 机制(投递/唤醒/消费/回执全复用),仅新增跨 channel 路由:
2568
- * - 权限:发送方必须是本 channel 启用成员中的 lead(worker/系统拒绝);
2569
- * - 同主约束:两个 channel 必须属于同一 owner(用户级隔离不破);
2570
- * - 守卫通行:x-aw-cross-channel 标记由服务端在发送时盖章(REST/工具入参不可伪造),
2571
- * 目标 channel 信箱守卫据此放行非成员发送方的跨 channel 消息;
2572
- * - 回执:目标 lead 经同一机制回信(其 send_message_to_agent / 本方法均可,
2573
- * in_reply_to 关联触发实时推送)。
2574
- */
2575
- async sendCrossChannelMessage(
2576
- fromChannelId: string,
2577
- fromAgentId: string,
2578
- input: { toChannelId: string, parts: Part[], requireReply?: boolean, inReplyTo?: string },
2579
- ): Promise<{ messageId: string, toChannelId: string, toChannelName: string, toLeadAgentId: string }> {
2580
- // 权限闸:发送方 = 本 channel 启用成员中的 lead
2581
- const sender = this.deps.repos.channelAgents.findByChannelAgent(fromChannelId, fromAgentId)
2582
- if (!sender || sender.enabled !== 1) {
2583
- throw new AppError(403, 'SCOPE_VIOLATION', '跨 Channel 通信的发送方必须是本 channel 的启用成员')
2584
- }
2585
- if (sender.role !== 'lead') {
2586
- throw new AppError(403, 'ROLE_FORBIDDEN', `跨 Channel 通信仅限 Leader 发起(${sender.name} 是 ${sender.role})`)
2587
- }
2588
-
2589
- // 目标 channel 解析(id 精确 > 名字精确 > 名字唯一包含);禁自指/禁停用/须有 lead
2590
- const needle = input.toChannelId.trim().toLowerCase()
2591
- const rows = this.deps.repos.channels.list()
2592
- const target = rows.find(c => c.id === input.toChannelId)
2593
- ?? rows.find(c => c.name.toLowerCase() === needle)
2594
- ?? (() => {
2595
- const partial = rows.filter(c => c.name.toLowerCase().includes(needle))
2596
- return partial.length === 1 ? partial[0] : undefined
2597
- })()
2598
- if (!target || target.id === fromChannelId) {
2599
- throw new AppError(404, 'CHANNEL_NOT_FOUND', `目标 channel 未命中(且不可为本 channel): ${input.toChannelId}`)
2600
- }
2601
- if (target.enabled !== 1) throw new AppError(400, 'CHANNEL_DISABLED', `目标 channel 已停用: ${target.name}`)
2602
- if (!target.leadAgentId) throw new AppError(400, 'NO_LEAD', `目标 channel 没有 lead,无法接收跨 Channel 消息: ${target.name}`)
2603
-
2604
- // 同主约束:跨团队协作不越用户边界
2605
- const sourceChannel = this.deps.repos.channels.findById(fromChannelId)
2606
- if (sourceChannel && target.ownerUserId !== null && sourceChannel.ownerUserId !== null
2607
- && sourceChannel.ownerUserId !== target.ownerUserId) {
2608
- throw new AppError(403, 'SCOPE_VIOLATION', '跨 Channel 通信仅限同一用户的 channel 之间')
2609
- }
2610
-
2611
- // 目标 lead 必须是目标 channel 的启用成员(防悬空 leadAgentId)
2612
- const targetLead = this.deps.repos.channelAgents.findByChannelAgent(target.id, target.leadAgentId)
2613
- if (!targetLead || targetLead.enabled !== 1) {
2614
- throw new AppError(400, 'NO_LEAD', `目标 channel 的 lead 成员缺失或已停用: ${target.name}`)
2615
- }
2616
-
2617
- const message = buildMessage(target.id, 'ROLE_AGENT', input.parts, {
2618
- 'x-aw-target-agent': targetLead.id,
2619
- 'x-aw-from-agent': fromAgentId,
2620
- 'x-aw-from-channel': fromChannelId,
2621
- 'x-aw-cross-channel': 'true',
2622
- 'x-aw-from-label': `跨Channel:${sourceChannel?.name ?? fromChannelId} / ${sender.name}`,
2623
- ...(input.requireReply ? { 'x-aw-require-reply': 'true' } : {}),
2624
- // in_reply_to 关联:channel-runtime 将其视为 realtime,回复即时推送对端
2625
- ...(input.inReplyTo ? { 'x-aw-in-reply-to': input.inReplyTo } : {}),
2626
- })
2627
- const delivered = this.route(target.id, message)
2628
- if (!delivered.includes(targetLead.id)) {
2629
- throw new AppError(502, 'DELIVERY_FAILED', `跨 Channel 消息未能投递到「${target.name}」的 lead 信箱,请重试`)
2630
- }
2631
- return {
2632
- messageId: message.messageId,
2633
- toChannelId: target.id,
2634
- toChannelName: target.name,
2635
- toLeadAgentId: targetLead.id,
2636
- }
2637
- }
2638
-
2639
- /**
2640
- * 跨团队可见性(仅 lead):其他 channel 的场景任务概览(同主、启用)。
2641
- * 协同工作流的第一步——先看别的团队在做什么/做过什么,再决定是否发信请求协作。
2642
- */
2643
- listOtherTeamsOverview(channelId: string, agentId: string): Array<{
2644
- channelId: string
2645
- name: string
2646
- description: string
2647
- leadName: string | null
2648
- /** 团队共享域知识量(实现体第 2661 行已产出;原声明漏写 → 与 AgentWorkspace.listOtherTeams 漂移) */
2649
- sharedMemories: number
2650
- activeTasks: Array<{ id: string, title: string, state: string }>
2651
- recentCompleted: Array<{ title: string }>
2652
- }> {
2653
- this.requireMember(channelId, agentId)
2654
- const sender = this.deps.repos.channelAgents.findByChannelAgent(channelId, agentId)
2655
- if (!sender || sender.role !== 'lead') {
2656
- throw new AppError(403, 'ROLE_FORBIDDEN', `团队任务概览仅限 Leader(${sender?.name ?? agentId} 是 ${sender?.role ?? '非成员'})`)
2657
- }
2658
- const terminal = new Set(['COMPLETED', 'FAILED', 'CANCELED'])
2659
- return this.otherSameOwnerChannels(channelId).map((c) => {
2660
- const tasks = this.deps.repos.tasks.listByChannel(c.id)
2661
- const leadRow = c.leadAgentId ? this.deps.repos.channelAgents.findById(c.leadAgentId) : undefined
2662
- return {
2663
- channelId: c.id,
2664
- name: c.name,
2665
- description: c.description ?? '',
2666
- leadName: leadRow?.name ?? null,
2667
- /** 团队共享域知识量:>0 说明该队有可检索的作业结论(search_other_teams_memory) */
2668
- sharedMemories: this.deps.repos.memories.countTeamShared(c.id),
2669
- activeTasks: tasks
2670
- .filter(t => !terminal.has(t.state))
2671
- .map(t => ({ id: t.id, title: t.title, state: t.state })),
2672
- recentCompleted: tasks
2673
- .filter(t => t.state === 'COMPLETED')
2674
- .slice(0, 3)
2675
- .map(t => ({ title: t.title })),
2676
- }
2677
- })
2678
- }
2679
-
2680
- /**
2681
- * 跨团队共享记忆检索(lead/worker 皆可,只读):其他 channel 的 __team__ 公共域。
2682
- * 全员可见——worker 由此知道别的团队做过什么;发现相关经验/结论可直接复用,
2683
- * 无需跨 channel 发信;查无所得而有协作必要时,再由 lead 发起跨 channel 通信。
2684
- */
2685
- recallOtherTeamsMemory(channelId: string, agentId: string, input: { query: string, limit?: number }): Array<{
2686
- channelId: string
2687
- channelName: string
2688
- title: string
2689
- content: string
2690
- importance: number
2691
- createdAt: string
2692
- }> {
2693
- this.requireMember(channelId, agentId)
2694
- const q = input.query.trim()
2695
- if (!q) return []
2696
- const others = this.otherSameOwnerChannels(channelId)
2697
- if (others.length === 0) return []
2698
- const matchQuery = segmentCJK(q).split(/\s+/).filter(Boolean).join(' OR ')
2699
- const rows = this.deps.repos.memories.searchTeamSharedAcross(
2700
- matchQuery,
2701
- others.map(c => c.id),
2702
- Math.min(Math.max(input.limit ?? 5, 1), 20),
2703
- )
2704
- // 触摸命中行(access_count/last_accessed_at):与 recallRows 同信号,强化后续召回排序
2705
- for (const r of rows) this.deps.repos.memories.touch(r.id)
2706
- return rows.map(r => ({
2707
- channelId: r.channelId,
2708
- channelName: others.find(c => c.id === r.channelId)?.name ?? r.channelId,
2709
- title: r.title,
2710
- content: unsegmentCJK(r.content).slice(0, 400),
2711
- importance: r.importance,
2712
- createdAt: r.createdAt,
2713
- }))
2714
- }
2715
-
2716
- /** 同主且启用的其他 channel 列表(跨团队可见性的作用域) */
2717
- private otherSameOwnerChannels(channelId: string): ChannelRow[] {
2718
- const self = this.deps.repos.channels.findById(channelId)
2719
- return this.deps.repos.channels.list().filter(c =>
2720
- c.id !== channelId
2721
- && c.enabled === 1
2722
- && (self?.ownerUserId == null || c.ownerUserId == null || c.ownerUserId === self.ownerUserId))
2723
- }
2724
-
2725
- /**
2726
- * 工具桥(协作工具族):按 agentId 定位 channel 并调用其 workspace 方法。
2727
- * 与工业工具桥同一服务层,供 REST 直调(测试/运维/控制台)。
2728
- */
2729
- async invokeAgentWorkspaceTool(agentId: string, tool: string, args: Record<string, unknown> = {}): Promise<{ text: string, isError?: boolean }> {
2730
- const row = this.deps.repos.channelAgents.findById(agentId)
2731
- if (!row || row.enabled !== 1) throw new AppError(404, 'NOT_FOUND', `agent 不存在或已停用: ${agentId}`)
2732
- const ws = this.ensureAgentRuntime(row.channelId, agentId)?.workspace
2733
- if (!ws) throw new AppError(400, 'AGENT_NOT_READY', `agent 运行时未装配: ${agentId}`)
2734
- switch (tool) {
2735
- case 'list_other_teams': {
2736
- const teams = ws.listOtherTeams()
2737
- if (teams.length === 0) return { text: '当前没有其他团队(或均未启用)。' }
2738
- const text = teams.map((t) => {
2739
- const active = t.activeTasks.length > 0
2740
- ? t.activeTasks.map(x => `「${x.title}」(${x.state})`).join('、')
2741
- : '无进行中任务'
2742
- const done = t.recentCompleted.length > 0
2743
- ? t.recentCompleted.map(x => `「${x.title}」`).join('、')
2744
- : '无'
2745
- const mem = t.sharedMemories > 0 ? `共享记忆 ${t.sharedMemories} 条(可检索)` : '暂无共享记忆'
2746
- return `- ${t.name}${t.description ? `(${t.description})` : ''} · lead=${t.leadName ?? '?'} · ${mem}\n 进行中: ${active}\n 近期完成: ${done}\n channel_id: ${t.channelId}`
2747
- }).join('\n')
2748
- return { text: `其他团队概览:\n${text}\n(需要协作时用 send_cross_channel_message 向对应团队 Leader 发信;查具体知识用 search_other_teams_memory)` }
2749
- }
2750
- case 'search_other_teams_memory': {
2751
- const query = String(args.query ?? '')
2752
- if (!query) return { text: '缺少 query', isError: true }
2753
- const rows = ws.searchOtherTeamsMemory({ query, limit: Number(args.limit ?? 5) })
2754
- if (rows.length === 0) return { text: `其他团队的共享记忆中没有命中「${query}」的内容。` }
2755
- const text = rows.map(r =>
2756
- `- [${r.channelName}] 「${r.title}」(${r.createdAt.slice(0, 10)}): ${r.content}`).join('\n')
2757
- return { text: `其他团队共享记忆命中 ${rows.length} 条:\n${text}` }
2758
- }
2759
- case 'send_cross_channel_message': {
2760
- if (!args.to_channel_id || !args.message) return { text: '缺少 to_channel_id 或 message', isError: true }
2761
- const r = await ws.sendCrossChannelMessage({
2762
- toChannelId: String(args.to_channel_id),
2763
- parts: [{ text: String(args.message) }],
2764
- requireReply: args.require_reply === true,
2765
- inReplyTo: typeof args.in_reply_to === 'string' ? args.in_reply_to : undefined,
2766
- })
2767
- return { text: `跨 Channel 消息已送达「${r.toChannelName}」的 Leader(channel=${r.toChannelId}, lead=${r.toLeadAgentId.slice(0, 8)}),消息 id=${r.messageId.slice(0, 8)}。` }
2768
- }
2769
- default:
2770
- throw new AppError(400, 'BAD_REQUEST', `工具桥不支持该协作工具: ${tool}`)
2771
- }
2772
- }
2773
-
2774
- /**
2775
- * harness 无关全量工具直调(agent token 鉴权;stdio MCP 桥回程的唯一入口)。
2776
- * 插件工具最先(与 host-tool-bridge 同源过滤,不依赖引擎运行时 —— mock 等无引擎
2777
- * 工具面的成员经 REST invoke 同样可用);其余 impl.dispatchHostTool 优先,未实现
2778
- * 回退协作工具族。
2779
- */
2780
- async invokeHostTool(input: { agentId: string, token?: string, tool: string, args?: Record<string, unknown> }): Promise<{ text: string, isError?: boolean }> {
2781
- const row = this.deps.repos.channelAgents.findById(input.agentId)
2782
- if (!row || row.enabled !== 1) throw new AppError(404, 'NOT_FOUND', `agent 不存在或已停用: ${input.agentId}`)
2783
- // token 鉴权(MCP 桥路径必带;缺省视为服务端内部调用,走 REST 已有用户鉴权)
2784
- if (input.token !== undefined && input.token !== row.token) {
2785
- throw new AppError(401, 'UNAUTHORIZED', 'agent token 校验失败')
2786
- }
2787
- // 工具执行错误(业务约束/目标不存在等)一律降级为 isError 文本——
2788
- // 绝不让 AppError 以 unhandledRejection 逃逸拖垮 worker(stability-guard 会因此退出整进程)
2789
- try {
2790
- // 活性登记:调度器停滞看门狗以「最近工具调用」为健康信号(见 SchedulerLoopOptions.toolActivityOf)
2791
- this.lastToolInvokeAt.set(input.agentId, Date.now())
2792
- // 插件工具:团队开关过滤 + handler 直调(ctx.omp 注册的自定义工具全 harness 同源)
2793
- const pluginTool = listPluginTools().get(input.tool)
2794
- if (pluginTool) {
2795
- const channelOff = getChannelPluginsRepo().explicitFor(row.channelId)
2796
- const owner = pluginOfTool(input.tool)
2797
- if (channelOff && owner && channelOff.get(owner) === false) {
2798
- return {
2799
- text: `该团队未启用插件「${owner}」,${input.tool} 不可用。可在团队设置→插件中开启。`,
2800
- isError: true,
2801
- }
2802
- }
2803
- const identity = {
2804
- agentId: row.id,
2805
- channelId: row.channelId,
2806
- role: (row.role === 'lead' ? 'lead' : 'worker') as 'lead' | 'worker',
2807
- name: row.name,
2808
- }
2809
- return await pluginTool.handler(input.args ?? {}, identity)
2810
- }
2811
- const runtime = this.ensureAgentRuntime(row.channelId, input.agentId)
2812
- if (runtime) {
2813
- const viaImpl = await runtime.dispatchHostTool(input.tool, input.args ?? {})
2814
- if (viaImpl) return viaImpl
2815
- }
2816
- // 回退:impl 未实现工具面(如 mock)→ 协作工具族直调
2817
- return await this.invokeAgentWorkspaceTool(input.agentId, input.tool, input.args ?? {})
2818
- }
2819
- catch (err) {
2820
- const reason = err instanceof Error ? err.message : String(err)
2821
- return { text: `工具「${input.tool}」调用失败: ${reason}`, isError: true }
2822
- }
2823
- }
2824
-
2825
- /** 按 token 解析 agent(桥侧只需 token 的自证路径;未命中返回 null) */
2826
- resolveAgentByToken(token: string): { agentId: string, channelId: string } | null {
2827
- if (!token) return null
2828
- const row = this.deps.repos.channelAgents.findByToken(token)
2829
- if (!row || row.enabled !== 1) return null
2830
- return { agentId: row.id, channelId: row.channelId }
2831
- }
2832
-
2833
- /** 工具面 schema(MCP 桥 tools/list):按 agent 角色装配,与 omp 注入面同源 */
2834
- hostToolDefsFor(agentId: string): Array<{ name: string, label?: string, description: string, parameters: Record<string, unknown> }> {
2835
- const row = this.deps.repos.channelAgents.findById(agentId)
2836
- if (!row) throw new AppError(404, 'NOT_FOUND', `agent 不存在: ${agentId}`)
2837
- return hostToolsForRole(row.role === 'lead' ? 'lead' : 'worker', row.channelId)
2838
- }
2839
-
2840
- /**
2841
- * HITL 应答传导(codex/opencode/dsh 审批;omp-dialog 走 terminal 通道不经此)。
2842
- * 找不到运行时或 impl 未实现 → 409(条目不可应答)。
2843
- */
2844
- async respondHarnessHitl(agentId: string, kind: string, id: string, outcome: {
2845
- confirmed?: boolean
2846
- cancelled?: boolean
2847
- value?: string
2848
- response?: string
2849
- comment?: string
2850
- }): Promise<void> {
2851
- const row = this.deps.repos.channelAgents.findById(agentId)
2852
- if (!row) throw new AppError(404, 'NOT_FOUND', `agent 不存在: ${agentId}`)
2853
- const runtime = this.ensureAgentRuntime(row.channelId, agentId)
2854
- if (!runtime) throw new AppError(409, 'NOT_RESPONDABLE', 'agent 运行时未装配,无法应答')
2855
- const ok = await runtime.respondHitl(kind, id, outcome)
2856
- if (!ok) throw new AppError(409, 'NOT_RESPONDABLE', '该 harness 不支持程序化应答')
2857
- }
2858
-
2859
- /** 阻塞长轮询(poll_messages):到信即时唤醒,250ms 兜底重查 */
2860
- async waitMailbox(channelId: string, callerAgentId: string, limit: number, waitMs: number): Promise<A2AMessage[]> {
2861
- this.requireMember(channelId, callerAgentId)
2862
- const runtime = this.ensureAgentRuntime(channelId, callerAgentId)
2863
- if (runtime) return runtime.waitPending(limit, waitMs)
2864
- // 运行时未装配(极端时序):退化为一次性快照查询
2865
- return this.pollMailbox(channelId, callerAgentId, limit)
2866
- }
2867
-
2868
- async pollMailbox(channelId: string, callerAgentId: string, limit = 100): Promise<A2AMessage[]> {
2869
- this.requireMember(channelId, callerAgentId)
2870
- return this.deps.repos.messages
2871
- .listPendingByChannelAgent(channelId, callerAgentId)
2872
- .slice(0, limit)
2873
- .map(rowToMessage)
2874
- }
2875
-
2876
- /** 确认消费自己 mailbox 的协作消息(读即取;id 须属于 caller 的 pending 集) */
2877
- ackMailbox(channelId: string, callerAgentId: string, messageIds: string[]): void {
2878
- this.requireMember(channelId, callerAgentId)
2879
- const pending = new Set(
2880
- this.deps.repos.messages
2881
- .listPendingByChannelAgent(channelId, callerAgentId)
2882
- .map(r => r.id),
2883
- )
2884
- for (const id of messageIds) {
2885
- // claim 守卫:与 steer 注入原子竞争(peek 与 ack 之间消息可能被认领),
2886
- // 认领成功才标记消费——失败说明 steer 已注入运行中会话,不再重复投递
2887
- if (pending.has(id) && this.deps.repos.messages.claim(id)) {
2888
- this.deps.repos.messages.markConsumed(id)
2889
- }
2890
- }
2891
- }
2892
-
2893
- /**
2894
- * (仅 lead)Channel 邮件全览:全部 agent 间消息(含已消费/任务投递),按时间倒序。
2895
- * lead 调度观察面——worker 间的点对点通信(含结果回执)对 lead 可见,
2896
- * 供派发前判断"该结果是否已由某 worker 经 mail 产出",避免重复派发浪费资源。
2897
- * 可选 agentId 过滤参与方(from 或 to)。
2898
- */
2899
- async listChannelMail(
2900
- channelId: string,
2901
- callerAgentId: string,
2902
- opts: { limit?: number, agentId?: string } = {},
2903
- ): Promise<ChannelMail[]> {
2904
- const caller = this.requireMember(channelId, callerAgentId)
2905
- if (caller.role !== 'lead') {
2906
- throw new AppError(403, 'SCOPE_VIOLATION', '仅 lead 可查看 Channel 全部邮件')
2907
- }
2908
- const limit = Math.max(1, Math.min(500, opts.limit ?? 200))
2909
- const mails = this.deps.repos.messages
2910
- .listRecentByChannel(channelId, limit)
2911
- .map(rowToChannelMail)
2912
- if (opts.agentId) {
2913
- return mails.filter(m => m.fromAgentId === opts.agentId || m.toAgentId === opts.agentId)
2914
- }
2915
- return mails
2916
- }
2917
-
2918
- async subscribe(channelId: string, callerAgentId: string, input: { agentIds?: string[] }): Promise<void> {
2919
- this.requireMember(channelId, callerAgentId)
2920
- for (const targetId of input.agentIds ?? []) {
2921
- const target = this.deps.repos.channelAgents.findByChannelAgent(channelId, targetId)
2922
- if (!target) {
2923
- throw new AppError(403, 'SCOPE_VIOLATION', `目标 Agent ${targetId} 不在本 channel`)
2924
- }
2925
- this.deps.repos.subscriptions.add(channelId, callerAgentId, targetId)
2926
- }
2927
- }
2928
-
2929
- /** 实例级 token → 实例视图(AgentInfo) */
2930
- findByToken(token: string): AgentInfo | undefined {
2931
- const m = this.deps.repos.channelAgents.findByToken(token)
2932
- return m ? instanceToAgentInfo(m) : undefined
2933
- }
2934
-
2935
- async restore(): Promise<void> {
2936
- this.deps.repos.messages.resetConsuming()
2937
- const nonTerminal = this.deps.repos.tasks.listNonTerminal()
2938
- const activeChannelIds = new Set(nonTerminal.map(t => t.channelId))
2939
- for (const channelId of activeChannelIds) {
2940
- const channel = this.deps.repos.channels.findById(channelId)
2941
- if (!channel || channel.enabled !== 1) continue
2942
- this.ensureChannelActive(channelId)
2943
- }
2944
- // 断线重连:ASSIGNED/WORKING 的叶子任务(无子任务)若无 pending assign 投递
2945
- // (消息已被消费但任务未完成——进程内 run 抛错、或崩溃落在消费后),
2946
- // 无人会重新驱动它(调度循环只 dispatch lead 名下任务;停滞检测要 stallMs×2 才 cancel)。
2947
- // 重投 assign + 唤醒 assignee,由 processMessage 的终态检查保证幂等(执行从头重放)。
2948
- // 父任务(WAITING/有子任务)不重投:由调度循环按子任务进度汇总推进。
2949
- // 父任务集合按 channel 全量任务计算(含已完成子任务):
2950
- // 「子任务全部完成、父任务 WAITING 待汇总」的父任务不能误判为叶子而重投。
2951
- const parentIds = new Set<string>()
2952
- for (const channelId of activeChannelIds) {
2953
- for (const t of this.deps.repos.tasks.listByChannel(channelId)) {
2954
- if (t.parentId) parentIds.add(t.parentId)
2955
- }
2956
- }
2957
- for (const task of nonTerminal) {
2958
- if (task.state !== 'ASSIGNED' && task.state !== 'WORKING') continue
2959
- if (parentIds.has(task.id)) continue
2960
- if (this.deps.repos.messages.hasPendingAssign(task.id)) continue
2961
- this.getTaskEngine().redeliverAssign(task.id)
2962
- }
2963
- // 唤醒有未消费消息的 agent:重启前 consuming 的 assign 消息已被 resetConsuming 重投为 pending,
2964
- // 若无人唤醒,worker 的运行时(懒加载)不会装配,重投消息滞留 pending,任务永远无法恢复。
2965
- // 任务状态保持原样(不重置为 ASSIGNED):调度循环按 SUBMITTED/WORKING 重新驱动 lead 任务,
2966
- // worker 经消息重放从 ASSIGNED/WORKING 恢复执行;WAITING 父任务等子任务完成后正常汇总。
2967
- for (const { channelId, toAgentId } of this.deps.repos.messages.listPendingTargets()) {
2968
- this.wakeAgent(channelId, toAgentId)
2969
- }
2970
- }
2971
-
2972
- // ===== 内部辅助 =====
2973
-
2974
- private route(channelId: string, message: A2AMessage): string[] {
2975
- // 总线通知(a2a.message)由 ChannelRuntime 构造时注入的 onRouted 回调统一发出
2976
- // (见 ensureChannelRuntime):调度器直呼 runtime.route 的消息同样可见
2977
- return this.ensureChannelRuntime(channelId).route(message)
2978
- }
2979
-
2980
- private wakeAgent(channelId: string, agentId: string): void {
2981
- this.ensureAgentRuntime(channelId, agentId)?.wakeMailbox()
2982
- }
2983
-
2984
- /**
2985
- * 成员寻址(A2A 身份命中率的核心):接受 id(实例/模板)、名字、唯一名字前缀。
2986
- * 多智能体对话中 LLM 常以名字称呼同事,名册缓存也可能滞后于成员重建 ——
2987
- * 精确 id 未命中时按名字/前缀解析,让"想发给谁"总能落到"谁"的实例上;
2988
- * 解析失败时把当前名册(id | 名字)放进错误信息,LLM 下一轮即可自我纠正。
2989
- */
2990
- private resolveMemberRef(channelId: string, ref: string): ChannelAgentRow {
2991
- const trimmed = ref.trim()
2992
- if (!trimmed) throw new AppError(400, 'BAD_REQUEST', '缺少目标成员引用(to_agent_id/assignee_id)')
2993
- const members = this.deps.repos.channelAgents.listByChannel(channelId).filter(m => m.enabled === 1)
2994
- // ① 精确实例 id
2995
- const byId = members.find(m => m.id === trimmed)
2996
- if (byId) return byId
2997
- // ② 模板 id(名册/记忆中的旧实例 id 复用同一模板 → 按模板命中当前实例)
2998
- const byTemplate = members.find(m => m.templateId === trimmed)
2999
- if (byTemplate) return byTemplate
3000
- // ③ 名字精确(大小写不敏感;含"← 你"等标记已剥离)
3001
- const lower = trimmed.toLowerCase()
3002
- const byName = members.find(m => m.name.toLowerCase() === lower)
3003
- if (byName) return byName
3004
- // ④ 唯一名字前缀/包含(多候选 → 拒绝,防止误投)
3005
- const partial = members.filter(m => m.name.toLowerCase().includes(lower))
3006
- if (partial.length === 1) return partial[0]!
3007
- const roster = members.map(m => `${m.id} | ${m.name}(${m.role})`).join('; ')
3008
- throw new AppError(404, 'MEMBER_NOT_FOUND',
3009
- `目标成员未命中: "${trimmed}"。当前 Channel 名册(用其中 id 或名字寻址): ${roster}`)
3010
- }
3011
-
3012
- /** 成员寻址(公开包装:REST/工具桥共用;语义同 resolveMemberRef) */
3013
- resolveChannelMember(channelId: string, ref: string): { id: string, name: string, role: string } {
3014
- const m = this.resolveMemberRef(channelId, ref)
3015
- return { id: m.id, name: m.name, role: m.role }
3016
- }
3017
-
3018
- /** 校验调用方是本 channel 实例;返回实例行(含 role) */
3019
- private requireMember(channelId: string, agentId: string): ChannelAgentRow {
3020
- const m = this.deps.repos.channelAgents.findByChannelAgent(channelId, agentId)
3021
- if (!m) throw new AppError(403, 'SCOPE_VIOLATION', '调用方 Agent 不在本 channel')
3022
- return m
3023
- }
3024
-
3025
- private requireTaskInScope(channelId: string, callerAgentId: string, taskId: string): WorkspaceTask {
3026
- this.requireMember(channelId, callerAgentId)
3027
- const row = this.deps.repos.tasks.findById(taskId)
3028
- if (!row) throw new AppError(404, 'NOT_FOUND', `任务不存在: ${taskId}`)
3029
- if (row.channelId !== channelId) {
3030
- throw new AppError(403, 'SCOPE_VIOLATION', '任务不在本 channel')
3031
- }
3032
- return rowToTask(row)
3033
- }
3034
- }
3035
-
3036
- /** 工厂:创建 manager(测试与集成均可注入依赖) */
3037
- export function createAgentChannelManager(deps: ManagerDeps): AgentChannelManager {
3038
- return new AgentChannelManager(deps)
3039
- }
3040
-
3041
- let managerSingleton: AgentChannelManager | null = null
3042
-
3043
- export function initWorkshopManager(deps: ManagerDeps): AgentChannelManager {
3044
- managerSingleton = new AgentChannelManager(deps)
3045
- return managerSingleton
3046
- }
3047
-
3048
- export function getWorkshopManagerOrNull(): AgentChannelManager | null {
3049
- return managerSingleton
3050
- }