@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.
- package/README.md +31 -71
- package/dist/hive.js +4318 -2898
- package/dist/tool-worker.js +2691 -1969
- package/dist/ui/assets/AgentCreateForm-b7xHyfNc.js +1 -0
- package/dist/ui/assets/AgentDetailPage-VHy3M7mI.js +1 -0
- package/dist/ui/assets/AgentNewPage-BnWImQMx.js +1 -0
- package/dist/ui/{dist/assets/AgentsPage-DGNLDXjR.js → assets/AgentsPage-WFy5abqx.js} +5 -5
- package/dist/ui/assets/ApiClientPage-BV7zLIL7.js +3 -0
- package/dist/ui/assets/{CanvasPage-CnMO1FN8.js → CanvasPage-B9zuIrTm.js} +7 -7
- package/dist/ui/assets/ChannelsPage-DiN3NvIM.js +8 -0
- package/dist/ui/{dist/assets/DashboardPage-VyXXp3U1.js → assets/DashboardPage-CHjARjVK.js} +2 -2
- package/dist/ui/assets/{LoginPage-DPj2s2Qq.js → LoginPage-Dwd_XxoU.js} +1 -1
- package/dist/ui/assets/LogsPage-DW8Nnqe6.js +1 -0
- package/dist/ui/assets/MeetingPage-D3bkiKYt.js +1 -0
- package/dist/ui/assets/{NotFound-BMeQSGcG.js → NotFound-BIUDlIXU.js} +1 -1
- package/dist/ui/assets/ProvidersPage-UqsDAxPQ.js +1 -0
- package/dist/ui/{dist/assets/RecoverPage-B-hDZUM2.js → assets/RecoverPage-8hTjr_JU.js} +1 -1
- package/dist/ui/assets/SettingsPage-DNa0jOkA.js +9 -0
- package/dist/ui/assets/SetupPage-Bdm2irQG.js +1 -0
- package/dist/ui/assets/WebChatPage-DElJg6P2.js +16 -0
- package/dist/ui/assets/accordion-CnLzKNHK.js +1 -0
- package/dist/ui/{dist/assets/alert-Bq6awLlW.js → assets/alert-DylmSCDJ.js} +1 -1
- package/dist/ui/{dist/assets/alert-dialog-DQvltYmf.js → assets/alert-dialog-DNNWN_SI.js} +1 -1
- package/dist/ui/assets/{badge-DXUDdTed.js → badge-ChENFgkC.js} +1 -1
- package/dist/ui/assets/bell-8BqRYmzf.js +1 -0
- package/dist/ui/assets/chevron-down-DIosfU_U.js +1 -0
- package/dist/ui/assets/chevron-up-CI-W21Fy.js +1 -0
- package/dist/ui/assets/circle-x-DjLkFDO8.js +1 -0
- package/dist/ui/assets/copy-Bu5d7C-0.js +1 -0
- package/dist/ui/{dist/assets/dialog-bI9jImCS.js → assets/dialog-BJ-npIv8.js} +1 -1
- package/dist/ui/{dist/assets/dropdown-menu-BK-CO3Od.js → assets/dropdown-menu-DDiaHg5y.js} +1 -1
- package/dist/ui/assets/{es-Cg8zdT52.js → es-ecSKCyB6.js} +1 -1
- package/dist/ui/assets/index-CawKP29y.js +116 -0
- package/dist/ui/assets/index-DIcsEkyd.css +2 -0
- package/dist/ui/{dist/assets/label-CrH0Jj3v.js → assets/label-Bi6udtSd.js} +1 -1
- package/dist/ui/assets/progress-D5c-Eilm.js +1 -0
- package/dist/ui/assets/scroll-area-CihOx0cb.js +1 -0
- package/dist/ui/assets/search-DzDptO9s.js +1 -0
- package/dist/ui/assets/select-BQCOjM2j.js +1 -0
- package/dist/ui/assets/send-BPk9XbIq.js +1 -0
- package/dist/ui/assets/shield-CxhcUT39.js +1 -0
- package/dist/ui/assets/{slider-CsiUDxc3.js → slider-bcUiUfx0.js} +1 -1
- package/dist/ui/assets/switch-BR30E4ej.js +1 -0
- package/dist/ui/assets/table-B3aGEaVp.js +1 -0
- package/dist/ui/assets/tabs-LQidMKRS.js +1 -0
- package/dist/ui/assets/textarea-B6Z1Zc6W.js +1 -0
- package/dist/ui/assets/useProviders-Dlizq_8q.js +1 -0
- package/dist/ui/{dist/assets/vendor-radix-cw1bQaVC.js → assets/vendor-radix-D6rA7xKY.js} +4 -4
- package/dist/ui/assets/{vendor-react-D4s9E-zj.js → vendor-react-BU5iQU4f.js} +1 -1
- package/dist/ui/dist/assets/AgentCreateForm-b7xHyfNc.js +1 -0
- package/dist/ui/dist/assets/AgentDetailPage-VHy3M7mI.js +1 -0
- package/dist/ui/dist/assets/AgentNewPage-BnWImQMx.js +1 -0
- package/dist/ui/{assets/AgentsPage-DGNLDXjR.js → dist/assets/AgentsPage-WFy5abqx.js} +5 -5
- package/dist/ui/dist/assets/ApiClientPage-BV7zLIL7.js +3 -0
- package/dist/ui/dist/assets/{CanvasPage-CnMO1FN8.js → CanvasPage-B9zuIrTm.js} +7 -7
- package/dist/ui/dist/assets/ChannelsPage-DiN3NvIM.js +8 -0
- package/dist/ui/{assets/DashboardPage-VyXXp3U1.js → dist/assets/DashboardPage-CHjARjVK.js} +2 -2
- package/dist/ui/dist/assets/{LoginPage-DPj2s2Qq.js → LoginPage-Dwd_XxoU.js} +1 -1
- package/dist/ui/dist/assets/LogsPage-DW8Nnqe6.js +1 -0
- package/dist/ui/dist/assets/MeetingPage-D3bkiKYt.js +1 -0
- package/dist/ui/dist/assets/{NotFound-BMeQSGcG.js → NotFound-BIUDlIXU.js} +1 -1
- package/dist/ui/dist/assets/ProvidersPage-UqsDAxPQ.js +1 -0
- package/dist/ui/{assets/RecoverPage-B-hDZUM2.js → dist/assets/RecoverPage-8hTjr_JU.js} +1 -1
- package/dist/ui/dist/assets/SettingsPage-DNa0jOkA.js +9 -0
- package/dist/ui/dist/assets/SetupPage-Bdm2irQG.js +1 -0
- package/dist/ui/dist/assets/WebChatPage-DElJg6P2.js +16 -0
- package/dist/ui/dist/assets/accordion-CnLzKNHK.js +1 -0
- package/dist/ui/{assets/alert-Bq6awLlW.js → dist/assets/alert-DylmSCDJ.js} +1 -1
- package/dist/ui/{assets/alert-dialog-DQvltYmf.js → dist/assets/alert-dialog-DNNWN_SI.js} +1 -1
- package/dist/ui/dist/assets/{badge-DXUDdTed.js → badge-ChENFgkC.js} +1 -1
- package/dist/ui/dist/assets/bell-8BqRYmzf.js +1 -0
- package/dist/ui/dist/assets/chevron-down-DIosfU_U.js +1 -0
- package/dist/ui/dist/assets/chevron-up-CI-W21Fy.js +1 -0
- package/dist/ui/dist/assets/circle-x-DjLkFDO8.js +1 -0
- package/dist/ui/dist/assets/copy-Bu5d7C-0.js +1 -0
- package/dist/ui/{assets/dialog-bI9jImCS.js → dist/assets/dialog-BJ-npIv8.js} +1 -1
- package/dist/ui/{assets/dropdown-menu-BK-CO3Od.js → dist/assets/dropdown-menu-DDiaHg5y.js} +1 -1
- package/dist/ui/dist/assets/{es-Cg8zdT52.js → es-ecSKCyB6.js} +1 -1
- package/dist/ui/dist/assets/index-CawKP29y.js +116 -0
- package/dist/ui/dist/assets/index-DIcsEkyd.css +2 -0
- package/dist/ui/{assets/label-CrH0Jj3v.js → dist/assets/label-Bi6udtSd.js} +1 -1
- package/dist/ui/dist/assets/progress-D5c-Eilm.js +1 -0
- package/dist/ui/dist/assets/scroll-area-CihOx0cb.js +1 -0
- package/dist/ui/dist/assets/search-DzDptO9s.js +1 -0
- package/dist/ui/dist/assets/select-BQCOjM2j.js +1 -0
- package/dist/ui/dist/assets/send-BPk9XbIq.js +1 -0
- package/dist/ui/dist/assets/shield-CxhcUT39.js +1 -0
- package/dist/ui/dist/assets/{slider-CsiUDxc3.js → slider-bcUiUfx0.js} +1 -1
- package/dist/ui/dist/assets/switch-BR30E4ej.js +1 -0
- package/dist/ui/dist/assets/table-B3aGEaVp.js +1 -0
- package/dist/ui/dist/assets/tabs-LQidMKRS.js +1 -0
- package/dist/ui/dist/assets/textarea-B6Z1Zc6W.js +1 -0
- package/dist/ui/dist/assets/useProviders-Dlizq_8q.js +1 -0
- package/dist/ui/{assets/vendor-radix-cw1bQaVC.js → dist/assets/vendor-radix-D6rA7xKY.js} +4 -4
- package/dist/ui/dist/assets/{vendor-react-D4s9E-zj.js → vendor-react-BU5iQU4f.js} +1 -1
- package/dist/ui/dist/index.html +6 -6
- package/dist/ui/index.html +6 -6
- package/package.json +1 -1
- package/packages/cli/src/adapters/binary.ts +8 -4
- package/packages/cli/src/adapters/bun-global.ts +5 -1
- package/packages/cli/src/adapters/config.ts +4 -3
- package/packages/cli/src/adapters/docker.ts +2 -1
- package/packages/cli/src/commands/gateway.ts +123 -9
- package/packages/cli/src/commands/logs.ts +2 -1
- package/packages/cli/src/commands/onboard.ts +27 -1
- package/packages/cli/src/commands/sessions.ts +2 -1
- package/packages/cli/src/commands/skills.ts +2 -1
- package/packages/core/src/agent/agent-loop.ts +104 -2
- package/packages/core/src/agent/context-compiler.ts +6 -0
- package/packages/core/src/agent/llm-client.ts +6 -0
- package/packages/core/src/agent/llm-providers/anthropic.ts +23 -8
- package/packages/core/src/agent/llm-providers/hiveagents.ts +248 -0
- package/packages/core/src/agent/llm-providers/interface.ts +7 -1
- package/packages/core/src/agent/llm-providers/minimax.ts +13 -0
- package/packages/core/src/agent/llm-providers/openai-compat-base.ts +49 -25
- package/packages/core/src/agent/llm-providers/opencode-go.ts +9 -0
- package/packages/core/src/agent/providers/index.ts +3 -2
- package/packages/core/src/agent/stuck-loop.ts +90 -14
- package/packages/core/src/channels/base.ts +7 -1
- package/packages/core/src/channels/whatsapp.ts +13 -1
- package/packages/core/src/config/loader.ts +8 -8
- package/packages/core/src/gateway/helpers/path.ts +2 -1
- package/packages/core/src/gateway/initializer.ts +4 -4
- package/packages/core/src/gateway/llm-local/downloader.ts +130 -11
- package/packages/core/src/gateway/llm-local/index.ts +2 -0
- package/packages/core/src/gateway/llm-local/models.ts +4 -3
- package/packages/core/src/gateway/router.ts +7 -5
- package/packages/core/src/gateway/routes/http-client.ts +16 -0
- package/packages/core/src/gateway/routes/llm-local.ts +51 -5
- package/packages/core/src/gateway/routes/providers.ts +99 -2
- package/packages/core/src/gateway/server.ts +131 -57
- package/packages/core/src/gateway/slash-commands.ts +7 -1
- package/packages/core/src/gateway/tts/src/install.ts +17 -9
- package/packages/core/src/storage/crypto.ts +152 -20
- package/packages/core/src/storage/migrate.ts +51 -18
- package/packages/core/src/storage/onboarding.ts +28 -0
- package/packages/core/src/storage/seed.ts +52 -2
- package/packages/core/src/tool-runtime/index.ts +22 -1
- package/packages/core/src/tools/api/api-request.ts +174 -0
- package/packages/core/src/tools/api/index.ts +16 -0
- package/packages/core/src/tools/index.ts +12 -0
- package/packages/core/src/tools/web/browser-click.ts +2 -2
- package/packages/core/src/tools/web/browser-extract.ts +22 -6
- package/packages/core/src/tools/web/browser-navigate.ts +34 -18
- package/packages/core/src/tools/web/browser-screenshot.ts +40 -8
- package/packages/core/src/tools/web/browser-script.ts +2 -2
- package/packages/core/src/tools/web/browser-service.ts +295 -341
- package/packages/core/src/tools/web/browser-type.ts +5 -10
- package/packages/core/src/tools/web/browser-wait.ts +2 -2
- package/packages/core/src/tools/web/index.ts +1 -1
- package/packages/core/src/utils/logger.ts +2 -1
- package/packages/mcp/src/manager.ts +2 -1
- package/packages/skills/src/bundled/api/api_client/SKILL.md +132 -0
- package/packages/skills/src/bundled-data.generated.ts +1191 -1134
- package/packages/skills/src/loader.ts +2 -1
- package/dist/ui/assets/AgentCreateForm-0oFbN3gj.js +0 -1
- package/dist/ui/assets/AgentDetailPage-BJ4L2fNJ.js +0 -1
- package/dist/ui/assets/AgentNewPage-B3n0LUck.js +0 -1
- package/dist/ui/assets/ChannelsPage-fbF8K4MR.js +0 -8
- package/dist/ui/assets/LogsPage-B2lY9maY.js +0 -1
- package/dist/ui/assets/MeetingPage-2ky_hKiG.js +0 -1
- package/dist/ui/assets/ProvidersPage-CEyUM2tD.js +0 -1
- package/dist/ui/assets/SettingsPage-eO0i3g8p.js +0 -9
- package/dist/ui/assets/SetupPage-ByYqTELb.js +0 -1
- package/dist/ui/assets/WebChatPage-BuGT2AL0.js +0 -16
- package/dist/ui/assets/accordion-C5d5Rm5z.js +0 -1
- package/dist/ui/assets/chevron-up-BYhk0K2J.js +0 -1
- package/dist/ui/assets/globe-DeCQTCDJ.js +0 -1
- package/dist/ui/assets/index-B2fCYtTS.css +0 -2
- package/dist/ui/assets/index-CQ7fn00w.js +0 -116
- package/dist/ui/assets/progress-BherYzY6.js +0 -1
- package/dist/ui/assets/scroll-area-DkeyX32e.js +0 -1
- package/dist/ui/assets/send-B0H5SEIE.js +0 -1
- package/dist/ui/assets/switch-BDwN8RYV.js +0 -1
- package/dist/ui/assets/table-CSc8ubon.js +0 -1
- package/dist/ui/assets/textarea-CXgXWKrT.js +0 -1
- package/dist/ui/assets/useProviders-CnlC_qCS.js +0 -1
- package/dist/ui/dist/assets/AgentCreateForm-0oFbN3gj.js +0 -1
- package/dist/ui/dist/assets/AgentDetailPage-BJ4L2fNJ.js +0 -1
- package/dist/ui/dist/assets/AgentNewPage-B3n0LUck.js +0 -1
- package/dist/ui/dist/assets/ChannelsPage-fbF8K4MR.js +0 -8
- package/dist/ui/dist/assets/LogsPage-B2lY9maY.js +0 -1
- package/dist/ui/dist/assets/MeetingPage-2ky_hKiG.js +0 -1
- package/dist/ui/dist/assets/ProvidersPage-CEyUM2tD.js +0 -1
- package/dist/ui/dist/assets/SettingsPage-eO0i3g8p.js +0 -9
- package/dist/ui/dist/assets/SetupPage-ByYqTELb.js +0 -1
- package/dist/ui/dist/assets/WebChatPage-BuGT2AL0.js +0 -16
- package/dist/ui/dist/assets/accordion-C5d5Rm5z.js +0 -1
- package/dist/ui/dist/assets/chevron-up-BYhk0K2J.js +0 -1
- package/dist/ui/dist/assets/globe-DeCQTCDJ.js +0 -1
- package/dist/ui/dist/assets/index-B2fCYtTS.css +0 -2
- package/dist/ui/dist/assets/index-CQ7fn00w.js +0 -116
- package/dist/ui/dist/assets/progress-BherYzY6.js +0 -1
- package/dist/ui/dist/assets/scroll-area-DkeyX32e.js +0 -1
- package/dist/ui/dist/assets/send-B0H5SEIE.js +0 -1
- package/dist/ui/dist/assets/switch-BDwN8RYV.js +0 -1
- package/dist/ui/dist/assets/table-CSc8ubon.js +0 -1
- package/dist/ui/dist/assets/textarea-CXgXWKrT.js +0 -1
- package/dist/ui/dist/assets/useProviders-CnlC_qCS.js +0 -1
- /package/dist/ui/assets/{card-CNf6BS2e.js → card-DFKnZ6ky.js} +0 -0
- /package/dist/ui/assets/{circle-alert-CyHDwUj8.js → circle-alert-KuAm2FWh.js} +0 -0
- /package/dist/ui/assets/{circle-check-Bb54Ebmu.js → circle-check-6Ard1-2z.js} +0 -0
- /package/dist/ui/assets/{cpu-Cdgc_B1K.js → cpu-KDy6-FAI.js} +0 -0
- /package/dist/ui/assets/{download-C3ifGMjJ.js → download-Cjbk4Rek.js} +0 -0
- /package/dist/ui/assets/{external-link-BvxYeTP1.js → external-link-6sTlRDUR.js} +0 -0
- /package/dist/ui/assets/{eye-DqNTU_GD.js → eye-Df8o0tkC.js} +0 -0
- /package/dist/ui/assets/{file-text-BT_9S9SM.js → file-text-lnxnjBp0.js} +0 -0
- /package/dist/ui/assets/{folder-open-BhH8y9ac.js → folder-open-DJBLDFjv.js} +0 -0
- /package/dist/ui/assets/{format-GVHeOyWI.js → format-BwdV8bB5.js} +0 -0
- /package/dist/ui/assets/{gateway-url-COCbW0IR.js → gateway-url-DwzPmoc8.js} +0 -0
- /package/dist/ui/assets/{gauge-D_TMa4i9.js → gauge-B8Tj43rC.js} +0 -0
- /package/dist/ui/assets/{hexagon-DsGOUl-H.js → hexagon-6L79pgVK.js} +0 -0
- /package/dist/ui/assets/{history-BSG-Ypqf.js → history-CAF_R34_.js} +0 -0
- /package/dist/ui/assets/{info-NwLoa2Mj.js → info-WjromB4Y.js} +0 -0
- /package/dist/ui/assets/{key-3EP0dhkT.js → key-DyKOoQh5.js} +0 -0
- /package/dist/ui/assets/{loader-circle-CZNax6kS.js → loader-circle-BmBOgYze.js} +0 -0
- /package/dist/ui/assets/{lock-Ei1_J-Nq.js → lock-BS6OLXPv.js} +0 -0
- /package/dist/ui/assets/{pause-BUqah9Bi.js → pause-VqeUmp2Z.js} +0 -0
- /package/dist/ui/assets/{play-NcZ4swwL.js → play-zJpWuhrr.js} +0 -0
- /package/dist/ui/assets/{plus-CX1xyhp5.js → plus-BZQX26Dr.js} +0 -0
- /package/dist/ui/assets/{refresh-cw-DaYdjQFk.js → refresh-cw-CCzDCAuz.js} +0 -0
- /package/dist/ui/assets/{save-CUdYyHNy.js → save-hUmZhceG.js} +0 -0
- /package/dist/ui/assets/{settings-Ds4SqD8s.js → settings-BGfrZ_zM.js} +0 -0
- /package/dist/ui/assets/{sparkles-yUEb-7oH.js → sparkles-BhwlS1pc.js} +0 -0
- /package/dist/ui/assets/{square-BD81nFtN.js → square-DMNWw4Hi.js} +0 -0
- /package/dist/ui/assets/{terminal-DN38Q456.js → terminal--7G943As.js} +0 -0
- /package/dist/ui/assets/{trash-2-CNjMkoq6.js → trash-2-xD2o4SgX.js} +0 -0
- /package/dist/ui/assets/{triangle-alert-C9Y8Ub4X.js → triangle-alert-pVIJGjga.js} +0 -0
- /package/dist/ui/assets/{vendor-router-C9pIYwbJ.js → vendor-router-gqiZ7xhx.js} +0 -0
- /package/dist/ui/assets/{volume-2-CeSXNDv4.js → volume-2-BekVQl6P.js} +0 -0
- /package/dist/ui/assets/{zap-hlXjpSeA.js → zap-B4RaNNO5.js} +0 -0
- /package/dist/ui/dist/assets/{card-CNf6BS2e.js → card-DFKnZ6ky.js} +0 -0
- /package/dist/ui/dist/assets/{circle-alert-CyHDwUj8.js → circle-alert-KuAm2FWh.js} +0 -0
- /package/dist/ui/dist/assets/{circle-check-Bb54Ebmu.js → circle-check-6Ard1-2z.js} +0 -0
- /package/dist/ui/dist/assets/{cpu-Cdgc_B1K.js → cpu-KDy6-FAI.js} +0 -0
- /package/dist/ui/dist/assets/{download-C3ifGMjJ.js → download-Cjbk4Rek.js} +0 -0
- /package/dist/ui/dist/assets/{external-link-BvxYeTP1.js → external-link-6sTlRDUR.js} +0 -0
- /package/dist/ui/dist/assets/{eye-DqNTU_GD.js → eye-Df8o0tkC.js} +0 -0
- /package/dist/ui/dist/assets/{file-text-BT_9S9SM.js → file-text-lnxnjBp0.js} +0 -0
- /package/dist/ui/dist/assets/{folder-open-BhH8y9ac.js → folder-open-DJBLDFjv.js} +0 -0
- /package/dist/ui/dist/assets/{format-GVHeOyWI.js → format-BwdV8bB5.js} +0 -0
- /package/dist/ui/dist/assets/{gateway-url-COCbW0IR.js → gateway-url-DwzPmoc8.js} +0 -0
- /package/dist/ui/dist/assets/{gauge-D_TMa4i9.js → gauge-B8Tj43rC.js} +0 -0
- /package/dist/ui/dist/assets/{hexagon-DsGOUl-H.js → hexagon-6L79pgVK.js} +0 -0
- /package/dist/ui/dist/assets/{history-BSG-Ypqf.js → history-CAF_R34_.js} +0 -0
- /package/dist/ui/dist/assets/{info-NwLoa2Mj.js → info-WjromB4Y.js} +0 -0
- /package/dist/ui/dist/assets/{key-3EP0dhkT.js → key-DyKOoQh5.js} +0 -0
- /package/dist/ui/dist/assets/{loader-circle-CZNax6kS.js → loader-circle-BmBOgYze.js} +0 -0
- /package/dist/ui/dist/assets/{lock-Ei1_J-Nq.js → lock-BS6OLXPv.js} +0 -0
- /package/dist/ui/dist/assets/{pause-BUqah9Bi.js → pause-VqeUmp2Z.js} +0 -0
- /package/dist/ui/dist/assets/{play-NcZ4swwL.js → play-zJpWuhrr.js} +0 -0
- /package/dist/ui/dist/assets/{plus-CX1xyhp5.js → plus-BZQX26Dr.js} +0 -0
- /package/dist/ui/dist/assets/{refresh-cw-DaYdjQFk.js → refresh-cw-CCzDCAuz.js} +0 -0
- /package/dist/ui/dist/assets/{save-CUdYyHNy.js → save-hUmZhceG.js} +0 -0
- /package/dist/ui/dist/assets/{settings-Ds4SqD8s.js → settings-BGfrZ_zM.js} +0 -0
- /package/dist/ui/dist/assets/{sparkles-yUEb-7oH.js → sparkles-BhwlS1pc.js} +0 -0
- /package/dist/ui/dist/assets/{square-BD81nFtN.js → square-DMNWw4Hi.js} +0 -0
- /package/dist/ui/dist/assets/{terminal-DN38Q456.js → terminal--7G943As.js} +0 -0
- /package/dist/ui/dist/assets/{trash-2-CNjMkoq6.js → trash-2-xD2o4SgX.js} +0 -0
- /package/dist/ui/dist/assets/{triangle-alert-C9Y8Ub4X.js → triangle-alert-pVIJGjga.js} +0 -0
- /package/dist/ui/dist/assets/{vendor-router-C9pIYwbJ.js → vendor-router-gqiZ7xhx.js} +0 -0
- /package/dist/ui/dist/assets/{volume-2-CeSXNDv4.js → volume-2-BekVQl6P.js} +0 -0
- /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
|
-
|
|
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
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
+
}
|