@openhands/agent-canvas 1.0.0-alpha.6 → 1.0.0-alpha.8
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 +32 -7
- package/bin/agent-canvas.mjs +35 -2
- package/build/assets/{QueryClientProvider-DITRCGAK.js → QueryClientProvider-B7kl84Kj.js} +1 -1
- package/build/assets/{Trans-D43bd3yR.js → Trans-1j65oy9O.js} +1 -1
- package/build/assets/{acp-providers-SCPK1BIU.js → acp-providers-DauuOsW9.js} +1 -1
- package/build/assets/{acp-route-guard-IWlFmS6x.js → acp-route-guard-CQTmeJwM.js} +1 -1
- package/build/assets/{active-backend-context-CkP3ZEJs.js → active-backend-context-TVbjnvmP.js} +1 -1
- package/build/assets/add-backend-modal-KMmPQNZU.js +1 -0
- package/build/assets/{agent-server-client-options-8OJSXbm8.js → agent-server-client-options-DT2GP6VJ.js} +1 -1
- package/build/assets/{agent-server-compatibility-DvKtnXHw.js → agent-server-compatibility-2aOx5iWd.js} +1 -1
- package/build/assets/{agent-server-conversation-service.api-BdEre_71.js → agent-server-conversation-service.api-DSl9G5UR.js} +3 -3
- package/build/assets/{agent-settings-DdisD2Xx.js → agent-settings-B247S9G3.js} +2 -2
- package/build/assets/{alert-banner-CvTYN73l.js → alert-banner-BWoqueRw.js} +1 -1
- package/build/assets/{analytics-consent-form-modal-BKgT9i2w.js → analytics-consent-form-modal-C7sXfxRh.js} +1 -1
- package/build/assets/{app-settings-DcYXtxGP.js → app-settings-BVeSaty9.js} +1 -1
- package/build/assets/automation-detail-g5-RZ0da.js +1 -0
- package/build/assets/automations-list-DHoq_0MM.js +1 -0
- package/build/assets/{backend-form-modal-KudhWUX8.js → backend-form-modal-K6IMCr3p.js} +1 -1
- package/build/assets/{backend-synced-settings-badge-BFy2HylT.js → backend-synced-settings-badge-nAfiUWvM.js} +1 -1
- package/build/assets/{base-modal-B4HvlFHE.js → base-modal-CQRvRHu1.js} +1 -1
- package/build/assets/{brand-button-8fVVei4i.js → brand-button-C2nEKopC.js} +1 -1
- package/build/assets/{browser-vYpdU3CR.js → browser-DKG63inJ.js} +1 -1
- package/build/assets/{browser-tab-DTM6RyoV.js → browser-tab-B_BuTvrO.js} +1 -1
- package/build/assets/{checkmark-BcvXE9bf.js → checkmark-BJJrZUF8.js} +1 -1
- package/build/assets/{chevron-left-small-BqSkXTeq.js → chevron-left-small-CSh-sE9L.js} +1 -1
- package/build/assets/{circle-plus-check-toggle-DRvuu-RD.js → circle-plus-check-toggle-qs8Va1cC.js} +1 -1
- package/build/assets/{clock-DfoVUZVq.js → clock-ZR4Kn-_Y.js} +1 -1
- package/build/assets/{close-SnIy2eLD.js → close-BdmyeRqS.js} +1 -1
- package/build/assets/{combobox-caret-BMsz5mQX.js → combobox-caret-B53O9Hsq.js} +1 -1
- package/build/assets/{condenser-settings-DduLQcpV.js → condenser-settings-A35V3yng.js} +1 -1
- package/build/assets/{confirmation-modal-B-DOYMUH.js → confirmation-modal-C9-La0h3.js} +1 -1
- package/build/assets/{context-menu-list-item-DzjPB8aC.js → context-menu-list-item-Buu9nc0q.js} +1 -1
- package/build/assets/conversation-BD5WemJI.js +19 -0
- package/build/assets/conversation-C47K62n8.js +1 -0
- package/build/assets/conversation-panel-Dn-S56Gk.js +1 -0
- package/build/assets/{conversation-service.api-YTGTw0pz.js → conversation-service.api-C8pYCyV6.js} +1 -1
- package/build/assets/{conversation-tab-empty-state-BtFDbyTe.js → conversation-tab-empty-state-D8dNvo-V.js} +1 -1
- package/build/assets/conversation-websocket-context-Ywrxd_9p.js +3 -0
- package/build/assets/{copy-BxgbrjDT.js → copy-C7Ti2d8C.js} +1 -1
- package/build/assets/{custom-toast-handlers-BYxhSr3t.js → custom-toast-handlers-BOc3qeQ7.js} +1 -1
- package/build/assets/declaration-D378OjpZ.js +1 -0
- package/build/assets/{device-verify-CTbXX9CQ.js → device-verify-CMusn8nX.js} +1 -1
- package/build/assets/edit-automation-modal-Dnjxbjn7.js +1 -0
- package/build/assets/{ellipsis-button-BoU2-xlG.js → ellipsis-button-ugUATsNo.js} +1 -1
- package/build/assets/{entry.client-DU7-q4ZU.js → entry.client-D9uR9Blz.js} +2 -2
- package/build/assets/{enum-filter-dropdown-BJt-NplD.js → enum-filter-dropdown-1vpOGySB.js} +1 -1
- package/build/assets/{environment-switch-overlay-DQ1n6Iu6.js → environment-switch-overlay-CTCTQikP.js} +1 -1
- package/build/assets/{extensions-hub-BW1FAKFJ.js → extensions-hub-BSUseHVF.js} +1 -1
- package/build/assets/{extensions-navigation-CbPMhSML.js → extensions-navigation-CT1kc1u_.js} +1 -1
- package/build/assets/{files-tab-CbJ4s7Ik.js → files-tab-B3A1NDlZ.js} +1 -1
- package/build/assets/{folder-CerIk8uG.js → folder-0WSMImNX.js} +1 -1
- package/build/assets/git-control-bar-branch-button-CcIpmyfM.js +27 -0
- package/build/assets/{git-provider-icon-D8RE4unY.js → git-provider-icon-DYE9n7fs.js} +1 -1
- package/build/assets/{home-D9fJfhQA.js → home-dIzxi5Dd.js} +1 -1
- package/build/assets/{i18n-DkYgs32x.js → i18n-DjAGhTis.js} +1 -1
- package/build/assets/install-server-modal-z5VaHeXd.js +1 -0
- package/build/assets/{launch-DKCU9uJH.js → launch-hZ0ifhcV.js} +1 -1
- package/build/assets/{lesson-plan-CmkRbe6Z.js → lesson-plan-DRYG5SLI.js} +1 -1
- package/build/assets/{link-external-CvxB0BmI.js → link-external-Df8J52xI.js} +1 -1
- package/build/assets/{llm-client-BpIfxETv.js → llm-client-ChQzg4wX.js} +1 -1
- package/build/assets/llm-settings-2036m7Wt.js +1 -0
- package/build/assets/{llm-settings-BOJC4vD-.js → llm-settings-CcHqGOYL.js} +1 -1
- package/build/assets/{loading-spinner-91b5FiMQ.js → loading-spinner-C04FGh14.js} +1 -1
- package/build/assets/{manage-backends-modal-DqpzcxdI.js → manage-backends-modal-rYeyGx7j.js} +1 -1
- package/build/assets/{manage-workspaces-modal-eG6XgAvw.js → manage-workspaces-modal-C5EuW8m1.js} +1 -1
- package/build/assets/manifest-97e839da.js +1 -0
- package/build/assets/{markdown-renderer-wZnLDbA1.js → markdown-renderer-CEX4Becj.js} +1 -1
- package/build/assets/mcp-C06YssEI.js +9 -0
- package/build/assets/messages-T2ewVkbp.js +36 -0
- package/build/assets/{modal-backdrop-B04pVYAD.js → modal-backdrop-DTYGVmOR.js} +1 -1
- package/build/assets/{modal-body-CgUoFQA1.js → modal-body-YElmM1dV.js} +1 -1
- package/build/assets/{modal-close-button-SM_WXzDY.js → modal-close-button-C_GpQt9F.js} +1 -1
- package/build/assets/{model-selector-7id-Uirf.js → model-selector-DeMmw-Xa.js} +1 -1
- package/build/assets/{navigation-context-BFjstyH6.js → navigation-context-DeIPtGPp.js} +1 -1
- package/build/assets/{navigation-link-DFQ7YcWq.js → navigation-link-C9JD4PYD.js} +1 -1
- package/build/assets/{openhands-logo-DkDp75rC.js → openhands-logo-CI5Fhn1W.js} +1 -1
- package/build/assets/{option-service.api-DN0ZcGjw.js → option-service.api-DsI1UW7N.js} +1 -1
- package/build/assets/{organization-service.api-Ct2dZF8M.js → organization-service.api-COwMPFg5.js} +1 -1
- package/build/assets/{path-utils-D1ZtqFC7.js → path-utils-CqJboYxo.js} +1 -1
- package/build/assets/{plan-components-gOm-daR3.js → plan-components-DEjMuDDG.js} +1 -1
- package/build/assets/{planner-tab-yubfN-6U.js → planner-tab-BrntFmb1.js} +1 -1
- package/build/assets/{profiles-client-D4twHRVf.js → profiles-client-BGkKEV9j.js} +1 -1
- package/build/assets/{providers-C2T07PM3.js → providers-DXvCAN_u.js} +1 -1
- package/build/assets/{proxy-BMZyC45G.js → proxy-CurRmrqf.js} +1 -1
- package/build/assets/{query-client-config-CiK0GJJO.js → query-client-config-Ba7qAAoO.js} +1 -1
- package/build/assets/recommended-automations-launcher-BI9NhG8Y.js +52 -0
- package/build/assets/root-BS1Td78t.js +2 -0
- package/build/assets/root-DHeCXo9N.css +1 -0
- package/build/assets/root-layout-BLjAEgle.js +2 -0
- package/build/assets/{sdk-section-page-03k88tIR.js → sdk-section-page-CJW0G04-.js} +1 -1
- package/build/assets/{sdk-settings-schema-BY8dOy3a.js → sdk-settings-schema-QBYH-ONX.js} +1 -1
- package/build/assets/{search-BCAF9EDS.js → search-Cq_cFrDt.js} +1 -1
- package/build/assets/{secrets-service-Z3qtRb_G.js → secrets-service-Bwd5DeUs.js} +1 -1
- package/build/assets/{secrets-settings-BnlByuMZ.js → secrets-settings-MLXqOtX2.js} +1 -1
- package/build/assets/{server-client-CG1zHqph.js → server-client-C3mC8Hl3.js} +1 -1
- package/build/assets/{settings-DyzGLF_d.js → settings-D7E2U5tK.js} +1 -1
- package/build/assets/{settings-client-CkXDJwIY.js → settings-client-CwjfwoiB.js} +1 -1
- package/build/assets/{settings-dropdown-input-CAQWQgx-.js → settings-dropdown-input-VwAXNrOb.js} +1 -1
- package/build/assets/{settings-gear-D4ZkEDGb.js → settings-gear-BJwWR1ej.js} +1 -1
- package/build/assets/{settings-index-KtTw49xL.js → settings-index-J-3BNR0W.js} +1 -1
- package/build/assets/{settings-input-BWCZt9g2.js → settings-input-DBywAnA7.js} +1 -1
- package/build/assets/{settings-list-classes-xMleGkTC.js → settings-list-classes-BOS092DR.js} +1 -1
- package/build/assets/{settings-modal-Cv2YWSUY.js → settings-modal-B8vgWDTe.js} +1 -1
- package/build/assets/{settings-section-header-context-1wfkgjZZ.js → settings-section-header-context-32x6WTyL.js} +1 -1
- package/build/assets/settings-service.api-FvJGK45W.js +1 -0
- package/build/assets/{settings-switch-CGap2LtG.js → settings-switch-DTKmHC8F.js} +1 -1
- package/build/assets/{settings-utils-BBozxqqi.js → settings-utils-BsvSU3OM.js} +1 -1
- package/build/assets/{shared-conversation-BfZNCsvo.js → shared-conversation-a0QV8o99.js} +1 -1
- package/build/assets/{sidebar-mobile-menu-toggle-DXplko7u.js → sidebar-mobile-menu-toggle-DTUNI1WQ.js} +1 -1
- package/build/assets/{sidebar-nav-link-B4h8naZ7.js → sidebar-nav-link-CnWoZcwc.js} +1 -1
- package/build/assets/{skill-card-pill-row-D0oTWx-a.js → skill-card-pill-row-tZ599jli.js} +1 -1
- package/build/assets/{skills-BN8atjgW.js → skills-ZyAO5dyK.js} +1 -1
- package/build/assets/{skills-plugins-BTnp7QcQ.js → skills-plugins-BSRz041I.js} +1 -1
- package/build/assets/{skills-settings-CbOQvzkR.js → skills-settings-DOnMn9q1.js} +2 -2
- package/build/assets/{status-DDL-ipIP.js → status-CsatcFbK.js} +1 -1
- package/build/assets/{styled-tooltip-Awq4HMw3.js → styled-tooltip-CS3mB_1X.js} +1 -1
- package/build/assets/{switch-skeleton-Bv21RGWd.js → switch-skeleton-C-CfhYYV.js} +1 -1
- package/build/assets/{task-list-tab-B45ktzHM.js → task-list-tab-Day9nhRT.js} +1 -1
- package/build/assets/{terminal-DGuR4559.js → terminal-LNa-iU5c.js} +1 -1
- package/build/assets/{terminal-D5pzR9Ru.js → terminal-ro4SNjUU.js} +1 -1
- package/build/assets/{toggle-switch-gj6T-wsU.js → toggle-switch-k-IZCDbt.js} +1 -1
- package/build/assets/{typography-BbaUAC4V.js → typography-vVUMoNUg.js} +1 -1
- package/build/assets/{u-check-circle-DHGiAi-w.js → u-check-circle-DplbarS5.js} +1 -1
- package/build/assets/{u-check-circle-half-BPcWtWwv.js → u-check-circle-half-yDuiSZHC.js} +1 -1
- package/build/assets/{u-circuit-B_nK9hOu.js → u-circuit-C9tYkpeK.js} +1 -1
- package/build/assets/{u-edit-BPFJBd34.js → u-edit-KAUlufD8.js} +1 -1
- package/build/assets/{use-active-conversation-Bu5J9iLy.js → use-active-conversation-D15D9GgR.js} +1 -1
- package/build/assets/{use-agent-settings-schema-BbtOsR7P.js → use-agent-settings-schema-Bvp5UzV8.js} +1 -1
- package/build/assets/{use-agent-state-DN9Nc5pP.js → use-agent-state-DE5dlEXJ.js} +1 -1
- package/build/assets/{use-cloud-current-user-id-B_rMUiu8.js → use-cloud-current-user-id-DWVar4st.js} +1 -1
- package/build/assets/{use-config-Bcz2JL2t.js → use-config-BSu_53GL.js} +1 -1
- package/build/assets/{use-conversation-id-BOaaZahn.js → use-conversation-id-DajhCn2A.js} +1 -1
- package/build/assets/{use-create-conversation-BWFA_FId.js → use-create-conversation-DW7AGgLA.js} +1 -1
- package/build/assets/{use-handle-plan-click-CgrCGmT1.js → use-handle-plan-click-DpgEQDAV.js} +1 -1
- package/build/assets/use-is-authed-hXC8vxgT.js +1 -0
- package/build/assets/{use-is-creating-conversation-DhoM7UAB.js → use-is-creating-conversation-DhDeeWfA.js} +1 -1
- package/build/assets/{use-launch-skill-in-chat-DOyQsXFO.js → use-launch-skill-in-chat-DVGPFrbI.js} +1 -1
- package/build/assets/{use-llm-profiles-CAIzHJDX.js → use-llm-profiles-D3-KXwQ0.js} +1 -1
- package/build/assets/use-runtime-is-ready-XFbT16BD.js +1 -0
- package/build/assets/{use-save-settings-5m3w89Ph.js → use-save-settings-CEEKSTWG.js} +1 -1
- package/build/assets/{use-settings-DzG0C3vO.js → use-settings-DQ7Oo1Hj.js} +1 -1
- package/build/assets/{use-settings-nav-items-BIsKeX52.js → use-settings-nav-items-YmrXrjn9.js} +2 -2
- package/build/assets/{use-skills-Cn-78xP1.js → use-skills-Xe0vjPMt.js} +1 -1
- package/build/assets/{use-unified-vscode-url-C5iI-Z5A.js → use-unified-vscode-url-BOsIOd-b.js} +1 -1
- package/build/assets/use-user-conversation-Mc0mQgkl.js +1 -0
- package/build/assets/{useMutation-CRJwk4cR.js → useMutation-B4OUESdw.js} +1 -1
- package/build/assets/{useTranslation-01pF7z10.js → useTranslation-CpIcQBq6.js} +1 -1
- package/build/assets/{utils-Czcl6buL.js → utils-D-HX7JCe.js} +1 -1
- package/build/assets/{vendor~conversation-panel~conversation-CbjvWBSu.js → vendor~conversation-panel~conversation-BlCIz9XQ.js} +1 -1
- package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-CofhIDpd.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-Ds9quNZ9.js} +1 -1
- package/build/assets/vendor~home~mcp~automations-list-C5PoHCy6.js +1 -0
- package/build/assets/{vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-BQPOygpY.js → vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-CGlZoBKa.js} +1 -1
- package/build/assets/{vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-CyYIBiBk.js → vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-DE11mPxp.js} +1 -1
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-CuGq_cxH.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-8b8V5bfO.js} +1 -1
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-CFpDeb9o.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-Dy7L6fMG.js} +1 -1
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~k776hupu-C1p8-pMr.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~k776hupu-D40EXhZx.js} +1 -1
- package/build/assets/vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~dp08i1qy-CHrEOFl6.js +48 -0
- package/build/assets/{vendor~root~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-s~kyz9p27j-DlKA6SoO.js → vendor~root~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-s~kyz9p27j-CyUbhpbm.js} +1 -1
- package/build/assets/{verification-settings-DbziMp4K.js → verification-settings-BtlTiHP8.js} +1 -1
- package/build/assets/{vscode-tab-BVhQR2rt.js → vscode-tab-C0ShhiSU.js} +1 -1
- package/build/assets/{waiting-for-runtime-message-JotSOBdC.js → waiting-for-runtime-message-DWPl_Yby.js} +1 -1
- package/build/assets/{x-mark-CZ57VvRX.js → x-mark-CWI0f9yI.js} +1 -1
- package/build/favicon.svg +1 -0
- package/build/index.html +4 -4
- package/build/locales/ar/openhands.json +8 -0
- package/build/locales/ca/openhands.json +8 -0
- package/build/locales/de/openhands.json +8 -0
- package/build/locales/en/openhands.json +8 -0
- package/build/locales/es/openhands.json +8 -0
- package/build/locales/fr/openhands.json +8 -0
- package/build/locales/it/openhands.json +8 -0
- package/build/locales/ja/openhands.json +8 -0
- package/build/locales/ko-KR/openhands.json +8 -0
- package/build/locales/no/openhands.json +8 -0
- package/build/locales/pt/openhands.json +8 -0
- package/build/locales/tr/openhands.json +8 -0
- package/build/locales/uk/openhands.json +8 -0
- package/build/locales/zh-CN/openhands.json +8 -0
- package/build/locales/zh-TW/openhands.json +8 -0
- package/config/defaults.json +1 -1
- package/dist/api/agent-server-config.cjs +1 -1
- package/dist/api/agent-server-config.cjs.map +1 -1
- package/dist/api/agent-server-config.d.ts +1 -1
- package/dist/api/agent-server-config.js +1 -1
- package/dist/api/agent-server-config.js.map +1 -1
- package/dist/api/conversation-service/agent-server-conversation-service.api.cjs +1 -1
- package/dist/api/conversation-service/agent-server-conversation-service.api.cjs.map +1 -1
- package/dist/api/conversation-service/agent-server-conversation-service.api.d.ts +12 -0
- package/dist/api/conversation-service/agent-server-conversation-service.api.js +4 -0
- package/dist/api/conversation-service/agent-server-conversation-service.api.js.map +1 -1
- package/dist/api/mcp-service/mcp-service.api.cjs +2 -0
- package/dist/api/mcp-service/mcp-service.api.cjs.map +1 -0
- package/dist/api/mcp-service/mcp-service.api.d.ts +6 -0
- package/dist/api/mcp-service/mcp-service.api.js +36 -0
- package/dist/api/mcp-service/mcp-service.api.js.map +1 -0
- package/dist/api/settings-service/settings-service.api.cjs +1 -1
- package/dist/api/settings-service/settings-service.api.cjs.map +1 -1
- package/dist/api/settings-service/settings-service.api.d.ts +1 -0
- package/dist/api/settings-service/settings-service.api.js +59 -41
- package/dist/api/settings-service/settings-service.api.js.map +1 -1
- package/dist/components/features/automations/detail/activity-log-item.d.ts +1 -1
- package/dist/components/features/automations/recommended-automations-launcher.d.ts +1 -1
- package/dist/components/features/backends/backend-selector.cjs +1 -1
- package/dist/components/features/backends/backend-selector.cjs.map +1 -1
- package/dist/components/features/backends/backend-selector.js +95 -95
- package/dist/components/features/backends/backend-selector.js.map +1 -1
- package/dist/components/features/chat/change-agent-button.cjs +1 -1
- package/dist/components/features/chat/change-agent-button.cjs.map +1 -1
- package/dist/components/features/chat/change-agent-button.js +65 -59
- package/dist/components/features/chat/change-agent-button.js.map +1 -1
- package/dist/components/features/chat/chat-interface.cjs +2 -2
- package/dist/components/features/chat/chat-interface.cjs.map +1 -1
- package/dist/components/features/chat/chat-interface.js +15 -14
- package/dist/components/features/chat/chat-interface.js.map +1 -1
- package/dist/components/features/chat/components/chat-input-actions.cjs +1 -1
- package/dist/components/features/chat/components/chat-input-actions.cjs.map +1 -1
- package/dist/components/features/chat/components/chat-input-actions.js +115 -137
- package/dist/components/features/chat/components/chat-input-actions.js.map +1 -1
- package/dist/components/features/chat/components/chat-input-model.cjs +1 -1
- package/dist/components/features/chat/components/chat-input-model.cjs.map +1 -1
- package/dist/components/features/chat/components/chat-input-model.d.ts +10 -0
- package/dist/components/features/chat/components/chat-input-model.js +95 -60
- package/dist/components/features/chat/components/chat-input-model.js.map +1 -1
- package/dist/components/features/chat/components/slash-command-menu.cjs +1 -1
- package/dist/components/features/chat/components/slash-command-menu.cjs.map +1 -1
- package/dist/components/features/chat/components/slash-command-menu.js +1 -1
- package/dist/components/features/chat/components/slash-command-menu.js.map +1 -1
- package/dist/components/features/chat/git-control-bar.cjs +1 -1
- package/dist/components/features/chat/git-control-bar.cjs.map +1 -1
- package/dist/components/features/chat/git-control-bar.js +60 -59
- package/dist/components/features/chat/git-control-bar.js.map +1 -1
- package/dist/components/features/conversation/conversation-name-with-status.cjs +1 -1
- package/dist/components/features/conversation/conversation-name-with-status.cjs.map +1 -1
- package/dist/components/features/conversation/conversation-name-with-status.js +2 -2
- package/dist/components/features/conversation/conversation-name-with-status.js.map +1 -1
- package/dist/components/features/conversation/conversation-name.cjs +1 -1
- package/dist/components/features/conversation/conversation-name.cjs.map +1 -1
- package/dist/components/features/conversation/conversation-name.js +3 -3
- package/dist/components/features/conversation/conversation-name.js.map +1 -1
- package/dist/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.cjs +1 -1
- package/dist/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.cjs.map +1 -1
- package/dist/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.js +1 -1
- package/dist/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.js.map +1 -1
- package/dist/components/features/conversation/conversation-tabs/conversation-tabs.cjs +1 -1
- package/dist/components/features/conversation/conversation-tabs/conversation-tabs.cjs.map +1 -1
- package/dist/components/features/conversation/conversation-tabs/conversation-tabs.js +16 -16
- package/dist/components/features/conversation/conversation-tabs/conversation-tabs.js.map +1 -1
- package/dist/components/features/mcp-logo-badge.cjs +1 -1
- package/dist/components/features/mcp-logo-badge.cjs.map +1 -1
- package/dist/components/features/mcp-logo-badge.d.ts +2 -2
- package/dist/components/features/mcp-logo-badge.js +1 -1
- package/dist/components/features/mcp-logo-badge.js.map +1 -1
- package/dist/components/features/mcp-page/custom-server-editor.cjs +1 -1
- package/dist/components/features/mcp-page/custom-server-editor.cjs.map +1 -1
- package/dist/components/features/mcp-page/custom-server-editor.js +64 -41
- package/dist/components/features/mcp-page/custom-server-editor.js.map +1 -1
- package/dist/components/features/mcp-page/install-server-modal.cjs +1 -1
- package/dist/components/features/mcp-page/install-server-modal.cjs.map +1 -1
- package/dist/components/features/mcp-page/install-server-modal.d.ts +1 -1
- package/dist/components/features/mcp-page/install-server-modal.js +126 -102
- package/dist/components/features/mcp-page/install-server-modal.js.map +1 -1
- package/dist/components/features/mcp-page/installed-server-card.cjs +1 -1
- package/dist/components/features/mcp-page/installed-server-card.cjs.map +1 -1
- package/dist/components/features/mcp-page/installed-server-card.js +1 -1
- package/dist/components/features/mcp-page/installed-server-card.js.map +1 -1
- package/dist/components/features/mcp-page/marketplace-card.cjs +1 -1
- package/dist/components/features/mcp-page/marketplace-card.cjs.map +1 -1
- package/dist/components/features/mcp-page/marketplace-card.d.ts +1 -1
- package/dist/components/features/mcp-page/marketplace-card.js +27 -25
- package/dist/components/features/mcp-page/marketplace-card.js.map +1 -1
- package/dist/components/features/mcp-page/marketplace-section.cjs +1 -1
- package/dist/components/features/mcp-page/marketplace-section.cjs.map +1 -1
- package/dist/components/features/mcp-page/marketplace-section.d.ts +1 -1
- package/dist/components/features/mcp-page/marketplace-section.js +1 -1
- package/dist/components/features/mcp-page/marketplace-section.js.map +1 -1
- package/dist/components/features/mcp-page/mcp-logo-stack-badge.d.ts +2 -2
- package/dist/components/features/settings/mcp-settings/mcp-server-form.cjs +7 -7
- package/dist/components/features/settings/mcp-settings/mcp-server-form.cjs.map +1 -1
- package/dist/components/features/settings/mcp-settings/mcp-server-form.d.ts +8 -12
- package/dist/components/features/settings/mcp-settings/mcp-server-form.js +114 -87
- package/dist/components/features/settings/mcp-settings/mcp-server-form.js.map +1 -1
- package/dist/components/features/sidebar/sidebar-rail-body.cjs +1 -1
- package/dist/components/features/sidebar/sidebar-rail-body.cjs.map +1 -1
- package/dist/components/features/sidebar/sidebar-rail-body.d.ts +1 -2
- package/dist/components/features/sidebar/sidebar-rail-body.js +104 -104
- package/dist/components/features/sidebar/sidebar-rail-body.js.map +1 -1
- package/dist/components/features/sidebar/sidebar.cjs +1 -1
- package/dist/components/features/sidebar/sidebar.cjs.map +1 -1
- package/dist/components/features/sidebar/sidebar.js +82 -83
- package/dist/components/features/sidebar/sidebar.js.map +1 -1
- package/dist/context/scroll-context.cjs +1 -1
- package/dist/context/scroll-context.cjs.map +1 -1
- package/dist/context/scroll-context.d.ts +1 -0
- package/dist/context/scroll-context.js +4 -1
- package/dist/context/scroll-context.js.map +1 -1
- package/dist/contexts/conversation-websocket-context.cjs +3 -3
- package/dist/contexts/conversation-websocket-context.cjs.map +1 -1
- package/dist/contexts/conversation-websocket-context.js +36 -36
- package/dist/contexts/conversation-websocket-context.js.map +1 -1
- package/dist/favicon.svg +1 -0
- package/dist/hooks/mutation/use-switch-acp-model.cjs +2 -0
- package/dist/hooks/mutation/use-switch-acp-model.cjs.map +1 -0
- package/dist/hooks/mutation/use-switch-acp-model.d.ts +23 -0
- package/dist/hooks/mutation/use-switch-acp-model.js +26 -0
- package/dist/hooks/mutation/use-switch-acp-model.js.map +1 -0
- package/dist/hooks/mutation/use-test-mcp-server.cjs +2 -0
- package/dist/hooks/mutation/use-test-mcp-server.cjs.map +1 -0
- package/dist/hooks/mutation/use-test-mcp-server.d.ts +2 -0
- package/dist/hooks/mutation/use-test-mcp-server.js +10 -0
- package/dist/hooks/mutation/use-test-mcp-server.js.map +1 -0
- package/dist/hooks/query/use-automation-detail.d.ts +3 -2
- package/dist/hooks/query/use-local-git-info.cjs +3 -1
- package/dist/hooks/query/use-local-git-info.cjs.map +1 -1
- package/dist/hooks/query/use-local-git-info.d.ts +2 -2
- package/dist/hooks/query/use-local-git-info.js +27 -24
- package/dist/hooks/query/use-local-git-info.js.map +1 -1
- package/dist/hooks/use-acp-model-context.cjs.map +1 -1
- package/dist/hooks/use-acp-model-context.d.ts +3 -4
- package/dist/hooks/use-acp-model-context.js.map +1 -1
- package/dist/hooks/use-chat-input-model-state.cjs +2 -0
- package/dist/hooks/use-chat-input-model-state.cjs.map +1 -0
- package/dist/hooks/use-chat-input-model-state.d.ts +12 -0
- package/dist/hooks/use-chat-input-model-state.js +29 -0
- package/dist/hooks/use-chat-input-model-state.js.map +1 -0
- package/dist/i18n/declaration.cjs +1 -1
- package/dist/i18n/declaration.cjs.map +1 -1
- package/dist/i18n/declaration.d.ts +8 -0
- package/dist/i18n/declaration.js +1 -1
- package/dist/i18n/declaration.js.map +1 -1
- package/dist/i18n/translation.cjs +2 -2
- package/dist/i18n/translation.cjs.map +1 -1
- package/dist/i18n/translation.js +136 -0
- package/dist/i18n/translation.js.map +1 -1
- package/dist/locales/ar/openhands.json +8 -0
- package/dist/locales/ca/openhands.json +8 -0
- package/dist/locales/de/openhands.json +8 -0
- package/dist/locales/en/openhands.json +8 -0
- package/dist/locales/es/openhands.json +8 -0
- package/dist/locales/fr/openhands.json +8 -0
- package/dist/locales/it/openhands.json +8 -0
- package/dist/locales/ja/openhands.json +8 -0
- package/dist/locales/ko-KR/openhands.json +8 -0
- package/dist/locales/no/openhands.json +8 -0
- package/dist/locales/pt/openhands.json +8 -0
- package/dist/locales/tr/openhands.json +8 -0
- package/dist/locales/uk/openhands.json +8 -0
- package/dist/locales/zh-CN/openhands.json +8 -0
- package/dist/locales/zh-TW/openhands.json +8 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/airtable.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/airtable.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/airtable.js +37 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/airtable.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/apify.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/apify.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/apify.js +36 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/apify.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/atlassian.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/atlassian.js +15 -5
- package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/brave-search.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/brave-search.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/brave-search.js +36 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/brave-search.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/browser-mcp.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/browser-mcp.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/browser-mcp.js +31 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/browser-mcp.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/clickhouse.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/clickhouse.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/clickhouse.js +52 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/clickhouse.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-bindings.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-bindings.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-bindings.js +15 -5
- package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-bindings.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-browser-rendering.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-browser-rendering.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-browser-rendering.js +15 -5
- package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-browser-rendering.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-builds.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-builds.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-builds.js +15 -5
- package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-builds.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-docs.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-docs.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-docs.js +15 -5
- package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-docs.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-observability.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-observability.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-observability.js +15 -5
- package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-observability.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/deepwiki.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/deepwiki.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/deepwiki.js +15 -5
- package/dist/node_modules/@openhands/extensions/integrations/catalog/deepwiki.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/elevenlabs.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/elevenlabs.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/elevenlabs.js +36 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/elevenlabs.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/everything.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/everything.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/everything.js +13 -6
- package/dist/node_modules/@openhands/extensions/integrations/catalog/everything.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/exa.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/exa.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/exa.js +36 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/exa.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/fetch.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/fetch.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/fetch.js +13 -6
- package/dist/node_modules/@openhands/extensions/integrations/catalog/fetch.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/figma.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/figma.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/figma.js +40 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/figma.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/filesystem.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/filesystem.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/filesystem.js +39 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/filesystem.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/firecrawl.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/firecrawl.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/firecrawl.js +36 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/firecrawl.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/git.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/git.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/git.js +40 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/git.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/github.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/github.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/github.js +47 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/github.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/huggingface.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/huggingface.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/huggingface.js +15 -5
- package/dist/node_modules/@openhands/extensions/integrations/catalog/huggingface.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/kagi.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/kagi.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/kagi.js +36 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/kagi.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/linear.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/linear.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/linear.js +15 -5
- package/dist/node_modules/@openhands/extensions/integrations/catalog/linear.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/memory.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/memory.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/memory.js +13 -6
- package/dist/node_modules/@openhands/extensions/integrations/catalog/memory.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/mongodb.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/mongodb.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/mongodb.js +36 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/mongodb.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/neon.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/neon.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/neon.js +40 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/neon.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.js +39 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/obsidian.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/obsidian.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/obsidian.js +38 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/obsidian.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/paypal.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/paypal.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/paypal.js +15 -5
- package/dist/node_modules/@openhands/extensions/integrations/catalog/paypal.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/playwright.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/playwright.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/playwright.js +13 -6
- package/dist/node_modules/@openhands/extensions/integrations/catalog/playwright.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/redis.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/redis.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/redis.js +43 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/redis.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/resend.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/resend.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/resend.js +41 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/resend.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/sentry.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/sentry.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/sentry.js +15 -5
- package/dist/node_modules/@openhands/extensions/integrations/catalog/sentry.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/sequential-thinking.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/sequential-thinking.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/sequential-thinking.js +13 -6
- package/dist/node_modules/@openhands/extensions/integrations/catalog/sequential-thinking.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.js +45 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/stripe.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/stripe.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/stripe.js +15 -5
- package/dist/node_modules/@openhands/extensions/integrations/catalog/stripe.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/supabase.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/supabase.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/supabase.js +37 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/supabase.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/tavily.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/tavily.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/tavily.js +39 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/tavily.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/time.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/time.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/time.js +13 -6
- package/dist/node_modules/@openhands/extensions/integrations/catalog/time.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/index.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/index.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/index.js +175 -0
- package/dist/node_modules/@openhands/extensions/integrations/index.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/logos.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/logos.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/{mcps → integrations}/logos.js +2 -2
- package/dist/node_modules/@openhands/extensions/integrations/logos.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-catalog.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-catalog.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-catalog.js +548 -0
- package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-catalog.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-registration-defaults.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-registration-defaults.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-registration-defaults.js +482 -0
- package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-registration-defaults.js.map +1 -0
- package/dist/node_modules/@openhands/typescript-client/dist/client/conversation-client.cjs +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/conversation-client.cjs.map +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/conversation-client.js +3 -0
- package/dist/node_modules/@openhands/typescript-client/dist/client/conversation-client.js.map +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/mcp-client.cjs +2 -0
- package/dist/node_modules/@openhands/typescript-client/dist/client/mcp-client.cjs.map +1 -0
- package/dist/node_modules/@openhands/typescript-client/dist/client/mcp-client.js +22 -0
- package/dist/node_modules/@openhands/typescript-client/dist/client/mcp-client.js.map +1 -0
- package/dist/node_modules/@openhands/typescript-client/dist/index.cjs +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/index.js +1 -0
- package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.cjs +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.cjs.map +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.js +3 -0
- package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.js.map +1 -1
- package/dist/package.cjs +1 -1
- package/dist/package.cjs.map +1 -1
- package/dist/package.js +6 -4
- package/dist/package.js.map +1 -1
- package/dist/routes/mcp.cjs +1 -1
- package/dist/routes/mcp.cjs.map +1 -1
- package/dist/routes/mcp.js +1 -1
- package/dist/routes/mcp.js.map +1 -1
- package/dist/stores/error-message-store.cjs +1 -1
- package/dist/stores/error-message-store.cjs.map +1 -1
- package/dist/stores/error-message-store.d.ts +10 -1
- package/dist/stores/error-message-store.js +16 -3
- package/dist/stores/error-message-store.js.map +1 -1
- package/dist/utils/mcp-marketplace-utils.cjs +1 -1
- package/dist/utils/mcp-marketplace-utils.cjs.map +1 -1
- package/dist/utils/mcp-marketplace-utils.d.ts +21 -1
- package/dist/utils/mcp-marketplace-utils.js +23 -13
- package/dist/utils/mcp-marketplace-utils.js.map +1 -1
- package/dist/utils/settings-utils.cjs.map +1 -1
- package/dist/utils/settings-utils.js.map +1 -1
- package/package.json +6 -4
- package/scripts/check-sdk-version-sync.mjs +6 -6
- package/scripts/dev-safe.mjs +25 -7
- package/scripts/dev-static.mjs +6 -0
- package/scripts/dev-with-automation.mjs +12 -1
- package/scripts/static-server.mjs +85 -4
- package/tools/canvas_ui_tool.py +129 -0
- package/build/assets/add-backend-modal-CqjNjGqY.js +0 -1
- package/build/assets/automation-detail-CQrtk33s.js +0 -1
- package/build/assets/automations-list-COmogz0S.js +0 -1
- package/build/assets/conversation-CeGMBOyB.js +0 -1
- package/build/assets/conversation-D8scXOe7.js +0 -17
- package/build/assets/conversation-panel-DMz46ji-.js +0 -1
- package/build/assets/conversation-websocket-context-B0Gd3yiT.js +0 -3
- package/build/assets/declaration-C9nuq2Dj.js +0 -1
- package/build/assets/edit-automation-modal-DnTHJrf1.js +0 -1
- package/build/assets/git-control-bar-branch-button-DhpPgadK.js +0 -27
- package/build/assets/install-server-modal-VB5hOBpW.js +0 -1
- package/build/assets/llm-settings-CIdxmimN.js +0 -1
- package/build/assets/manifest-6400820c.js +0 -1
- package/build/assets/mcp-BdfyCW1l.js +0 -9
- package/build/assets/messages-BfaEAG2q.js +0 -36
- package/build/assets/recommended-automations-launcher-Cx7svuGE.js +0 -52
- package/build/assets/root-6AdVEJBT.js +0 -2
- package/build/assets/root-DEotKI6b.css +0 -1
- package/build/assets/root-layout-DvYGxAnr.js +0 -2
- package/build/assets/settings-service.api-Z6x0l0GU.js +0 -1
- package/build/assets/use-is-authed-BFoh8Ogh.js +0 -1
- package/build/assets/use-runtime-is-ready-BQWLEyqa.js +0 -1
- package/build/assets/use-user-conversation-BCYpbPT1.js +0 -1
- package/build/assets/vendor~home~mcp~automations-list-DRfWZRnF.js +0 -1
- package/build/assets/vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~dp08i1qy-BJm2mGIp.js +0 -48
- package/dist/node_modules/@openhands/extensions/mcps/catalog/airtable.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/airtable.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/airtable.js +0 -30
- package/dist/node_modules/@openhands/extensions/mcps/catalog/airtable.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/apify.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/apify.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/apify.js +0 -29
- package/dist/node_modules/@openhands/extensions/mcps/catalog/apify.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/atlassian.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/atlassian.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/brave-search.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/brave-search.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/brave-search.js +0 -29
- package/dist/node_modules/@openhands/extensions/mcps/catalog/brave-search.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/browser-mcp.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/browser-mcp.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/browser-mcp.js +0 -24
- package/dist/node_modules/@openhands/extensions/mcps/catalog/browser-mcp.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/clickhouse.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/clickhouse.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/clickhouse.js +0 -45
- package/dist/node_modules/@openhands/extensions/mcps/catalog/clickhouse.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-bindings.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-bindings.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-browser-rendering.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-browser-rendering.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-browser-rendering.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-builds.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-builds.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-docs.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-docs.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-observability.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-observability.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-observability.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/deepwiki.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/deepwiki.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/elevenlabs.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/elevenlabs.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/elevenlabs.js +0 -29
- package/dist/node_modules/@openhands/extensions/mcps/catalog/elevenlabs.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/everything.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/everything.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/exa.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/exa.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/exa.js +0 -29
- package/dist/node_modules/@openhands/extensions/mcps/catalog/exa.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/fetch.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/fetch.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/figma.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/figma.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/figma.js +0 -33
- package/dist/node_modules/@openhands/extensions/mcps/catalog/figma.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/filesystem.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/filesystem.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/filesystem.js +0 -32
- package/dist/node_modules/@openhands/extensions/mcps/catalog/filesystem.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/firecrawl.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/firecrawl.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/firecrawl.js +0 -29
- package/dist/node_modules/@openhands/extensions/mcps/catalog/firecrawl.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/git.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/git.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/git.js +0 -33
- package/dist/node_modules/@openhands/extensions/mcps/catalog/git.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/github.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/github.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/github.js +0 -40
- package/dist/node_modules/@openhands/extensions/mcps/catalog/github.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/huggingface.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/huggingface.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/kagi.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/kagi.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/kagi.js +0 -29
- package/dist/node_modules/@openhands/extensions/mcps/catalog/kagi.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/linear.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/linear.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/memory.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/memory.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/memory.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/mongodb.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/mongodb.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/mongodb.js +0 -29
- package/dist/node_modules/@openhands/extensions/mcps/catalog/mongodb.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/neon.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/neon.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/neon.js +0 -33
- package/dist/node_modules/@openhands/extensions/mcps/catalog/neon.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/notion.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/notion.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/notion.js +0 -32
- package/dist/node_modules/@openhands/extensions/mcps/catalog/notion.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/obsidian.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/obsidian.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/obsidian.js +0 -31
- package/dist/node_modules/@openhands/extensions/mcps/catalog/obsidian.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/paypal.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/paypal.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/paypal.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/playwright.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/playwright.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/playwright.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/redis.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/redis.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/redis.js +0 -36
- package/dist/node_modules/@openhands/extensions/mcps/catalog/redis.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/resend.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/resend.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/resend.js +0 -34
- package/dist/node_modules/@openhands/extensions/mcps/catalog/resend.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/sentry.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/sentry.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/sentry.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/sequential-thinking.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/sequential-thinking.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/sequential-thinking.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/slack.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/slack.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/slack.js +0 -38
- package/dist/node_modules/@openhands/extensions/mcps/catalog/slack.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/stripe.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/stripe.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/stripe.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/supabase.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/supabase.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/supabase.js +0 -30
- package/dist/node_modules/@openhands/extensions/mcps/catalog/supabase.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/tavily.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/tavily.js +0 -32
- package/dist/node_modules/@openhands/extensions/mcps/catalog/tavily.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/time.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/catalog/time.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/catalog/time.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/index.cjs +0 -2
- package/dist/node_modules/@openhands/extensions/mcps/index.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/index.js +0 -87
- package/dist/node_modules/@openhands/extensions/mcps/index.js.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/logos.cjs.map +0 -1
- package/dist/node_modules/@openhands/extensions/mcps/logos.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-service.api.js","names":[],"sources":["../../../src/api/settings-service/settings-service.api.ts"],"sourcesContent":["import { SettingsClient } from \"@openhands/typescript-client/clients\";\nimport { DEFAULT_SETTINGS } from \"#/services/settings\";\nimport { Settings, SettingsSchema, SettingsValue } from \"#/types/settings\";\nimport {\n extractAppPreferences,\n readStoredAppPreferences,\n writeStoredAppPreferences,\n} from \"../app-preferences-store\";\nimport { getActiveBackend } from \"../backend-registry/active-store\";\nimport {\n fetchCloudConversationSettingsSchema,\n fetchCloudSettings,\n fetchCloudSettingsSchema,\n saveCloudSettings,\n} from \"../cloud/settings-service.api\";\nimport { getAgentServerClientOptions } from \"../agent-server-client-options\";\n\n/**\n * Response from GET /api/settings\n * Mirrors the SettingsResponse model in the agent server\n */\nexport interface SettingsApiResponse {\n agent_settings: Record<string, SettingsValue>;\n conversation_settings: Record<string, SettingsValue>;\n llm_api_key_is_set: boolean;\n}\n\n/**\n * Request payload for PATCH /api/settings\n */\nexport interface SettingsUpdateRequest {\n agent_settings_diff?: Record<string, SettingsValue>;\n conversation_settings_diff?: Record<string, SettingsValue>;\n disabled_skills?: string[];\n}\n\n/**\n * Secret exposure mode for X-Expose-Secrets header.\n *\n * - undefined: Returns redacted secrets (\"**********\")\n * - \"encrypted\": Returns cipher-encrypted values (safe for frontend to round-trip)\n * - \"plaintext\": Returns raw secret values (backend use only!)\n */\nexport type ExposeSecretsMode = \"encrypted\" | \"plaintext\" | undefined;\n\nconst deepClone = <T>(value: T): T => JSON.parse(JSON.stringify(value)) as T;\n\nconst mergeRecords = (\n base: Record<string, SettingsValue> | null | undefined,\n next: Record<string, SettingsValue> | null | undefined,\n) => ({ ...(base ?? {}), ...(next ?? {}) });\n\n/**\n * Retry helper for API calls with exponential backoff.\n */\nasync function withRetry<T>(\n fn: () => Promise<T>,\n maxRetries: number = 3,\n baseDelayMs: number = 500,\n): Promise<T> {\n for (let attempt = 0; attempt < maxRetries; attempt += 1) {\n try {\n return await fn();\n } catch (error) {\n if (attempt >= maxRetries - 1) {\n throw error;\n }\n\n const delay = baseDelayMs * 2 ** attempt;\n\n await new Promise<void>((resolve) => {\n setTimeout(resolve, delay);\n });\n }\n }\n\n throw new Error(\"Retry attempts exhausted\");\n}\n\n/**\n * In-memory cache for settings to avoid repeated network calls.\n * The cache is invalidated on save operations.\n */\nlet settingsCache: {\n /** Settings with redacted secrets for display */\n redacted: SettingsApiResponse | null;\n /** Settings with encrypted secrets for conversation start */\n encrypted: SettingsApiResponse | null;\n /** Timestamp when the cache was last populated */\n timestamp: number;\n} = {\n redacted: null,\n encrypted: null,\n timestamp: 0,\n};\n\nconst CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes\n\nconst isCacheValid = () => Date.now() - settingsCache.timestamp < CACHE_TTL_MS;\n\nconst clearCache = () => {\n settingsCache = { redacted: null, encrypted: null, timestamp: 0 };\n};\n\n/**\n * Transform API response into Settings object with derived fields.\n */\nconst transformApiResponse = (\n response: SettingsApiResponse,\n): Partial<Settings> => {\n const agentSettings = response.agent_settings ?? {};\n const conversationSettings = response.conversation_settings ?? {};\n\n return {\n agent_settings: agentSettings,\n conversation_settings: conversationSettings,\n llm_api_key_set: response.llm_api_key_is_set,\n };\n};\n\n/**\n * Sync derived settings fields from agent_settings and conversation_settings.\n * This ensures backward compatibility with code that reads top-level fields.\n */\nconst syncDerivedSettings = (settings: Partial<Settings>): Settings => {\n const agentSettings = mergeRecords(\n DEFAULT_SETTINGS.agent_settings ?? {},\n settings.agent_settings ?? {},\n );\n const conversationSettings = mergeRecords(\n DEFAULT_SETTINGS.conversation_settings ?? {},\n settings.conversation_settings ?? {},\n );\n\n // App-level user preferences (language, git identity, sound notifications,\n // analytics consent) live in localStorage in local mode. In cloud mode the\n // server response carries them and overrides the local cache.\n const storedAppPrefs = readStoredAppPreferences();\n\n const merged = {\n ...deepClone(DEFAULT_SETTINGS),\n ...storedAppPrefs,\n ...settings,\n provider_tokens_set: {\n ...(DEFAULT_SETTINGS.provider_tokens_set ?? {}),\n ...(settings.provider_tokens_set ?? {}),\n },\n agent_settings: agentSettings,\n conversation_settings: conversationSettings,\n } as Settings;\n\n const llm = agentSettings.llm as Record<string, SettingsValue> | undefined;\n const condenser = agentSettings.condenser as\n | Record<string, SettingsValue>\n | undefined;\n\n if (typeof agentSettings.agent === \"string\") {\n merged.agent = agentSettings.agent;\n }\n if (typeof llm?.model === \"string\" && llm.model.length > 0) {\n merged.llm_model = llm.model;\n }\n if (typeof llm?.base_url === \"string\") {\n merged.llm_base_url = llm.base_url;\n }\n // Note: api_key may be redacted (\"**********\") when fetched without expose header\n // We don't sync it to top-level llm_api_key to avoid overwriting with redacted value\n if (typeof condenser?.enabled === \"boolean\") {\n merged.enable_default_condenser = condenser.enabled;\n }\n if (typeof condenser?.max_size === \"number\") {\n merged.condenser_max_size = condenser.max_size;\n }\n if (agentSettings.mcp_config) {\n merged.mcp_config = agentSettings.mcp_config as Settings[\"mcp_config\"];\n }\n\n if (typeof conversationSettings.confirmation_mode === \"boolean\") {\n merged.confirmation_mode = conversationSettings.confirmation_mode;\n }\n if (\n typeof conversationSettings.security_analyzer === \"string\" ||\n conversationSettings.security_analyzer === null\n ) {\n merged.security_analyzer = conversationSettings.security_analyzer as\n | string\n | null;\n }\n if (typeof conversationSettings.max_iterations === \"number\") {\n merged.max_iterations = conversationSettings.max_iterations;\n }\n\n merged.search_api_key_set = !!merged.search_api_key;\n\n return merged;\n};\n\nclass SettingsService {\n /**\n * Fetch settings from the agent server API with retry logic.\n *\n * @param exposeSecrets - Controls how secrets are returned:\n * - undefined: Secrets are redacted (\"**********\") - safe for display\n * - \"encrypted\": Secrets are cipher-encrypted - safe for round-trip to start conversation\n * - \"plaintext\": Raw secrets - DO NOT USE from frontend\n */\n static async fetchSettingsFromApi(\n exposeSecrets?: ExposeSecretsMode,\n ): Promise<SettingsApiResponse> {\n return withRetry(() =>\n new SettingsClient(getAgentServerClientOptions()).getSettings({\n exposeSecrets,\n }),\n ) as Promise<SettingsApiResponse>;\n }\n\n /**\n * Get settings for display (secrets are redacted).\n * Uses in-memory cache for performance.\n */\n static async getSettings(): Promise<Settings> {\n // Cloud uses a different settings shape (flat top-level fields\n // including provider_tokens_set, llm_model, etc.). Branch out before\n // touching the local-only cache: cloud responses bypass the local\n // SettingsApiResponse shape and feed straight into syncDerivedSettings\n // so cloud-native fields like provider_tokens_set reach the GUI's\n // useUserProviders → useAppInstallations → useGitRepositories chain.\n if (getActiveBackend().backend.kind === \"cloud\") {\n try {\n const cloud = await withRetry(() => fetchCloudSettings());\n return syncDerivedSettings(cloud);\n } catch (error) {\n console.warn(\"Failed to fetch cloud settings, using defaults:\", error);\n return syncDerivedSettings({});\n }\n }\n\n // Check cache first\n if (isCacheValid() && settingsCache.redacted) {\n return syncDerivedSettings(transformApiResponse(settingsCache.redacted));\n }\n\n try {\n const response = await this.fetchSettingsFromApi();\n settingsCache.redacted = response;\n settingsCache.timestamp = Date.now();\n return syncDerivedSettings(transformApiResponse(response));\n } catch (error) {\n // If API fails, return defaults\n console.warn(\"Failed to fetch settings from API, using defaults:\", error);\n return syncDerivedSettings({});\n }\n }\n\n /**\n * Get settings with encrypted secrets for starting conversations.\n * The encrypted secrets can be passed to the start conversation API\n * with secrets_encrypted=true for server-side decryption.\n *\n * @throws Error if encrypted settings cannot be fetched - conversations\n * should not start with broken/redacted credentials.\n */\n static async getSettingsForConversation(): Promise<{\n agentSettings: Record<string, SettingsValue>;\n conversationSettings: Record<string, SettingsValue>;\n secretsEncrypted: boolean;\n }> {\n // Check cache first\n if (isCacheValid() && settingsCache.encrypted) {\n return {\n agentSettings: settingsCache.encrypted.agent_settings,\n conversationSettings: settingsCache.encrypted.conversation_settings,\n secretsEncrypted: true,\n };\n }\n\n // Fetch encrypted settings - this MUST succeed for conversations to work.\n // Do not fall back to redacted settings as that would cause auth failures.\n const response = await this.fetchSettingsFromApi(\"encrypted\");\n settingsCache.encrypted = response;\n if (!settingsCache.timestamp) {\n settingsCache.timestamp = Date.now();\n }\n return {\n agentSettings: response.agent_settings,\n conversationSettings: response.conversation_settings,\n secretsEncrypted: true,\n };\n }\n\n static async getSettingsSchema(): Promise<SettingsSchema> {\n if (getActiveBackend().backend.kind === \"cloud\") {\n return (await fetchCloudSettingsSchema()) as SettingsSchema;\n }\n return (await new SettingsClient(\n getAgentServerClientOptions(),\n ).getAgentSchema()) as SettingsSchema;\n }\n\n static async getConversationSettingsSchema(): Promise<SettingsSchema> {\n if (getActiveBackend().backend.kind === \"cloud\") {\n return (await fetchCloudConversationSettingsSchema()) as SettingsSchema;\n }\n return (await new SettingsClient(\n getAgentServerClientOptions(),\n ).getConversationSchema()) as SettingsSchema;\n }\n\n /**\n * Save settings to the agent server API.\n * Uses PATCH for incremental updates.\n */\n static async saveSettings(\n settings: Partial<Settings> & Record<string, unknown>,\n ): Promise<boolean> {\n // Split app-level user-preference fields (language, git identity, sound\n // notifications, analytics consent) off before building the diff payload.\n // The local agent-server's PATCH /api/settings has no schema for these\n // and Pydantic would drop them silently; persist them in localStorage\n // instead, and forward them as flat top-level keys to the cloud POST.\n const { extracted: appPreferences, rest } = extractAppPreferences(\n settings as Record<string, unknown>,\n );\n const hasAppPreferences = Object.keys(appPreferences).length > 0;\n if (hasAppPreferences) {\n writeStoredAppPreferences(appPreferences);\n }\n\n const payload: SettingsUpdateRequest = {};\n\n // Extract agent_settings_diff\n const agentSettingsDiff = rest.agent_settings_diff as\n | Record<string, SettingsValue>\n | undefined;\n if (agentSettingsDiff && Object.keys(agentSettingsDiff).length > 0) {\n payload.agent_settings_diff = agentSettingsDiff;\n }\n\n // Extract conversation_settings_diff\n const conversationSettingsDiff = rest.conversation_settings_diff as\n | Record<string, SettingsValue>\n | undefined;\n if (\n conversationSettingsDiff &&\n Object.keys(conversationSettingsDiff).length > 0\n ) {\n payload.conversation_settings_diff = conversationSettingsDiff;\n }\n\n // Extract disabled_skills (cloud-only — local agent-server has no skills concept)\n const disabledSkills = rest.disabled_skills as string[] | undefined;\n if (Array.isArray(disabledSkills)) {\n payload.disabled_skills = disabledSkills;\n }\n\n const isCloud = getActiveBackend().backend.kind === \"cloud\";\n\n // The backend applies ``agent_settings_diff`` by deep-merging it into the\n // existing ``agent_settings`` dict (see SDK\n // ``openhands.agent_server.persistence.models._deep_merge``). That works\n // for scalar fields but is wrong for ``mcp_config.mcpServers``, which is\n // a name-keyed map: a diff that omits a server cannot remove it (stale\n // key stays), and a diff whose key indices shift (e.g. after deleting\n // index 0, the second server is renumbered) leaves the original keys\n // behind as duplicates pointing to the wrong server config.\n //\n // The only way to make ``mcp_config`` behave like a replace through this\n // API is to first null it out — ``null`` is not a dict, so deep-merge\n // takes the else branch and sets the field to ``None`` outright — and\n // then send the new value in a follow-up call. We do this for every\n // ``mcp_config`` write, including adds (the wasted round-trip is\n // negligible for this user action and avoids divergent code paths).\n const agentDiff = payload.agent_settings_diff;\n // Send a pre-clear PATCH when the diff sets ``mcp_config`` to a non-null\n // value. A second PATCH below then writes the new value. Skipping the\n // pre-clear when the caller is already clearing (``mcp_config: null``)\n // avoids a pointless duplicate request.\n const needsMcpPreClear =\n !!agentDiff && \"mcp_config\" in agentDiff && agentDiff.mcp_config !== null;\n\n // The pre-clear is destructive: if the follow-up write fails after the\n // clear succeeds, the user's MCP config is left empty. Snapshot the\n // previous value (in raw SDK shape, NOT the GUI's parsed MCPConfig)\n // before pre-clearing so we can attempt a best-effort rollback. The\n // original write error is always re-thrown to the caller regardless\n // of rollback success — the GUI's react-query mutations surface that\n // as an error toast so the user knows to retry.\n //\n // Snapshot must be the SDK shape (``{ mcpServers: { name: cfg }}``)\n // because that is what the backend expects on the rollback PATCH.\n // ``SettingsService.getSettings`` returns a GUI Settings object whose\n // ``mcp_config`` is typed as the parsed frontend MCPConfig and\n // defaults to empty arrays when nothing is installed, so it is not\n // suitable for round-tripping back to the backend.\n let mcpConfigSnapshot: unknown = undefined;\n if (needsMcpPreClear) {\n try {\n if (isCloud) {\n const raw = (await fetchCloudSettings()) as {\n agent_settings?: { mcp_config?: unknown };\n };\n mcpConfigSnapshot = raw?.agent_settings?.mcp_config;\n } else {\n const raw = (await SettingsService.fetchSettingsFromApi()) as {\n agent_settings?: { mcp_config?: unknown };\n };\n mcpConfigSnapshot = raw?.agent_settings?.mcp_config;\n }\n } catch {\n // Snapshot failed (network blip, etc.). Continue without rollback\n // ability — the original write error will still surface.\n }\n }\n\n if (isCloud) {\n const hasCloudWork =\n !!payload.agent_settings_diff ||\n !!payload.conversation_settings_diff ||\n payload.disabled_skills !== undefined ||\n hasAppPreferences;\n if (!hasCloudWork) {\n return true;\n }\n if (needsMcpPreClear) {\n await withRetry(() =>\n saveCloudSettings({\n agent_settings_diff: { mcp_config: null },\n }),\n );\n }\n try {\n await withRetry(() =>\n saveCloudSettings({\n ...payload,\n ...(hasAppPreferences ? { app_preferences: appPreferences } : {}),\n }),\n );\n } catch (err) {\n if (needsMcpPreClear && mcpConfigSnapshot) {\n // Best-effort rollback. We deliberately do not wrap in withRetry:\n // the user's session is already in a degraded state and we want\n // to surface the original error promptly. Swallowing the restore\n // error preserves the original failure context for the caller.\n try {\n await saveCloudSettings({\n agent_settings_diff: {\n mcp_config: mcpConfigSnapshot as SettingsValue,\n },\n });\n } catch {\n // Rollback failed; the original error takes precedence.\n }\n }\n throw err;\n }\n } else {\n // The local agent-server PATCH /api/settings rejects unknown fields and\n // requires at least one of the two diff fields. Strip disabled_skills\n // and skip the request entirely if no diffs remain. App preferences\n // are persisted to localStorage above and never sent to this endpoint.\n const localPayload = { ...payload };\n delete localPayload.disabled_skills;\n const hasLocalDiffs =\n !!localPayload.agent_settings_diff ||\n !!localPayload.conversation_settings_diff;\n if (!hasLocalDiffs) {\n if (hasAppPreferences) {\n // The localStorage write changed user-visible settings; clear the\n // in-memory cache so the next getSettings() re-derives from disk.\n clearCache();\n }\n return true;\n }\n if (needsMcpPreClear) {\n await withRetry(() =>\n new SettingsClient(getAgentServerClientOptions()).updateSettings({\n agent_settings_diff: { mcp_config: null },\n }),\n );\n }\n try {\n await withRetry(() =>\n new SettingsClient(getAgentServerClientOptions()).updateSettings(\n localPayload,\n ),\n );\n } catch (err) {\n if (needsMcpPreClear && mcpConfigSnapshot) {\n // See cloud branch above for rationale.\n try {\n await new SettingsClient(\n getAgentServerClientOptions(),\n ).updateSettings({\n agent_settings_diff: {\n mcp_config: mcpConfigSnapshot as SettingsValue,\n },\n });\n } catch {\n // Rollback failed; the original error takes precedence.\n }\n }\n throw err;\n }\n }\n\n // Invalidate cache after successful save\n clearCache();\n\n return true;\n }\n\n /**\n * Invalidate the settings cache.\n * Call this when settings may have changed externally.\n */\n static invalidateCache(): void {\n clearCache();\n }\n}\n\nexport default SettingsService;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"settings-service.api.js","names":[],"sources":["../../../src/api/settings-service/settings-service.api.ts"],"sourcesContent":["import { SettingsClient } from \"@openhands/typescript-client/clients\";\nimport { DEFAULT_SETTINGS } from \"#/services/settings\";\nimport { Settings, SettingsSchema, SettingsValue } from \"#/types/settings\";\nimport {\n extractAppPreferences,\n readStoredAppPreferences,\n writeStoredAppPreferences,\n} from \"../app-preferences-store\";\nimport { getActiveBackend } from \"../backend-registry/active-store\";\nimport {\n fetchCloudConversationSettingsSchema,\n fetchCloudSettings,\n fetchCloudSettingsSchema,\n saveCloudSettings,\n} from \"../cloud/settings-service.api\";\nimport { getAgentServerClientOptions } from \"../agent-server-client-options\";\n\n/**\n * Response from GET /api/settings\n * Mirrors the SettingsResponse model in the agent server\n */\nexport interface SettingsApiResponse {\n agent_settings: Record<string, SettingsValue>;\n conversation_settings: Record<string, SettingsValue>;\n llm_api_key_is_set: boolean;\n}\n\n/**\n * Request payload for PATCH /api/settings\n */\nexport interface SettingsUpdateRequest {\n agent_settings_diff?: Record<string, SettingsValue>;\n conversation_settings_diff?: Record<string, SettingsValue>;\n disabled_skills?: string[];\n}\n\n/**\n * Secret exposure mode for X-Expose-Secrets header.\n *\n * - undefined: Returns redacted secrets (\"**********\")\n * - \"encrypted\": Returns cipher-encrypted values (safe for frontend to round-trip)\n * - \"plaintext\": Returns raw secret values (backend use only!)\n */\nexport type ExposeSecretsMode = \"encrypted\" | \"plaintext\" | undefined;\n\nconst deepClone = <T>(value: T): T => JSON.parse(JSON.stringify(value)) as T;\n\n// disabled_skills is not persisted by the local agent-server, so we mirror\n// the app-preferences pattern: write to localStorage on save, read back on fetch.\nexport const DISABLED_SKILLS_STORAGE_KEY =\n \"openhands-agent-server-disabled-skills\";\n\nconst readStoredDisabledSkills = (): string[] | null => {\n if (typeof window === \"undefined\") return null;\n try {\n const raw = window.localStorage.getItem(DISABLED_SKILLS_STORAGE_KEY);\n if (!raw) return null;\n const parsed: unknown = JSON.parse(raw);\n if (!Array.isArray(parsed)) return null;\n return parsed.filter((v): v is string => typeof v === \"string\");\n } catch {\n return null;\n }\n};\n\nconst writeStoredDisabledSkills = (skills: string[]): void => {\n if (typeof window === \"undefined\") return;\n try {\n window.localStorage.setItem(\n DISABLED_SKILLS_STORAGE_KEY,\n JSON.stringify(skills),\n );\n } catch {\n // ignore write failures (e.g. private-browsing quota exceeded)\n }\n};\n\nconst mergeRecords = (\n base: Record<string, SettingsValue> | null | undefined,\n next: Record<string, SettingsValue> | null | undefined,\n) => ({ ...(base ?? {}), ...(next ?? {}) });\n\n/**\n * Retry helper for API calls with exponential backoff.\n */\nasync function withRetry<T>(\n fn: () => Promise<T>,\n maxRetries: number = 3,\n baseDelayMs: number = 500,\n): Promise<T> {\n for (let attempt = 0; attempt < maxRetries; attempt += 1) {\n try {\n return await fn();\n } catch (error) {\n if (attempt >= maxRetries - 1) {\n throw error;\n }\n\n const delay = baseDelayMs * 2 ** attempt;\n\n await new Promise<void>((resolve) => {\n setTimeout(resolve, delay);\n });\n }\n }\n\n throw new Error(\"Retry attempts exhausted\");\n}\n\n/**\n * In-memory cache for settings to avoid repeated network calls.\n * The cache is invalidated on save operations.\n */\nlet settingsCache: {\n /** Settings with redacted secrets for display */\n redacted: SettingsApiResponse | null;\n /** Settings with encrypted secrets for conversation start */\n encrypted: SettingsApiResponse | null;\n /** Timestamp when the cache was last populated */\n timestamp: number;\n} = {\n redacted: null,\n encrypted: null,\n timestamp: 0,\n};\n\nconst CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes\n\nconst isCacheValid = () => Date.now() - settingsCache.timestamp < CACHE_TTL_MS;\n\nconst clearCache = () => {\n settingsCache = { redacted: null, encrypted: null, timestamp: 0 };\n};\n\n/**\n * Transform API response into Settings object with derived fields.\n */\nconst transformApiResponse = (\n response: SettingsApiResponse,\n): Partial<Settings> => {\n const agentSettings = response.agent_settings ?? {};\n const conversationSettings = response.conversation_settings ?? {};\n\n const partial: Partial<Settings> = {\n agent_settings: agentSettings,\n conversation_settings: conversationSettings,\n llm_api_key_set: response.llm_api_key_is_set,\n };\n\n // The local agent-server never returns disabled_skills; read it from\n // localStorage where saveSettings writes it for local-mode clients.\n const stored = readStoredDisabledSkills();\n if (stored !== null) {\n partial.disabled_skills = stored;\n }\n\n return partial;\n};\n\n/**\n * Sync derived settings fields from agent_settings and conversation_settings.\n * This ensures backward compatibility with code that reads top-level fields.\n */\nconst syncDerivedSettings = (settings: Partial<Settings>): Settings => {\n const agentSettings = mergeRecords(\n DEFAULT_SETTINGS.agent_settings ?? {},\n settings.agent_settings ?? {},\n );\n const conversationSettings = mergeRecords(\n DEFAULT_SETTINGS.conversation_settings ?? {},\n settings.conversation_settings ?? {},\n );\n\n // App-level user preferences (language, git identity, sound notifications,\n // analytics consent) live in localStorage in local mode. In cloud mode the\n // server response carries them and overrides the local cache.\n const storedAppPrefs = readStoredAppPreferences();\n\n const merged = {\n ...deepClone(DEFAULT_SETTINGS),\n ...storedAppPrefs,\n ...settings,\n provider_tokens_set: {\n ...(DEFAULT_SETTINGS.provider_tokens_set ?? {}),\n ...(settings.provider_tokens_set ?? {}),\n },\n agent_settings: agentSettings,\n conversation_settings: conversationSettings,\n } as Settings;\n\n const llm = agentSettings.llm as Record<string, SettingsValue> | undefined;\n const condenser = agentSettings.condenser as\n | Record<string, SettingsValue>\n | undefined;\n\n if (typeof agentSettings.agent === \"string\") {\n merged.agent = agentSettings.agent;\n }\n if (typeof llm?.model === \"string\" && llm.model.length > 0) {\n merged.llm_model = llm.model;\n }\n if (typeof llm?.base_url === \"string\") {\n merged.llm_base_url = llm.base_url;\n }\n // Note: api_key may be redacted (\"**********\") when fetched without expose header\n // We don't sync it to top-level llm_api_key to avoid overwriting with redacted value\n if (typeof condenser?.enabled === \"boolean\") {\n merged.enable_default_condenser = condenser.enabled;\n }\n if (typeof condenser?.max_size === \"number\") {\n merged.condenser_max_size = condenser.max_size;\n }\n if (agentSettings.mcp_config) {\n merged.mcp_config = agentSettings.mcp_config as Settings[\"mcp_config\"];\n }\n\n if (typeof conversationSettings.confirmation_mode === \"boolean\") {\n merged.confirmation_mode = conversationSettings.confirmation_mode;\n }\n if (\n typeof conversationSettings.security_analyzer === \"string\" ||\n conversationSettings.security_analyzer === null\n ) {\n merged.security_analyzer = conversationSettings.security_analyzer as\n | string\n | null;\n }\n if (typeof conversationSettings.max_iterations === \"number\") {\n merged.max_iterations = conversationSettings.max_iterations;\n }\n\n merged.search_api_key_set = !!merged.search_api_key;\n\n return merged;\n};\n\nclass SettingsService {\n /**\n * Fetch settings from the agent server API with retry logic.\n *\n * @param exposeSecrets - Controls how secrets are returned:\n * - undefined: Secrets are redacted (\"**********\") - safe for display\n * - \"encrypted\": Secrets are cipher-encrypted - safe for round-trip to start conversation\n * - \"plaintext\": Raw secrets - DO NOT USE from frontend\n */\n static async fetchSettingsFromApi(\n exposeSecrets?: ExposeSecretsMode,\n ): Promise<SettingsApiResponse> {\n return withRetry(() =>\n new SettingsClient(getAgentServerClientOptions()).getSettings({\n exposeSecrets,\n }),\n ) as Promise<SettingsApiResponse>;\n }\n\n /**\n * Get settings for display (secrets are redacted).\n * Uses in-memory cache for performance.\n */\n static async getSettings(): Promise<Settings> {\n // Cloud uses a different settings shape (flat top-level fields\n // including provider_tokens_set, llm_model, etc.). Branch out before\n // touching the local-only cache: cloud responses bypass the local\n // SettingsApiResponse shape and feed straight into syncDerivedSettings\n // so cloud-native fields like provider_tokens_set reach the GUI's\n // useUserProviders → useAppInstallations → useGitRepositories chain.\n if (getActiveBackend().backend.kind === \"cloud\") {\n try {\n const cloud = await withRetry(() => fetchCloudSettings());\n return syncDerivedSettings(cloud);\n } catch (error) {\n console.warn(\"Failed to fetch cloud settings, using defaults:\", error);\n return syncDerivedSettings({});\n }\n }\n\n // Check cache first\n if (isCacheValid() && settingsCache.redacted) {\n return syncDerivedSettings(transformApiResponse(settingsCache.redacted));\n }\n\n try {\n const response = await this.fetchSettingsFromApi();\n settingsCache.redacted = response;\n settingsCache.timestamp = Date.now();\n return syncDerivedSettings(transformApiResponse(response));\n } catch (error) {\n // If API fails, return defaults\n console.warn(\"Failed to fetch settings from API, using defaults:\", error);\n return syncDerivedSettings({});\n }\n }\n\n /**\n * Get settings with encrypted secrets for starting conversations.\n * The encrypted secrets can be passed to the start conversation API\n * with secrets_encrypted=true for server-side decryption.\n *\n * @throws Error if encrypted settings cannot be fetched - conversations\n * should not start with broken/redacted credentials.\n */\n static async getSettingsForConversation(): Promise<{\n agentSettings: Record<string, SettingsValue>;\n conversationSettings: Record<string, SettingsValue>;\n secretsEncrypted: boolean;\n }> {\n // Check cache first\n if (isCacheValid() && settingsCache.encrypted) {\n return {\n agentSettings: settingsCache.encrypted.agent_settings,\n conversationSettings: settingsCache.encrypted.conversation_settings,\n secretsEncrypted: true,\n };\n }\n\n // Fetch encrypted settings - this MUST succeed for conversations to work.\n // Do not fall back to redacted settings as that would cause auth failures.\n const response = await this.fetchSettingsFromApi(\"encrypted\");\n settingsCache.encrypted = response;\n if (!settingsCache.timestamp) {\n settingsCache.timestamp = Date.now();\n }\n return {\n agentSettings: response.agent_settings,\n conversationSettings: response.conversation_settings,\n secretsEncrypted: true,\n };\n }\n\n static async getSettingsSchema(): Promise<SettingsSchema> {\n if (getActiveBackend().backend.kind === \"cloud\") {\n return (await fetchCloudSettingsSchema()) as SettingsSchema;\n }\n return (await new SettingsClient(\n getAgentServerClientOptions(),\n ).getAgentSchema()) as SettingsSchema;\n }\n\n static async getConversationSettingsSchema(): Promise<SettingsSchema> {\n if (getActiveBackend().backend.kind === \"cloud\") {\n return (await fetchCloudConversationSettingsSchema()) as SettingsSchema;\n }\n return (await new SettingsClient(\n getAgentServerClientOptions(),\n ).getConversationSchema()) as SettingsSchema;\n }\n\n /**\n * Save settings to the agent server API.\n * Uses PATCH for incremental updates.\n */\n static async saveSettings(\n settings: Partial<Settings> & Record<string, unknown>,\n ): Promise<boolean> {\n // Split app-level user-preference fields (language, git identity, sound\n // notifications, analytics consent) off before building the diff payload.\n // The local agent-server's PATCH /api/settings has no schema for these\n // and Pydantic would drop them silently; persist them in localStorage\n // instead, and forward them as flat top-level keys to the cloud POST.\n const { extracted: appPreferences, rest } = extractAppPreferences(\n settings as Record<string, unknown>,\n );\n const hasAppPreferences = Object.keys(appPreferences).length > 0;\n if (hasAppPreferences) {\n writeStoredAppPreferences(appPreferences);\n }\n\n const payload: SettingsUpdateRequest = {};\n\n // Extract agent_settings_diff\n const agentSettingsDiff = rest.agent_settings_diff as\n | Record<string, SettingsValue>\n | undefined;\n if (agentSettingsDiff && Object.keys(agentSettingsDiff).length > 0) {\n payload.agent_settings_diff = agentSettingsDiff;\n }\n\n // Extract conversation_settings_diff\n const conversationSettingsDiff = rest.conversation_settings_diff as\n | Record<string, SettingsValue>\n | undefined;\n if (\n conversationSettingsDiff &&\n Object.keys(conversationSettingsDiff).length > 0\n ) {\n payload.conversation_settings_diff = conversationSettingsDiff;\n }\n\n // Extract disabled_skills (cloud-only — local agent-server has no skills concept)\n const disabledSkills = rest.disabled_skills as string[] | undefined;\n if (Array.isArray(disabledSkills)) {\n payload.disabled_skills = disabledSkills;\n }\n\n const isCloud = getActiveBackend().backend.kind === \"cloud\";\n\n // The backend applies ``agent_settings_diff`` by deep-merging it into the\n // existing ``agent_settings`` dict (see SDK\n // ``openhands.agent_server.persistence.models._deep_merge``). That works\n // for scalar fields but is wrong for ``mcp_config.mcpServers``, which is\n // a name-keyed map: a diff that omits a server cannot remove it (stale\n // key stays), and a diff whose key indices shift (e.g. after deleting\n // index 0, the second server is renumbered) leaves the original keys\n // behind as duplicates pointing to the wrong server config.\n //\n // The only way to make ``mcp_config`` behave like a replace through this\n // API is to first null it out — ``null`` is not a dict, so deep-merge\n // takes the else branch and sets the field to ``None`` outright — and\n // then send the new value in a follow-up call. We do this for every\n // ``mcp_config`` write, including adds (the wasted round-trip is\n // negligible for this user action and avoids divergent code paths).\n const agentDiff = payload.agent_settings_diff;\n // Send a pre-clear PATCH when the diff sets ``mcp_config`` to a non-null\n // value. A second PATCH below then writes the new value. Skipping the\n // pre-clear when the caller is already clearing (``mcp_config: null``)\n // avoids a pointless duplicate request.\n const needsMcpPreClear =\n !!agentDiff && \"mcp_config\" in agentDiff && agentDiff.mcp_config !== null;\n\n // The pre-clear is destructive: if the follow-up write fails after the\n // clear succeeds, the user's MCP config is left empty. Snapshot the\n // previous value (in raw SDK shape, NOT the GUI's parsed MCPConfig)\n // before pre-clearing so we can attempt a best-effort rollback. The\n // original write error is always re-thrown to the caller regardless\n // of rollback success — the GUI's react-query mutations surface that\n // as an error toast so the user knows to retry.\n //\n // Snapshot must be the SDK shape (``{ mcpServers: { name: cfg }}``)\n // because that is what the backend expects on the rollback PATCH.\n // ``SettingsService.getSettings`` returns a GUI Settings object whose\n // ``mcp_config`` is typed as the parsed frontend MCPConfig and\n // defaults to empty arrays when nothing is installed, so it is not\n // suitable for round-tripping back to the backend.\n let mcpConfigSnapshot: unknown = undefined;\n if (needsMcpPreClear) {\n try {\n if (isCloud) {\n const raw = (await fetchCloudSettings()) as {\n agent_settings?: { mcp_config?: unknown };\n };\n mcpConfigSnapshot = raw?.agent_settings?.mcp_config;\n } else {\n const raw = (await SettingsService.fetchSettingsFromApi()) as {\n agent_settings?: { mcp_config?: unknown };\n };\n mcpConfigSnapshot = raw?.agent_settings?.mcp_config;\n }\n } catch {\n // Snapshot failed (network blip, etc.). Continue without rollback\n // ability — the original write error will still surface.\n }\n }\n\n if (isCloud) {\n const hasCloudWork =\n !!payload.agent_settings_diff ||\n !!payload.conversation_settings_diff ||\n payload.disabled_skills !== undefined ||\n hasAppPreferences;\n if (!hasCloudWork) {\n return true;\n }\n if (needsMcpPreClear) {\n await withRetry(() =>\n saveCloudSettings({\n agent_settings_diff: { mcp_config: null },\n }),\n );\n }\n try {\n await withRetry(() =>\n saveCloudSettings({\n ...payload,\n ...(hasAppPreferences ? { app_preferences: appPreferences } : {}),\n }),\n );\n } catch (err) {\n if (needsMcpPreClear && mcpConfigSnapshot) {\n // Best-effort rollback. We deliberately do not wrap in withRetry:\n // the user's session is already in a degraded state and we want\n // to surface the original error promptly. Swallowing the restore\n // error preserves the original failure context for the caller.\n try {\n await saveCloudSettings({\n agent_settings_diff: {\n mcp_config: mcpConfigSnapshot as SettingsValue,\n },\n });\n } catch {\n // Rollback failed; the original error takes precedence.\n }\n }\n throw err;\n }\n } else {\n // The local agent-server PATCH /api/settings rejects unknown fields and\n // requires at least one of the two diff fields. Strip disabled_skills\n // and skip the request entirely if no diffs remain. App preferences\n // are persisted to localStorage above and never sent to this endpoint.\n if (Array.isArray(disabledSkills)) {\n writeStoredDisabledSkills(disabledSkills);\n }\n const localPayload = { ...payload };\n delete localPayload.disabled_skills;\n const hasLocalDiffs =\n !!localPayload.agent_settings_diff ||\n !!localPayload.conversation_settings_diff;\n if (!hasLocalDiffs) {\n if (hasAppPreferences) {\n // The localStorage write changed user-visible settings; clear the\n // in-memory cache so the next getSettings() re-derives from disk.\n clearCache();\n }\n return true;\n }\n if (needsMcpPreClear) {\n await withRetry(() =>\n new SettingsClient(getAgentServerClientOptions()).updateSettings({\n agent_settings_diff: { mcp_config: null },\n }),\n );\n }\n try {\n await withRetry(() =>\n new SettingsClient(getAgentServerClientOptions()).updateSettings(\n localPayload,\n ),\n );\n } catch (err) {\n if (needsMcpPreClear && mcpConfigSnapshot) {\n // See cloud branch above for rationale.\n try {\n await new SettingsClient(\n getAgentServerClientOptions(),\n ).updateSettings({\n agent_settings_diff: {\n mcp_config: mcpConfigSnapshot as SettingsValue,\n },\n });\n } catch {\n // Rollback failed; the original error takes precedence.\n }\n }\n throw err;\n }\n }\n\n // Invalidate cache after successful save\n clearCache();\n\n return true;\n }\n\n /**\n * Invalidate the settings cache.\n * Call this when settings may have changed externally.\n */\n static invalidateCache(): void {\n clearCache();\n }\n}\n\nexport default SettingsService;\n"],"mappings":"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"}
|
|
@@ -3,5 +3,5 @@ interface RecommendedAutomationsLauncherProps {
|
|
|
3
3
|
onLaunched?: () => void;
|
|
4
4
|
}
|
|
5
5
|
export declare function buildAutomationPrompt(basePrompt: string, backendKind: "local" | "cloud", backendHost?: string): string;
|
|
6
|
-
export declare function RecommendedAutomationsLauncher({ query, onLaunched, }: RecommendedAutomationsLauncherProps): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export declare function RecommendedAutomationsLauncher({ query, onLaunched, }: RecommendedAutomationsLauncherProps): import("react/jsx-runtime").JSX.Element | null;
|
|
7
7
|
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require(`../../../_virtual/_rolldown/runtime.cjs`),t=require(`../../../node_modules/react-i18next/dist/es/useTranslation.cjs`),n=require(`../../../i18n/declaration.cjs`),r=require(`../../../utils/utils.cjs`),i=require(`../../../stores/conversation-store.cjs`),a=require(`../../../contexts/active-backend-context.cjs`),o=require(`../../../node_modules/lucide-react/dist/esm/icons/plus.cjs`),s=require(`../../../node_modules/lucide-react/dist/esm/icons/settings.cjs`),c=require(`../../../utils/form-control-classes.cjs`),l=require(`../../shared/buttons/styled-tooltip.cjs`),u=require(`../../../hooks/query/use-cloud-organizations.cjs`),
|
|
1
|
+
const e=require(`../../../_virtual/_rolldown/runtime.cjs`),t=require(`../../../node_modules/react-i18next/dist/es/useTranslation.cjs`),n=require(`../../../i18n/declaration.cjs`),r=require(`../../../utils/utils.cjs`),i=require(`../../../stores/conversation-store.cjs`),a=require(`../../../contexts/active-backend-context.cjs`),o=require(`../../../node_modules/lucide-react/dist/esm/icons/plus.cjs`),s=require(`../../../node_modules/lucide-react/dist/esm/icons/settings.cjs`),c=require(`../../../utils/form-control-classes.cjs`),l=require(`../../shared/buttons/styled-tooltip.cjs`),u=require(`../../shared/navigation-link.cjs`),d=require(`../../../hooks/query/use-cloud-organizations.cjs`),f=require(`../../../hooks/query/use-cloud-current-user-id.cjs`),p=require(`../../../ui/dropdown/dropdown.cjs`),m=require(`../../../hooks/query/use-backends-health.cjs`),h=require(`./environment-switch-store.cjs`),g=require(`./backend-status-dot.cjs`),_=require(`./add-backend-modal.cjs`),v=require(`./manage-backends-modal.cjs`);let y=require(`react`);y=e.__toESM(y,1);let b=require(`react/jsx-runtime`),x=require(`react-router`);var S=`::`;function C(e,t){return t?`${e}${S}${t}`:e}function w(e){let[t,n]=e.split(S);return{backendId:t,orgId:n??null}}function T(e){return(0,b.jsx)(g.BackendStatusDot,{isConnected:e?.isConnected??null})}function E(e,t,n,r,i){let a=[],o=e.filter(e=>e.kind===`local`),s=e.filter(e=>e.kind===`cloud`);for(let e of o)a.push({value:C(e.id,null),label:e.name,prefix:T(i[e.id])});for(let e of s){let o=n[e.id],s=T(i[e.id]);if(!o||o.orgs.length===0)a.push({value:C(e.id,null),label:e.name,prefix:s});else{let n=r[e.id]?.userId??null;for(let r of o.orgs){let i=n&&n===r.id?t:r.name;a.push({value:C(e.id,r.id),label:`${e.name} – ${i}`,prefix:s})}}}return a}function D({openUpward:e=!1,hideTrigger:g=!1,defaultOpen:S=!1,onSelectOption:D,onOpenAddBackend:O,onOpenManageBackends:k,sidebarCollapsed:A=!1}={}){let{t:j}=t.useTranslation(`openhands`),{backends:M,active:N,setActive:P}=a.useActiveBackendContext(),F=d.useAllCloudOrganizations(),I=f.useCloudCurrentUserId(),L=m.useBackendsHealth(M),R=(0,x.useNavigate)(),z=(0,x.useMatch)(`/settings`),B=(0,x.useMatch)(`/settings/*`),V=(0,x.useMatch)(`/conversations/:conversationId`),H=(0,x.useMatch)(`/automations/:automationId`),[U,W]=y.default.useState(!1),[G,K]=y.default.useState(!1),q=j(n.I18nKey.BACKEND$PERSONAL_WORKSPACE),J=y.default.useMemo(()=>E(M,q,F,I,L),[M,q,F,I,L]),Y=C(N.backend.id,N.orgId),X=J.find(e=>e.value===Y),Z=!!(z||B),Q=j(n.I18nKey.SIDEBAR$SETTINGS),ee=i.useConversationStore(e=>e.isRightPanelShown),te=!A||V&&ee?`top`:`left`,ne=Object.values(F).some(e=>e.isLoading);y.default.useEffect(()=>{if(N.backend.kind!==`cloud`||N.orgId)return;let{backend:e}=N,t=F[e.id];if(!t||t.orgs.length===0)return;let n=I[e.id]?.userId??null,r=(n?t.orgs.find(e=>e.id===n):void 0)??t.orgs[0];r&&P(e.id,r.id)},[N,F,I,P]);let re=y.default.useCallback(()=>{if(O){O(),D?.();return}W(!0)},[O,D]),ie=y.default.useCallback(()=>{if(k){k(),D?.();return}K(!0)},[k,D]),$=y.default.useCallback(e=>{e.preventDefault(),e.stopPropagation()},[]),ae=(0,b.jsxs)(`div`,{className:`flex flex-col`,children:[(0,b.jsxs)(`button`,{type:`button`,"data-testid":`add-backend-menu-item`,onMouseDown:$,onClick:re,className:`flex w-full items-center gap-2 px-2 py-2 rounded-md text-sm cursor-pointer text-white hover:bg-[var(--oh-interactive-hover)]`,children:[(0,b.jsx)(o.Plus,{width:16,height:16,className:`text-white shrink-0`}),j(n.I18nKey.BACKEND$ADD)]}),(0,b.jsxs)(`button`,{type:`button`,"data-testid":`manage-backends-menu-item`,onMouseDown:$,onClick:ie,className:`flex w-full items-center gap-2 px-2 py-2 rounded-md text-sm cursor-pointer text-white hover:bg-[var(--oh-interactive-hover)]`,children:[(0,b.jsx)(s.Settings,{width:16,height:16,className:`text-white shrink-0`}),j(n.I18nKey.BACKEND$MANAGE)]})]}),oe=y.default.useCallback(async e=>{if(e===Y)return;let{backendId:t,orgId:n}=w(e),r=M.find(e=>e.id===t);r&&(h.triggerEnvironmentSwitch(J.find(t=>t.value===e)?.label??r.name),await new Promise(e=>{setTimeout(e,400)}),V?R(`/conversations`):H&&R(`/automations`),P(r.id,n),D?.())},[Y,M,V,H,R,J,P,j,D]);return(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)(`div`,{className:`flex items-center gap-2 w-full`,children:[(0,b.jsx)(`div`,{className:`flex-1 min-w-0`,children:(0,b.jsx)(p.Dropdown,{testId:`backend-selector`,defaultValue:X??{value:Y,label:N.backend.name,prefix:T(L[N.backend.id])},footer:ae,openUpward:e,hideTrigger:g,defaultOpen:S,openOnHover:!g,onChange:e=>{e&&oe(e.value)},placeholder:N.backend.name,loading:ne,options:J,className:`h-10 px-2 py-0 bg-transparent border-transparent hover:bg-[var(--oh-surface-raised)] focus-within:bg-[var(--oh-surface-raised)] focus-within:border-transparent focus-within:ring-0`},`${Y}-${X?.label??``}`)}),g?null:(0,b.jsx)(l.StyledTooltip,{content:Q,placement:te,offset:10,children:(0,b.jsx)(u.NavigationLink,{to:`/settings`,"data-testid":`backend-selector-settings-link`,"data-active":Z,"aria-label":Q,className:Z?r.cn(`inline-flex items-center justify-center shrink-0 w-9 h-9 rounded-md bg-tertiary text-white font-normal cursor-pointer`,c.formControlTransitionClassName):r.cn(`inline-flex items-center justify-center shrink-0 w-9 h-9 rounded-md text-[var(--oh-muted)] hover:text-white hover:bg-[var(--oh-surface-raised)] cursor-pointer`,c.formControlTransitionClassName),children:(0,b.jsx)(s.Settings,{width:16,height:16})})})]}),U?(0,b.jsx)(_.AddBackendModal,{onClose:()=>W(!1)}):null,G?(0,b.jsx)(v.ManageBackendsModal,{onClose:()=>K(!1)}):null]})}exports.BackendSelector=D;
|
|
2
2
|
//# sourceMappingURL=backend-selector.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backend-selector.cjs","names":[],"sources":["../../../../src/components/features/backends/backend-selector.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { useMatch, useNavigate } from \"react-router\";\nimport { Plus, Settings } from \"lucide-react\";\nimport { Dropdown } from \"#/ui/dropdown/dropdown\";\nimport { DropdownOption } from \"#/ui/dropdown/types\";\nimport { useActiveBackendContext } from \"#/contexts/active-backend-context\";\nimport { useAllCloudOrganizations } from \"#/hooks/query/use-cloud-organizations\";\nimport { useCloudCurrentUserId } from \"#/hooks/query/use-cloud-current-user-id\";\nimport {\n useBackendsHealth,\n type BackendHealth,\n} from \"#/hooks/query/use-backends-health\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport type { Backend } from \"#/api/backend-registry/types\";\n// Import the trigger helpers from the lightweight store, not the overlay\n// component, so the eagerly-mounted sidebar/backend-selector graph does not\n// pull in the overlay's render code (the overlay is lazy-loaded from\n// `routes/root-layout.tsx`).\nimport {\n ENVIRONMENT_SWITCH_SETACTIVE_DELAY_MS,\n triggerEnvironmentSwitch,\n} from \"#/components/features/backends/environment-switch-store\";\nimport { StyledTooltip } from \"#/components/shared/buttons/styled-tooltip\";\nimport { useConversationStore } from \"#/stores/conversation-store\";\nimport { AddBackendModal } from \"./add-backend-modal\";\nimport { BackendStatusDot } from \"./backend-status-dot\";\nimport { ManageBackendsModal } from \"./manage-backends-modal\";\nimport { cn } from \"#/utils/utils\";\nimport { formControlTransitionClassName } from \"#/utils/form-control-classes\";\n\nconst VALUE_SEPARATOR = \"::\";\n\nfunction makeOptionValue(backendId: string, orgId: string | null): string {\n return orgId ? `${backendId}${VALUE_SEPARATOR}${orgId}` : backendId;\n}\n\nfunction parseOptionValue(value: string): {\n backendId: string;\n orgId: string | null;\n} {\n const [backendId, orgId] = value.split(VALUE_SEPARATOR);\n return { backendId, orgId: orgId ?? null };\n}\n\nfunction buildStatusPrefix(health: BackendHealth | undefined) {\n return <BackendStatusDot isConnected={health?.isConnected ?? null} />;\n}\n\nfunction buildOptions(\n registered: Backend[],\n personalWorkspaceLabel: string,\n cloudOrgs: ReturnType<typeof useAllCloudOrganizations>,\n currentUserIds: ReturnType<typeof useCloudCurrentUserId>,\n healthByBackendId: Record<string, BackendHealth>,\n): DropdownOption[] {\n const options: DropdownOption[] = [];\n\n const locals = registered.filter((b) => b.kind === \"local\");\n const clouds = registered.filter((b) => b.kind === \"cloud\");\n\n for (const b of locals) {\n options.push({\n value: makeOptionValue(b.id, null),\n label: b.name,\n prefix: buildStatusPrefix(healthByBackendId[b.id]),\n });\n }\n\n for (const b of clouds) {\n const entry = cloudOrgs[b.id];\n const prefix = buildStatusPrefix(healthByBackendId[b.id]);\n if (!entry || entry.orgs.length === 0) {\n options.push({\n value: makeOptionValue(b.id, null),\n label: b.name,\n prefix,\n });\n } else {\n // Personal-workspace rule (per the cloud contract): the org whose\n // id matches the calling user's id is the user's personal\n // workspace. We resolve `user_id` once per backend (via /me on any\n // one org) and apply it across all orgs of that backend.\n const userIdForBackend = currentUserIds[b.id]?.userId ?? null;\n\n for (const org of entry.orgs) {\n const isPersonal = !!userIdForBackend && userIdForBackend === org.id;\n const orgLabel = isPersonal ? personalWorkspaceLabel : org.name;\n options.push({\n value: makeOptionValue(b.id, org.id),\n label: `${b.name} – ${orgLabel}`,\n // All org rows for the same cloud backend share that backend's\n // single connectivity verdict — there is no per-org probe.\n prefix,\n });\n }\n }\n }\n\n return options;\n}\n\ninterface BackendSelectorProps {\n /** Render the menu above the trigger (e.g. when pinned to bottom of sidebar). */\n openUpward?: boolean;\n /** Hide the selector input trigger and only render the dropdown menu. */\n hideTrigger?: boolean;\n /** Whether the dropdown menu should start open on mount. */\n defaultOpen?: boolean;\n /** Callback fired after selecting a backend/org option. */\n onSelectOption?: () => void;\n /**\n * Override the internal Add Backend modal handling. When provided,\n * clicking \"Add Backend\" calls this instead of opening BackendSelector's\n * own modal. Useful when the selector is mounted inside an ephemeral\n * container (e.g. the collapsed-sidebar popover) and the modal must\n * survive the parent unmounting.\n */\n onOpenAddBackend?: () => void;\n /** Same as onOpenAddBackend but for the Manage Backends modal. */\n onOpenManageBackends?: () => void;\n /**\n * Whether the surrounding sidebar rail is in its collapsed variant. Passed\n * down from `SidebarRailBody` so the mobile drawer (which always renders\n * the expanded rail) can override the persisted desktop value.\n */\n sidebarCollapsed?: boolean;\n}\n\nexport function BackendSelector({\n openUpward = false,\n hideTrigger = false,\n defaultOpen = false,\n onSelectOption,\n onOpenAddBackend,\n onOpenManageBackends,\n sidebarCollapsed = false,\n}: BackendSelectorProps = {}) {\n const { t } = useTranslation(\"openhands\");\n const { backends, active, setActive } = useActiveBackendContext();\n const cloudOrgs = useAllCloudOrganizations();\n const currentUserIds = useCloudCurrentUserId();\n // Probe each registered backend every 10s.\n const healthByBackendId = useBackendsHealth(backends);\n const navigate = useNavigate();\n const settingsMatch = useMatch(\"/settings\");\n const settingsSubrouteMatch = useMatch(\"/settings/*\");\n const conversationMatch = useMatch(\"/conversations/:conversationId\");\n const automationDetailMatch = useMatch(\"/automations/:automationId\");\n const [addBackendModalOpen, setAddBackendModalOpen] = React.useState(false);\n const [manageBackendsModalOpen, setManageBackendsModalOpen] =\n React.useState(false);\n\n const personalWorkspaceLabel = t(I18nKey.BACKEND$PERSONAL_WORKSPACE);\n\n const options = React.useMemo(\n () =>\n buildOptions(\n backends,\n personalWorkspaceLabel,\n cloudOrgs,\n currentUserIds,\n healthByBackendId,\n ),\n [\n backends,\n personalWorkspaceLabel,\n cloudOrgs,\n currentUserIds,\n healthByBackendId,\n ],\n );\n\n const activeValue = makeOptionValue(active.backend.id, active.orgId);\n const activeOption = options.find((o) => o.value === activeValue);\n const isSettingsActive = Boolean(settingsMatch || settingsSubrouteMatch);\n const settingsLabel = t(I18nKey.SIDEBAR$SETTINGS);\n const isRightPanelShown = useConversationStore(\n (state) => state.isRightPanelShown,\n );\n // When the sidebar rail is expanded, `placement=\"left\"` hugs the main\n // canvas and reads awkwardly; prefer above the control. When the rail is\n // collapsed, keep left except on active conversation + open right drawer.\n const settingsTooltipPlacement =\n !sidebarCollapsed || (conversationMatch && isRightPanelShown)\n ? \"top\"\n : \"left\";\n\n const someCloudLoading = Object.values(cloudOrgs).some((c) => c.isLoading);\n\n // Self-heal a malformed `(cloudBackendId, null)` selection.\n //\n // Once a cloud backend's orgs resolve, the dropdown only renders\n // per-org rows for it — the `(backendId, null)` row disappears, so\n // selecting that shape would drift from what the dropdown can render\n // (UI says \"Local\", APIs hit cloud). When we detect the drift, snap\n // the selection onto the personal-workspace org (or, lacking a /me\n // result, the first org). The selection is recorded locally only;\n // the cloud request scope follows from the API key's bound org and the\n // X-Org-Id header sent by `callCloudProxy`, so the cloud UI's\n // org choice is never mutated as a side effect.\n React.useEffect(() => {\n if (active.backend.kind !== \"cloud\" || active.orgId) return;\n const { backend } = active;\n const entry = cloudOrgs[backend.id];\n if (!entry || entry.orgs.length === 0) return;\n\n const userId = currentUserIds[backend.id]?.userId ?? null;\n const personal = userId\n ? entry.orgs.find((o) => o.id === userId)\n : undefined;\n const target = personal ?? entry.orgs[0];\n if (target) {\n setActive(backend.id, target.id);\n }\n }, [active, cloudOrgs, currentUserIds, setActive]);\n\n const openAddBackendModal = React.useCallback(() => {\n if (onOpenAddBackend) {\n onOpenAddBackend();\n onSelectOption?.();\n return;\n }\n setAddBackendModalOpen(true);\n }, [onOpenAddBackend, onSelectOption]);\n\n const openManageBackendsModal = React.useCallback(() => {\n if (onOpenManageBackends) {\n onOpenManageBackends();\n onSelectOption?.();\n return;\n }\n setManageBackendsModalOpen(true);\n }, [onOpenManageBackends, onSelectOption]);\n\n const preventDropdownMenuClose = React.useCallback(\n (event: React.MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n event.stopPropagation();\n },\n [],\n );\n\n const addBackendFooter = (\n <div className=\"flex flex-col\">\n <button\n type=\"button\"\n data-testid=\"add-backend-menu-item\"\n onMouseDown={preventDropdownMenuClose}\n onClick={openAddBackendModal}\n className=\"flex w-full items-center gap-2 px-2 py-2 rounded-md text-sm cursor-pointer text-white hover:bg-[var(--oh-interactive-hover)]\"\n >\n <Plus width={16} height={16} className=\"text-white shrink-0\" />\n {t(I18nKey.BACKEND$ADD)}\n </button>\n <button\n type=\"button\"\n data-testid=\"manage-backends-menu-item\"\n onMouseDown={preventDropdownMenuClose}\n onClick={openManageBackendsModal}\n className=\"flex w-full items-center gap-2 px-2 py-2 rounded-md text-sm cursor-pointer text-white hover:bg-[var(--oh-interactive-hover)]\"\n >\n <Settings width={16} height={16} className=\"text-white shrink-0\" />\n {t(I18nKey.BACKEND$MANAGE)}\n </button>\n </div>\n );\n\n const handleSelectBackend = React.useCallback(\n async (value: string) => {\n if (value === activeValue) return;\n\n const { backendId, orgId } = parseOptionValue(value);\n const target = backends.find((b) => b.id === backendId);\n if (!target) return;\n\n triggerEnvironmentSwitch(\n options.find((option) => option.value === value)?.label ?? target.name,\n );\n await new Promise<void>((resolve) => {\n setTimeout(resolve, ENVIRONMENT_SWITCH_SETACTIVE_DELAY_MS);\n });\n\n // @spec BM-002 — Switching backends keeps the user on the same page\n if (conversationMatch) navigate(\"/conversations\");\n else if (automationDetailMatch) navigate(\"/automations\");\n\n setActive(target.id, orgId);\n onSelectOption?.();\n },\n [\n activeValue,\n backends,\n conversationMatch,\n automationDetailMatch,\n navigate,\n options,\n setActive,\n t,\n onSelectOption,\n ],\n );\n\n return (\n <>\n <div className=\"flex items-center gap-2 w-full\">\n <div className=\"flex-1 min-w-0\">\n <Dropdown\n testId=\"backend-selector\"\n key={`${activeValue}-${activeOption?.label ?? \"\"}`}\n defaultValue={\n activeOption ?? {\n value: activeValue,\n label: active.backend.name,\n prefix: buildStatusPrefix(healthByBackendId[active.backend.id]),\n }\n }\n footer={addBackendFooter}\n openUpward={openUpward}\n hideTrigger={hideTrigger}\n defaultOpen={defaultOpen}\n openOnHover={!hideTrigger}\n onChange={(item) => {\n if (!item) return;\n void handleSelectBackend(item.value);\n }}\n placeholder={active.backend.name}\n loading={someCloudLoading}\n options={options}\n className=\"h-10 px-2 py-0 bg-transparent border-transparent hover:bg-[var(--oh-surface-raised)] focus-within:bg-[var(--oh-surface-raised)] focus-within:border-transparent focus-within:ring-0\"\n />\n </div>\n {!hideTrigger ? (\n <StyledTooltip\n content={settingsLabel}\n placement={settingsTooltipPlacement}\n offset={10}\n >\n <button\n type=\"button\"\n data-testid=\"backend-selector-settings-link\"\n data-active={isSettingsActive}\n aria-label={settingsLabel}\n onClick={() => navigate(\"/settings\")}\n className={\n isSettingsActive\n ? cn(\n \"inline-flex items-center justify-center shrink-0 w-9 h-9 rounded-md bg-tertiary text-white font-normal cursor-pointer\",\n formControlTransitionClassName,\n )\n : cn(\n \"inline-flex items-center justify-center shrink-0 w-9 h-9 rounded-md text-[var(--oh-muted)] hover:text-white hover:bg-[var(--oh-surface-raised)] cursor-pointer\",\n formControlTransitionClassName,\n )\n }\n >\n <Settings width={16} height={16} />\n </button>\n </StyledTooltip>\n ) : null}\n </div>\n {addBackendModalOpen ? (\n <AddBackendModal onClose={() => setAddBackendModalOpen(false)} />\n ) : null}\n {manageBackendsModalOpen ? (\n <ManageBackendsModal\n onClose={() => setManageBackendsModalOpen(false)}\n />\n ) : null}\n </>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"backend-selector.cjs","names":[],"sources":["../../../../src/components/features/backends/backend-selector.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { useMatch, useNavigate } from \"react-router\";\nimport { Plus, Settings } from \"lucide-react\";\nimport { Dropdown } from \"#/ui/dropdown/dropdown\";\nimport { DropdownOption } from \"#/ui/dropdown/types\";\nimport { useActiveBackendContext } from \"#/contexts/active-backend-context\";\nimport { useAllCloudOrganizations } from \"#/hooks/query/use-cloud-organizations\";\nimport { useCloudCurrentUserId } from \"#/hooks/query/use-cloud-current-user-id\";\nimport {\n useBackendsHealth,\n type BackendHealth,\n} from \"#/hooks/query/use-backends-health\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport type { Backend } from \"#/api/backend-registry/types\";\n// Import the trigger helpers from the lightweight store, not the overlay\n// component, so the eagerly-mounted sidebar/backend-selector graph does not\n// pull in the overlay's render code (the overlay is lazy-loaded from\n// `routes/root-layout.tsx`).\nimport {\n ENVIRONMENT_SWITCH_SETACTIVE_DELAY_MS,\n triggerEnvironmentSwitch,\n} from \"#/components/features/backends/environment-switch-store\";\nimport { NavigationLink } from \"#/components/shared/navigation-link\";\nimport { StyledTooltip } from \"#/components/shared/buttons/styled-tooltip\";\nimport { useConversationStore } from \"#/stores/conversation-store\";\nimport { AddBackendModal } from \"./add-backend-modal\";\nimport { BackendStatusDot } from \"./backend-status-dot\";\nimport { ManageBackendsModal } from \"./manage-backends-modal\";\nimport { cn } from \"#/utils/utils\";\nimport { formControlTransitionClassName } from \"#/utils/form-control-classes\";\n\nconst VALUE_SEPARATOR = \"::\";\n\nfunction makeOptionValue(backendId: string, orgId: string | null): string {\n return orgId ? `${backendId}${VALUE_SEPARATOR}${orgId}` : backendId;\n}\n\nfunction parseOptionValue(value: string): {\n backendId: string;\n orgId: string | null;\n} {\n const [backendId, orgId] = value.split(VALUE_SEPARATOR);\n return { backendId, orgId: orgId ?? null };\n}\n\nfunction buildStatusPrefix(health: BackendHealth | undefined) {\n return <BackendStatusDot isConnected={health?.isConnected ?? null} />;\n}\n\nfunction buildOptions(\n registered: Backend[],\n personalWorkspaceLabel: string,\n cloudOrgs: ReturnType<typeof useAllCloudOrganizations>,\n currentUserIds: ReturnType<typeof useCloudCurrentUserId>,\n healthByBackendId: Record<string, BackendHealth>,\n): DropdownOption[] {\n const options: DropdownOption[] = [];\n\n const locals = registered.filter((b) => b.kind === \"local\");\n const clouds = registered.filter((b) => b.kind === \"cloud\");\n\n for (const b of locals) {\n options.push({\n value: makeOptionValue(b.id, null),\n label: b.name,\n prefix: buildStatusPrefix(healthByBackendId[b.id]),\n });\n }\n\n for (const b of clouds) {\n const entry = cloudOrgs[b.id];\n const prefix = buildStatusPrefix(healthByBackendId[b.id]);\n if (!entry || entry.orgs.length === 0) {\n options.push({\n value: makeOptionValue(b.id, null),\n label: b.name,\n prefix,\n });\n } else {\n // Personal-workspace rule (per the cloud contract): the org whose\n // id matches the calling user's id is the user's personal\n // workspace. We resolve `user_id` once per backend (via /me on any\n // one org) and apply it across all orgs of that backend.\n const userIdForBackend = currentUserIds[b.id]?.userId ?? null;\n\n for (const org of entry.orgs) {\n const isPersonal = !!userIdForBackend && userIdForBackend === org.id;\n const orgLabel = isPersonal ? personalWorkspaceLabel : org.name;\n options.push({\n value: makeOptionValue(b.id, org.id),\n label: `${b.name} – ${orgLabel}`,\n // All org rows for the same cloud backend share that backend's\n // single connectivity verdict — there is no per-org probe.\n prefix,\n });\n }\n }\n }\n\n return options;\n}\n\ninterface BackendSelectorProps {\n /** Render the menu above the trigger (e.g. when pinned to bottom of sidebar). */\n openUpward?: boolean;\n /** Hide the selector input trigger and only render the dropdown menu. */\n hideTrigger?: boolean;\n /** Whether the dropdown menu should start open on mount. */\n defaultOpen?: boolean;\n /** Callback fired after selecting a backend/org option. */\n onSelectOption?: () => void;\n /**\n * Override the internal Add Backend modal handling. When provided,\n * clicking \"Add Backend\" calls this instead of opening BackendSelector's\n * own modal. Useful when the selector is mounted inside an ephemeral\n * container (e.g. the collapsed-sidebar popover) and the modal must\n * survive the parent unmounting.\n */\n onOpenAddBackend?: () => void;\n /** Same as onOpenAddBackend but for the Manage Backends modal. */\n onOpenManageBackends?: () => void;\n /**\n * Whether the surrounding sidebar rail is in its collapsed variant. Passed\n * down from `SidebarRailBody` so the mobile drawer (which always renders\n * the expanded rail) can override the persisted desktop value.\n */\n sidebarCollapsed?: boolean;\n}\n\nexport function BackendSelector({\n openUpward = false,\n hideTrigger = false,\n defaultOpen = false,\n onSelectOption,\n onOpenAddBackend,\n onOpenManageBackends,\n sidebarCollapsed = false,\n}: BackendSelectorProps = {}) {\n const { t } = useTranslation(\"openhands\");\n const { backends, active, setActive } = useActiveBackendContext();\n const cloudOrgs = useAllCloudOrganizations();\n const currentUserIds = useCloudCurrentUserId();\n // Probe each registered backend every 10s.\n const healthByBackendId = useBackendsHealth(backends);\n const navigate = useNavigate();\n const settingsMatch = useMatch(\"/settings\");\n const settingsSubrouteMatch = useMatch(\"/settings/*\");\n const conversationMatch = useMatch(\"/conversations/:conversationId\");\n const automationDetailMatch = useMatch(\"/automations/:automationId\");\n const [addBackendModalOpen, setAddBackendModalOpen] = React.useState(false);\n const [manageBackendsModalOpen, setManageBackendsModalOpen] =\n React.useState(false);\n\n const personalWorkspaceLabel = t(I18nKey.BACKEND$PERSONAL_WORKSPACE);\n\n const options = React.useMemo(\n () =>\n buildOptions(\n backends,\n personalWorkspaceLabel,\n cloudOrgs,\n currentUserIds,\n healthByBackendId,\n ),\n [\n backends,\n personalWorkspaceLabel,\n cloudOrgs,\n currentUserIds,\n healthByBackendId,\n ],\n );\n\n const activeValue = makeOptionValue(active.backend.id, active.orgId);\n const activeOption = options.find((o) => o.value === activeValue);\n const isSettingsActive = Boolean(settingsMatch || settingsSubrouteMatch);\n const settingsLabel = t(I18nKey.SIDEBAR$SETTINGS);\n const isRightPanelShown = useConversationStore(\n (state) => state.isRightPanelShown,\n );\n // When the sidebar rail is expanded, `placement=\"left\"` hugs the main\n // canvas and reads awkwardly; prefer above the control. When the rail is\n // collapsed, keep left except on active conversation + open right drawer.\n const settingsTooltipPlacement =\n !sidebarCollapsed || (conversationMatch && isRightPanelShown)\n ? \"top\"\n : \"left\";\n\n const someCloudLoading = Object.values(cloudOrgs).some((c) => c.isLoading);\n\n // Self-heal a malformed `(cloudBackendId, null)` selection.\n //\n // Once a cloud backend's orgs resolve, the dropdown only renders\n // per-org rows for it — the `(backendId, null)` row disappears, so\n // selecting that shape would drift from what the dropdown can render\n // (UI says \"Local\", APIs hit cloud). When we detect the drift, snap\n // the selection onto the personal-workspace org (or, lacking a /me\n // result, the first org). The selection is recorded locally only;\n // the cloud request scope follows from the API key's bound org and the\n // X-Org-Id header sent by `callCloudProxy`, so the cloud UI's\n // org choice is never mutated as a side effect.\n React.useEffect(() => {\n if (active.backend.kind !== \"cloud\" || active.orgId) return;\n const { backend } = active;\n const entry = cloudOrgs[backend.id];\n if (!entry || entry.orgs.length === 0) return;\n\n const userId = currentUserIds[backend.id]?.userId ?? null;\n const personal = userId\n ? entry.orgs.find((o) => o.id === userId)\n : undefined;\n const target = personal ?? entry.orgs[0];\n if (target) {\n setActive(backend.id, target.id);\n }\n }, [active, cloudOrgs, currentUserIds, setActive]);\n\n const openAddBackendModal = React.useCallback(() => {\n if (onOpenAddBackend) {\n onOpenAddBackend();\n onSelectOption?.();\n return;\n }\n setAddBackendModalOpen(true);\n }, [onOpenAddBackend, onSelectOption]);\n\n const openManageBackendsModal = React.useCallback(() => {\n if (onOpenManageBackends) {\n onOpenManageBackends();\n onSelectOption?.();\n return;\n }\n setManageBackendsModalOpen(true);\n }, [onOpenManageBackends, onSelectOption]);\n\n const preventDropdownMenuClose = React.useCallback(\n (event: React.MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n event.stopPropagation();\n },\n [],\n );\n\n const addBackendFooter = (\n <div className=\"flex flex-col\">\n <button\n type=\"button\"\n data-testid=\"add-backend-menu-item\"\n onMouseDown={preventDropdownMenuClose}\n onClick={openAddBackendModal}\n className=\"flex w-full items-center gap-2 px-2 py-2 rounded-md text-sm cursor-pointer text-white hover:bg-[var(--oh-interactive-hover)]\"\n >\n <Plus width={16} height={16} className=\"text-white shrink-0\" />\n {t(I18nKey.BACKEND$ADD)}\n </button>\n <button\n type=\"button\"\n data-testid=\"manage-backends-menu-item\"\n onMouseDown={preventDropdownMenuClose}\n onClick={openManageBackendsModal}\n className=\"flex w-full items-center gap-2 px-2 py-2 rounded-md text-sm cursor-pointer text-white hover:bg-[var(--oh-interactive-hover)]\"\n >\n <Settings width={16} height={16} className=\"text-white shrink-0\" />\n {t(I18nKey.BACKEND$MANAGE)}\n </button>\n </div>\n );\n\n const handleSelectBackend = React.useCallback(\n async (value: string) => {\n if (value === activeValue) return;\n\n const { backendId, orgId } = parseOptionValue(value);\n const target = backends.find((b) => b.id === backendId);\n if (!target) return;\n\n triggerEnvironmentSwitch(\n options.find((option) => option.value === value)?.label ?? target.name,\n );\n await new Promise<void>((resolve) => {\n setTimeout(resolve, ENVIRONMENT_SWITCH_SETACTIVE_DELAY_MS);\n });\n\n // @spec BM-002 — Switching backends keeps the user on the same page\n if (conversationMatch) navigate(\"/conversations\");\n else if (automationDetailMatch) navigate(\"/automations\");\n\n setActive(target.id, orgId);\n onSelectOption?.();\n },\n [\n activeValue,\n backends,\n conversationMatch,\n automationDetailMatch,\n navigate,\n options,\n setActive,\n t,\n onSelectOption,\n ],\n );\n\n return (\n <>\n <div className=\"flex items-center gap-2 w-full\">\n <div className=\"flex-1 min-w-0\">\n <Dropdown\n testId=\"backend-selector\"\n key={`${activeValue}-${activeOption?.label ?? \"\"}`}\n defaultValue={\n activeOption ?? {\n value: activeValue,\n label: active.backend.name,\n prefix: buildStatusPrefix(healthByBackendId[active.backend.id]),\n }\n }\n footer={addBackendFooter}\n openUpward={openUpward}\n hideTrigger={hideTrigger}\n defaultOpen={defaultOpen}\n openOnHover={!hideTrigger}\n onChange={(item) => {\n if (!item) return;\n void handleSelectBackend(item.value);\n }}\n placeholder={active.backend.name}\n loading={someCloudLoading}\n options={options}\n className=\"h-10 px-2 py-0 bg-transparent border-transparent hover:bg-[var(--oh-surface-raised)] focus-within:bg-[var(--oh-surface-raised)] focus-within:border-transparent focus-within:ring-0\"\n />\n </div>\n {!hideTrigger ? (\n <StyledTooltip\n content={settingsLabel}\n placement={settingsTooltipPlacement}\n offset={10}\n >\n <NavigationLink\n to=\"/settings\"\n data-testid=\"backend-selector-settings-link\"\n data-active={isSettingsActive}\n aria-label={settingsLabel}\n className={\n isSettingsActive\n ? cn(\n \"inline-flex items-center justify-center shrink-0 w-9 h-9 rounded-md bg-tertiary text-white font-normal cursor-pointer\",\n formControlTransitionClassName,\n )\n : cn(\n \"inline-flex items-center justify-center shrink-0 w-9 h-9 rounded-md text-[var(--oh-muted)] hover:text-white hover:bg-[var(--oh-surface-raised)] cursor-pointer\",\n formControlTransitionClassName,\n )\n }\n >\n <Settings width={16} height={16} />\n </NavigationLink>\n </StyledTooltip>\n ) : null}\n </div>\n {addBackendModalOpen ? (\n <AddBackendModal onClose={() => setAddBackendModalOpen(false)} />\n ) : null}\n {manageBackendsModalOpen ? (\n <ManageBackendsModal\n onClose={() => setManageBackendsModalOpen(false)}\n />\n ) : null}\n </>\n );\n}\n"],"mappings":"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"}
|
|
@@ -6,44 +6,45 @@ import { useActiveBackendContext as i } from "../../../contexts/active-backend-c
|
|
|
6
6
|
import { Plus as a } from "../../../node_modules/lucide-react/dist/esm/icons/plus.js";
|
|
7
7
|
import { Settings as o } from "../../../node_modules/lucide-react/dist/esm/icons/settings.js";
|
|
8
8
|
import { formControlTransitionClassName as s } from "../../../utils/form-control-classes.js";
|
|
9
|
-
import { StyledTooltip as
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
9
|
+
import { StyledTooltip as ee } from "../../shared/buttons/styled-tooltip.js";
|
|
10
|
+
import { NavigationLink as te } from "../../shared/navigation-link.js";
|
|
11
|
+
import { useAllCloudOrganizations as c } from "../../../hooks/query/use-cloud-organizations.js";
|
|
12
|
+
import { useCloudCurrentUserId as l } from "../../../hooks/query/use-cloud-current-user-id.js";
|
|
13
|
+
import { Dropdown as u } from "../../../ui/dropdown/dropdown.js";
|
|
14
|
+
import { useBackendsHealth as d } from "../../../hooks/query/use-backends-health.js";
|
|
15
|
+
import { triggerEnvironmentSwitch as f } from "./environment-switch-store.js";
|
|
15
16
|
import { BackendStatusDot as p } from "./backend-status-dot.js";
|
|
16
17
|
import { AddBackendModal as m } from "./add-backend-modal.js";
|
|
17
|
-
import { ManageBackendsModal as
|
|
18
|
-
import
|
|
19
|
-
import { Fragment as
|
|
20
|
-
import { useMatch as
|
|
18
|
+
import { ManageBackendsModal as h } from "./manage-backends-modal.js";
|
|
19
|
+
import g from "react";
|
|
20
|
+
import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
|
|
21
|
+
import { useMatch as b, useNavigate as x } from "react-router";
|
|
21
22
|
//#region src/components/features/backends/backend-selector.tsx
|
|
22
|
-
var
|
|
23
|
-
function
|
|
24
|
-
return t ? `${e}${
|
|
23
|
+
var S = "::";
|
|
24
|
+
function C(e, t) {
|
|
25
|
+
return t ? `${e}${S}${t}` : e;
|
|
25
26
|
}
|
|
26
27
|
function ne(e) {
|
|
27
|
-
let [t, n] = e.split(
|
|
28
|
+
let [t, n] = e.split(S);
|
|
28
29
|
return {
|
|
29
30
|
backendId: t,
|
|
30
31
|
orgId: n ?? null
|
|
31
32
|
};
|
|
32
33
|
}
|
|
33
|
-
function
|
|
34
|
-
return /* @__PURE__ */
|
|
34
|
+
function w(e) {
|
|
35
|
+
return /* @__PURE__ */ v(p, { isConnected: e?.isConnected ?? null });
|
|
35
36
|
}
|
|
36
|
-
function
|
|
37
|
+
function T(e, t, n, r, i) {
|
|
37
38
|
let a = [], o = e.filter((e) => e.kind === "local"), s = e.filter((e) => e.kind === "cloud");
|
|
38
39
|
for (let e of o) a.push({
|
|
39
|
-
value:
|
|
40
|
+
value: C(e.id, null),
|
|
40
41
|
label: e.name,
|
|
41
|
-
prefix:
|
|
42
|
+
prefix: w(i[e.id])
|
|
42
43
|
});
|
|
43
44
|
for (let e of s) {
|
|
44
|
-
let o = n[e.id], s =
|
|
45
|
+
let o = n[e.id], s = w(i[e.id]);
|
|
45
46
|
if (!o || o.orgs.length === 0) a.push({
|
|
46
|
-
value:
|
|
47
|
+
value: C(e.id, null),
|
|
47
48
|
label: e.name,
|
|
48
49
|
prefix: s
|
|
49
50
|
});
|
|
@@ -52,7 +53,7 @@ function w(e, t, n, r, i) {
|
|
|
52
53
|
for (let r of o.orgs) {
|
|
53
54
|
let i = n && n === r.id ? t : r.name;
|
|
54
55
|
a.push({
|
|
55
|
-
value:
|
|
56
|
+
value: C(e.id, r.id),
|
|
56
57
|
label: `${e.name} – ${i}`,
|
|
57
58
|
prefix: s
|
|
58
59
|
});
|
|
@@ -61,130 +62,129 @@ function w(e, t, n, r, i) {
|
|
|
61
62
|
}
|
|
62
63
|
return a;
|
|
63
64
|
}
|
|
64
|
-
function
|
|
65
|
-
let { t:
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
P,
|
|
65
|
+
function E({ openUpward: p = !1, hideTrigger: S = !1, defaultOpen: E = !1, onSelectOption: D, onOpenAddBackend: O, onOpenManageBackends: k, sidebarCollapsed: A = !1 } = {}) {
|
|
66
|
+
let { t: j } = e("openhands"), { backends: M, active: N, setActive: P } = i(), F = c(), I = l(), L = d(M), R = x(), z = b("/settings"), B = b("/settings/*"), V = b("/conversations/:conversationId"), H = b("/automations/:automationId"), [U, W] = g.useState(!1), [G, K] = g.useState(!1), q = j(t.BACKEND$PERSONAL_WORKSPACE), J = g.useMemo(() => T(M, q, F, I, L), [
|
|
67
|
+
M,
|
|
68
|
+
q,
|
|
69
69
|
F,
|
|
70
|
-
I
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
I,
|
|
71
|
+
L
|
|
72
|
+
]), Y = C(N.backend.id, N.orgId), X = J.find((e) => e.value === Y), Z = !!(z || B), Q = j(t.SIDEBAR$SETTINGS), re = r((e) => e.isRightPanelShown), ie = !A || V && re ? "top" : "left", ae = Object.values(F).some((e) => e.isLoading);
|
|
73
|
+
g.useEffect(() => {
|
|
74
|
+
if (N.backend.kind !== "cloud" || N.orgId) return;
|
|
75
|
+
let { backend: e } = N, t = F[e.id];
|
|
75
76
|
if (!t || t.orgs.length === 0) return;
|
|
76
|
-
let n =
|
|
77
|
-
r &&
|
|
77
|
+
let n = I[e.id]?.userId ?? null, r = (n ? t.orgs.find((e) => e.id === n) : void 0) ?? t.orgs[0];
|
|
78
|
+
r && P(e.id, r.id);
|
|
78
79
|
}, [
|
|
79
|
-
|
|
80
|
-
P,
|
|
80
|
+
N,
|
|
81
81
|
F,
|
|
82
|
-
|
|
82
|
+
I,
|
|
83
|
+
P
|
|
83
84
|
]);
|
|
84
|
-
let
|
|
85
|
-
if (
|
|
86
|
-
|
|
85
|
+
let oe = g.useCallback(() => {
|
|
86
|
+
if (O) {
|
|
87
|
+
O(), D?.();
|
|
87
88
|
return;
|
|
88
89
|
}
|
|
89
|
-
|
|
90
|
-
}, [
|
|
91
|
-
if (
|
|
92
|
-
|
|
90
|
+
W(!0);
|
|
91
|
+
}, [O, D]), se = g.useCallback(() => {
|
|
92
|
+
if (k) {
|
|
93
|
+
k(), D?.();
|
|
93
94
|
return;
|
|
94
95
|
}
|
|
95
|
-
|
|
96
|
-
}, [
|
|
96
|
+
K(!0);
|
|
97
|
+
}, [k, D]), $ = g.useCallback((e) => {
|
|
97
98
|
e.preventDefault(), e.stopPropagation();
|
|
98
|
-
}, []),
|
|
99
|
+
}, []), ce = /* @__PURE__ */ y("div", {
|
|
99
100
|
className: "flex flex-col",
|
|
100
|
-
children: [/* @__PURE__ */
|
|
101
|
+
children: [/* @__PURE__ */ y("button", {
|
|
101
102
|
type: "button",
|
|
102
103
|
"data-testid": "add-backend-menu-item",
|
|
103
104
|
onMouseDown: $,
|
|
104
|
-
onClick:
|
|
105
|
+
onClick: oe,
|
|
105
106
|
className: "flex w-full items-center gap-2 px-2 py-2 rounded-md text-sm cursor-pointer text-white hover:bg-[var(--oh-interactive-hover)]",
|
|
106
|
-
children: [/* @__PURE__ */
|
|
107
|
+
children: [/* @__PURE__ */ v(a, {
|
|
107
108
|
width: 16,
|
|
108
109
|
height: 16,
|
|
109
110
|
className: "text-white shrink-0"
|
|
110
|
-
}),
|
|
111
|
-
}), /* @__PURE__ */
|
|
111
|
+
}), j(t.BACKEND$ADD)]
|
|
112
|
+
}), /* @__PURE__ */ y("button", {
|
|
112
113
|
type: "button",
|
|
113
114
|
"data-testid": "manage-backends-menu-item",
|
|
114
115
|
onMouseDown: $,
|
|
115
|
-
onClick:
|
|
116
|
+
onClick: se,
|
|
116
117
|
className: "flex w-full items-center gap-2 px-2 py-2 rounded-md text-sm cursor-pointer text-white hover:bg-[var(--oh-interactive-hover)]",
|
|
117
|
-
children: [/* @__PURE__ */
|
|
118
|
+
children: [/* @__PURE__ */ v(o, {
|
|
118
119
|
width: 16,
|
|
119
120
|
height: 16,
|
|
120
121
|
className: "text-white shrink-0"
|
|
121
|
-
}),
|
|
122
|
+
}), j(t.BACKEND$MANAGE)]
|
|
122
123
|
})]
|
|
123
|
-
}),
|
|
124
|
-
if (e ===
|
|
125
|
-
let { backendId: t, orgId: n } = ne(e), r =
|
|
126
|
-
r && (
|
|
124
|
+
}), le = g.useCallback(async (e) => {
|
|
125
|
+
if (e === Y) return;
|
|
126
|
+
let { backendId: t, orgId: n } = ne(e), r = M.find((e) => e.id === t);
|
|
127
|
+
r && (f(J.find((t) => t.value === e)?.label ?? r.name), await new Promise((e) => {
|
|
127
128
|
setTimeout(e, 400);
|
|
128
|
-
}),
|
|
129
|
+
}), V ? R("/conversations") : H && R("/automations"), P(r.id, n), D?.());
|
|
129
130
|
}, [
|
|
131
|
+
Y,
|
|
132
|
+
M,
|
|
133
|
+
V,
|
|
134
|
+
H,
|
|
135
|
+
R,
|
|
130
136
|
J,
|
|
137
|
+
P,
|
|
131
138
|
j,
|
|
132
|
-
|
|
133
|
-
V,
|
|
134
|
-
L,
|
|
135
|
-
q,
|
|
136
|
-
N,
|
|
137
|
-
A,
|
|
138
|
-
E
|
|
139
|
+
D
|
|
139
140
|
]);
|
|
140
|
-
return /* @__PURE__ */
|
|
141
|
-
/* @__PURE__ */
|
|
141
|
+
return /* @__PURE__ */ y(_, { children: [
|
|
142
|
+
/* @__PURE__ */ y("div", {
|
|
142
143
|
className: "flex items-center gap-2 w-full",
|
|
143
|
-
children: [/* @__PURE__ */
|
|
144
|
+
children: [/* @__PURE__ */ v("div", {
|
|
144
145
|
className: "flex-1 min-w-0",
|
|
145
|
-
children: /* @__PURE__ */
|
|
146
|
+
children: /* @__PURE__ */ v(u, {
|
|
146
147
|
testId: "backend-selector",
|
|
147
|
-
defaultValue:
|
|
148
|
-
value:
|
|
149
|
-
label:
|
|
150
|
-
prefix:
|
|
148
|
+
defaultValue: X ?? {
|
|
149
|
+
value: Y,
|
|
150
|
+
label: N.backend.name,
|
|
151
|
+
prefix: w(L[N.backend.id])
|
|
151
152
|
},
|
|
152
|
-
footer:
|
|
153
|
+
footer: ce,
|
|
153
154
|
openUpward: p,
|
|
154
|
-
hideTrigger:
|
|
155
|
-
defaultOpen:
|
|
156
|
-
openOnHover: !
|
|
155
|
+
hideTrigger: S,
|
|
156
|
+
defaultOpen: E,
|
|
157
|
+
openOnHover: !S,
|
|
157
158
|
onChange: (e) => {
|
|
158
|
-
e &&
|
|
159
|
+
e && le(e.value);
|
|
159
160
|
},
|
|
160
|
-
placeholder:
|
|
161
|
+
placeholder: N.backend.name,
|
|
161
162
|
loading: ae,
|
|
162
|
-
options:
|
|
163
|
+
options: J,
|
|
163
164
|
className: "h-10 px-2 py-0 bg-transparent border-transparent hover:bg-[var(--oh-surface-raised)] focus-within:bg-[var(--oh-surface-raised)] focus-within:border-transparent focus-within:ring-0"
|
|
164
|
-
}, `${
|
|
165
|
-
}),
|
|
166
|
-
content:
|
|
165
|
+
}, `${Y}-${X?.label ?? ""}`)
|
|
166
|
+
}), S ? null : /* @__PURE__ */ v(ee, {
|
|
167
|
+
content: Q,
|
|
167
168
|
placement: ie,
|
|
168
169
|
offset: 10,
|
|
169
|
-
children: /* @__PURE__ */
|
|
170
|
-
|
|
170
|
+
children: /* @__PURE__ */ v(te, {
|
|
171
|
+
to: "/settings",
|
|
171
172
|
"data-testid": "backend-selector-settings-link",
|
|
172
|
-
"data-active":
|
|
173
|
-
"aria-label":
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
children: /* @__PURE__ */ _(o, {
|
|
173
|
+
"data-active": Z,
|
|
174
|
+
"aria-label": Q,
|
|
175
|
+
className: n(Z ? "inline-flex items-center justify-center shrink-0 w-9 h-9 rounded-md bg-tertiary text-white font-normal cursor-pointer" : "inline-flex items-center justify-center shrink-0 w-9 h-9 rounded-md text-[var(--oh-muted)] hover:text-white hover:bg-[var(--oh-surface-raised)] cursor-pointer", s),
|
|
176
|
+
children: /* @__PURE__ */ v(o, {
|
|
177
177
|
width: 16,
|
|
178
178
|
height: 16
|
|
179
179
|
})
|
|
180
180
|
})
|
|
181
181
|
})]
|
|
182
182
|
}),
|
|
183
|
-
|
|
184
|
-
|
|
183
|
+
U ? /* @__PURE__ */ v(m, { onClose: () => W(!1) }) : null,
|
|
184
|
+
G ? /* @__PURE__ */ v(h, { onClose: () => K(!1) }) : null
|
|
185
185
|
] });
|
|
186
186
|
}
|
|
187
187
|
//#endregion
|
|
188
|
-
export {
|
|
188
|
+
export { E as BackendSelector };
|
|
189
189
|
|
|
190
190
|
//# sourceMappingURL=backend-selector.js.map
|