bloby-bot 0.30.1 → 0.32.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (348) hide show
  1. package/dist-bloby/assets/angular-html-DxXh-QMA.js +1 -0
  2. package/dist-bloby/assets/{angular-ts-BJPoZ_vo.js → angular-ts-BNEmshfa.js} +1 -1
  3. package/dist-bloby/assets/{apl-CyVuPSCb.js → apl-CD5excG6.js} +1 -1
  4. package/dist-bloby/assets/{astro-CKc3-gwH.js → astro-BsuvMd51.js} +1 -1
  5. package/dist-bloby/assets/{blade-DMAsVBaV.js → blade-BzCfsa5s.js} +1 -1
  6. package/dist-bloby/assets/{bloby-CqtSjokc.js → bloby-B1w9ReAR.js} +19 -19
  7. package/dist-bloby/assets/{bsl-B1qbqNES.js → bsl-BODK--Fo.js} +1 -1
  8. package/dist-bloby/assets/c-QpHxjkb9.js +1 -0
  9. package/dist-bloby/assets/{cairo-BDj8wWhy.js → cairo-BwpHIzLA.js} +1 -1
  10. package/dist-bloby/assets/{cobol-hBjMZW-R.js → cobol-Dvyhsqyz.js} +1 -1
  11. package/dist-bloby/assets/{coffee-B4OtR3w-.js → coffee-CyaHgmLy.js} +1 -1
  12. package/dist-bloby/assets/cpp-DlbkFQj0.js +1 -0
  13. package/dist-bloby/assets/{crystal-x3k4USY-.js → crystal-CR4Yni1K.js} +1 -1
  14. package/dist-bloby/assets/css-jgrsA6xW.js +1 -0
  15. package/dist-bloby/assets/{edge-B-9TrlZC.js → edge-CeStCG6d.js} +1 -1
  16. package/dist-bloby/assets/{elixir-CXCzbj1r.js → elixir-CNfWtFyr.js} +1 -1
  17. package/dist-bloby/assets/{elm-BdRiwmde.js → elm-WhyRrsYH.js} +1 -1
  18. package/dist-bloby/assets/{erb-C9tvRzx3.js → erb-BvJkfco6.js} +1 -1
  19. package/dist-bloby/assets/{erlang-Bc4hQuqa.js → erlang-CjZU-VwD.js} +1 -1
  20. package/dist-bloby/assets/{fortran-fixed-form-B02FOYI-.js → fortran-fixed-form-CLgNuKMV.js} +1 -1
  21. package/dist-bloby/assets/{fsharp-DhdR18vN.js → fsharp-kVgJ9XJy.js} +1 -1
  22. package/dist-bloby/assets/{gdresource-DgnrMPIx.js → gdresource-DDsMuL8p.js} +1 -1
  23. package/dist-bloby/assets/{git-commit-DGJi7qBD.js → git-commit-BKhxSJdF.js} +1 -1
  24. package/dist-bloby/assets/{git-rebase-HwDSB2qJ.js → git-rebase-C1GyNmcX.js} +1 -1
  25. package/dist-bloby/assets/{glimmer-js-B6LF_BMd.js → glimmer-js-Cl3u7vjy.js} +1 -1
  26. package/dist-bloby/assets/{glimmer-ts-Cn42BUKe.js → glimmer-ts-CtPlRgiA.js} +1 -1
  27. package/dist-bloby/assets/globals-B1T5ANQV.js +18 -0
  28. package/dist-bloby/assets/globals-CcIc79IH.css +2 -0
  29. package/dist-bloby/assets/glsl-Bz5r7Lln.js +1 -0
  30. package/dist-bloby/assets/graphql-IV9ZCUty.js +1 -0
  31. package/dist-bloby/assets/{hack-DDEqRjBe.js → hack-XsNdYtzr.js} +1 -1
  32. package/dist-bloby/assets/haml-BDRqXh7d.js +1 -0
  33. package/dist-bloby/assets/{handlebars-g9Qe0ao2.js → handlebars-Rv2-mTii.js} +1 -1
  34. package/dist-bloby/assets/highlighted-body-OFNGDK62-CHkKxiLr.js +1 -0
  35. package/dist-bloby/assets/html-BkYSbpwH.js +1 -0
  36. package/dist-bloby/assets/{html-derivative-D-XvNBA6.js → html-derivative-CNiypDIO.js} +1 -1
  37. package/dist-bloby/assets/{http-qlhghEti.js → http-Vgn8hmbu.js} +1 -1
  38. package/dist-bloby/assets/{hurl-CHIKfBKk.js → hurl-C_EA75yu.js} +1 -1
  39. package/dist-bloby/assets/{hxml-adC65L_J.js → hxml-YehGxZ3T.js} +1 -1
  40. package/dist-bloby/assets/java-div3J5pm.js +1 -0
  41. package/dist-bloby/assets/javascript-D7sYfeLa.js +1 -0
  42. package/dist-bloby/assets/{jinja-BHZt0_Dn.js → jinja-BovBDArb.js} +1 -1
  43. package/dist-bloby/assets/{jison-TqJYWKkW.js → jison-C7UZOdoh.js} +1 -1
  44. package/dist-bloby/assets/json-DsAnzN7U.js +1 -0
  45. package/dist-bloby/assets/jsx-CftCCFil.js +1 -0
  46. package/dist-bloby/assets/jsx-runtime-DsY8nUeV.js +1 -0
  47. package/dist-bloby/assets/{julia-CW07fy07.js → julia-D8hM3XBr.js} +1 -1
  48. package/dist-bloby/assets/{just-DBcWo9WY.js → just-CHnwfRRG.js} +1 -1
  49. package/dist-bloby/assets/{latex-D6lXiPTF.js → latex-Ccu-ZO0T.js} +1 -1
  50. package/dist-bloby/assets/{liquid-DhYYAQ41.js → liquid-BRbNyfzr.js} +1 -1
  51. package/dist-bloby/assets/lua-BcwT4KiU.js +1 -0
  52. package/dist-bloby/assets/{marko-xtrIBdcL.js → marko-Both7s0f.js} +1 -1
  53. package/dist-bloby/assets/{mdc-DyZVNnwP.js → mdc-7TpRllSI.js} +1 -1
  54. package/dist-bloby/assets/mermaid-GHXKKRXX-LsCge3XG.js +1 -0
  55. package/dist-bloby/assets/{nextflow-JEyYUlIq.js → nextflow-C2lnptGp.js} +1 -1
  56. package/dist-bloby/assets/{nginx-CGgm1VOJ.js → nginx-1MGd6YK-.js} +1 -1
  57. package/dist-bloby/assets/{nim-Br7S817Z.js → nim-CXWhMB6N.js} +1 -1
  58. package/dist-bloby/assets/onboard-DdL-0meC.js +1 -0
  59. package/dist-bloby/assets/{perl-DqDX-7VG.js → perl-s-whHxj8.js} +1 -1
  60. package/dist-bloby/assets/{php-DYSqNNGJ.js → php-KdIqqcNq.js} +1 -1
  61. package/dist-bloby/assets/{pug-Bob3gNio.js → pug-Cj_1QUAx.js} +1 -1
  62. package/dist-bloby/assets/{qml-CsMafcqN.js → qml-BQHwZF2t.js} +1 -1
  63. package/dist-bloby/assets/r-BW3neTZ6.js +1 -0
  64. package/dist-bloby/assets/{razor-B4PzhaZX.js → razor-D4oLdRr2.js} +1 -1
  65. package/dist-bloby/assets/regexp-CK2Vecnb.js +1 -0
  66. package/dist-bloby/assets/rolldown-runtime-C-57s9n3.js +1 -0
  67. package/dist-bloby/assets/{rst-BXuz-2b8.js → rst-kaCCXG10.js} +1 -1
  68. package/dist-bloby/assets/{ruby-CXP5_4kq.js → ruby-DIAu88GV.js} +1 -1
  69. package/dist-bloby/assets/{sas-Cov9PzAD.js → sas-DW2U5bKI.js} +1 -1
  70. package/dist-bloby/assets/scss-CpUwMEPb.js +1 -0
  71. package/dist-bloby/assets/{shaderlab-DZ3Lsiak.js → shaderlab-CCgEvKkt.js} +1 -1
  72. package/dist-bloby/assets/shellscript-BhywzMlr.js +1 -0
  73. package/dist-bloby/assets/{shellsession-BHLVblBB.js → shellsession-vB5Hy6UU.js} +1 -1
  74. package/dist-bloby/assets/{soy-e0u3-wIA.js → soy-BNDHXm4e.js} +1 -1
  75. package/dist-bloby/assets/{sparql-B9c85a_o.js → sparql-DH0hFmAi.js} +1 -1
  76. package/dist-bloby/assets/sql-D395ukne.js +1 -0
  77. package/dist-bloby/assets/{stata-B1mLEMrz.js → stata-BHXdpuN3.js} +1 -1
  78. package/dist-bloby/assets/{surrealql-BTKo2XFY.js → surrealql-eiBkI2Jy.js} +1 -1
  79. package/dist-bloby/assets/{svelte-B7URZ-wm.js → svelte-DcqzCcP6.js} +1 -1
  80. package/dist-bloby/assets/{templ-DVRYIgGq.js → templ-DpMCsFaT.js} +1 -1
  81. package/dist-bloby/assets/{tex-CdJ24HJj.js → tex-B71AZ6Vb.js} +1 -1
  82. package/dist-bloby/assets/{ts-tags-CCSbelDn.js → ts-tags-CRuJWBGV.js} +1 -1
  83. package/dist-bloby/assets/tsx-CEFbrBOd.js +1 -0
  84. package/dist-bloby/assets/{twig-Dn4ruiVl.js → twig-CuSIh_aH.js} +1 -1
  85. package/dist-bloby/assets/typescript-CV9iMaP7.js +1 -0
  86. package/dist-bloby/assets/{vue-D19cWHwY.js → vue-YbgnWnT2.js} +1 -1
  87. package/dist-bloby/assets/{vue-html-_j-KC7Cs.js → vue-html-CXsio3-X.js} +1 -1
  88. package/dist-bloby/assets/{vue-vine-BC03MN6c.js → vue-vine-C8pVogU0.js} +1 -1
  89. package/dist-bloby/assets/xml-Zmzpltp0.js +1 -0
  90. package/dist-bloby/assets/{xsl-DR-zOeBm.js → xsl-CqzL2w2F.js} +1 -1
  91. package/dist-bloby/assets/yaml-Dc_auW1I.js +1 -0
  92. package/dist-bloby/bloby.html +5 -4
  93. package/dist-bloby/onboard.html +5 -4
  94. package/package.json +1 -1
  95. package/supervisor/bloby-agent.ts +65 -633
  96. package/supervisor/chat/OnboardWizard.tsx +315 -69
  97. package/supervisor/harnesses/claude.ts +684 -0
  98. package/supervisor/harnesses/codex.ts +73 -0
  99. package/supervisor/harnesses/types.ts +81 -0
  100. package/supervisor/index.ts +1 -1
  101. package/worker/codex-auth.ts +362 -137
  102. package/worker/index.ts +30 -4
  103. package/dist-bloby/assets/angular-html-olSuI25H.js +0 -1
  104. package/dist-bloby/assets/c-BvB8CVo8.js +0 -1
  105. package/dist-bloby/assets/cpp-BblbpnyR.js +0 -1
  106. package/dist-bloby/assets/css-zY4NE9yA.js +0 -1
  107. package/dist-bloby/assets/globals-LpXKrQgt.css +0 -2
  108. package/dist-bloby/assets/globals-zKQhzQOX.js +0 -18
  109. package/dist-bloby/assets/glsl-CEMf-THb.js +0 -1
  110. package/dist-bloby/assets/graphql-dBCd2Czl.js +0 -1
  111. package/dist-bloby/assets/haml-Ck5pVAEG.js +0 -1
  112. package/dist-bloby/assets/highlighted-body-OFNGDK62-B0W8hCx-.js +0 -1
  113. package/dist-bloby/assets/html-CzX0w7K_.js +0 -1
  114. package/dist-bloby/assets/java-BqKEu7zh.js +0 -1
  115. package/dist-bloby/assets/javascript-CzjRtS1s.js +0 -1
  116. package/dist-bloby/assets/json-CdFmZMJc.js +0 -1
  117. package/dist-bloby/assets/jsx-BL6Wh6Qw.js +0 -1
  118. package/dist-bloby/assets/jsx-runtime-C0W9Wf2W.js +0 -1
  119. package/dist-bloby/assets/lua-B4ezzssg.js +0 -1
  120. package/dist-bloby/assets/mermaid-GHXKKRXX-Dr8I7wwH.js +0 -1
  121. package/dist-bloby/assets/onboard-C1yXK8uT.js +0 -1
  122. package/dist-bloby/assets/r-CGji9_vM.js +0 -1
  123. package/dist-bloby/assets/regexp-CvWG4lI-.js +0 -1
  124. package/dist-bloby/assets/scss-Efq7Dmbs.js +0 -1
  125. package/dist-bloby/assets/shellscript-BbEstezf.js +0 -1
  126. package/dist-bloby/assets/sql-CB6kO6Km.js +0 -1
  127. package/dist-bloby/assets/tsx-DrzBggF8.js +0 -1
  128. package/dist-bloby/assets/typescript-COZIw7xM.js +0 -1
  129. package/dist-bloby/assets/xml-BlDEvPia.js +0 -1
  130. package/dist-bloby/assets/yaml-iUXljnLs.js +0 -1
  131. /package/dist-bloby/assets/{abap-smLpETzL.js → abap--vzi7Rxy.js} +0 -0
  132. /package/dist-bloby/assets/{actionscript-3-o-aRvjY5.js → actionscript-3-CV21uODD.js} +0 -0
  133. /package/dist-bloby/assets/{ada-D5RRX1i4.js → ada-DpXSEmbw.js} +0 -0
  134. /package/dist-bloby/assets/{andromeeda-N4z3YzmR.js → andromeeda-C1V0Cb0M.js} +0 -0
  135. /package/dist-bloby/assets/{apache-DttKlSqg.js → apache-CRmVjs8c.js} +0 -0
  136. /package/dist-bloby/assets/{apex-DL7j-a2n.js → apex-DIIc4r7E.js} +0 -0
  137. /package/dist-bloby/assets/{applescript-DCbL_2FX.js → applescript-DMX6NGuU.js} +0 -0
  138. /package/dist-bloby/assets/{ara-DqheWJCe.js → ara-3SArX2Zn.js} +0 -0
  139. /package/dist-bloby/assets/{asciidoc-BH2sf2K4.js → asciidoc-CnVFjb7X.js} +0 -0
  140. /package/dist-bloby/assets/{asm-rfjOMz3U.js → asm-Cb-CgaBD.js} +0 -0
  141. /package/dist-bloby/assets/{aurora-x-CND-FqEb.js → aurora-x-CjvoFyi0.js} +0 -0
  142. /package/dist-bloby/assets/{awk-CMV5n9Z7.js → awk-BYjsWVhV.js} +0 -0
  143. /package/dist-bloby/assets/{ayu-dark-on7xzq_B.js → ayu-dark-C4UVdT_g.js} +0 -0
  144. /package/dist-bloby/assets/{ayu-light-DnGeGGc2.js → ayu-light-CFJ-dST-.js} +0 -0
  145. /package/dist-bloby/assets/{ayu-mirage-DG3LlYC_.js → ayu-mirage-BxM9D2Mi.js} +0 -0
  146. /package/dist-bloby/assets/{ballerina-BjMqJjlr.js → ballerina-BsKCUtAm.js} +0 -0
  147. /package/dist-bloby/assets/{bat-BaVbo_qw.js → bat-CJlQOahT.js} +0 -0
  148. /package/dist-bloby/assets/{beancount-DBt5Mbc_.js → beancount-Cyf6Xlzd.js} +0 -0
  149. /package/dist-bloby/assets/{berry-Cyjuxiss.js → berry-DHYmFnza.js} +0 -0
  150. /package/dist-bloby/assets/{bibtex-BV_0nsPq.js → bibtex-BUB9btZd.js} +0 -0
  151. /package/dist-bloby/assets/{bicep-C2gEwu4J.js → bicep-CNVX4dQj.js} +0 -0
  152. /package/dist-bloby/assets/{bird2-BRyaEJd0.js → bird2-LZP25z1s.js} +0 -0
  153. /package/dist-bloby/assets/{c3-DTTbp5N2.js → c3-BI41OB2W.js} +0 -0
  154. /package/dist-bloby/assets/{cadence-CPz83cmI.js → cadence-BDnzkZFt.js} +0 -0
  155. /package/dist-bloby/assets/{catppuccin-frappe-Dr22sraq.js → catppuccin-frappe-DpT1lCYX.js} +0 -0
  156. /package/dist-bloby/assets/{catppuccin-latte-C57EeX8c.js → catppuccin-latte-qMMse1WJ.js} +0 -0
  157. /package/dist-bloby/assets/{catppuccin-macchiato-CpheI4uD.js → catppuccin-macchiato-DMu0Ac9B.js} +0 -0
  158. /package/dist-bloby/assets/{catppuccin-mocha-D8Lmdks_.js → catppuccin-mocha-DicTaD9V.js} +0 -0
  159. /package/dist-bloby/assets/{clarity-CFJ2Yc3q.js → clarity-CPz-yzAn.js} +0 -0
  160. /package/dist-bloby/assets/{clojure-6R01QgJC.js → clojure-BxJLFKTj.js} +0 -0
  161. /package/dist-bloby/assets/{cmake-D5rSbMir.js → cmake-BmC4o4J9.js} +0 -0
  162. /package/dist-bloby/assets/{codeowners-_3A-ClkN.js → codeowners-BPHDuybI.js} +0 -0
  163. /package/dist-bloby/assets/{codeql-DlIhJTR7.js → codeql-DYWyWzRY.js} +0 -0
  164. /package/dist-bloby/assets/{common-lisp-BvQzz173.js → common-lisp-CsDdrwfa.js} +0 -0
  165. /package/dist-bloby/assets/{coq-DTNXReIC.js → coq-BZNwxllS.js} +0 -0
  166. /package/dist-bloby/assets/{csharp-BDKQY1K9.js → csharp-BLhQzhUA.js} +0 -0
  167. /package/dist-bloby/assets/{csv-DNUpVBxl.js → csv-DPc9UZFt.js} +0 -0
  168. /package/dist-bloby/assets/{cue-DDdBc2s3.js → cue-Bat8Mt8Y.js} +0 -0
  169. /package/dist-bloby/assets/{cypher-CguaznO2.js → cypher-CTnWkM4Y.js} +0 -0
  170. /package/dist-bloby/assets/{d-CHcoyjv3.js → d-CccbtpLU.js} +0 -0
  171. /package/dist-bloby/assets/{dark-plus-CqeW_0kH.js → dark-plus-CKh7uIvz.js} +0 -0
  172. /package/dist-bloby/assets/{dart-RM3aRphk.js → dart-SbRHwU1n.js} +0 -0
  173. /package/dist-bloby/assets/{dax-nbnY1d79.js → dax-vVKSTwd9.js} +0 -0
  174. /package/dist-bloby/assets/{desktop-BD76cvxT.js → desktop-rdWGepy4.js} +0 -0
  175. /package/dist-bloby/assets/{diff-CdkWtnkL.js → diff-G5H-0DNT.js} +0 -0
  176. /package/dist-bloby/assets/{docker-ZyPHc6zB.js → docker-CC20slQp.js} +0 -0
  177. /package/dist-bloby/assets/{dotenv-BdJZEwA6.js → dotenv-C36c6TdP.js} +0 -0
  178. /package/dist-bloby/assets/{dracula-CtqCPLGa.js → dracula-nNMQZYa7.js} +0 -0
  179. /package/dist-bloby/assets/{dracula-soft-DmBpwRAy.js → dracula-soft-BPmUsSlJ.js} +0 -0
  180. /package/dist-bloby/assets/{dream-maker-BJL4qlg3.js → dream-maker-DleGc9Hy.js} +0 -0
  181. /package/dist-bloby/assets/{emacs-lisp-_LyYa2Ky.js → emacs-lisp-D_QlcMHs.js} +0 -0
  182. /package/dist-bloby/assets/{everforest-dark-CrbyKk4n.js → everforest-dark-FkVvIMUl.js} +0 -0
  183. /package/dist-bloby/assets/{everforest-light-DRbSh8Tm.js → everforest-light-d3V1wTAd.js} +0 -0
  184. /package/dist-bloby/assets/{fennel-CC2BkRsS.js → fennel-BEssPROc.js} +0 -0
  185. /package/dist-bloby/assets/{fish-D2ZCzqcE.js → fish-Cz5yLEyJ.js} +0 -0
  186. /package/dist-bloby/assets/{fluent-DKAm3m7q.js → fluent-TGO8KajN.js} +0 -0
  187. /package/dist-bloby/assets/{fortran-free-form-BPTf0lbT.js → fortran-free-form-CHQXX5JB.js} +0 -0
  188. /package/dist-bloby/assets/{gdscript-CsadCSaZ.js → gdscript-DBkVGsC6.js} +0 -0
  189. /package/dist-bloby/assets/{gdshader-PfnN_8tR.js → gdshader-CWQhZP7Q.js} +0 -0
  190. /package/dist-bloby/assets/{genie-Bj-orPAV.js → genie-7iw14YxB.js} +0 -0
  191. /package/dist-bloby/assets/{gherkin-COVWpJ-Q.js → gherkin-D4AlAQSH.js} +0 -0
  192. /package/dist-bloby/assets/{github-dark-ipGuFGYC.js → github-dark-CpBni1SQ.js} +0 -0
  193. /package/dist-bloby/assets/{github-dark-default-DX3IG_X0.js → github-dark-default-Cr5Q59Ad.js} +0 -0
  194. /package/dist-bloby/assets/{github-dark-dimmed-CH6p_7ez.js → github-dark-dimmed-WEORr92a.js} +0 -0
  195. /package/dist-bloby/assets/{github-dark-high-contrast-Bg2sSao5.js → github-dark-high-contrast-uM2plAzl.js} +0 -0
  196. /package/dist-bloby/assets/{github-light-BxjqOQl0.js → github-light-BROm54vS.js} +0 -0
  197. /package/dist-bloby/assets/{github-light-default-DwpDd1IQ.js → github-light-default-jSwgX00f.js} +0 -0
  198. /package/dist-bloby/assets/{github-light-high-contrast-C0QeixPf.js → github-light-high-contrast-Bp9ESXtp.js} +0 -0
  199. /package/dist-bloby/assets/{gleam-BF2NigGj.js → gleam-D1LXnIj0.js} +0 -0
  200. /package/dist-bloby/assets/{gn-CMIt9roj.js → gn-CReOiE5m.js} +0 -0
  201. /package/dist-bloby/assets/{gnuplot-DgWlRTEj.js → gnuplot-DufViamc.js} +0 -0
  202. /package/dist-bloby/assets/{go-DLnOLj8q.js → go-DC_Zm44P.js} +0 -0
  203. /package/dist-bloby/assets/{groovy-B9qLWIkE.js → groovy-DEGDVBi0.js} +0 -0
  204. /package/dist-bloby/assets/{gruvbox-dark-hard-BIMX9ePb.js → gruvbox-dark-hard-C-zANgxR.js} +0 -0
  205. /package/dist-bloby/assets/{gruvbox-dark-medium-DxuwyVzM.js → gruvbox-dark-medium-DY7Z6TBK.js} +0 -0
  206. /package/dist-bloby/assets/{gruvbox-dark-soft-ba2fjht0.js → gruvbox-dark-soft-Bpj6owGh.js} +0 -0
  207. /package/dist-bloby/assets/{gruvbox-light-hard-DAJK2PqC.js → gruvbox-light-hard-DVwTvHam.js} +0 -0
  208. /package/dist-bloby/assets/{gruvbox-light-medium-WRifDAJD.js → gruvbox-light-medium-98PeoD5Y.js} +0 -0
  209. /package/dist-bloby/assets/{gruvbox-light-soft-B0dBOoVB.js → gruvbox-light-soft-BHI2PZTB.js} +0 -0
  210. /package/dist-bloby/assets/{haskell-BaGpmm_c.js → haskell-B-K-GoPf.js} +0 -0
  211. /package/dist-bloby/assets/{haxe-DfXTCEOz.js → haxe-md5t_Y_E.js} +0 -0
  212. /package/dist-bloby/assets/{hcl-CbCtpSbi.js → hcl-qSvp9jTg.js} +0 -0
  213. /package/dist-bloby/assets/{hjson-_4-w-pHU.js → hjson-BNeV6JDA.js} +0 -0
  214. /package/dist-bloby/assets/{hlsl-DpuYn7pp.js → hlsl-CFf5czm3.js} +0 -0
  215. /package/dist-bloby/assets/{horizon-C5RtD1fY.js → horizon-C4a2pCDo.js} +0 -0
  216. /package/dist-bloby/assets/{horizon-bright-pEOice34.js → horizon-bright-Bgpx-0aF.js} +0 -0
  217. /package/dist-bloby/assets/{houston-A0zg9vNP.js → houston-BZHNDhe5.js} +0 -0
  218. /package/dist-bloby/assets/{hy-t9zDXBje.js → hy-hI-CUgFt.js} +0 -0
  219. /package/dist-bloby/assets/{imba-Bxu-TDfw.js → imba-Dr5pZl3x.js} +0 -0
  220. /package/dist-bloby/assets/{ini-D-v34c8N.js → ini-KxzJ-qxg.js} +0 -0
  221. /package/dist-bloby/assets/{json5-D0XL1D5m.js → json5-SRM7tKmT.js} +0 -0
  222. /package/dist-bloby/assets/{jsonc-BBgf3TX3.js → jsonc-Cix1XnqC.js} +0 -0
  223. /package/dist-bloby/assets/{jsonl-KrKLbtB7.js → jsonl-BzKwo-fD.js} +0 -0
  224. /package/dist-bloby/assets/{jsonnet-B2ZwWMOt.js → jsonnet-DaiLv8or.js} +0 -0
  225. /package/dist-bloby/assets/{jssm-ByRpI9-B.js → jssm-B1pV58QJ.js} +0 -0
  226. /package/dist-bloby/assets/{kanagawa-dragon-CtPmcCMp.js → kanagawa-dragon-BihvT_N-.js} +0 -0
  227. /package/dist-bloby/assets/{kanagawa-lotus-DpOXEGCa.js → kanagawa-lotus-DQN_bzSt.js} +0 -0
  228. /package/dist-bloby/assets/{kanagawa-wave-CLVCyc-n.js → kanagawa-wave-Bvz_F3hD.js} +0 -0
  229. /package/dist-bloby/assets/{kdl-6FPPEH4H.js → kdl-DupMG4Bk.js} +0 -0
  230. /package/dist-bloby/assets/{kotlin-D4L3Nd2D.js → kotlin-rOGI_fXV.js} +0 -0
  231. /package/dist-bloby/assets/{kusto-D-mmc07O.js → kusto-CHXnQR8L.js} +0 -0
  232. /package/dist-bloby/assets/{laserwave-7fEj4XGb.js → laserwave-CPMyzJF3.js} +0 -0
  233. /package/dist-bloby/assets/{lean-BMVMuP2E.js → lean-B76KugVy.js} +0 -0
  234. /package/dist-bloby/assets/{less-C95PyOu0.js → less-DwUMKQAG.js} +0 -0
  235. /package/dist-bloby/assets/{light-plus-DHI2dh3p.js → light-plus-C6sdUQiS.js} +0 -0
  236. /package/dist-bloby/assets/{llvm-Dy3qORTl.js → llvm-DumY6MCH.js} +0 -0
  237. /package/dist-bloby/assets/{log-BQop7fzg.js → log-DdP6k-FU.js} +0 -0
  238. /package/dist-bloby/assets/{logo-DKtnYmrp.js → logo-Cx0gX691.js} +0 -0
  239. /package/dist-bloby/assets/{luau-Dha4KG0q.js → luau-CI4wJBxI.js} +0 -0
  240. /package/dist-bloby/assets/{make-DfmS6buu.js → make-BlyBJiAs.js} +0 -0
  241. /package/dist-bloby/assets/{markdown-BaI9LyM4.js → markdown-BFgBvytj.js} +0 -0
  242. /package/dist-bloby/assets/{material-theme-Dm6ETY8i.js → material-theme-CyGvAAeY.js} +0 -0
  243. /package/dist-bloby/assets/{material-theme-darker-BeyjmM5Z.js → material-theme-darker-DJAOSarR.js} +0 -0
  244. /package/dist-bloby/assets/{material-theme-lighter-CCOYYzKL.js → material-theme-lighter-Cb7t96j2.js} +0 -0
  245. /package/dist-bloby/assets/{material-theme-ocean-CUtPiiX3.js → material-theme-ocean-EZZ55_HD.js} +0 -0
  246. /package/dist-bloby/assets/{material-theme-palenight-2L4zMwIM.js → material-theme-palenight-DtmMSfya.js} +0 -0
  247. /package/dist-bloby/assets/{matlab-BT79Cq_j.js → matlab-BFLobVcp.js} +0 -0
  248. /package/dist-bloby/assets/{mdx-CxGBwLNt.js → mdx-Baux4qlv.js} +0 -0
  249. /package/dist-bloby/assets/{mermaid-DLf3axBN.js → mermaid-DHr7T0Rt.js} +0 -0
  250. /package/dist-bloby/assets/{min-dark-B8TUPGHg.js → min-dark-C9N1U4-e.js} +0 -0
  251. /package/dist-bloby/assets/{min-light-BDOoBxcA.js → min-light-Ce9oxBvH.js} +0 -0
  252. /package/dist-bloby/assets/{mipsasm-DXuU_0cI.js → mipsasm-Cgb1v7yV.js} +0 -0
  253. /package/dist-bloby/assets/{mojo-1Omp2pIo.js → mojo-BnTBKscO.js} +0 -0
  254. /package/dist-bloby/assets/{monokai-E_VBmXGZ.js → monokai-BGD_YBH-.js} +0 -0
  255. /package/dist-bloby/assets/{moonbit-DZzq699o.js → moonbit-HXw0ZM4h.js} +0 -0
  256. /package/dist-bloby/assets/{move-DxDAOJVd.js → move-DG2efXqI.js} +0 -0
  257. /package/dist-bloby/assets/{narrat-CxDcPPb9.js → narrat-BSasSB5t.js} +0 -0
  258. /package/dist-bloby/assets/{nextflow-groovy-wvmJO4hi.js → nextflow-groovy-DXLl8k8E.js} +0 -0
  259. /package/dist-bloby/assets/{night-owl-DefhalNX.js → night-owl-DxqNTXDa.js} +0 -0
  260. /package/dist-bloby/assets/{night-owl-light-byb3AbEn.js → night-owl-light-MPn8GCyh.js} +0 -0
  261. /package/dist-bloby/assets/{nix-DsFTDHWT.js → nix-BpnttlWr.js} +0 -0
  262. /package/dist-bloby/assets/{nord-D5rQzHT-.js → nord-Mt6M_qHE.js} +0 -0
  263. /package/dist-bloby/assets/{nushell-BQ_rO0AM.js → nushell-CS7Mvg-G.js} +0 -0
  264. /package/dist-bloby/assets/{objective-c-BMq6JT_m.js → objective-c-U4EuJXJs.js} +0 -0
  265. /package/dist-bloby/assets/{objective-cpp-DRwojuGv.js → objective-cpp-CE_PrXRW.js} +0 -0
  266. /package/dist-bloby/assets/{ocaml-e4_gKO6E.js → ocaml-ZsxDKzyv.js} +0 -0
  267. /package/dist-bloby/assets/{odin-mdTPwYOg.js → odin-CDoDiNYU.js} +0 -0
  268. /package/dist-bloby/assets/{one-dark-pro-DxXww9jg.js → one-dark-pro-B9P_I1yh.js} +0 -0
  269. /package/dist-bloby/assets/{one-light-D9c03w7t.js → one-light-Cv3j6GXq.js} +0 -0
  270. /package/dist-bloby/assets/{openscad-D2aTdNfr.js → openscad-CfJwW9dY.js} +0 -0
  271. /package/dist-bloby/assets/{pascal-D4n_G8vj.js → pascal-CjE0UTC7.js} +0 -0
  272. /package/dist-bloby/assets/{pkl-DcjhAp0L.js → pkl-BN6EkHr9.js} +0 -0
  273. /package/dist-bloby/assets/{plastic-uOsw7z1x.js → plastic-BCnZnfMk.js} +0 -0
  274. /package/dist-bloby/assets/{plsql-BSy3Ag0J.js → plsql-1LW-CqWM.js} +0 -0
  275. /package/dist-bloby/assets/{po-Be96RYkA.js → po-Cf5hRC9x.js} +0 -0
  276. /package/dist-bloby/assets/{poimandres-CyO4HORD.js → poimandres-B_zC30Vt.js} +0 -0
  277. /package/dist-bloby/assets/{polar-BmhMKWum.js → polar-S6fWkEw8.js} +0 -0
  278. /package/dist-bloby/assets/{postcss-BTQso3H9.js → postcss-cZXfRCsF.js} +0 -0
  279. /package/dist-bloby/assets/{powerquery-DVyQv3M2.js → powerquery-CoRQQdNP.js} +0 -0
  280. /package/dist-bloby/assets/{powershell-BmtCGJVD.js → powershell-B2VxwRch.js} +0 -0
  281. /package/dist-bloby/assets/{prisma-CCFA9rEj.js → prisma-sLrt38jj.js} +0 -0
  282. /package/dist-bloby/assets/{prolog-DWGEEo78.js → prolog-CL99toUJ.js} +0 -0
  283. /package/dist-bloby/assets/{proto-C3eop1kM.js → proto-CtiBQJNn.js} +0 -0
  284. /package/dist-bloby/assets/{puppet-C0_7Nv5A.js → puppet-BlbpxWq2.js} +0 -0
  285. /package/dist-bloby/assets/{purescript-Bv-B8yRw.js → purescript-DPcVkoDV.js} +0 -0
  286. /package/dist-bloby/assets/{python-CKg5r0C3.js → python-BLpCXkJ6.js} +0 -0
  287. /package/dist-bloby/assets/{qmldir-Cqfb4Lox.js → qmldir-BcwbwUc8.js} +0 -0
  288. /package/dist-bloby/assets/{qss-Csho9BH8.js → qss-erDfnnzG.js} +0 -0
  289. /package/dist-bloby/assets/{racket-D8-uWeQH.js → racket-Dch6VQku.js} +0 -0
  290. /package/dist-bloby/assets/{raku-Cj4JSa8p.js → raku-Db8mfsiE.js} +0 -0
  291. /package/dist-bloby/assets/{red-z4H4llUY.js → red-DWyyM82l.js} +0 -0
  292. /package/dist-bloby/assets/{reg-DXGFiJSl.js → reg-3F9yjO5J.js} +0 -0
  293. /package/dist-bloby/assets/{rel-CunnVTBK.js → rel-CQq8nxxL.js} +0 -0
  294. /package/dist-bloby/assets/{riscv-C8BcOCkS.js → riscv-CsUwotvK.js} +0 -0
  295. /package/dist-bloby/assets/{ron-DiDyR9oa.js → ron-BwlS4rWu.js} +0 -0
  296. /package/dist-bloby/assets/{rose-pine-BADquuIH.js → rose-pine-DEj8gOox.js} +0 -0
  297. /package/dist-bloby/assets/{rose-pine-dawn-BLcEeBoh.js → rose-pine-dawn-DjarqQ2I.js} +0 -0
  298. /package/dist-bloby/assets/{rose-pine-moon-BK_tLY1Y.js → rose-pine-moon-D7ffkR_D.js} +0 -0
  299. /package/dist-bloby/assets/{rosmsg-CHmL1Uyj.js → rosmsg-BmwwVMq5.js} +0 -0
  300. /package/dist-bloby/assets/{rust-DjJFInu3.js → rust-DsIgDjpj.js} +0 -0
  301. /package/dist-bloby/assets/{sass-D3xZ5o-v.js → sass-CkIFK_bT.js} +0 -0
  302. /package/dist-bloby/assets/{scala-B0IRml5w.js → scala-C0TSxhxD.js} +0 -0
  303. /package/dist-bloby/assets/{scheme-BhwcV3Av.js → scheme-e-5nJ58U.js} +0 -0
  304. /package/dist-bloby/assets/{sdbl-BmWYR-pI.js → sdbl-DOe8Nral.js} +0 -0
  305. /package/dist-bloby/assets/{slack-dark-DOnVms5P.js → slack-dark-CClHvLju.js} +0 -0
  306. /package/dist-bloby/assets/{slack-ochin-DcRTft4q.js → slack-ochin-DwCpSVBI.js} +0 -0
  307. /package/dist-bloby/assets/{smalltalk-DVQuUMII.js → smalltalk-fjkC4HKG.js} +0 -0
  308. /package/dist-bloby/assets/{snazzy-light-x9CLJ1W9.js → snazzy-light-2nD216w0.js} +0 -0
  309. /package/dist-bloby/assets/{solarized-dark-BB1sh-pe.js → solarized-dark-BkxMSETv.js} +0 -0
  310. /package/dist-bloby/assets/{solarized-light-9-RPS998.js → solarized-light-BScqQ1C4.js} +0 -0
  311. /package/dist-bloby/assets/{solidity-gQ4WXILB.js → solidity-DbOxJfAY.js} +0 -0
  312. /package/dist-bloby/assets/{splunk-OB48_RcD.js → splunk-BW0l10cw.js} +0 -0
  313. /package/dist-bloby/assets/{ssh-config-DA9YMRGV.js → ssh-config-XN7RWvZy.js} +0 -0
  314. /package/dist-bloby/assets/{stylus-sKwvsUaC.js → stylus-D69is74S.js} +0 -0
  315. /package/dist-bloby/assets/{swift-C72NbAtg.js → swift-CqNHAbQB.js} +0 -0
  316. /package/dist-bloby/assets/{synthwave-84-eJ9uRN_S.js → synthwave-84-Ct3Np89a.js} +0 -0
  317. /package/dist-bloby/assets/{system-verilog-CnWMF7Nq.js → system-verilog-CHbvBf8h.js} +0 -0
  318. /package/dist-bloby/assets/{systemd-DMzItW5N.js → systemd-BBC3Z_R4.js} +0 -0
  319. /package/dist-bloby/assets/{talonscript-DopQCWDL.js → talonscript-DhYQB2ic.js} +0 -0
  320. /package/dist-bloby/assets/{tasl-C28SYKbq.js → tasl-CNtai3BH.js} +0 -0
  321. /package/dist-bloby/assets/{tcl-DHq7zmoF.js → tcl-DFzyQSXW.js} +0 -0
  322. /package/dist-bloby/assets/{terraform-CogS1YKX.js → terraform-BijD6Khb.js} +0 -0
  323. /package/dist-bloby/assets/{tokyo-night-B9N7LyrF.js → tokyo-night-Dd5BGAxh.js} +0 -0
  324. /package/dist-bloby/assets/{toml-BH_iPsgK.js → toml-DZofdujH.js} +0 -0
  325. /package/dist-bloby/assets/{tsv-BIkdBZX1.js → tsv-DOp6g7sz.js} +0 -0
  326. /package/dist-bloby/assets/{turtle-CqNXyJWZ.js → turtle-BKcRDROw.js} +0 -0
  327. /package/dist-bloby/assets/{typespec-CQ9LYD_e.js → typespec-Mmt3-2Cw.js} +0 -0
  328. /package/dist-bloby/assets/{typst-T-Fsk-Sv.js → typst-CndOdNo_.js} +0 -0
  329. /package/dist-bloby/assets/{v-BhMEOw9x.js → v-DjlZIA0C.js} +0 -0
  330. /package/dist-bloby/assets/{vala-DzajMnwt.js → vala-C5Nm5NXo.js} +0 -0
  331. /package/dist-bloby/assets/{vb-7Xr8dEYW.js → vb-zZeWbE2_.js} +0 -0
  332. /package/dist-bloby/assets/{verilog-AvXtwZir.js → verilog-CyZIVfoz.js} +0 -0
  333. /package/dist-bloby/assets/{vesper-CtgQQ2sf.js → vesper-B0BMGbco.js} +0 -0
  334. /package/dist-bloby/assets/{vhdl-BHu0zg1P.js → vhdl-DH1mJdjZ.js} +0 -0
  335. /package/dist-bloby/assets/{viml-Di0QpLfC.js → viml-e-oP1x-l.js} +0 -0
  336. /package/dist-bloby/assets/{vitesse-black-jXdfyqgD.js → vitesse-black-BRAUsA4Q.js} +0 -0
  337. /package/dist-bloby/assets/{vitesse-dark-B88PxG1r.js → vitesse-dark-Dyg71HnT.js} +0 -0
  338. /package/dist-bloby/assets/{vitesse-light-BXxZh2iV.js → vitesse-light-BJKZKqvd.js} +0 -0
  339. /package/dist-bloby/assets/{vyper-C3R5yXgx.js → vyper-BRPzCrki.js} +0 -0
  340. /package/dist-bloby/assets/{wasm-Chsuwt1A.js → wasm-DYMpDie-.js} +0 -0
  341. /package/dist-bloby/assets/{wasm-CEUrWlVz.js → wasm-Drz0Uqci.js} +0 -0
  342. /package/dist-bloby/assets/{wenyan-BonVcr2i.js → wenyan-BiJ0NePu.js} +0 -0
  343. /package/dist-bloby/assets/{wgsl-D59WYmNq.js → wgsl-CNe_V6SG.js} +0 -0
  344. /package/dist-bloby/assets/{wikitext-ariTI2Wk.js → wikitext-DZrjZKWn.js} +0 -0
  345. /package/dist-bloby/assets/{wit-EA4fa3Dt.js → wit-BUTESHa8.js} +0 -0
  346. /package/dist-bloby/assets/{wolfram-DDp7LhyU.js → wolfram-COEZldPx.js} +0 -0
  347. /package/dist-bloby/assets/{zenscript-4WaROUyc.js → zenscript-DThCxjUC.js} +0 -0
  348. /package/dist-bloby/assets/{zig-CJoLJGwV.js → zig-Bu6QWpR2.js} +0 -0
@@ -1,550 +1,112 @@
1
1
  /**
2
- * Claude Agent SDK wrapper — v2 Long-lived Query Model
2
+ * Agent harness dispatcher.
3
3
  *
4
- * Two modes:
5
- * 1. Live Conversation (main chat + admin WhatsApp):
6
- * Single long-lived query() per conversation. User messages pushed into async queue.
7
- * Agent stays alive, processes messages as they arrive, reports sub-agent completions.
4
+ * Picks the right harness implementation based on `cfg.ai.provider` and
5
+ * forwards every call. The supervisor, channels, and scheduler still import
6
+ * from `./bloby-agent.js` exactly as they did before this file is a
7
+ * compatibility shim so the harness split is invisible to callers.
8
8
  *
9
- * 2. One-shot Query (customer WhatsApp, scheduler):
10
- * Classic request-response: one query() per message. Backward compat.
9
+ * Provider routing:
10
+ * anthropic (or empty/default) Claude Agent SDK harness — unchanged
11
+ * openai → Codex app-server harness — Phase 2
12
+ *
13
+ * Cleanup operations (`endAllConversations`, `endConversation(id)`) are
14
+ * fanned out to *both* harnesses so a stale conversation on a previously
15
+ * active provider can't outlive a provider switch.
11
16
  */
12
17
 
13
- import { query, type SDKMessage, type SDKUserMessage, type Options } from '@anthropic-ai/claude-agent-sdk';
14
- import fs from 'fs';
15
- import path from 'path';
16
- import { log } from '../shared/logger.js';
17
- import { WORKSPACE_DIR } from '../shared/paths.js';
18
+ import * as claude from './harnesses/claude.js';
19
+ import * as codex from './harnesses/codex.js';
20
+ import type { Harness, OnAgentMessage, RecentMessage, AgentAttachment } from './harnesses/types.js';
18
21
  import type { SavedFile } from './file-saver.js';
19
- import { getClaudeAccessToken } from '../worker/claude-auth.js';
20
- import { assembleSystemPrompt } from '../worker/prompts/prompt-assembler.js';
21
- import { buildAgents } from './agents/index.js';
22
- import { preWarm, claimWarmup, discardWarmup } from './cli-warmup.js';
23
-
24
- // ── Types ──────────────────────────────────────────────────────────────────
25
-
26
- export interface RecentMessage {
27
- role: 'user' | 'assistant';
28
- content: string;
29
- }
30
-
31
- export interface AgentAttachment {
32
- type: 'image' | 'file';
33
- name: string;
34
- mediaType: string;
35
- data: string; // base64
36
- }
37
-
38
- // ── Async Queue ────────────────────────────────────────────────────────────
39
-
40
- interface AsyncQueue<T> extends AsyncIterable<T> {
41
- push(item: T): void;
42
- end(): void;
43
- }
44
-
45
- /** Create an async queue that can be used as an AsyncIterable prompt for the SDK */
46
- function createAsyncQueue<T>(): AsyncQueue<T> {
47
- const pending: T[] = [];
48
- let resolve: ((value: IteratorResult<T>) => void) | null = null;
49
- let done = false;
50
-
51
- return {
52
- push(item: T) {
53
- if (done) return;
54
- if (resolve) {
55
- resolve({ value: item, done: false });
56
- resolve = null;
57
- } else {
58
- pending.push(item);
59
- }
60
- },
61
- end() {
62
- done = true;
63
- if (resolve) resolve({ value: undefined as any, done: true });
64
- },
65
- [Symbol.asyncIterator]() {
66
- return {
67
- next(): Promise<IteratorResult<T>> {
68
- if (pending.length > 0) {
69
- return Promise.resolve({ value: pending.shift()!, done: false });
70
- }
71
- if (done) return Promise.resolve({ value: undefined as any, done: true });
72
- return new Promise((r) => { resolve = r; });
73
- },
74
- };
75
- },
76
- };
77
- }
78
-
79
- // ── Live Conversation Manager ──────────────────────────────────────────────
80
-
81
- interface LiveConversation {
82
- id: string;
83
- inputQueue: AsyncQueue<SDKUserMessage>;
84
- abortController: AbortController;
85
- queryHandle: any;
86
- onMessage: (type: string, data: any) => void;
87
- /** True while the model is actively processing (between message push and result) */
88
- busy: boolean;
89
- }
90
-
91
- const liveConversations = new Map<string, LiveConversation>();
92
-
93
- /** Check if a live conversation exists */
94
- export function hasConversation(conversationId: string): boolean {
95
- return liveConversations.has(conversationId);
96
- }
22
+ import { loadConfig } from '../shared/config.js';
97
23
 
98
- /** End all live conversations (e.g. after re-auth so they restart with fresh token) */
99
- export function endAllConversations(): void {
100
- for (const convId of liveConversations.keys()) {
101
- log.info(`[conversation] Ending conversation ${convId} (auth changed)`);
102
- endConversation(convId);
103
- }
104
- // The pre-warmed subprocess was initialized with the old OAuth token — drop it.
105
- discardWarmup();
106
- }
24
+ export type { RecentMessage, AgentAttachment };
107
25
 
108
- // ── Helpers ─────────────────────────────────────────────────────────────────
26
+ const HARNESSES: Record<string, Harness> = {
27
+ anthropic: claude,
28
+ openai: codex,
29
+ };
109
30
 
110
- /** Read a memory file from workspace, returning '(empty)' if missing or empty */
111
- function readMemoryFile(filename: string): string {
31
+ /** Resolve the harness for the currently-configured provider. */
32
+ function activeHarness(): Harness {
33
+ let provider = '';
112
34
  try {
113
- const content = fs.readFileSync(path.join(WORKSPACE_DIR, filename), 'utf-8').trim();
114
- return content || '(empty)';
35
+ provider = loadConfig().ai?.provider || '';
115
36
  } catch {
116
- return '(empty)';
37
+ // Pre-onboard or transient config error: fall through to default.
117
38
  }
39
+ return HARNESSES[provider] ?? claude;
118
40
  }
119
41
 
120
- /** Read all memory + config files */
121
- function readMemoryFiles() {
122
- return {
123
- myself: readMemoryFile('MYSELF.md'),
124
- myhuman: readMemoryFile('MYHUMAN.md'),
125
- memory: readMemoryFile('MEMORY.md'),
126
- pulse: readMemoryFile('PULSE.json'),
127
- crons: readMemoryFile('CRONS.json'),
128
- };
129
- }
130
-
131
- /** Format recent messages as conversation history text */
132
- function formatConversationHistory(messages: RecentMessage[]): string {
133
- if (!messages.length) return '';
134
- return messages.map((m) => `${m.role}: ${m.content}`).join('\n\n');
135
- }
42
+ /* ── Live conversation API ─────────────────────────────────────────────── */
136
43
 
137
- /** Load MCP server config from workspace/MCP.json */
138
- function loadMcpServers(): Record<string, any> | undefined {
139
- try {
140
- const mcpConfigPath = path.join(WORKSPACE_DIR, 'MCP.json');
141
- const mcpConfig = JSON.parse(fs.readFileSync(mcpConfigPath, 'utf-8'));
142
- if (mcpConfig && typeof mcpConfig === 'object' && !Array.isArray(mcpConfig) && Object.keys(mcpConfig).length) {
143
- return mcpConfig;
144
- } else if (Array.isArray(mcpConfig) && mcpConfig.length) {
145
- return Object.assign({}, ...mcpConfig);
146
- }
147
- } catch {}
148
- return undefined;
149
- }
150
-
151
- /** Build an SDKUserMessage from text + optional attachments */
152
- function buildUserMessage(text: string, attachments?: AgentAttachment[], savedFiles?: SavedFile[]): SDKUserMessage {
153
- const content: any[] = [];
154
-
155
- if (attachments?.length) {
156
- for (const att of attachments) {
157
- if (att.type === 'image') {
158
- content.push({
159
- type: 'image',
160
- source: { type: 'base64', media_type: att.mediaType, data: att.data },
161
- });
162
- } else {
163
- content.push({
164
- type: 'document',
165
- source: { type: 'base64', media_type: att.mediaType, data: att.data },
166
- });
167
- }
168
- }
169
- }
170
-
171
- let promptText = text || '(attached files)';
172
- if (savedFiles?.length) {
173
- const lines = savedFiles.map((f) => `- ${f.name} -> ${f.relPath}`);
174
- promptText += `\n\n[Attached files saved to disk]\n${lines.join('\n')}\nYou can read or reference these files using the paths above (relative to your cwd).`;
175
- }
176
-
177
- content.push({ type: 'text', text: promptText });
178
-
179
- return {
180
- type: 'user' as const,
181
- message: { role: 'user' as const, content },
182
- parent_tool_use_id: null,
183
- } as SDKUserMessage;
184
- }
185
-
186
- // ── Live Conversation API ──────────────────────────────────────────────────
187
-
188
- /**
189
- * Build the options for a live conversation's query(). Shared by
190
- * `startConversation` and the boot-time pre-warmer so a warmed subprocess
191
- * has byte-identical options.
192
- */
193
- async function buildConversationOptions(
194
- model: string,
195
- oauthToken: string,
196
- names?: { botName: string; humanName: string },
197
- recentMessages?: RecentMessage[],
198
- ): Promise<Omit<Options, 'abortController' | 'stderr'>> {
199
- const memoryFiles = readMemoryFiles();
200
- const basePrompt = await assembleSystemPrompt(names?.botName, names?.humanName);
201
- let systemPrompt = basePrompt;
202
- systemPrompt += `\n\n---\n# Your Memory Files\n\n## MYSELF.md\n${memoryFiles.myself}\n\n## MYHUMAN.md\n${memoryFiles.myhuman}\n\n## MEMORY.md\n${memoryFiles.memory}\n\n---\n# Your Config Files\n\n## PULSE.json\n${memoryFiles.pulse}\n\n## CRONS.json\n${memoryFiles.crons}`;
203
-
204
- try {
205
- const { loadConfig: loadCfg } = await import('../shared/config.js');
206
- const cfg = loadCfg();
207
- const channels = (cfg as any).channels;
208
- if (channels) {
209
- systemPrompt += `\n\n---\n# Channel Config\n\`\`\`json\n${JSON.stringify(channels, null, 2)}\n\`\`\``;
210
- }
211
- } catch {}
212
-
213
- if (recentMessages?.length) {
214
- systemPrompt += `\n\n---\n# Recent Conversation\n${formatConversationHistory(recentMessages)}`;
215
- }
216
-
217
- const agents = buildAgents();
218
- const mcpServers = loadMcpServers();
219
-
220
- return {
221
- model,
222
- cwd: WORKSPACE_DIR,
223
- permissionMode: 'bypassPermissions',
224
- allowDangerouslySkipPermissions: true,
225
- systemPrompt,
226
- mcpServers,
227
- agents,
228
- agentProgressSummaries: true,
229
- env: {
230
- ...process.env as Record<string, string>,
231
- CLAUDE_CODE_OAUTH_TOKEN: oauthToken,
232
- CLAUDE_CODE_BUBBLEWRAP: '1',
233
- },
234
- };
235
- }
236
-
237
- /**
238
- * Pre-warm the Claude CLI subprocess for the next live conversation. Call
239
- * fire-and-forget at supervisor boot (and after a conversation ends) so the
240
- * first user message doesn't pay CLI startup latency.
241
- */
242
- export async function warmUpForLiveConversation(
243
- model: string,
244
- names?: { botName: string; humanName: string },
245
- ): Promise<void> {
246
- if (!model) return;
247
- try {
248
- const oauthToken = await getClaudeAccessToken();
249
- if (!oauthToken) return;
250
- const options = await buildConversationOptions(model, oauthToken, names);
251
- await preWarm(options);
252
- } catch (err: any) {
253
- log.warn(`[conversation] Warm-up skipped: ${err?.message || err}`);
254
- }
255
- }
256
-
257
- /**
258
- * Start a long-lived conversation.
259
- * Creates a single query() with an async input queue.
260
- * Messages are pushed via pushMessage(). The query stays alive until endConversation().
261
- */
262
- export async function startConversation(
44
+ export function startConversation(
263
45
  conversationId: string,
264
46
  model: string,
265
- onMessage: (type: string, data: any) => void,
47
+ onMessage: OnAgentMessage,
266
48
  names?: { botName: string; humanName: string },
267
49
  recentMessages?: RecentMessage[],
268
50
  ): Promise<boolean> {
269
- log.info(`[conversation] ──── STARTING CONVERSATION ────`);
270
- log.info(`[conversation] Conv ID: ${conversationId}`);
271
- log.info(`[conversation] Model: ${model}`);
272
-
273
- // End any existing conversation with this ID
274
- if (liveConversations.has(conversationId)) {
275
- log.info(`[conversation] Ending existing conversation ${conversationId} before starting new one`);
276
- endConversation(conversationId);
277
- }
278
-
279
- const oauthToken = await getClaudeAccessToken();
280
- if (!oauthToken) {
281
- log.warn('[conversation] No OAuth token — cannot start');
282
- onMessage('bot:error', { conversationId, error: 'Claude OAuth token not found. Please authenticate via the dashboard.' });
283
- return false;
284
- }
285
-
286
- const baseOptions = await buildConversationOptions(model, oauthToken, names, recentMessages);
287
- const systemPromptLen = typeof baseOptions.systemPrompt === 'string' ? baseOptions.systemPrompt.length : 0;
288
- log.info(`[conversation] Loaded ${Object.keys(baseOptions.agents || {}).length} sub-agent(s): ${Object.keys(baseOptions.agents || {}).join(', ')}`);
289
- if (baseOptions.mcpServers) {
290
- log.info(`[conversation] MCP servers: ${Object.keys(baseOptions.mcpServers).join(', ')}`);
291
- }
292
-
293
- // Try to claim a pre-warmed subprocess — its abortController is the one
294
- // baked into the warm query and must be reused for end/abort to reach it.
295
- const claimed = claimWarmup(baseOptions);
296
- const abortController = claimed?.abortController ?? new AbortController();
297
-
298
- // Create the async input queue
299
- const inputQueue = createAsyncQueue<SDKUserMessage>();
300
-
301
- // Store the conversation
302
- const conv: LiveConversation = {
303
- id: conversationId,
304
- inputQueue,
305
- abortController,
306
- queryHandle: null,
307
- onMessage,
308
- busy: false,
309
- };
310
- liveConversations.set(conversationId, conv);
311
-
312
- log.info(`[conversation] System prompt: ${systemPromptLen} chars`);
313
- log.info(`[conversation] Starting long-lived query... (${claimed ? 'warm' : 'cold'})`);
314
-
315
- // Run the for-await loop in the background (fire and forget)
316
- (async () => {
317
- let fullText = '';
318
- const usedTools = new Set<string>();
319
- let stderrBuf = '';
320
-
321
- try {
322
- const claudeQuery = claimed
323
- ? claimed.warmQuery.query(inputQueue)
324
- : query({
325
- prompt: inputQueue,
326
- options: {
327
- ...baseOptions,
328
- abortController,
329
- stderr: (chunk: string) => { stderrBuf += chunk; },
330
- },
331
- });
332
-
333
- conv.queryHandle = claudeQuery;
334
- log.info(`[conversation] ──── QUERY LOOP STARTED ────`);
335
-
336
- for await (const msg of claudeQuery) {
337
- if (abortController.signal.aborted) {
338
- log.info(`[conversation] Query aborted — exiting loop`);
339
- break;
340
- }
341
-
342
- switch (msg.type) {
343
- case 'assistant': {
344
- const assistantMsg = msg.message;
345
- if (!assistantMsg?.content) break;
346
-
347
- for (const block of assistantMsg.content) {
348
- if (block.type === 'text' && block.text) {
349
- if (fullText && !fullText.endsWith('\n')) {
350
- fullText += '\n\n';
351
- onMessage('bot:token', { conversationId, token: '\n\n' });
352
- }
353
- fullText += block.text;
354
- onMessage('bot:token', { conversationId, token: block.text });
355
- } else if (block.type === 'tool_use') {
356
- usedTools.add(block.name);
357
- onMessage('bot:tool', { conversationId, name: block.name, input: block.input });
358
- }
359
- }
360
- break;
361
- }
362
-
363
- case 'result': {
364
- // Agent finished processing the current message
365
- log.info(`[conversation] ──── TURN COMPLETE ────`);
366
- log.info(`[conversation] Response length: ${fullText.length} chars`);
367
- log.info(`[conversation] Tools used this turn: ${Array.from(usedTools).join(', ') || 'none'}`);
368
-
369
- if (fullText) {
370
- onMessage('bot:response', { conversationId, content: fullText });
371
- fullText = '';
372
- } else if (msg.subtype?.startsWith('error')) {
373
- const errorText = (msg as any).errors?.join('; ') || 'Agent turn failed';
374
- log.warn(`[conversation] Turn error: ${errorText}`);
375
- onMessage('bot:error', { conversationId, error: errorText });
376
- }
377
-
378
- // Signal turn complete — backend restart + UI update
379
- const FILE_TOOLS = ['Write', 'Edit'];
380
- const usedFileTools = FILE_TOOLS.some((t) => usedTools.has(t));
381
- onMessage('bot:turn-complete', { conversationId, usedFileTools });
382
-
383
- // Reset per-turn state
384
- usedTools.clear();
385
- conv.busy = false;
386
- log.info(`[conversation] Agent idle — waiting for next message`);
387
- break;
388
- }
389
-
390
- case 'tool_progress':
391
- onMessage('bot:tool', {
392
- conversationId,
393
- name: (msg as any).tool_name || 'working',
394
- status: 'running',
395
- });
396
- break;
397
-
398
- // ── Background sub-agent events ──
399
- case 'system': {
400
- const sysMsg = msg as any;
401
- if (sysMsg.subtype === 'task_started') {
402
- log.info(`[conversation] ──── SUB-AGENT STARTED ────`);
403
- log.info(`[conversation] Task ID: ${sysMsg.task_id}`);
404
- log.info(`[conversation] Description: ${sysMsg.description}`);
405
- onMessage('bot:task-created', {
406
- conversationId,
407
- taskId: sysMsg.task_id,
408
- description: sysMsg.description,
409
- type: sysMsg.task_type,
410
- });
411
- } else if (sysMsg.subtype === 'task_progress') {
412
- const summary = sysMsg.summary || sysMsg.last_tool_name || 'working';
413
- log.info(`[conversation] Sub-agent ${sysMsg.task_id} | ${summary} | Tools: ${sysMsg.usage?.tool_uses || 0} | ${Math.round((sysMsg.usage?.duration_ms || 0) / 1000)}s`);
414
- onMessage('bot:task-progress', {
415
- conversationId,
416
- taskId: sysMsg.task_id,
417
- summary,
418
- lastTool: sysMsg.last_tool_name,
419
- usage: sysMsg.usage,
420
- });
421
- } else if (sysMsg.subtype === 'task_notification') {
422
- log.info(`[conversation] ──── SUB-AGENT ${sysMsg.status?.toUpperCase()} ────`);
423
- log.info(`[conversation] Task ID: ${sysMsg.task_id}`);
424
- log.info(`[conversation] Status: ${sysMsg.status}`);
425
- log.info(`[conversation] Summary: ${sysMsg.summary?.slice(0, 200)}`);
426
- log.info(`[conversation] Tokens: ${sysMsg.usage?.total_tokens || 0} | Tools: ${sysMsg.usage?.tool_uses || 0} | Duration: ${Math.round((sysMsg.usage?.duration_ms || 0) / 1000)}s`);
427
- onMessage('bot:task-done', {
428
- conversationId,
429
- taskId: sysMsg.task_id,
430
- status: sysMsg.status,
431
- summary: sysMsg.summary,
432
- usage: sysMsg.usage,
433
- });
434
- // Sub-agent completion may have written files
435
- if (sysMsg.status === 'completed') {
436
- onMessage('bot:turn-complete', { conversationId, usedFileTools: true });
437
- }
438
- }
439
- break;
440
- }
441
- }
442
- }
443
-
444
- log.info(`[conversation] ──── QUERY LOOP ENDED ────`);
445
-
446
- // Send any remaining text
447
- if (fullText && !abortController.signal.aborted) {
448
- onMessage('bot:response', { conversationId, content: fullText });
449
- }
450
- } catch (err: any) {
451
- if (!abortController.signal.aborted) {
452
- const detail = stderrBuf.trim();
453
- const errMsg = detail ? `${err.message}\n\nCLI stderr:\n${detail}` : err.message;
454
- log.warn(`[conversation] Query error: ${errMsg}`);
455
- onMessage('bot:error', { conversationId, error: errMsg });
456
- }
457
- } finally {
458
- log.info(`[conversation] Cleaning up conversation ${conversationId}`);
459
- liveConversations.delete(conversationId);
460
- onMessage('bot:conversation-ended', { conversationId });
461
- // Pre-warm a fresh subprocess for the next live conversation (fire-and-forget).
462
- warmUpForLiveConversation(model, names);
463
- }
464
- })();
465
-
466
- return true;
51
+ return activeHarness().startConversation(conversationId, model, onMessage, names, recentMessages);
467
52
  }
468
53
 
469
- /**
470
- * Push a user message into an existing live conversation.
471
- * The agent will process it as part of the ongoing conversation.
472
- */
473
54
  export function pushMessage(
474
55
  conversationId: string,
475
56
  content: string,
476
57
  attachments?: AgentAttachment[],
477
58
  savedFiles?: SavedFile[],
478
59
  ): boolean {
479
- const conv = liveConversations.get(conversationId);
480
- if (!conv) {
481
- log.warn(`[conversation] pushMessage no live conversation ${conversationId}`);
482
- return false;
60
+ // Push to whichever harness owns this conversation; routing by current
61
+ // config alone could miss a conversation that was started under a previous
62
+ // provider (rare but possible during a switch).
63
+ for (const h of Object.values(HARNESSES)) {
64
+ if (h.hasConversation(conversationId)) {
65
+ return h.pushMessage(conversationId, content, attachments, savedFiles);
66
+ }
483
67
  }
68
+ return activeHarness().pushMessage(conversationId, content, attachments, savedFiles);
69
+ }
484
70
 
485
- log.info(`[conversation] ──── PUSH MESSAGE ────`);
486
- log.info(`[conversation] Conv: ${conversationId}`);
487
- log.info(`[conversation] Content: "${content.slice(0, 100)}..."`);
488
- log.info(`[conversation] Attachments: ${attachments?.length || 0}`);
489
- log.info(`[conversation] Agent busy: ${conv.busy}`);
490
-
491
- const userMessage = buildUserMessage(content, attachments, savedFiles);
492
- conv.busy = true;
493
- conv.inputQueue.push(userMessage);
494
-
495
- // Emit typing indicator
496
- conv.onMessage('bot:typing', { conversationId });
497
-
498
- return true;
71
+ export function hasConversation(conversationId: string): boolean {
72
+ return Object.values(HARNESSES).some((h) => h.hasConversation(conversationId));
499
73
  }
500
74
 
501
- /** End a live conversation */
502
75
  export function endConversation(conversationId: string): void {
503
- const conv = liveConversations.get(conversationId);
504
- if (!conv) return;
505
-
506
- log.info(`[conversation] ──── ENDING CONVERSATION ────`);
507
- log.info(`[conversation] Conv: ${conversationId}`);
76
+ for (const h of Object.values(HARNESSES)) h.endConversation(conversationId);
77
+ }
508
78
 
509
- conv.inputQueue.end();
510
- conv.abortController.abort();
511
- liveConversations.delete(conversationId);
79
+ export function endAllConversations(): void {
80
+ for (const h of Object.values(HARNESSES)) h.endAllConversations();
512
81
  }
513
82
 
514
- /** Check if the agent is currently busy processing a message */
515
83
  export function isConversationBusy(conversationId: string): boolean {
516
- return liveConversations.get(conversationId)?.busy || false;
84
+ return Object.values(HARNESSES).some((h) => h.isConversationBusy(conversationId));
517
85
  }
518
86
 
519
- /** Stop a specific background sub-agent task */
520
87
  export async function stopSubAgentTask(conversationId: string, taskId: string): Promise<void> {
521
- const conv = liveConversations.get(conversationId);
522
- if (conv?.queryHandle?.stopTask) {
523
- log.info(`[conversation] Stopping sub-agent task: ${taskId}`);
524
- await conv.queryHandle.stopTask(taskId);
525
- } else {
526
- log.warn(`[conversation] Cannot stop task ${taskId} — no live conversation ${conversationId}`);
88
+ for (const h of Object.values(HARNESSES)) {
89
+ if (h.hasConversation(conversationId)) {
90
+ await h.stopSubAgentTask(conversationId, taskId);
91
+ return;
92
+ }
527
93
  }
528
94
  }
529
95
 
530
- // ── One-shot Query API (backward compat) ────────────────────────────────────
531
- // Used by: customer WhatsApp (handleCustomerMessage), scheduler (triggerAgent)
532
-
533
- interface ActiveQuery {
534
- abortController: AbortController;
96
+ export function warmUpForLiveConversation(
97
+ model: string,
98
+ names?: { botName: string; humanName: string },
99
+ ): Promise<void> {
100
+ return activeHarness().warmUpForLiveConversation(model, names);
535
101
  }
536
102
 
537
- const activeQueries = new Map<string, ActiveQuery>();
103
+ /* ── One-shot API ──────────────────────────────────────────────────────── */
538
104
 
539
- /**
540
- * Run a one-shot Agent SDK query (classic request-response).
541
- * Used for customer-facing messages and scheduler triggers.
542
- */
543
- export async function startBlobyAgentQuery(
105
+ export function startBlobyAgentQuery(
544
106
  conversationId: string,
545
107
  prompt: string,
546
108
  model: string,
547
- onMessage: (type: string, data: any) => void,
109
+ onMessage: OnAgentMessage,
548
110
  attachments?: AgentAttachment[],
549
111
  savedFiles?: SavedFile[],
550
112
  names?: { botName: string; humanName: string },
@@ -552,142 +114,12 @@ export async function startBlobyAgentQuery(
552
114
  supportPrompt?: string,
553
115
  maxTurns?: number,
554
116
  ): Promise<void> {
555
- const oauthToken = await getClaudeAccessToken();
556
- if (!oauthToken) {
557
- onMessage('bot:error', { conversationId, error: 'Claude OAuth token not found. Please authenticate via the dashboard.' });
558
- return;
559
- }
560
-
561
- const abortController = new AbortController();
562
- const memoryFiles = readMemoryFiles();
563
-
564
- let enrichedPrompt: string;
565
- if (supportPrompt) {
566
- enrichedPrompt = supportPrompt;
567
- } else {
568
- const basePrompt = await assembleSystemPrompt(names?.botName, names?.humanName);
569
- enrichedPrompt = basePrompt;
570
- enrichedPrompt += `\n\n---\n# Your Memory Files\n\n## MYSELF.md\n${memoryFiles.myself}\n\n## MYHUMAN.md\n${memoryFiles.myhuman}\n\n## MEMORY.md\n${memoryFiles.memory}\n\n---\n# Your Config Files\n\n## PULSE.json\n${memoryFiles.pulse}\n\n## CRONS.json\n${memoryFiles.crons}`;
571
-
572
- try {
573
- const { loadConfig: loadCfg } = await import('../shared/config.js');
574
- const cfg = loadCfg();
575
- const channels = (cfg as any).channels;
576
- if (channels) {
577
- enrichedPrompt += `\n\n---\n# Channel Config\n\`\`\`json\n${JSON.stringify(channels, null, 2)}\n\`\`\``;
578
- }
579
- } catch {}
580
- }
581
-
582
- if (recentMessages?.length) {
583
- enrichedPrompt += `\n\n---\n# Recent Conversation\n${formatConversationHistory(recentMessages)}`;
584
- }
585
-
586
- activeQueries.set(conversationId, { abortController });
587
-
588
- let fullText = '';
589
- const usedTools = new Set<string>();
590
- let stderrBuf = '';
591
-
592
- let plainPrompt = prompt;
593
- if (savedFiles?.length && !attachments?.length) {
594
- const lines = savedFiles.map((f) => `- ${f.name} -> ${f.relPath}`);
595
- plainPrompt += `\n\n[Attached files saved to disk]\n${lines.join('\n')}\nYou can read or reference these files using the paths above (relative to your cwd).`;
596
- }
597
-
598
- const sdkPrompt: string | AsyncIterable<SDKUserMessage> =
599
- attachments?.length ? (async function* () {
600
- yield buildUserMessage(prompt, attachments, savedFiles);
601
- })() : plainPrompt;
602
-
603
- try {
604
- const mcpServers = loadMcpServers();
605
- const effectiveMaxTurns = maxTurns ?? 50;
606
-
607
- log.info(`[bloby-agent] One-shot query: conv=${conversationId}, maxTurns=${effectiveMaxTurns}`);
608
-
609
- const claudeQuery = query({
610
- prompt: sdkPrompt,
611
- options: {
612
- model,
613
- cwd: WORKSPACE_DIR,
614
- permissionMode: 'bypassPermissions',
615
- allowDangerouslySkipPermissions: true,
616
- maxTurns: effectiveMaxTurns,
617
- abortController,
618
- systemPrompt: enrichedPrompt,
619
- mcpServers,
620
- stderr: (chunk: string) => { stderrBuf += chunk; },
621
- env: {
622
- ...process.env as Record<string, string>,
623
- CLAUDE_CODE_OAUTH_TOKEN: oauthToken,
624
- CLAUDE_CODE_BUBBLEWRAP: '1',
625
- },
626
- },
627
- });
628
-
629
- onMessage('bot:typing', { conversationId });
630
-
631
- for await (const msg of claudeQuery) {
632
- if (abortController.signal.aborted) break;
633
-
634
- switch (msg.type) {
635
- case 'assistant': {
636
- const assistantMsg = msg.message;
637
- if (!assistantMsg?.content) break;
638
- for (const block of assistantMsg.content) {
639
- if (block.type === 'text' && block.text) {
640
- if (fullText && !fullText.endsWith('\n')) {
641
- fullText += '\n\n';
642
- onMessage('bot:token', { conversationId, token: '\n\n' });
643
- }
644
- fullText += block.text;
645
- onMessage('bot:token', { conversationId, token: block.text });
646
- } else if (block.type === 'tool_use') {
647
- usedTools.add(block.name);
648
- onMessage('bot:tool', { conversationId, name: block.name, input: block.input });
649
- }
650
- }
651
- break;
652
- }
653
- case 'result': {
654
- if (fullText) {
655
- onMessage('bot:response', { conversationId, content: fullText });
656
- fullText = '';
657
- } else if (msg.subtype?.startsWith('error')) {
658
- onMessage('bot:error', { conversationId, error: (msg as any).errors?.join('; ') || 'Agent query failed' });
659
- }
660
- break;
661
- }
662
- case 'tool_progress':
663
- onMessage('bot:tool', { conversationId, name: (msg as any).tool_name || 'working', status: 'running' });
664
- break;
665
- }
666
- }
667
-
668
- if (fullText && !abortController.signal.aborted) {
669
- onMessage('bot:response', { conversationId, content: fullText });
670
- }
671
- } catch (err: any) {
672
- if (!abortController.signal.aborted) {
673
- const detail = stderrBuf.trim();
674
- const errMsg = detail ? `${err.message}\n\nCLI stderr:\n${detail}` : err.message;
675
- log.warn(`Bloby agent error (${conversationId}): ${errMsg}`);
676
- onMessage('bot:error', { conversationId, error: errMsg });
677
- }
678
- } finally {
679
- activeQueries.delete(conversationId);
680
- const FILE_TOOLS = ['Write', 'Edit'];
681
- const usedFileTools = FILE_TOOLS.some((t) => usedTools.has(t));
682
- onMessage('bot:done', { conversationId, usedFileTools });
683
- }
117
+ return activeHarness().startBlobyAgentQuery(
118
+ conversationId, prompt, model, onMessage, attachments, savedFiles,
119
+ names, recentMessages, supportPrompt, maxTurns,
120
+ );
684
121
  }
685
122
 
686
- /** Stop a one-shot query */
687
123
  export function stopBlobyAgentQuery(conversationId: string): void {
688
- const q = activeQueries.get(conversationId);
689
- if (q) {
690
- q.abortController.abort();
691
- activeQueries.delete(conversationId);
692
- }
124
+ for (const h of Object.values(HARNESSES)) h.stopBlobyAgentQuery(conversationId);
693
125
  }