@johpaz/hive-agents 0.0.38 → 0.0.40

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 (263) hide show
  1. package/README.md +31 -71
  2. package/dist/hive.js +4318 -2898
  3. package/dist/tool-worker.js +2691 -1969
  4. package/dist/ui/assets/AgentCreateForm-b7xHyfNc.js +1 -0
  5. package/dist/ui/assets/AgentDetailPage-VHy3M7mI.js +1 -0
  6. package/dist/ui/assets/AgentNewPage-BnWImQMx.js +1 -0
  7. package/dist/ui/{dist/assets/AgentsPage-DGNLDXjR.js → assets/AgentsPage-WFy5abqx.js} +5 -5
  8. package/dist/ui/assets/ApiClientPage-BV7zLIL7.js +3 -0
  9. package/dist/ui/assets/{CanvasPage-CnMO1FN8.js → CanvasPage-B9zuIrTm.js} +7 -7
  10. package/dist/ui/assets/ChannelsPage-DiN3NvIM.js +8 -0
  11. package/dist/ui/{dist/assets/DashboardPage-VyXXp3U1.js → assets/DashboardPage-CHjARjVK.js} +2 -2
  12. package/dist/ui/assets/{LoginPage-DPj2s2Qq.js → LoginPage-Dwd_XxoU.js} +1 -1
  13. package/dist/ui/assets/LogsPage-DW8Nnqe6.js +1 -0
  14. package/dist/ui/assets/MeetingPage-D3bkiKYt.js +1 -0
  15. package/dist/ui/assets/{NotFound-BMeQSGcG.js → NotFound-BIUDlIXU.js} +1 -1
  16. package/dist/ui/assets/ProvidersPage-UqsDAxPQ.js +1 -0
  17. package/dist/ui/{dist/assets/RecoverPage-B-hDZUM2.js → assets/RecoverPage-8hTjr_JU.js} +1 -1
  18. package/dist/ui/assets/SettingsPage-DNa0jOkA.js +9 -0
  19. package/dist/ui/assets/SetupPage-Bdm2irQG.js +1 -0
  20. package/dist/ui/assets/WebChatPage-DElJg6P2.js +16 -0
  21. package/dist/ui/assets/accordion-CnLzKNHK.js +1 -0
  22. package/dist/ui/{dist/assets/alert-Bq6awLlW.js → assets/alert-DylmSCDJ.js} +1 -1
  23. package/dist/ui/{dist/assets/alert-dialog-DQvltYmf.js → assets/alert-dialog-DNNWN_SI.js} +1 -1
  24. package/dist/ui/assets/{badge-DXUDdTed.js → badge-ChENFgkC.js} +1 -1
  25. package/dist/ui/assets/bell-8BqRYmzf.js +1 -0
  26. package/dist/ui/assets/chevron-down-DIosfU_U.js +1 -0
  27. package/dist/ui/assets/chevron-up-CI-W21Fy.js +1 -0
  28. package/dist/ui/assets/circle-x-DjLkFDO8.js +1 -0
  29. package/dist/ui/assets/copy-Bu5d7C-0.js +1 -0
  30. package/dist/ui/{dist/assets/dialog-bI9jImCS.js → assets/dialog-BJ-npIv8.js} +1 -1
  31. package/dist/ui/{dist/assets/dropdown-menu-BK-CO3Od.js → assets/dropdown-menu-DDiaHg5y.js} +1 -1
  32. package/dist/ui/assets/{es-Cg8zdT52.js → es-ecSKCyB6.js} +1 -1
  33. package/dist/ui/assets/index-CawKP29y.js +116 -0
  34. package/dist/ui/assets/index-DIcsEkyd.css +2 -0
  35. package/dist/ui/{dist/assets/label-CrH0Jj3v.js → assets/label-Bi6udtSd.js} +1 -1
  36. package/dist/ui/assets/progress-D5c-Eilm.js +1 -0
  37. package/dist/ui/assets/scroll-area-CihOx0cb.js +1 -0
  38. package/dist/ui/assets/search-DzDptO9s.js +1 -0
  39. package/dist/ui/assets/select-BQCOjM2j.js +1 -0
  40. package/dist/ui/assets/send-BPk9XbIq.js +1 -0
  41. package/dist/ui/assets/shield-CxhcUT39.js +1 -0
  42. package/dist/ui/assets/{slider-CsiUDxc3.js → slider-bcUiUfx0.js} +1 -1
  43. package/dist/ui/assets/switch-BR30E4ej.js +1 -0
  44. package/dist/ui/assets/table-B3aGEaVp.js +1 -0
  45. package/dist/ui/assets/tabs-LQidMKRS.js +1 -0
  46. package/dist/ui/assets/textarea-B6Z1Zc6W.js +1 -0
  47. package/dist/ui/assets/useProviders-Dlizq_8q.js +1 -0
  48. package/dist/ui/{dist/assets/vendor-radix-cw1bQaVC.js → assets/vendor-radix-D6rA7xKY.js} +4 -4
  49. package/dist/ui/assets/{vendor-react-D4s9E-zj.js → vendor-react-BU5iQU4f.js} +1 -1
  50. package/dist/ui/dist/assets/AgentCreateForm-b7xHyfNc.js +1 -0
  51. package/dist/ui/dist/assets/AgentDetailPage-VHy3M7mI.js +1 -0
  52. package/dist/ui/dist/assets/AgentNewPage-BnWImQMx.js +1 -0
  53. package/dist/ui/{assets/AgentsPage-DGNLDXjR.js → dist/assets/AgentsPage-WFy5abqx.js} +5 -5
  54. package/dist/ui/dist/assets/ApiClientPage-BV7zLIL7.js +3 -0
  55. package/dist/ui/dist/assets/{CanvasPage-CnMO1FN8.js → CanvasPage-B9zuIrTm.js} +7 -7
  56. package/dist/ui/dist/assets/ChannelsPage-DiN3NvIM.js +8 -0
  57. package/dist/ui/{assets/DashboardPage-VyXXp3U1.js → dist/assets/DashboardPage-CHjARjVK.js} +2 -2
  58. package/dist/ui/dist/assets/{LoginPage-DPj2s2Qq.js → LoginPage-Dwd_XxoU.js} +1 -1
  59. package/dist/ui/dist/assets/LogsPage-DW8Nnqe6.js +1 -0
  60. package/dist/ui/dist/assets/MeetingPage-D3bkiKYt.js +1 -0
  61. package/dist/ui/dist/assets/{NotFound-BMeQSGcG.js → NotFound-BIUDlIXU.js} +1 -1
  62. package/dist/ui/dist/assets/ProvidersPage-UqsDAxPQ.js +1 -0
  63. package/dist/ui/{assets/RecoverPage-B-hDZUM2.js → dist/assets/RecoverPage-8hTjr_JU.js} +1 -1
  64. package/dist/ui/dist/assets/SettingsPage-DNa0jOkA.js +9 -0
  65. package/dist/ui/dist/assets/SetupPage-Bdm2irQG.js +1 -0
  66. package/dist/ui/dist/assets/WebChatPage-DElJg6P2.js +16 -0
  67. package/dist/ui/dist/assets/accordion-CnLzKNHK.js +1 -0
  68. package/dist/ui/{assets/alert-Bq6awLlW.js → dist/assets/alert-DylmSCDJ.js} +1 -1
  69. package/dist/ui/{assets/alert-dialog-DQvltYmf.js → dist/assets/alert-dialog-DNNWN_SI.js} +1 -1
  70. package/dist/ui/dist/assets/{badge-DXUDdTed.js → badge-ChENFgkC.js} +1 -1
  71. package/dist/ui/dist/assets/bell-8BqRYmzf.js +1 -0
  72. package/dist/ui/dist/assets/chevron-down-DIosfU_U.js +1 -0
  73. package/dist/ui/dist/assets/chevron-up-CI-W21Fy.js +1 -0
  74. package/dist/ui/dist/assets/circle-x-DjLkFDO8.js +1 -0
  75. package/dist/ui/dist/assets/copy-Bu5d7C-0.js +1 -0
  76. package/dist/ui/{assets/dialog-bI9jImCS.js → dist/assets/dialog-BJ-npIv8.js} +1 -1
  77. package/dist/ui/{assets/dropdown-menu-BK-CO3Od.js → dist/assets/dropdown-menu-DDiaHg5y.js} +1 -1
  78. package/dist/ui/dist/assets/{es-Cg8zdT52.js → es-ecSKCyB6.js} +1 -1
  79. package/dist/ui/dist/assets/index-CawKP29y.js +116 -0
  80. package/dist/ui/dist/assets/index-DIcsEkyd.css +2 -0
  81. package/dist/ui/{assets/label-CrH0Jj3v.js → dist/assets/label-Bi6udtSd.js} +1 -1
  82. package/dist/ui/dist/assets/progress-D5c-Eilm.js +1 -0
  83. package/dist/ui/dist/assets/scroll-area-CihOx0cb.js +1 -0
  84. package/dist/ui/dist/assets/search-DzDptO9s.js +1 -0
  85. package/dist/ui/dist/assets/select-BQCOjM2j.js +1 -0
  86. package/dist/ui/dist/assets/send-BPk9XbIq.js +1 -0
  87. package/dist/ui/dist/assets/shield-CxhcUT39.js +1 -0
  88. package/dist/ui/dist/assets/{slider-CsiUDxc3.js → slider-bcUiUfx0.js} +1 -1
  89. package/dist/ui/dist/assets/switch-BR30E4ej.js +1 -0
  90. package/dist/ui/dist/assets/table-B3aGEaVp.js +1 -0
  91. package/dist/ui/dist/assets/tabs-LQidMKRS.js +1 -0
  92. package/dist/ui/dist/assets/textarea-B6Z1Zc6W.js +1 -0
  93. package/dist/ui/dist/assets/useProviders-Dlizq_8q.js +1 -0
  94. package/dist/ui/{assets/vendor-radix-cw1bQaVC.js → dist/assets/vendor-radix-D6rA7xKY.js} +4 -4
  95. package/dist/ui/dist/assets/{vendor-react-D4s9E-zj.js → vendor-react-BU5iQU4f.js} +1 -1
  96. package/dist/ui/dist/index.html +6 -6
  97. package/dist/ui/index.html +6 -6
  98. package/package.json +1 -1
  99. package/packages/cli/src/adapters/binary.ts +8 -4
  100. package/packages/cli/src/adapters/bun-global.ts +5 -1
  101. package/packages/cli/src/adapters/config.ts +4 -3
  102. package/packages/cli/src/adapters/docker.ts +2 -1
  103. package/packages/cli/src/commands/gateway.ts +123 -9
  104. package/packages/cli/src/commands/logs.ts +2 -1
  105. package/packages/cli/src/commands/onboard.ts +27 -1
  106. package/packages/cli/src/commands/sessions.ts +2 -1
  107. package/packages/cli/src/commands/skills.ts +2 -1
  108. package/packages/core/src/agent/agent-loop.ts +104 -2
  109. package/packages/core/src/agent/context-compiler.ts +6 -0
  110. package/packages/core/src/agent/llm-client.ts +6 -0
  111. package/packages/core/src/agent/llm-providers/anthropic.ts +23 -8
  112. package/packages/core/src/agent/llm-providers/hiveagents.ts +248 -0
  113. package/packages/core/src/agent/llm-providers/interface.ts +7 -1
  114. package/packages/core/src/agent/llm-providers/minimax.ts +13 -0
  115. package/packages/core/src/agent/llm-providers/openai-compat-base.ts +49 -25
  116. package/packages/core/src/agent/llm-providers/opencode-go.ts +9 -0
  117. package/packages/core/src/agent/providers/index.ts +3 -2
  118. package/packages/core/src/agent/stuck-loop.ts +90 -14
  119. package/packages/core/src/channels/base.ts +7 -1
  120. package/packages/core/src/channels/whatsapp.ts +13 -1
  121. package/packages/core/src/config/loader.ts +8 -8
  122. package/packages/core/src/gateway/helpers/path.ts +2 -1
  123. package/packages/core/src/gateway/initializer.ts +4 -4
  124. package/packages/core/src/gateway/llm-local/downloader.ts +130 -11
  125. package/packages/core/src/gateway/llm-local/index.ts +2 -0
  126. package/packages/core/src/gateway/llm-local/models.ts +4 -3
  127. package/packages/core/src/gateway/router.ts +7 -5
  128. package/packages/core/src/gateway/routes/http-client.ts +16 -0
  129. package/packages/core/src/gateway/routes/llm-local.ts +51 -5
  130. package/packages/core/src/gateway/routes/providers.ts +99 -2
  131. package/packages/core/src/gateway/server.ts +131 -57
  132. package/packages/core/src/gateway/slash-commands.ts +7 -1
  133. package/packages/core/src/gateway/tts/src/install.ts +17 -9
  134. package/packages/core/src/storage/crypto.ts +152 -20
  135. package/packages/core/src/storage/migrate.ts +51 -18
  136. package/packages/core/src/storage/onboarding.ts +28 -0
  137. package/packages/core/src/storage/seed.ts +52 -2
  138. package/packages/core/src/tool-runtime/index.ts +22 -1
  139. package/packages/core/src/tools/api/api-request.ts +174 -0
  140. package/packages/core/src/tools/api/index.ts +16 -0
  141. package/packages/core/src/tools/index.ts +12 -0
  142. package/packages/core/src/tools/web/browser-click.ts +2 -2
  143. package/packages/core/src/tools/web/browser-extract.ts +22 -6
  144. package/packages/core/src/tools/web/browser-navigate.ts +34 -18
  145. package/packages/core/src/tools/web/browser-screenshot.ts +40 -8
  146. package/packages/core/src/tools/web/browser-script.ts +2 -2
  147. package/packages/core/src/tools/web/browser-service.ts +295 -341
  148. package/packages/core/src/tools/web/browser-type.ts +5 -10
  149. package/packages/core/src/tools/web/browser-wait.ts +2 -2
  150. package/packages/core/src/tools/web/index.ts +1 -1
  151. package/packages/core/src/utils/logger.ts +2 -1
  152. package/packages/mcp/src/manager.ts +2 -1
  153. package/packages/skills/src/bundled/api/api_client/SKILL.md +132 -0
  154. package/packages/skills/src/bundled-data.generated.ts +1191 -1134
  155. package/packages/skills/src/loader.ts +2 -1
  156. package/dist/ui/assets/AgentCreateForm-0oFbN3gj.js +0 -1
  157. package/dist/ui/assets/AgentDetailPage-BJ4L2fNJ.js +0 -1
  158. package/dist/ui/assets/AgentNewPage-B3n0LUck.js +0 -1
  159. package/dist/ui/assets/ChannelsPage-fbF8K4MR.js +0 -8
  160. package/dist/ui/assets/LogsPage-B2lY9maY.js +0 -1
  161. package/dist/ui/assets/MeetingPage-2ky_hKiG.js +0 -1
  162. package/dist/ui/assets/ProvidersPage-CEyUM2tD.js +0 -1
  163. package/dist/ui/assets/SettingsPage-eO0i3g8p.js +0 -9
  164. package/dist/ui/assets/SetupPage-ByYqTELb.js +0 -1
  165. package/dist/ui/assets/WebChatPage-BuGT2AL0.js +0 -16
  166. package/dist/ui/assets/accordion-C5d5Rm5z.js +0 -1
  167. package/dist/ui/assets/chevron-up-BYhk0K2J.js +0 -1
  168. package/dist/ui/assets/globe-DeCQTCDJ.js +0 -1
  169. package/dist/ui/assets/index-B2fCYtTS.css +0 -2
  170. package/dist/ui/assets/index-CQ7fn00w.js +0 -116
  171. package/dist/ui/assets/progress-BherYzY6.js +0 -1
  172. package/dist/ui/assets/scroll-area-DkeyX32e.js +0 -1
  173. package/dist/ui/assets/send-B0H5SEIE.js +0 -1
  174. package/dist/ui/assets/switch-BDwN8RYV.js +0 -1
  175. package/dist/ui/assets/table-CSc8ubon.js +0 -1
  176. package/dist/ui/assets/textarea-CXgXWKrT.js +0 -1
  177. package/dist/ui/assets/useProviders-CnlC_qCS.js +0 -1
  178. package/dist/ui/dist/assets/AgentCreateForm-0oFbN3gj.js +0 -1
  179. package/dist/ui/dist/assets/AgentDetailPage-BJ4L2fNJ.js +0 -1
  180. package/dist/ui/dist/assets/AgentNewPage-B3n0LUck.js +0 -1
  181. package/dist/ui/dist/assets/ChannelsPage-fbF8K4MR.js +0 -8
  182. package/dist/ui/dist/assets/LogsPage-B2lY9maY.js +0 -1
  183. package/dist/ui/dist/assets/MeetingPage-2ky_hKiG.js +0 -1
  184. package/dist/ui/dist/assets/ProvidersPage-CEyUM2tD.js +0 -1
  185. package/dist/ui/dist/assets/SettingsPage-eO0i3g8p.js +0 -9
  186. package/dist/ui/dist/assets/SetupPage-ByYqTELb.js +0 -1
  187. package/dist/ui/dist/assets/WebChatPage-BuGT2AL0.js +0 -16
  188. package/dist/ui/dist/assets/accordion-C5d5Rm5z.js +0 -1
  189. package/dist/ui/dist/assets/chevron-up-BYhk0K2J.js +0 -1
  190. package/dist/ui/dist/assets/globe-DeCQTCDJ.js +0 -1
  191. package/dist/ui/dist/assets/index-B2fCYtTS.css +0 -2
  192. package/dist/ui/dist/assets/index-CQ7fn00w.js +0 -116
  193. package/dist/ui/dist/assets/progress-BherYzY6.js +0 -1
  194. package/dist/ui/dist/assets/scroll-area-DkeyX32e.js +0 -1
  195. package/dist/ui/dist/assets/send-B0H5SEIE.js +0 -1
  196. package/dist/ui/dist/assets/switch-BDwN8RYV.js +0 -1
  197. package/dist/ui/dist/assets/table-CSc8ubon.js +0 -1
  198. package/dist/ui/dist/assets/textarea-CXgXWKrT.js +0 -1
  199. package/dist/ui/dist/assets/useProviders-CnlC_qCS.js +0 -1
  200. /package/dist/ui/assets/{card-CNf6BS2e.js → card-DFKnZ6ky.js} +0 -0
  201. /package/dist/ui/assets/{circle-alert-CyHDwUj8.js → circle-alert-KuAm2FWh.js} +0 -0
  202. /package/dist/ui/assets/{circle-check-Bb54Ebmu.js → circle-check-6Ard1-2z.js} +0 -0
  203. /package/dist/ui/assets/{cpu-Cdgc_B1K.js → cpu-KDy6-FAI.js} +0 -0
  204. /package/dist/ui/assets/{download-C3ifGMjJ.js → download-Cjbk4Rek.js} +0 -0
  205. /package/dist/ui/assets/{external-link-BvxYeTP1.js → external-link-6sTlRDUR.js} +0 -0
  206. /package/dist/ui/assets/{eye-DqNTU_GD.js → eye-Df8o0tkC.js} +0 -0
  207. /package/dist/ui/assets/{file-text-BT_9S9SM.js → file-text-lnxnjBp0.js} +0 -0
  208. /package/dist/ui/assets/{folder-open-BhH8y9ac.js → folder-open-DJBLDFjv.js} +0 -0
  209. /package/dist/ui/assets/{format-GVHeOyWI.js → format-BwdV8bB5.js} +0 -0
  210. /package/dist/ui/assets/{gateway-url-COCbW0IR.js → gateway-url-DwzPmoc8.js} +0 -0
  211. /package/dist/ui/assets/{gauge-D_TMa4i9.js → gauge-B8Tj43rC.js} +0 -0
  212. /package/dist/ui/assets/{hexagon-DsGOUl-H.js → hexagon-6L79pgVK.js} +0 -0
  213. /package/dist/ui/assets/{history-BSG-Ypqf.js → history-CAF_R34_.js} +0 -0
  214. /package/dist/ui/assets/{info-NwLoa2Mj.js → info-WjromB4Y.js} +0 -0
  215. /package/dist/ui/assets/{key-3EP0dhkT.js → key-DyKOoQh5.js} +0 -0
  216. /package/dist/ui/assets/{loader-circle-CZNax6kS.js → loader-circle-BmBOgYze.js} +0 -0
  217. /package/dist/ui/assets/{lock-Ei1_J-Nq.js → lock-BS6OLXPv.js} +0 -0
  218. /package/dist/ui/assets/{pause-BUqah9Bi.js → pause-VqeUmp2Z.js} +0 -0
  219. /package/dist/ui/assets/{play-NcZ4swwL.js → play-zJpWuhrr.js} +0 -0
  220. /package/dist/ui/assets/{plus-CX1xyhp5.js → plus-BZQX26Dr.js} +0 -0
  221. /package/dist/ui/assets/{refresh-cw-DaYdjQFk.js → refresh-cw-CCzDCAuz.js} +0 -0
  222. /package/dist/ui/assets/{save-CUdYyHNy.js → save-hUmZhceG.js} +0 -0
  223. /package/dist/ui/assets/{settings-Ds4SqD8s.js → settings-BGfrZ_zM.js} +0 -0
  224. /package/dist/ui/assets/{sparkles-yUEb-7oH.js → sparkles-BhwlS1pc.js} +0 -0
  225. /package/dist/ui/assets/{square-BD81nFtN.js → square-DMNWw4Hi.js} +0 -0
  226. /package/dist/ui/assets/{terminal-DN38Q456.js → terminal--7G943As.js} +0 -0
  227. /package/dist/ui/assets/{trash-2-CNjMkoq6.js → trash-2-xD2o4SgX.js} +0 -0
  228. /package/dist/ui/assets/{triangle-alert-C9Y8Ub4X.js → triangle-alert-pVIJGjga.js} +0 -0
  229. /package/dist/ui/assets/{vendor-router-C9pIYwbJ.js → vendor-router-gqiZ7xhx.js} +0 -0
  230. /package/dist/ui/assets/{volume-2-CeSXNDv4.js → volume-2-BekVQl6P.js} +0 -0
  231. /package/dist/ui/assets/{zap-hlXjpSeA.js → zap-B4RaNNO5.js} +0 -0
  232. /package/dist/ui/dist/assets/{card-CNf6BS2e.js → card-DFKnZ6ky.js} +0 -0
  233. /package/dist/ui/dist/assets/{circle-alert-CyHDwUj8.js → circle-alert-KuAm2FWh.js} +0 -0
  234. /package/dist/ui/dist/assets/{circle-check-Bb54Ebmu.js → circle-check-6Ard1-2z.js} +0 -0
  235. /package/dist/ui/dist/assets/{cpu-Cdgc_B1K.js → cpu-KDy6-FAI.js} +0 -0
  236. /package/dist/ui/dist/assets/{download-C3ifGMjJ.js → download-Cjbk4Rek.js} +0 -0
  237. /package/dist/ui/dist/assets/{external-link-BvxYeTP1.js → external-link-6sTlRDUR.js} +0 -0
  238. /package/dist/ui/dist/assets/{eye-DqNTU_GD.js → eye-Df8o0tkC.js} +0 -0
  239. /package/dist/ui/dist/assets/{file-text-BT_9S9SM.js → file-text-lnxnjBp0.js} +0 -0
  240. /package/dist/ui/dist/assets/{folder-open-BhH8y9ac.js → folder-open-DJBLDFjv.js} +0 -0
  241. /package/dist/ui/dist/assets/{format-GVHeOyWI.js → format-BwdV8bB5.js} +0 -0
  242. /package/dist/ui/dist/assets/{gateway-url-COCbW0IR.js → gateway-url-DwzPmoc8.js} +0 -0
  243. /package/dist/ui/dist/assets/{gauge-D_TMa4i9.js → gauge-B8Tj43rC.js} +0 -0
  244. /package/dist/ui/dist/assets/{hexagon-DsGOUl-H.js → hexagon-6L79pgVK.js} +0 -0
  245. /package/dist/ui/dist/assets/{history-BSG-Ypqf.js → history-CAF_R34_.js} +0 -0
  246. /package/dist/ui/dist/assets/{info-NwLoa2Mj.js → info-WjromB4Y.js} +0 -0
  247. /package/dist/ui/dist/assets/{key-3EP0dhkT.js → key-DyKOoQh5.js} +0 -0
  248. /package/dist/ui/dist/assets/{loader-circle-CZNax6kS.js → loader-circle-BmBOgYze.js} +0 -0
  249. /package/dist/ui/dist/assets/{lock-Ei1_J-Nq.js → lock-BS6OLXPv.js} +0 -0
  250. /package/dist/ui/dist/assets/{pause-BUqah9Bi.js → pause-VqeUmp2Z.js} +0 -0
  251. /package/dist/ui/dist/assets/{play-NcZ4swwL.js → play-zJpWuhrr.js} +0 -0
  252. /package/dist/ui/dist/assets/{plus-CX1xyhp5.js → plus-BZQX26Dr.js} +0 -0
  253. /package/dist/ui/dist/assets/{refresh-cw-DaYdjQFk.js → refresh-cw-CCzDCAuz.js} +0 -0
  254. /package/dist/ui/dist/assets/{save-CUdYyHNy.js → save-hUmZhceG.js} +0 -0
  255. /package/dist/ui/dist/assets/{settings-Ds4SqD8s.js → settings-BGfrZ_zM.js} +0 -0
  256. /package/dist/ui/dist/assets/{sparkles-yUEb-7oH.js → sparkles-BhwlS1pc.js} +0 -0
  257. /package/dist/ui/dist/assets/{square-BD81nFtN.js → square-DMNWw4Hi.js} +0 -0
  258. /package/dist/ui/dist/assets/{terminal-DN38Q456.js → terminal--7G943As.js} +0 -0
  259. /package/dist/ui/dist/assets/{trash-2-CNjMkoq6.js → trash-2-xD2o4SgX.js} +0 -0
  260. /package/dist/ui/dist/assets/{triangle-alert-C9Y8Ub4X.js → triangle-alert-pVIJGjga.js} +0 -0
  261. /package/dist/ui/dist/assets/{vendor-router-C9pIYwbJ.js → vendor-router-gqiZ7xhx.js} +0 -0
  262. /package/dist/ui/dist/assets/{volume-2-CeSXNDv4.js → volume-2-BekVQl6P.js} +0 -0
  263. /package/dist/ui/dist/assets/{zap-hlXjpSeA.js → zap-B4RaNNO5.js} +0 -0
@@ -28,9 +28,12 @@ import { resolveUserId, resolveAgentId } from "../storage/onboarding"
28
28
  import type { ContentPart } from "../multimodal/types"
29
29
  import { loadConfig } from "../config/loader"
30
30
  import { executeToolBatch } from "../tool-runtime"
31
+ import { createStuckLoopDetector, getInterventionMessage, type StuckLoopState } from "./stuck-loop"
31
32
 
32
33
  const log = logger.child("agent-loop")
33
34
 
35
+ const DEFAULT_MAX_WALL_CLOCK_MS = 5 * 60 * 1000
36
+
34
37
  // ─── Types ────────────────────────────────────────────────────────────────────
35
38
 
36
39
  export interface AgentLoopOptions {
@@ -45,14 +48,19 @@ export interface AgentLoopOptions {
45
48
  isolated?: boolean
46
49
  taskContext?: string | ContentPart[]
47
50
  onStep?: (step: StepEvent) => Promise<void>
51
+ onToken?: (token: string) => void
48
52
  /** User ID for context propagation */
49
53
  userId?: string
50
54
  /** Abort signal to stop generation mid-execution */
51
55
  signal?: AbortSignal
52
56
  /** Clean text for FTS5 and tracing (extracted from userMessage if multimodal) */
53
57
  rawUserMessage?: string
58
+ /** Extra tools to force into the LLM loadout (used by tests/evals). */
59
+ extraTools?: any[]
54
60
  }
55
61
 
62
+ export type { StepEvent as AgentStepEvent }
63
+
56
64
  export interface StepEvent {
57
65
  type: "text" | "tool_call" | "tool_result"
58
66
  message: string
@@ -63,7 +71,7 @@ export interface StepEvent {
63
71
  // ─── Stream chunk types (compatible with providers/index.ts) ─────────────────
64
72
 
65
73
  export interface StreamChunk {
66
- agent?: { messages: any[] }
74
+ agent?: { messages: any[]; streamed?: boolean }
67
75
  tools?: { messages: any[] }
68
76
  usage?: { input_tokens: number; output_tokens: number }
69
77
  }
@@ -82,6 +90,12 @@ export async function* runAgent(
82
90
 
83
91
  const agentName = agent.name || opts.agentId
84
92
  const maxIterations = agent.max_iterations || 10
93
+ const maxWallClockMs = agent.max_wall_clock_ms || DEFAULT_MAX_WALL_CLOCK_MS
94
+ const wallClockDeadline = Date.now() + maxWallClockMs
95
+
96
+ // Stuck-loop protection
97
+ const stuckDetector = createStuckLoopDetector(loadConfig())
98
+ let stuckState: StuckLoopState | undefined
85
99
 
86
100
  // Resolve LLM provider config
87
101
  const providerCfg = await resolveProviderConfig(
@@ -122,6 +136,19 @@ export async function* runAgent(
122
136
  userId: opts.userId,
123
137
  })
124
138
 
139
+ // Force extra tools into the loadout (tests/evals)
140
+ if (opts.extraTools?.length) {
141
+ const existingNames = new Set(ctx.tools.map((t: any) => t.function?.name))
142
+ for (const tool of opts.extraTools) {
143
+ const name = tool.function?.name || tool.name
144
+ if (name && !existingNames.has(name)) {
145
+ ctx.tools.push(tool)
146
+ existingNames.add(name)
147
+ log.info(`[agent-loop] Force-injected tool into loadout: ${name}`)
148
+ }
149
+ }
150
+ }
151
+
125
152
  const systemPrompt = opts.systemPromptOverride || ctx.systemPrompt
126
153
 
127
154
  // Build initial messages array for the model
@@ -143,6 +170,9 @@ export async function* runAgent(
143
170
  let lastToolSignature = ""
144
171
  let consecutiveRepeat = 0
145
172
  let loopDetected = false
173
+ // Stall detection: iterations without a forward-progress tool call (write/click/navigate)
174
+ let idleIterations = 0
175
+ const PROGRESS_TOOLS = new Set(["browser_type", "browser_click", "browser_navigate"])
146
176
 
147
177
  // ── The loop ────────────────────────────────────────────────────────────
148
178
  while (iterations < maxIterations) {
@@ -152,12 +182,25 @@ export async function* runAgent(
152
182
  break
153
183
  }
154
184
 
185
+ if (Date.now() > wallClockDeadline) {
186
+ log.warn(`[agent-loop] Wall-clock timeout exceeded (${maxWallClockMs}ms). Breaking.`)
187
+ finalContent = "La tarea tomó demasiado tiempo. Te sugiero dividirla en pasos más pequeños o darme más detalles para continuar."
188
+ break
189
+ }
190
+
155
191
  iterations++
156
192
 
193
+ let streamedThisCall = false
157
194
  const response = await callLLM({
158
195
  ...providerCfg,
159
196
  messages: clearOldToolResults(messages) as LLMMessage[],
160
197
  tools: ctx.tools.length > 0 ? ctx.tools : undefined,
198
+ onToken: opts.onToken
199
+ ? (token: string) => {
200
+ streamedThisCall = true
201
+ opts.onToken?.(token)
202
+ }
203
+ : undefined,
161
204
  })
162
205
 
163
206
  // Accumulate usage
@@ -169,7 +212,7 @@ export async function* runAgent(
169
212
  // Emit agent chunk (compatible with providers/index.ts)
170
213
  const agentMsg: any = { content: response.content }
171
214
  if (response.tool_calls?.length) agentMsg.tool_calls = response.tool_calls
172
- yield { agent: { messages: [agentMsg] } }
215
+ yield { agent: { messages: [agentMsg], streamed: streamedThisCall } }
173
216
 
174
217
  // Notify onStep for narration text
175
218
  if (opts.onStep && response.content) {
@@ -287,6 +330,10 @@ export async function* runAgent(
287
330
  tool_call_id: tc.id,
288
331
  })
289
332
 
333
+ // Record tool call for stuck-loop detection
334
+ const errorMessage = toolResultLLM.startsWith("[Tool Error]") ? toolResultLLM : undefined
335
+ stuckDetector.recordToolCall(opts.threadId, toolName, tc.function.arguments as Record<string, unknown>, errorMessage)
336
+
290
337
  // Dynamic tool injection: when search_knowledge finds tools (native or MCP), add them to ctx.tools
291
338
  if (toolName === "search_knowledge") {
292
339
  // Use JS object directly (no parse needed)
@@ -463,6 +510,54 @@ export async function* runAgent(
463
510
 
464
511
  if (loopDetected) break
465
512
 
513
+ // Check for stuck loop after each iteration
514
+ stuckState = stuckDetector.check(opts.threadId)
515
+ if (stuckState.detected) {
516
+ const intervention = getInterventionMessage(stuckState)
517
+ log.warn(`[agent-loop] ${intervention}`)
518
+
519
+ if (stuckState.count >= 4) {
520
+ // Critical: break and notify user instead of looping forever
521
+ finalContent = intervention
522
+ loopDetected = true
523
+ emitCanvas("canvas:node_update", {
524
+ nodeId: opts.agentId,
525
+ changes: { status: "stuck", currentTool: stuckState.toolName },
526
+ })
527
+ break
528
+ } else {
529
+ // Warning: inject intervention message so the model changes strategy
530
+ messages.push({
531
+ role: "user",
532
+ content: intervention,
533
+ })
534
+ }
535
+ }
536
+
537
+ // Stall detection: no forward-progress tool for several iterations
538
+ const hadProgress = toolResults.some(
539
+ (r) => PROGRESS_TOOLS.has(r.toolName) && !String(r.result).startsWith("[Tool Error]")
540
+ )
541
+ if (hadProgress) {
542
+ idleIterations = 0
543
+ } else if (toolResults.length > 0) {
544
+ idleIterations++
545
+ }
546
+ if (idleIterations >= 3 && idleIterations < 5) {
547
+ const stallMsg = "ADVERTENCIA: Llevas varios pasos sin modificar la página. Si ya completaste el formulario, responde al usuario. Si no, avanza con browser_type/browser_click en lugar de seguir inspeccionando."
548
+ log.warn(`[agent-loop] ${stallMsg}`)
549
+ messages.push({ role: "user", content: stallMsg })
550
+ } else if (idleIterations >= 5) {
551
+ const stallMsg = "No logré avanzar en el formulario después de varios intentos. Puede que la página no sea compatible o que falten instrucciones. Te sugiero revisar la URL o darme más detalles."
552
+ log.warn(`[agent-loop] Stall break: ${stallMsg}`)
553
+ finalContent = stallMsg
554
+ emitCanvas("canvas:node_update", {
555
+ nodeId: opts.agentId,
556
+ changes: { status: "stuck", currentTool: "NO_PROGRESS" },
557
+ })
558
+ break
559
+ }
560
+
466
561
  emitCanvas("canvas:node_update", {
467
562
  nodeId: opts.agentId,
468
563
  changes: { status: "thinking", currentTool: null },
@@ -603,6 +698,10 @@ export class AgentLoop {
603
698
  raw_user_message?: string
604
699
  }
605
700
  signal?: AbortSignal
701
+ onToken?: (token: string) => void
702
+ onStep?: (step: StepEvent) => Promise<void>
703
+ /** Extra tools to force into the LLM loadout (tests/evals). */
704
+ extraTools?: any[]
606
705
  }
607
706
  ): AsyncIterable<StreamChunk> {
608
707
  // Resolve from database with priority: explicit param → DB lookup → single user/agent
@@ -647,6 +746,9 @@ export class AgentLoop {
647
746
  mcpManager: this.mcpManager,
648
747
  userId,
649
748
  signal: config.signal,
749
+ onToken: config.onToken,
750
+ onStep: config.onStep,
751
+ extraTools: config.extraTools,
650
752
  })
651
753
  }
652
754
 
@@ -183,6 +183,12 @@ export async function compileContext(opts: {
183
183
  // Sanitized name valid for all LLM providers (no spaces, max 64 chars)
184
184
  const fullName = mcpToolFullName(server.name, mcpTool.name)
185
185
 
186
+ // Skip tools whose sanitized name is empty or fails provider validation
187
+ if (!fullName || !/^[a-zA-Z0-9_-]{1,64}$/.test(fullName)) {
188
+ log.warn(`[context-compiler] Skipping MCP tool with unsupported name: "${mcpTool.name}" (server: ${server.name}, sanitized: "${fullName}")`)
189
+ continue
190
+ }
191
+
186
192
  // Executor for agent-loop (has the real call)
187
193
  mcpToolExecutors.push({
188
194
  name: fullName,
@@ -24,6 +24,9 @@ import { KimiProvider } from "./llm-providers/kimi"
24
24
  import { LocalLlamaProvider } from "./llm-providers/local-llama"
25
25
  import { NvidiaProvider } from "./llm-providers/nvidia"
26
26
  import { QwenProvider } from "./llm-providers/qwen"
27
+ import { MiniMaxProvider } from "./llm-providers/minimax"
28
+ import { OpenCodeGoProvider } from "./llm-providers/opencode-go"
29
+ import { HiveAgentsProvider } from "./llm-providers/hiveagents"
27
30
  import type { LLMProvider } from "./llm-providers/interface"
28
31
 
29
32
  const log = logger.child("llm-client")
@@ -109,6 +112,9 @@ function getProvider(provider: string): LLMProvider {
109
112
  case "local-llama": return new LocalLlamaProvider()
110
113
  case "nvidia": return new NvidiaProvider()
111
114
  case "qwen": return new QwenProvider()
115
+ case "minimax": return new MiniMaxProvider()
116
+ case "opencode-go": return new OpenCodeGoProvider()
117
+ case "hiveagents": return new HiveAgentsProvider()
112
118
  default:
113
119
  log.warn(`[llm-client] Unknown provider "${provider}" — falling back to OpenAI-compatible endpoint`)
114
120
  return new OpenAIProvider()
@@ -1,4 +1,5 @@
1
1
  import { logger } from "../../utils/logger"
2
+ import { normalizeToolName } from "./interface"
2
3
  import type { LLMCallOptions, LLMProvider, LLMResponse, LLMToolCall } from "./interface"
3
4
  import type { ContentPart, LLMMessage } from "../llm-client"
4
5
 
@@ -55,6 +56,10 @@ export class AnthropicProvider implements LLMProvider {
55
56
  const Anthropic = await import("@anthropic-ai/sdk")
56
57
  const client = new Anthropic.default({ apiKey: options.apiKey })
57
58
 
59
+ // Anthropic requires tool names to match ^[a-zA-Z0-9_-]{1,128}$
60
+ // Native Hive tools use dots (e.g. cron.create) which violate this.
61
+ const toolNameMap = new Map<string, string>() // wireName -> originalName
62
+
58
63
  const systemText = options.messages
59
64
  .filter((m) => m.role === "system")
60
65
  .map((m) => m.content)
@@ -82,7 +87,9 @@ export class AnthropicProvider implements LLMProvider {
82
87
  for (const tc of msg.tool_calls) {
83
88
  let input: Record<string, unknown>
84
89
  try { input = JSON.parse(tc.function.arguments || "{}") } catch { input = {} }
85
- content.push({ type: "tool_use", id: tc.id, name: tc.function.name, input })
90
+ const wireName = normalizeToolName(tc.function.name, "_")
91
+ if (wireName !== tc.function.name) toolNameMap.set(wireName, tc.function.name)
92
+ content.push({ type: "tool_use", id: tc.id, name: wireName, input })
86
93
  }
87
94
  anthropicMessages.push({ role: "assistant", content })
88
95
  continue
@@ -91,11 +98,16 @@ export class AnthropicProvider implements LLMProvider {
91
98
  anthropicMessages.push({ role: msg.role, content: Array.isArray(msg.content) ? this._convertUserContent(msg) : msg.content })
92
99
  }
93
100
 
94
- const tools: any[] = (options.tools ?? []).map((t) => ({
95
- name: t.function.name,
96
- description: t.function.description,
97
- input_schema: t.function.parameters,
98
- }))
101
+ const tools: any[] = (options.tools ?? []).map((t) => {
102
+ const originalName = t.function.name
103
+ const wireName = normalizeToolName(originalName, "_")
104
+ if (wireName !== originalName) toolNameMap.set(wireName, originalName)
105
+ return {
106
+ name: wireName,
107
+ description: t.function.description,
108
+ input_schema: t.function.parameters,
109
+ }
110
+ })
99
111
 
100
112
  const body: any = {
101
113
  model: options.model,
@@ -132,7 +144,9 @@ export class AnthropicProvider implements LLMProvider {
132
144
  for await (const event of stream) {
133
145
  if (event.type === "content_block_start") {
134
146
  if (event.content_block.type === "tool_use") {
135
- toolMeta[event.index] = { id: event.content_block.id, name: event.content_block.name }
147
+ const wireName = event.content_block.name
148
+ const originalName = toolNameMap.get(wireName) ?? wireName
149
+ toolMeta[event.index] = { id: event.content_block.id, name: originalName }
136
150
  partialInputs[event.index] = ""
137
151
  }
138
152
  } else if (event.type === "content_block_delta") {
@@ -187,10 +201,11 @@ export class AnthropicProvider implements LLMProvider {
187
201
  if (block.type === "tool_use") {
188
202
  let args: string
189
203
  try { args = JSON.stringify(block.input) } catch { args = "{}" }
204
+ const originalName = toolNameMap.get(block.name) ?? block.name
190
205
  tool_calls.push({
191
206
  id: block.id,
192
207
  type: "function",
193
- function: { name: block.name, arguments: args },
208
+ function: { name: originalName, arguments: args },
194
209
  })
195
210
  }
196
211
  }
@@ -0,0 +1,248 @@
1
+ import { logger } from "../../utils/logger"
2
+ import { OpenAICompatBase } from "./openai-compat-base"
3
+ import type { LLMCallOptions, LLMResponse } from "./interface"
4
+
5
+ const log = logger.child("llm-client")
6
+
7
+ const DEFAULT_BASE = "https://llm.hiveagents.io"
8
+
9
+ /** Contexto por defecto que se solicita al backend de HiveAgents al cargar un modelo. */
10
+ export const HIVEAGENTS_DEFAULT_LOAD_CTX = 50000
11
+
12
+ // Cloudflare blocks requests with the OpenAI SDK User-Agent and x-stainless-* fingerprint headers.
13
+ const BLOCKED_HEADERS = [
14
+ "user-agent",
15
+ "x-stainless-lang",
16
+ "x-stainless-package-version",
17
+ "x-stainless-runtime",
18
+ "x-stainless-runtime-version",
19
+ "x-stainless-arch",
20
+ "x-stainless-os",
21
+ ]
22
+
23
+ export interface HiveAgentsLoadResult {
24
+ success: boolean
25
+ loading?: boolean
26
+ error?: string
27
+ }
28
+
29
+ export interface HiveAgentsStatusResult {
30
+ loaded: boolean
31
+ model?: { name?: string; ctx?: number; n_ctx?: number }
32
+ }
33
+
34
+ function getApiBase(baseUrl?: string): string {
35
+ return (baseUrl?.replace(/\/v1\/?$/, "") || DEFAULT_BASE)
36
+ }
37
+
38
+ function getAuthHeaders(apiKey: string): Record<string, string> {
39
+ return {
40
+ "Content-Type": "application/json",
41
+ Authorization: `Bearer ${apiKey}`,
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Solicita la carga de un modelo GGUF en el backend de HiveAgents.
47
+ * Siempre pide ctx=HIVEAGENTS_LOAD_CTX para maximizar la ventana de contexto disponible.
48
+ */
49
+ /** Timeout para la petición de carga. Menor al límite de Cloudflare (100s) para evitar 524. */
50
+ const HIVEAGENTS_LOAD_FETCH_TIMEOUT_MS = 90000
51
+
52
+ export async function loadHiveAgentsModel(
53
+ modelId: string,
54
+ apiKey: string,
55
+ baseUrl?: string,
56
+ ctx = HIVEAGENTS_DEFAULT_LOAD_CTX
57
+ ): Promise<HiveAgentsLoadResult> {
58
+ const apiBase = getApiBase(baseUrl)
59
+ const headers = getAuthHeaders(apiKey)
60
+ const loadBody = {
61
+ model: modelId,
62
+ config: { ctx },
63
+ }
64
+
65
+ try {
66
+ log.info(`[hiveagents] → POST ${apiBase}/api/load`)
67
+ log.info(`[hiveagents] → Body: ${JSON.stringify(loadBody)}`)
68
+ const res = await fetch(`${apiBase}/api/load`, {
69
+ method: "POST",
70
+ headers,
71
+ body: JSON.stringify(loadBody),
72
+ signal: AbortSignal.timeout(HIVEAGENTS_LOAD_FETCH_TIMEOUT_MS),
73
+ })
74
+ const responseText = await res.text().catch(() => "")
75
+ if (!res.ok) {
76
+ // 524 = Cloudflare timeout. El backend puede seguir cargando, así que lo tratamos como "en progreso".
77
+ // 530 = Cloudflare Tunnel error (origen no resoluble); también puede ser transitorio.
78
+ const isTransientCloudflareError = [502, 503, 504, 524, 530].includes(res.status)
79
+ if (isTransientCloudflareError) {
80
+ log.warn(`[hiveagents] ← Load request hit transient error (HTTP ${res.status}); backend may still be loading`)
81
+ return { success: true, loading: true }
82
+ }
83
+ log.error(`[hiveagents] ← Load failed: HTTP ${res.status} ${res.statusText} — ${responseText}`)
84
+ return { success: false, error: `Load failed: HTTP ${res.status} — ${responseText || res.statusText}` }
85
+ }
86
+ log.info(`[hiveagents] ← Load accepted: ${responseText}`)
87
+ return { success: true }
88
+ } catch (err) {
89
+ const msg = (err as Error).message || ""
90
+ // AbortError por timeout interno: el backend puede seguir cargando.
91
+ if (msg.includes("timed out") || msg.includes("abort") || msg.includes("AbortError")) {
92
+ log.warn(`[hiveagents] ← Load request timed out after ${HIVEAGENTS_LOAD_FETCH_TIMEOUT_MS}ms; backend may still be loading`)
93
+ return { success: true, loading: true }
94
+ }
95
+ return { success: false, error: msg }
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Consulta el estado actual del backend de HiveAgents.
101
+ */
102
+ export async function getHiveAgentsModelStatus(
103
+ apiKey: string,
104
+ baseUrl?: string
105
+ ): Promise<HiveAgentsStatusResult> {
106
+ const apiBase = getApiBase(baseUrl)
107
+ const headers = getAuthHeaders(apiKey)
108
+
109
+ try {
110
+ const res = await fetch(`${apiBase}/api/status`, { headers })
111
+ if (!res.ok) return { loaded: false }
112
+ const data = await res.json() as any
113
+ return {
114
+ loaded: !!data.loaded,
115
+ model: data.model,
116
+ }
117
+ } catch {
118
+ return { loaded: false }
119
+ }
120
+ }
121
+
122
+ export class HiveAgentsProvider extends OpenAICompatBase {
123
+ private _currentModelId = ""
124
+
125
+ constructor() { super("hiveagents") }
126
+
127
+ private _isGemma4(modelId: string): boolean { return /^gemma-?4/i.test(modelId) }
128
+ private _isQwen3(modelId: string): boolean { return /^qwen3?/i.test(modelId) }
129
+
130
+ // Cloudflare WAF blocks requests carrying x-stainless-* headers from the OpenAI SDK.
131
+ // Strip them via a custom fetch wrapper so they never reach the WAF.
132
+ protected async resolveOpenAIClient(apiKey: string, baseURL: string | undefined): Promise<any> {
133
+ const { default: OpenAI } = await import("openai")
134
+ return new OpenAI({
135
+ apiKey,
136
+ baseURL,
137
+ fetch: async (url: RequestInfo | URL, init?: RequestInit) => {
138
+ const headers = new Headers(init?.headers as HeadersInit | undefined)
139
+ for (const h of BLOCKED_HEADERS) headers.delete(h)
140
+
141
+ // Debug: log exact request so we can replicate with curl
142
+ const headersObj: Record<string, string> = {}
143
+ headers.forEach((v, k) => { headersObj[k] = k.toLowerCase() === "authorization" ? `Bearer ••••${v.slice(-6)}` : v })
144
+ log.info(`[hiveagents] → POST ${url}`)
145
+ log.info(`[hiveagents] → Headers: ${JSON.stringify(headersObj)}`)
146
+ if (init?.body) {
147
+ try {
148
+ const parsed = JSON.parse(init.body as string)
149
+ const summary = { model: parsed.model, messages: parsed.messages?.length, tools: parsed.tools?.length, max_tokens: parsed.max_tokens, temperature: parsed.temperature, tool_choice: parsed.tool_choice, extra_body: parsed.extra_body }
150
+ log.info(`[hiveagents] → Body summary: ${JSON.stringify(summary)}`)
151
+ } catch { /* ignore */ }
152
+ }
153
+
154
+ const res = await fetch(url, { ...init, headers })
155
+ log.info(`[hiveagents] ← Response: ${res.status} ${res.statusText}`)
156
+ return res
157
+ },
158
+ })
159
+ }
160
+
161
+ async call(options: LLMCallOptions): Promise<LLMResponse> {
162
+ const realModelId = options.model.replace(/^hiveagents\//i, "")
163
+ if (realModelId && realModelId !== "local") {
164
+ await this._ensureModelLoaded(realModelId, options)
165
+ }
166
+ this._currentModelId = realModelId
167
+
168
+ let callOptions = { ...options, model: "hiveagents/local" }
169
+
170
+ // Qwen3: inject /no_think when thinking is explicitly disabled
171
+ if (this._isQwen3(realModelId) && options.thinking?.enabled === false) {
172
+ const msgs = callOptions.messages.map(m => ({ ...m }))
173
+ const sysMsg = msgs.find(m => m.role === "system")
174
+ if (sysMsg && typeof sysMsg.content === "string") {
175
+ if (!sysMsg.content.startsWith("/no_think"))
176
+ sysMsg.content = "/no_think\n" + sysMsg.content
177
+ } else {
178
+ msgs.unshift({ role: "system", content: "/no_think" })
179
+ }
180
+ callOptions = { ...callOptions, messages: msgs }
181
+ }
182
+
183
+ return super.call(callOptions)
184
+ }
185
+
186
+ // Gemma 4: inject chat_template_kwargs.enable_thinking via extra_body.
187
+ // Default is true (thinking ON) when options.thinking is not set.
188
+ protected modifyRequestBody(body: any, options: LLMCallOptions): any {
189
+ if (this._isGemma4(this._currentModelId)) {
190
+ const enableThinking = options.thinking?.enabled !== false
191
+ body.extra_body = {
192
+ ...(body.extra_body ?? {}),
193
+ chat_template_kwargs: { enable_thinking: enableThinking },
194
+ }
195
+ }
196
+ return body
197
+ }
198
+
199
+ /**
200
+ * Fallback defensivo: si la UI no cargó el modelo previamente,
201
+ * lo intenta cargar justo antes de inferir.
202
+ */
203
+ private async _ensureModelLoaded(modelId: string, options: LLMCallOptions): Promise<void> {
204
+ const status = await getHiveAgentsModelStatus(options.apiKey, options.baseUrl)
205
+ if (status.loaded && status.model?.name === modelId) {
206
+ log.info(`[hiveagents] Model ${modelId} already loaded`)
207
+ return
208
+ }
209
+ log.warn(`[hiveagents] Model ${modelId} not loaded. Triggering load with ctx=${HIVEAGENTS_DEFAULT_LOAD_CTX}`)
210
+ const result = await loadHiveAgentsModel(modelId, options.apiKey, options.baseUrl)
211
+ if (!result.success) {
212
+ log.warn(`[hiveagents] Auto-load failed for ${modelId}: ${result.error}`)
213
+ }
214
+ }
215
+
216
+ protected injectToolsIntoPrompt(body: any, preparedTools: any[]): void {
217
+ // When the backend already receives native OpenAI-style tools, do not confuse
218
+ // the model with an alternate <tool_call> text format. HiveAgents supports
219
+ // native tool_calls when the model/chat-template supports them.
220
+ if (body.tools && body.tools.length > 0) {
221
+ return
222
+ }
223
+
224
+ // Fallback for models/backends that do not expose native tool calling:
225
+ // inject the tool descriptions as text and instruct the model to emit
226
+ // a single JSON block wrapped in <tool_call> tags.
227
+ const toolDescriptions = preparedTools.map(t => JSON.stringify(t.function)).join("\n")
228
+ const instruction = [
229
+ "You have access to the following tools.",
230
+ "When you need to use a tool, output EXACTLY one JSON block wrapped in <tool_call> tags and NOTHING ELSE in that turn:",
231
+ "",
232
+ "<tool_call>",
233
+ '{"name": "browser_navigate", "arguments": {"url": "https://example.com"}}',
234
+ "</tool_call>",
235
+ "",
236
+ "Use the exact tool name and argument names from the list below. Do not add extra text, markdown, or explanations inside the tool_call block.",
237
+ "",
238
+ "Tools:",
239
+ toolDescriptions,
240
+ ].join("\n")
241
+ const sysMsg = body.messages.find((m: any) => m.role === "system")
242
+ if (sysMsg) {
243
+ sysMsg.content += "\n\n" + instruction
244
+ } else {
245
+ body.messages.unshift({ role: "system", content: instruction })
246
+ }
247
+ }
248
+ }
@@ -27,7 +27,10 @@ export const OPENAI_COMPAT_BASE_URLS: Record<string, string> = {
27
27
  kimi: "https://api.moonshot.ai/v1",
28
28
  "local-llama": "http://localhost:8081/v1",
29
29
  nvidia: "https://integrate.api.nvidia.com/v1",
30
- qwen: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
30
+ qwen: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
31
+ minimax: "https://api.minimaxi.com/v1",
32
+ "opencode-go": "https://opencode.ai/zen/go/v1",
33
+ hiveagents: "https://llm.hiveagents.io/v1",
31
34
  }
32
35
 
33
36
  // ─── Provider profiles ────────────────────────────────────────────────────────
@@ -66,6 +69,9 @@ export const PROVIDER_PROFILES: Record<string, ProviderProfile> = {
66
69
  nvidia: { ...DEFAULT_PROFILE, normalizeToolNames: true },
67
70
  qwen: { ...DEFAULT_PROFILE, normalizeToolNames: true, retryWithoutToolsOnCodes: [400, 422] },
68
71
  "local-llama": { ...DEFAULT_PROFILE },
72
+ minimax: { ...DEFAULT_PROFILE, normalizeToolNames: true, retryWithoutToolsOnCodes: [400, 422] },
73
+ "opencode-go": { ...DEFAULT_PROFILE, normalizeToolNames: true, retryWithoutToolsOnCodes: [400, 422] },
74
+ hiveagents: { ...DEFAULT_PROFILE, retryWithoutToolsOnCodes: [400, 422] },
69
75
  }
70
76
 
71
77
  export function getProviderProfile(provider: string): ProviderProfile {
@@ -0,0 +1,13 @@
1
+ import { OpenAICompatBase } from "./openai-compat-base"
2
+
3
+ export class MiniMaxProvider extends OpenAICompatBase {
4
+ static readonly secretKey = "MINIMAX_API_KEY"
5
+
6
+ constructor() {
7
+ super("minimax")
8
+ }
9
+
10
+ protected needsReasoningRoundtrip(): boolean {
11
+ return true
12
+ }
13
+ }