@openhands/agent-canvas 1.5.1 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README.windows.md +2 -2
- package/build/assets/{Trans-DqF_OEZB.js → Trans-52HCczKK.js} +1 -1
- package/build/assets/{acp-providers-DerAmTyY.js → acp-providers-xACMK9ZP.js} +1 -1
- package/build/assets/{active-backend-context-B8rMv0X9.js → active-backend-context-Cd1qcZsb.js} +1 -1
- package/build/assets/{add-backend-modal-CxC7BNEc.js → add-backend-modal-5chsfln3.js} +1 -1
- package/build/assets/{agent-profiles-settings-BJb8YXR1.js → agent-profiles-settings-BWK4H3kR.js} +1 -1
- package/build/assets/agent-server-compatibility-DMY0CihN.js +1 -0
- package/build/assets/agent-server-conversation-service.api-CI5-xmIX.js +41 -0
- package/build/assets/agent-settings-CMd8-O4f.js +2 -0
- package/build/assets/agent-settings-CdrhQJXX.js +1 -0
- package/build/assets/{alert-banner-Dh51WURQ.js → alert-banner-CLfWuIAX.js} +1 -1
- package/build/assets/api-key-entry-screen-Cc3aC7DZ.js +1 -0
- package/build/assets/app-settings-B-DQcBoB.js +1 -0
- package/build/assets/{automation-detail-CZsu2CoM.js → automation-detail-BgxBIpyK.js} +2 -2
- package/build/assets/automation-export-Dbur8OHa.js +2 -0
- package/build/assets/automations-list-BWfjizlp.js +1 -0
- package/build/assets/{back-nav-button-DVknCcSP.js → back-nav-button-CaKvsD1E.js} +1 -1
- package/build/assets/backend-form-modal-YcfpuBZo.js +1 -0
- package/build/assets/{backend-synced-settings-badge-BSfN0AZA.js → backend-synced-settings-badge-BellMmgC.js} +1 -1
- package/build/assets/{base-modal-CIF_785P.js → base-modal-Cw7enAHz.js} +1 -1
- package/build/assets/{brand-button-B1izLAdR.js → brand-button-BulEFHr3.js} +1 -1
- package/build/assets/{browser-DKaeq_sT.js → browser-DfVgUREb.js} +2 -2
- package/build/assets/browser-store-CBqI3tNR.js +1 -0
- package/build/assets/{browser-tab-qb_ftCxW.js → browser-tab-CmIKQB7S.js} +1 -1
- package/build/assets/chat-send-button-BchSSwuD.js +1 -0
- package/build/assets/circle-check-BXbQ5nEH.js +1 -0
- package/build/assets/{circle-plus-check-toggle-DoFIjVE0.js → circle-plus-check-toggle-BhpPjkh9.js} +1 -1
- package/build/assets/client-source-DAUgyJsi.js +1 -0
- package/build/assets/cloud-funnel-analytics-B5OeWh4y.js +1 -0
- package/build/assets/{color-themes-CHizm1xF.js → color-themes-QKMSVfDU.js} +1 -1
- package/build/assets/{combobox-caret-CxZpqoSR.js → combobox-caret-kNZtp53R.js} +1 -1
- package/build/assets/{command-menu-oTvKDU3Y.js → command-menu-tUsn23zy.js} +1 -1
- package/build/assets/{command-store-D8J5LMW1.js → command-store-B0hrIWMN.js} +1 -1
- package/build/assets/{condenser-settings-BGlWn93P.js → condenser-settings-BBizzfIH.js} +1 -1
- package/build/assets/{confirmation-modal-DGBWM2Ls.js → confirmation-modal-108xng7X.js} +1 -1
- package/build/assets/{context-menu-list-item-6psNyl7X.js → context-menu-list-item-BbKfFuN1.js} +1 -1
- package/build/assets/conversation-CTzSrLMq.js +1 -0
- package/build/assets/conversation-CgcXNb-Z.js +90 -0
- package/build/assets/conversation-panel-bscjGQda.js +1 -0
- package/build/assets/{conversation-service.api-_f9GlIEi.js → conversation-service.api-DbBvscJA.js} +1 -1
- package/build/assets/conversation-state-store-C5GagZHT.js +1 -0
- package/build/assets/{conversation-store-LptbOvKa.js → conversation-store-CyVqoa0d.js} +1 -1
- package/build/assets/{conversation-tab-empty-state-CNUmIms2.js → conversation-tab-empty-state-2KYlk5Bh.js} +1 -1
- package/build/assets/{copy-to-clipboard-button-CFzH_NOX.js → copy-to-clipboard-button-C54YRPMg.js} +1 -1
- package/build/assets/declaration-_yumYLEx.js +1 -0
- package/build/assets/{device-verify-WBSjJBLH.js → device-verify-D6FW_KZq.js} +1 -1
- package/build/assets/{dropdown-classes-D3wMJlXT.js → dropdown-classes-9uONlOg1.js} +1 -1
- package/build/assets/{ellipsis-button-CbNnHlIq.js → ellipsis-button-CoaUrKmQ.js} +1 -1
- package/build/assets/{entry.client-DNlPGxsu.js → entry.client-BJSVzw7V.js} +2 -2
- package/build/assets/{enum-filter-dropdown-JLYv1t8L.js → enum-filter-dropdown-qQzyjk_q.js} +1 -1
- package/build/assets/{environment-switch-overlay-B1PFO8P8.js → environment-switch-overlay-XRWCClLu.js} +1 -1
- package/build/assets/extensions-hub-DUp9sWQY.js +1 -0
- package/build/assets/extensions-navigation-DmkftjAx.js +1 -0
- package/build/assets/file-tUAzhmJ3.js +1 -0
- package/build/assets/files-tab-GV5hwiIM.js +1 -0
- package/build/assets/files-tab-store-DehyITNC.js +1 -0
- package/build/assets/{form-control-classes-CbdN5aO3.js → form-control-classes-BPUnoYyg.js} +1 -1
- package/build/assets/git-provider-icon-DDkru3b_.js +1 -0
- package/build/assets/highlighted-source-view-CYkPZUxr.js +1 -0
- package/build/assets/home-C53WekZ2.js +1 -0
- package/build/assets/home-EAwq8ah2.js +1 -0
- package/build/assets/index-home-kBdZGKtu.js +1 -0
- package/build/assets/install-server-modal-DYk4VP3-.js +1 -0
- package/build/assets/{launch-CAGavYl-.js → launch-CIecOy_y.js} +1 -1
- package/build/assets/lesson-plan-BSEUwflx.js +4 -0
- package/build/assets/llm-not-configured-banner-C8uv1PHT.js +27 -0
- package/build/assets/llm-settings-0Bb97NCk.js +1 -0
- package/build/assets/llm-settings-D4toJ90k.js +1 -0
- package/build/assets/{llm-subscription-service-Casyzgn1.js → llm-subscription-service-BPRw3u3H.js} +1 -1
- package/build/assets/{loading-spinner-BcdnT0mN.js → loading-spinner-BCInDEXB.js} +1 -1
- package/build/assets/manage-backends-modal-Bon32JYr.js +1 -0
- package/build/assets/manifest-ec000ae3.js +1 -0
- package/build/assets/markdown-renderer-BlaJOAI2.js +2 -0
- package/build/assets/mcp-CFIpOkn2.js +9 -0
- package/build/assets/messages-eRPeR4pW.js +40 -0
- package/build/assets/{modal-body-Cc2zp0xb.js → modal-body-Bg9UCeoV.js} +1 -1
- package/build/assets/{modal-classes-3qT9Ap7Q.js → modal-classes-H1KbJkeC.js} +1 -1
- package/build/assets/{modal-close-button-BcIBUdSq.js → modal-close-button-BMLYvo0C.js} +1 -1
- package/build/assets/{model-selector-DJrMrFAr.js → model-selector-BqX2RvEr.js} +1 -1
- package/build/assets/{navigation-link-D8hfwvxI.js → navigation-link-DoJzTCEz.js} +1 -1
- package/build/assets/onboarding-3KO4qE6R.js +1 -0
- package/build/assets/onboarding-modal-D4vqkJeT.js +1 -0
- package/build/assets/{organization-service.api-vrRNwOma.js → organization-service.api-CvfQugOt.js} +1 -1
- package/build/assets/{path-utils-PNfCKQDV.js → path-utils-DRgexxnX.js} +1 -1
- package/build/assets/{plan-components-BdZXPyZU.js → plan-components-qkMiGs_-.js} +1 -1
- package/build/assets/{planner-tab-ByOw1he8.js → planner-tab-ZrjiirRr.js} +1 -1
- package/build/assets/{plugins-management-service-B75jyC56.js → plugins-management-service-9qT-r_37.js} +1 -1
- package/build/assets/plus-CzE1b-wl.js +1 -0
- package/build/assets/{profiles-service.api-BQTklD5D.js → profiles-service.api-CRVlrQpT.js} +1 -1
- package/build/assets/{providers-DfTB2gPd.js → providers-C2DFGBrf.js} +1 -1
- package/build/assets/{proxy-B3tCGf0X.js → proxy-DnnDqkwn.js} +1 -1
- package/build/assets/puzzle-IHQnD54C.js +1 -0
- package/build/assets/recommended-automations-launcher-B97vgHuN.js +58 -0
- package/build/assets/refresh-cw-DxbAs3SK.js +1 -0
- package/build/assets/root-BbONavTg.css +1 -0
- package/build/assets/root-D01rpqZU.js +2 -0
- package/build/assets/root-layout-BiHbCIkS.js +2 -0
- package/build/assets/{runtime-waiting-state-CnyVhX4T.js → runtime-waiting-state-CbUV9txX.js} +1 -1
- package/build/assets/{schema-field-CUwk4wrQ.js → schema-field-B9-9Ta9u.js} +1 -1
- package/build/assets/sdk-section-page-DG1s25Pr.js +1 -0
- package/build/assets/{sdk-settings-schema-CLR01YIK.js → sdk-settings-schema-B42JFr5Y.js} +1 -1
- package/build/assets/{secrets-service-CvyPWJhg.js → secrets-service-DvyS6-mV.js} +1 -1
- package/build/assets/secrets-settings-CeSq6cQw.js +1 -0
- package/build/assets/{segmented-toggle-kzwZkLaj.js → segmented-toggle-DRVJBNy0.js} +1 -1
- package/build/assets/settings-Dzo0dJKM.js +1 -0
- package/build/assets/{settings-mQUckT0g.js → settings-HcwfqMjJ.js} +1 -1
- package/build/assets/{settings-dropdown-input-Dhx9ErGd.js → settings-dropdown-input-B6RL_mt0.js} +1 -1
- package/build/assets/settings-index-uAKHyijw.js +1 -0
- package/build/assets/{settings-input-BsgQWS5R.js → settings-input-ZoaAPNQh.js} +1 -1
- package/build/assets/{settings-list-classes-DSJJX99U.js → settings-list-classes-Dr8LgITi.js} +1 -1
- package/build/assets/settings-modal-BVX2G_IT.js +1 -0
- package/build/assets/{settings-service.api-DXk5TdeJ.js → settings-service.api-BY7ncxIz.js} +1 -1
- package/build/assets/{settings-switch-Bes8dIlV.js → settings-switch-DUlGnP0B.js} +1 -1
- package/build/assets/{settings-utils-DzCVfiR3.js → settings-utils-kWEEvcdv.js} +1 -1
- package/build/assets/shared-conversation-CV4Rtdz2.js +1 -0
- package/build/assets/{sidebar-layout-Bm7pa3Vk.js → sidebar-layout-BhGooCga.js} +1 -1
- package/build/assets/sidebar-mobile-menu-toggle-BntOJphE.js +1 -0
- package/build/assets/{sidebar-nav-link-CHqyFXwV.js → sidebar-nav-link-DkA1XWV8.js} +1 -1
- package/build/assets/{sidebar-store-uiUXBU1N.js → sidebar-store-CF3b12-m.js} +1 -1
- package/build/assets/{skill-card-pill-row-BPYKQ3IN.js → skill-card-pill-row-_gWe1Tws.js} +1 -1
- package/build/assets/skill-icon-badge-C-zbaXbD.js +1 -0
- package/build/assets/skills-plugins-BwoXKtrR.js +1 -0
- package/build/assets/skills-settings-Crq-fZSt.js +2 -0
- package/build/assets/{styled-tooltip-B14i_Uac.js → styled-tooltip-CdnCJ67u.js} +1 -1
- package/build/assets/syntax-highlighter-CZK2ab-O.js +1 -0
- package/build/assets/{task-list-tab-DyfgG4MC.js → task-list-tab-CONOO9iI.js} +1 -1
- package/build/assets/telemetry-CC32dJYW.js +2 -0
- package/build/assets/{terminal-DRXt2Lr4.js → terminal-CTkDpIU-.js} +1 -1
- package/build/assets/{toggle-switch-DX_k418f.js → toggle-switch-yVIzmJLM.js} +1 -1
- package/build/assets/{typography-CzfoD9DY.js → typography-BBVEW0un.js} +1 -1
- package/build/assets/{use-acp-credential-form-Bm8qXdlc.js → use-acp-credential-form-CIsp8hJe.js} +1 -1
- package/build/assets/use-activate-agent-profile-BfcTTJJG.js +1 -0
- package/build/assets/{use-active-agent-profile-hI-x-UBa.js → use-active-agent-profile-CCeFtmk9.js} +1 -1
- package/build/assets/{use-active-conversation-2qeez40F.js → use-active-conversation-Badxj8w4.js} +1 -1
- package/build/assets/{use-agent-profiles-0pr5bLS7.js → use-agent-profiles-BSWVN6hH.js} +1 -1
- package/build/assets/{use-agent-state-C6peDXUm.js → use-agent-state-BzRrhoPd.js} +1 -1
- package/build/assets/use-backends-health-BsZikyFW.js +1 -0
- package/build/assets/{use-can-manage-org-profiles-Ck_bsNbH.js → use-can-manage-org-profiles-Do6mYf6P.js} +1 -1
- package/build/assets/{use-cloud-current-user-id-DUCSxNjY.js → use-cloud-current-user-id-Cx3B_0-w.js} +1 -1
- package/build/assets/use-config-D9zUVw5b.js +1 -0
- package/build/assets/{use-create-conversation-r1JHfKO5.js → use-create-conversation-vvl0kvu7.js} +1 -1
- package/build/assets/{use-create-secret-Cf2N11d2.js → use-create-secret-CB7Dvd4s.js} +1 -1
- package/build/assets/use-event-store-BlpSUF7N.js +4 -0
- package/build/assets/{use-handle-plan-click-CsAW3FlH.js → use-handle-plan-click-DDZkew9p.js} +1 -1
- package/build/assets/use-is-creating-conversation-fxSzN778.js +1 -0
- package/build/assets/{use-launch-skill-in-chat-DJWEfVc5.js → use-launch-skill-in-chat-D6_n1fs3.js} +1 -1
- package/build/assets/use-llm-profiles-CNQm7HYS.js +1 -0
- package/build/assets/use-plugins-marketplace-CloojomS.js +1 -0
- package/build/assets/use-runtime-is-ready-Bx_4cfar.js +1 -0
- package/build/assets/{use-save-agent-profile-RqUGqTv6.js → use-save-agent-profile-Bj7N-1jS.js} +1 -1
- package/build/assets/{use-save-settings-Chvzeu2s.js → use-save-settings-BMsb2wk_.js} +1 -1
- package/build/assets/use-settings-B9XEmh7i.js +1 -0
- package/build/assets/use-settings-nav-items-BGfBS0yL.js +16 -0
- package/build/assets/{use-skills-xrVoKYrF.js → use-skills-CSRbvPle.js} +1 -1
- package/build/assets/{use-task-list-CfisapBW.js → use-task-list-CTIVLrQA.js} +1 -1
- package/build/assets/use-tracking-DjdCssvp.js +1 -0
- package/build/assets/{use-user-conversation-CnE4zhOA.js → use-user-conversation-BCpFn-Ei.js} +1 -1
- package/build/assets/{useTranslation-Cbf5AGg_.js → useTranslation-CHm_6BRr.js} +1 -1
- package/build/assets/{utils-DB9LsAzA.js → utils-CrRpzbM2.js} +1 -1
- package/build/assets/vendor-markdown-DzO4uO_0.js +37 -0
- package/build/assets/{vendor~browser-wXQ-WZEC.js → vendor~browser-Byfuq5J-.js} +1 -1
- package/build/assets/{vendor~browser-tab-CsMb-pta.js → vendor~browser-tab-BLk3qxhw.js} +1 -1
- package/build/assets/{vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~dhilvkxv-eGLBu60s.js → vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~dhilvkxv-DTJ_cjR5.js} +2 -2
- package/build/assets/{vendor~files-tab-B-5fBohe.js → vendor~files-tab-XmnauIZI.js} +1 -1
- package/build/assets/{vendor~launch-_Km3J77E.js → vendor~launch-DeC8QhXQ.js} +1 -1
- package/build/assets/{vendor~root-layout~conversation-panel~conversation~shared-conversation-BrguKXCn.js → vendor~root-layout~conversation-panel~conversation~shared-conversation-DDmLzCzm.js} +1 -1
- package/build/assets/vendor~root-layout~index-home~home~conversation-panel~conversation-YrfJYTQw.js +1 -0
- package/build/assets/{vendor~root-layout~index-home~home~conversation-panel~conversation~launch~skills-settings~a~j2jlu22h-mC0v44WR.js → vendor~root-layout~index-home~home~conversation-panel~conversation~launch~skills-settings~a~j2jlu22h-DoaS51iW.js} +123 -3
- package/build/assets/{vendor~root-layout~index-home~home~conversation-panel~conversation~shared-conversation~aler~gfu7qdtz-BOKQkbc6.js → vendor~root-layout~index-home~home~conversation-panel~conversation~shared-conversation~aler~gfu7qdtz-DEYwoy8u.js} +1 -1
- package/build/assets/vendor~root-layout~index-home~home~mcp~automations-list~onboarding-modal-DZHLw5Sr.js +1 -0
- package/build/assets/{vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~ftka0fnu-cFNmfAE6.js → vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~ftka0fnu-UJ4BNDJP.js} +1 -1
- package/build/assets/{verification-settings-CfkrXoSa.js → verification-settings-uwOfc16F.js} +1 -1
- package/build/index.html +4 -4
- package/build/locales/ar/openhands.json +38 -4
- package/build/locales/ca/openhands.json +38 -4
- package/build/locales/de/openhands.json +38 -4
- package/build/locales/en/openhands.json +38 -4
- package/build/locales/es/openhands.json +38 -4
- package/build/locales/fr/openhands.json +38 -4
- package/build/locales/it/openhands.json +38 -4
- package/build/locales/ja/openhands.json +38 -4
- package/build/locales/ko-KR/openhands.json +38 -4
- package/build/locales/no/openhands.json +38 -4
- package/build/locales/pt/openhands.json +38 -4
- package/build/locales/tr/openhands.json +38 -4
- package/build/locales/uk/openhands.json +38 -4
- package/build/locales/zh-CN/openhands.json +38 -4
- package/build/locales/zh-TW/openhands.json +38 -4
- package/config/defaults.json +7 -3
- package/dist/api/agent-canvas-updates.cjs +2 -0
- package/dist/api/agent-canvas-updates.cjs.map +1 -0
- package/dist/api/agent-canvas-updates.d.ts +7 -0
- package/dist/api/agent-canvas-updates.js +19 -0
- package/dist/api/agent-canvas-updates.js.map +1 -0
- package/dist/api/agent-server-adapter.cjs +1 -1
- package/dist/api/agent-server-adapter.cjs.map +1 -1
- package/dist/api/agent-server-adapter.d.ts +3 -0
- package/dist/api/agent-server-adapter.js +1 -0
- package/dist/api/agent-server-adapter.js.map +1 -1
- package/dist/api/agent-server-compatibility.cjs +1 -1
- package/dist/api/agent-server-compatibility.cjs.map +1 -1
- package/dist/api/agent-server-compatibility.d.ts +5 -0
- package/dist/api/agent-server-compatibility.js +24 -15
- package/dist/api/agent-server-compatibility.js.map +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.js +11 -8
- package/dist/api/agent-server-config.js.map +1 -1
- package/dist/api/automation-service/automation-service.api.cjs +2 -0
- package/dist/api/automation-service/automation-service.api.cjs.map +1 -0
- package/dist/api/automation-service/automation-service.api.d.ts +3 -0
- package/dist/api/automation-service/automation-service.api.js +283 -0
- package/dist/api/automation-service/automation-service.api.js.map +1 -0
- package/dist/api/client-source.cjs +1 -1
- package/dist/api/client-source.cjs.map +1 -1
- package/dist/api/client-source.d.ts +3 -0
- package/dist/api/client-source.js +4 -4
- package/dist/api/client-source.js.map +1 -1
- package/dist/api/cloud/settings-service.api.cjs.map +1 -1
- package/dist/api/cloud/settings-service.api.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.js +111 -109
- package/dist/api/conversation-service/agent-server-conversation-service.api.js.map +1 -1
- package/dist/api/mcp-health/mcp-health-store.cjs +2 -0
- package/dist/api/mcp-health/mcp-health-store.cjs.map +1 -0
- package/dist/api/mcp-health/mcp-health-store.d.ts +22 -0
- package/dist/api/mcp-health/mcp-health-store.js +45 -0
- package/dist/api/mcp-health/mcp-health-store.js.map +1 -0
- package/dist/api/mcp-health/probe-mcp-server-health.cjs +2 -0
- package/dist/api/mcp-health/probe-mcp-server-health.cjs.map +1 -0
- package/dist/api/mcp-health/probe-mcp-server-health.d.ts +31 -0
- package/dist/api/mcp-health/probe-mcp-server-health.js +57 -0
- package/dist/api/mcp-health/probe-mcp-server-health.js.map +1 -0
- package/dist/api/mcp-service/mcp-service.api.cjs +1 -1
- package/dist/api/mcp-service/mcp-service.api.cjs.map +1 -1
- package/dist/api/mcp-service/mcp-service.api.js +66 -46
- package/dist/api/mcp-service/mcp-service.api.js.map +1 -1
- package/dist/api/plugins-management-service.cjs.map +1 -1
- package/dist/api/plugins-management-service.d.ts +6 -1
- package/dist/api/plugins-management-service.js.map +1 -1
- package/dist/api/plugins-service.d.ts +30 -2
- package/dist/api/secrets-service.cjs +1 -1
- package/dist/api/secrets-service.cjs.map +1 -1
- package/dist/api/secrets-service.d.ts +6 -6
- package/dist/api/secrets-service.js +8 -3
- package/dist/api/secrets-service.js.map +1 -1
- 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 -1
- package/dist/api/settings-service/settings-service.api.js +1 -0
- package/dist/api/settings-service/settings-service.api.js.map +1 -1
- package/dist/components/conversation-events/chat/event-message-components/critic-result-display.cjs +1 -1
- package/dist/components/conversation-events/chat/event-message-components/critic-result-display.js +5 -5
- package/dist/components/features/backends/backend-form-modal.cjs +1 -1
- package/dist/components/features/backends/backend-form-modal.cjs.map +1 -1
- package/dist/components/features/backends/backend-form-modal.d.ts +4 -1
- package/dist/components/features/backends/backend-form-modal.js +15 -16
- package/dist/components/features/backends/backend-form-modal.js.map +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 +103 -102
- package/dist/components/features/backends/backend-selector.js.map +1 -1
- package/dist/components/features/backends/manage-backends-modal.cjs +1 -1
- package/dist/components/features/backends/manage-backends-modal.cjs.map +1 -1
- package/dist/components/features/backends/manage-backends-modal.js +85 -73
- package/dist/components/features/backends/manage-backends-modal.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 +131 -129
- package/dist/components/features/chat/chat-interface.js.map +1 -1
- package/dist/components/features/chat/confirmation-mode-enabled.cjs +1 -1
- package/dist/components/features/chat/confirmation-mode-enabled.js +4 -4
- package/dist/components/features/chat/skill-install-restart-banner.cjs +2 -0
- package/dist/components/features/chat/skill-install-restart-banner.cjs.map +1 -0
- package/dist/components/features/chat/skill-install-restart-banner.d.ts +11 -0
- package/dist/components/features/chat/skill-install-restart-banner.js +63 -0
- package/dist/components/features/chat/skill-install-restart-banner.js.map +1 -0
- package/dist/components/features/conversation/right-panel-toggle.cjs +1 -1
- package/dist/components/features/conversation/right-panel-toggle.cjs.map +1 -1
- package/dist/components/features/conversation/right-panel-toggle.js +1 -1
- package/dist/components/features/conversation/right-panel-toggle.js.map +1 -1
- package/dist/components/features/conversation-panel/conversation-panel.cjs +1 -1
- package/dist/components/features/conversation-panel/conversation-panel.js +10 -10
- 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 +78 -77
- 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 +4 -1
- package/dist/components/features/mcp-page/install-server-modal.js +135 -136
- 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 +40 -34
- package/dist/components/features/mcp-page/installed-server-card.js.map +1 -1
- package/dist/components/features/mcp-page/mcp-server-health.cjs +2 -0
- package/dist/components/features/mcp-page/mcp-server-health.cjs.map +1 -0
- package/dist/components/features/mcp-page/mcp-server-health.d.ts +18 -0
- package/dist/components/features/mcp-page/mcp-server-health.js +117 -0
- package/dist/components/features/mcp-page/mcp-server-health.js.map +1 -0
- package/dist/components/features/plugins/build-plugins-view-model.d.ts +10 -1
- package/dist/components/features/plugins/plugin-files-section.d.ts +13 -0
- package/dist/components/features/settings/agent-canvas-update-card.cjs +2 -0
- package/dist/components/features/settings/agent-canvas-update-card.cjs.map +1 -0
- package/dist/components/features/settings/agent-canvas-update-card.d.ts +7 -0
- package/dist/components/features/settings/agent-canvas-update-card.js +170 -0
- package/dist/components/features/settings/agent-canvas-update-card.js.map +1 -0
- package/dist/components/features/settings/integrations-settings-link.cjs +2 -0
- package/dist/components/features/settings/integrations-settings-link.cjs.map +1 -0
- package/dist/components/features/settings/integrations-settings-link.d.ts +5 -0
- package/dist/components/features/settings/integrations-settings-link.js +41 -0
- package/dist/components/features/settings/integrations-settings-link.js.map +1 -0
- package/dist/components/features/settings/llm-profiles/llm-settings-local-view.cjs +1 -1
- package/dist/components/features/settings/llm-profiles/llm-settings-local-view.js +1 -1
- package/dist/components/features/settings/settings-desktop-sidebar.cjs +1 -1
- package/dist/components/features/settings/settings-desktop-sidebar.cjs.map +1 -1
- package/dist/components/features/settings/settings-desktop-sidebar.js +31 -21
- package/dist/components/features/settings/settings-desktop-sidebar.js.map +1 -1
- package/dist/components/features/settings/settings-mobile-drawer.cjs +1 -1
- package/dist/components/features/settings/settings-mobile-drawer.cjs.map +1 -1
- package/dist/components/features/settings/settings-mobile-drawer.js +40 -30
- package/dist/components/features/settings/settings-mobile-drawer.js.map +1 -1
- package/dist/components/features/skills/extensions-navigation.cjs +1 -1
- package/dist/components/features/skills/extensions-navigation.cjs.map +1 -1
- package/dist/components/features/skills/extensions-navigation.js +54 -33
- package/dist/components/features/skills/extensions-navigation.js.map +1 -1
- package/dist/config/defaults.cjs +1 -1
- package/dist/config/defaults.cjs.map +1 -1
- package/dist/config/defaults.js +7 -3
- package/dist/config/defaults.js.map +1 -1
- package/dist/constants/acp-providers.cjs.map +1 -1
- package/dist/constants/acp-providers.js.map +1 -1
- package/dist/contexts/conversation-websocket-context.cjs +2 -2
- package/dist/contexts/conversation-websocket-context.cjs.map +1 -1
- package/dist/contexts/conversation-websocket-context.js +169 -166
- package/dist/contexts/conversation-websocket-context.js.map +1 -1
- package/dist/hooks/mutation/use-delete-llm-profile.cjs +1 -1
- package/dist/hooks/mutation/use-delete-llm-profile.js +1 -0
- package/dist/hooks/mutation/use-delete-mcp-server.cjs +1 -1
- package/dist/hooks/mutation/use-delete-mcp-server.cjs.map +1 -1
- package/dist/hooks/mutation/use-delete-mcp-server.js +8 -6
- package/dist/hooks/mutation/use-delete-mcp-server.js.map +1 -1
- package/dist/hooks/mutation/use-rename-llm-profile.cjs +1 -1
- package/dist/hooks/mutation/use-rename-llm-profile.js +1 -0
- package/dist/hooks/mutation/use-save-settings.cjs +1 -1
- package/dist/hooks/mutation/use-save-settings.js +3 -3
- package/dist/hooks/mutation/use-update-mcp-server.cjs +1 -1
- package/dist/hooks/mutation/use-update-mcp-server.cjs.map +1 -1
- package/dist/hooks/mutation/use-update-mcp-server.js +11 -9
- package/dist/hooks/mutation/use-update-mcp-server.js.map +1 -1
- package/dist/hooks/query/query-keys.cjs +1 -1
- package/dist/hooks/query/query-keys.cjs.map +1 -1
- package/dist/hooks/query/query-keys.d.ts +4 -0
- package/dist/hooks/query/query-keys.js +2 -2
- package/dist/hooks/query/query-keys.js.map +1 -1
- package/dist/hooks/query/use-automation-sdk-version.cjs +2 -0
- package/dist/hooks/query/use-automation-sdk-version.cjs.map +1 -0
- package/dist/hooks/query/use-automation-sdk-version.d.ts +3 -0
- package/dist/hooks/query/use-automation-sdk-version.js +63 -0
- package/dist/hooks/query/use-automation-sdk-version.js.map +1 -0
- package/dist/hooks/query/use-latest-agent-canvas-version.cjs +2 -0
- package/dist/hooks/query/use-latest-agent-canvas-version.cjs.map +1 -0
- package/dist/hooks/query/use-latest-agent-canvas-version.d.ts +10 -0
- package/dist/hooks/query/use-latest-agent-canvas-version.js +19 -0
- package/dist/hooks/query/use-latest-agent-canvas-version.js.map +1 -0
- package/dist/hooks/query/use-plugin-file-content.d.ts +7 -0
- package/dist/hooks/query/use-resolved-workspaces.cjs +1 -1
- package/dist/hooks/query/use-resolved-workspaces.cjs.map +1 -1
- package/dist/hooks/query/use-resolved-workspaces.js +25 -26
- package/dist/hooks/query/use-resolved-workspaces.js.map +1 -1
- package/dist/hooks/query/use-search-subdirs.cjs +1 -1
- package/dist/hooks/query/use-search-subdirs.cjs.map +1 -1
- package/dist/hooks/query/use-search-subdirs.d.ts +5 -0
- package/dist/hooks/query/use-search-subdirs.js +16 -4
- package/dist/hooks/query/use-search-subdirs.js.map +1 -1
- package/dist/hooks/query/use-task-polling.cjs +1 -1
- package/dist/hooks/query/use-task-polling.cjs.map +1 -1
- package/dist/hooks/query/use-task-polling.d.ts +19 -3
- package/dist/hooks/query/use-task-polling.js +36 -35
- package/dist/hooks/query/use-task-polling.js.map +1 -1
- package/dist/hooks/use-device-flow.cjs +1 -1
- package/dist/hooks/use-device-flow.js +6 -6
- package/dist/hooks/use-llm-configured.cjs +1 -1
- package/dist/hooks/use-llm-configured.js +3 -3
- package/dist/hooks/use-mcp-server-health.cjs +2 -0
- package/dist/hooks/use-mcp-server-health.cjs.map +1 -0
- package/dist/hooks/use-mcp-server-health.d.ts +11 -0
- package/dist/hooks/use-mcp-server-health.js +18 -0
- package/dist/hooks/use-mcp-server-health.js.map +1 -0
- package/dist/hooks/use-skill-installs.cjs +2 -0
- package/dist/hooks/use-skill-installs.cjs.map +1 -0
- package/dist/hooks/use-skill-installs.d.ts +10 -0
- package/dist/hooks/use-skill-installs.js +21 -0
- package/dist/hooks/use-skill-installs.js.map +1 -0
- package/dist/hooks/use-tracking.cjs +1 -1
- package/dist/hooks/use-tracking.cjs.map +1 -1
- package/dist/hooks/use-tracking.d.ts +3 -3
- package/dist/hooks/use-tracking.js +67 -52
- package/dist/hooks/use-tracking.js.map +1 -1
- package/dist/i18n/declaration.cjs +1 -1
- package/dist/i18n/declaration.cjs.map +1 -1
- package/dist/i18n/declaration.d.ts +35 -1
- package/dist/i18n/declaration.js +1 -1
- package/dist/i18n/declaration.js.map +1 -1
- package/dist/i18n/translation.cjs +3 -3
- package/dist/i18n/translation.cjs.map +1 -1
- package/dist/i18n/translation.js +623 -45
- package/dist/i18n/translation.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -2
- package/dist/lib/index.cjs +1 -1
- package/dist/lib/index.d.ts +0 -1
- package/dist/lib/index.js +0 -1
- package/dist/locales/ar/openhands.json +38 -4
- package/dist/locales/ca/openhands.json +38 -4
- package/dist/locales/de/openhands.json +38 -4
- package/dist/locales/en/openhands.json +38 -4
- package/dist/locales/es/openhands.json +38 -4
- package/dist/locales/fr/openhands.json +38 -4
- package/dist/locales/it/openhands.json +38 -4
- package/dist/locales/ja/openhands.json +38 -4
- package/dist/locales/ko-KR/openhands.json +38 -4
- package/dist/locales/no/openhands.json +38 -4
- package/dist/locales/pt/openhands.json +38 -4
- package/dist/locales/tr/openhands.json +38 -4
- package/dist/locales/uk/openhands.json +38 -4
- package/dist/locales/zh-CN/openhands.json +38 -4
- package/dist/locales/zh-TW/openhands.json +38 -4
- package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian-rovo.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian-rovo.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian-rovo.js +44 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian-rovo.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian.js +13 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian.js.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/github.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/github.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/github.js +21 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/github.js.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/linear.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/linear.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/linear.js +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/linear.js.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/microsoft-outlook.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/microsoft-outlook.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/microsoft-outlook.js +13 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/microsoft-outlook.js.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/microsoft-teams.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/microsoft-teams.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/microsoft-teams.js +13 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/microsoft-teams.js.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.js +13 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.js.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/onedrive.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/onedrive.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/onedrive.js +13 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/onedrive.js.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/sharepoint.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/sharepoint.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/sharepoint.js +13 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/sharepoint.js.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.js +16 -2
- package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.js.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/vanta.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/vanta.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/vanta.js +46 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/vanta.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog-index.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog-index.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog-index.js +74 -70
- package/dist/node_modules/@openhands/extensions/integrations/catalog-index.js.map +1 -1
- package/dist/node_modules/@openhands/extensions/skills/index.cjs +123 -3
- package/dist/node_modules/@openhands/extensions/skills/index.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/skills/index.js +7 -1
- package/dist/node_modules/@openhands/extensions/skills/index.js.map +1 -1
- package/dist/node_modules/lucide-react/dist/esm/icons/chevron-up.cjs +2 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/chevron-up.cjs.map +1 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/chevron-up.js +9 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/chevron-up.js.map +1 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/info.cjs +2 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/info.cjs.map +1 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/info.js +21 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/info.js.map +1 -0
- package/dist/package.cjs +1 -1
- package/dist/package.cjs.map +1 -1
- package/dist/package.js +10 -3
- package/dist/package.js.map +1 -1
- package/dist/routes/app-settings.cjs +1 -1
- package/dist/routes/app-settings.cjs.map +1 -1
- package/dist/routes/app-settings.js +113 -67
- package/dist/routes/app-settings.js.map +1 -1
- package/dist/routes/conversation.cjs +1 -1
- package/dist/routes/conversation.cjs.map +1 -1
- package/dist/routes/conversation.js +1 -1
- package/dist/routes/conversation.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 -0
- package/dist/routes/mcp.js.map +1 -1
- package/dist/services/cloud-funnel-analytics.cjs +1 -1
- package/dist/services/cloud-funnel-analytics.cjs.map +1 -1
- package/dist/services/cloud-funnel-analytics.d.ts +2 -2
- package/dist/services/cloud-funnel-analytics.js +18 -16
- package/dist/services/cloud-funnel-analytics.js.map +1 -1
- package/dist/services/settings.cjs +1 -1
- package/dist/services/settings.cjs.map +1 -1
- package/dist/services/settings.js +1 -0
- package/dist/services/settings.js.map +1 -1
- package/dist/services/telemetry-context.cjs +2 -0
- package/dist/services/telemetry-context.cjs.map +1 -0
- package/dist/services/telemetry-context.d.ts +17 -0
- package/dist/services/telemetry-context.js +27 -0
- package/dist/services/telemetry-context.js.map +1 -0
- package/dist/services/telemetry.cjs +1 -1
- package/dist/services/telemetry.cjs.map +1 -1
- package/dist/services/telemetry.d.ts +7 -5
- package/dist/services/telemetry.js +132 -123
- package/dist/services/telemetry.js.map +1 -1
- package/dist/stores/skill-install-banner-store.cjs +2 -0
- package/dist/stores/skill-install-banner-store.cjs.map +1 -0
- package/dist/stores/skill-install-banner-store.d.ts +32 -0
- package/dist/stores/skill-install-banner-store.js +14 -0
- package/dist/stores/skill-install-banner-store.js.map +1 -0
- package/dist/stores/use-event-store.cjs +1 -1
- package/dist/stores/use-event-store.cjs.map +1 -1
- package/dist/stores/use-event-store.js +35 -35
- package/dist/stores/use-event-store.js.map +1 -1
- package/dist/types/mcp-health.cjs +2 -0
- package/dist/types/mcp-health.cjs.map +1 -0
- package/dist/types/mcp-health.d.ts +21 -0
- package/dist/types/mcp-health.js +6 -0
- package/dist/types/mcp-health.js.map +1 -0
- package/dist/types/settings.d.ts +1 -0
- package/dist/utils/handle-event-for-ui.cjs +1 -1
- package/dist/utils/handle-event-for-ui.cjs.map +1 -1
- package/dist/utils/handle-event-for-ui.d.ts +5 -0
- package/dist/utils/handle-event-for-ui.js +71 -57
- package/dist/utils/handle-event-for-ui.js.map +1 -1
- package/dist/utils/mcp-credential-validation.cjs +1 -1
- package/dist/utils/mcp-credential-validation.cjs.map +1 -1
- package/dist/utils/mcp-credential-validation.js +32 -16
- package/dist/utils/mcp-credential-validation.js.map +1 -1
- package/dist/utils/mcp-server-health-key.cjs +2 -0
- package/dist/utils/mcp-server-health-key.cjs.map +1 -0
- package/dist/utils/mcp-server-health-key.d.ts +16 -0
- package/dist/utils/mcp-server-health-key.js +23 -0
- package/dist/utils/mcp-server-health-key.js.map +1 -0
- package/dist/utils/mcp-test-error-message.cjs +2 -0
- package/dist/utils/mcp-test-error-message.cjs.map +1 -0
- package/dist/utils/mcp-test-error-message.d.ts +8 -0
- package/dist/utils/mcp-test-error-message.js +14 -0
- package/dist/utils/mcp-test-error-message.js.map +1 -0
- package/dist/utils/redact-mcp-secrets.cjs +2 -0
- package/dist/utils/redact-mcp-secrets.cjs.map +1 -0
- package/dist/utils/redact-mcp-secrets.d.ts +13 -0
- package/dist/utils/redact-mcp-secrets.js +57 -0
- package/dist/utils/redact-mcp-secrets.js.map +1 -0
- package/dist/utils/settings-utils.cjs.map +1 -1
- package/dist/utils/settings-utils.js.map +1 -1
- package/dist/utils/skill-install-events.cjs +3 -0
- package/dist/utils/skill-install-events.cjs.map +1 -0
- package/dist/utils/skill-install-events.d.ts +16 -0
- package/dist/utils/skill-install-events.js +26 -0
- package/dist/utils/skill-install-events.js.map +1 -0
- package/dist/utils/title-llm-profile.cjs +2 -0
- package/dist/utils/title-llm-profile.cjs.map +1 -0
- package/dist/utils/title-llm-profile.d.ts +2 -0
- package/dist/utils/title-llm-profile.js +11 -0
- package/dist/utils/title-llm-profile.js.map +1 -0
- package/package.json +10 -3
- package/scripts/check-sdk-version-sync.mjs +6 -6
- package/scripts/check-translation-completeness.cjs +2 -0
- package/scripts/dev-process-utils.mjs +62 -1
- package/scripts/dev-safe.mjs +2 -2
- package/scripts/dev-static.mjs +5 -3
- package/scripts/dev-with-automation.mjs +98 -14
- package/scripts/download-node.mjs +382 -0
- package/scripts/download-uv.mjs +204 -0
- package/scripts/logger.mjs +64 -35
- package/build/assets/agent-server-compatibility-BWN-EIQn.js +0 -1
- package/build/assets/agent-server-conversation-service.api-DSPIkMwJ.js +0 -41
- package/build/assets/agent-settings-CgCnqaAA.js +0 -2
- package/build/assets/agent-settings-DDkSavD7.js +0 -1
- package/build/assets/api-key-entry-screen-iZc7n8AI.js +0 -1
- package/build/assets/app-settings-B5zyipxJ.js +0 -1
- package/build/assets/automation-export-BwRX6H32.js +0 -2
- package/build/assets/automations-list-lHAVzMoA.js +0 -1
- package/build/assets/backend-form-modal-RGcu909r.js +0 -1
- package/build/assets/browser-store-BI6uklCG.js +0 -1
- package/build/assets/chat-send-button-BZHG2hAW.js +0 -1
- package/build/assets/client-source-BZK8vRs2.js +0 -1
- package/build/assets/cloud-funnel-analytics-Zcv57hfT.js +0 -1
- package/build/assets/conversation-BoCYx8n2.js +0 -89
- package/build/assets/conversation-DgHqMjnY.js +0 -1
- package/build/assets/conversation-panel-78Rxh_-I.js +0 -1
- package/build/assets/conversation-state-store-B2Bp32XI.js +0 -1
- package/build/assets/declaration-BGsHjPEW.js +0 -1
- package/build/assets/extensions-hub-CCbLA7IM.js +0 -1
- package/build/assets/extensions-navigation-CPNjMNvR.js +0 -1
- package/build/assets/files-tab-store-DJsPxYdg.js +0 -1
- package/build/assets/files-tab-y4K7EXBO.js +0 -1
- package/build/assets/git-provider-icon-ITvsH4Ko.js +0 -1
- package/build/assets/home-BwbeOWwU.js +0 -1
- package/build/assets/home-DKPGQ5P3.js +0 -1
- package/build/assets/index-home-Bko2Itv5.js +0 -1
- package/build/assets/install-server-modal-Qk1gwyI8.js +0 -1
- package/build/assets/lesson-plan-DMCPdtrf.js +0 -4
- package/build/assets/llm-not-configured-banner-C1ktyb3C.js +0 -27
- package/build/assets/llm-settings-BBsZFi9l.js +0 -1
- package/build/assets/llm-settings-DFkJQr_w.js +0 -1
- package/build/assets/manage-backends-modal-CKQ46rvw.js +0 -1
- package/build/assets/manifest-03478bbf.js +0 -1
- package/build/assets/markdown-renderer-B4V2OMFP.js +0 -2
- package/build/assets/mcp-BapoJsDc.js +0 -9
- package/build/assets/messages-CUBFMY5o.js +0 -40
- package/build/assets/objectWithoutPropertiesLoose-BgYIAs2y.js +0 -1
- package/build/assets/onboarding-6NMkdNxV.js +0 -1
- package/build/assets/onboarding-modal-Q4AnpIdg.js +0 -1
- package/build/assets/recommended-automations-launcher-Bj7PuHY1.js +0 -58
- package/build/assets/refresh-cw-B9B7-vsy.js +0 -1
- package/build/assets/root-CDnuTToz.js +0 -2
- package/build/assets/root-CYWeTrWE.css +0 -1
- package/build/assets/root-layout-DfYVlcRG.js +0 -2
- package/build/assets/sdk-section-page-DLLNrYjI.js +0 -1
- package/build/assets/secrets-settings-CHy72A5C.js +0 -1
- package/build/assets/settings-B9S8UVQr.js +0 -1
- package/build/assets/settings-index-BKDl2CQ-.js +0 -1
- package/build/assets/settings-modal-DeK11CyT.js +0 -1
- package/build/assets/shared-conversation-9atDzTR4.js +0 -1
- package/build/assets/sidebar-mobile-menu-toggle-giMMZctn.js +0 -1
- package/build/assets/skills-plugins-Tropusio.js +0 -1
- package/build/assets/skills-settings-BvzBBCWk.js +0 -2
- package/build/assets/telemetry-C5JMEfqB.js +0 -2
- package/build/assets/use-activate-agent-profile-DlykqEfN.js +0 -1
- package/build/assets/use-backends-health-CLHPitJM.js +0 -1
- package/build/assets/use-config-B5r8erYt.js +0 -1
- package/build/assets/use-event-store-Bbaz51GR.js +0 -4
- package/build/assets/use-llm-profiles-Dr5__SlZ.js +0 -1
- package/build/assets/use-plugins-marketplace-BplU65ae.js +0 -1
- package/build/assets/use-runtime-is-ready-vCFOcLFa.js +0 -1
- package/build/assets/use-settings-CyxSlyTQ.js +0 -1
- package/build/assets/use-settings-nav-items-zEkSO_Bf.js +0 -16
- package/build/assets/use-tracking-D2Qg5Lpd.js +0 -1
- package/build/assets/useMutationState-OnAsCLA_.js +0 -1
- package/build/assets/vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-BD7v71DM.js +0 -2
- package/build/assets/vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-BT05Osu4.js +0 -28
- package/build/assets/vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-COhHANvV.js +0 -2
- package/build/assets/vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DgzWSMRc.js +0 -2
- package/build/assets/vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DqZatR3B.js +0 -7
- package/build/assets/vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-FghQ3Z1a.js +0 -1
- package/build/assets/vendor~root-layout~index-home~home~conversation-panel~conversation-BTvhGHHG.js +0 -1
- package/build/assets/vendor~root-layout~index-home~home~mcp~automations-list~onboarding-modal-C4-GDgiF.js +0 -1
- package/dist/components/features/analytics/telemetry-consent-banner.cjs +0 -2
- package/dist/components/features/analytics/telemetry-consent-banner.cjs.map +0 -1
- package/dist/components/features/analytics/telemetry-consent-banner.d.ts +0 -29
- package/dist/components/features/analytics/telemetry-consent-banner.js +0 -59
- package/dist/components/features/analytics/telemetry-consent-banner.js.map +0 -1
- /package/build/assets/{__vite-browser-external-BQUj0sYu.js → __vite-browser-external-CKHVBTNC.js} +0 -0
- /package/build/assets/{agent-server-ui-style-scope-qhnhZHBV.js → agent-server-ui-style-scope-BvSa9on7.js} +0 -0
- /package/build/assets/{automation-LZB0MjdV.js → automation-BGiPmxFR.js} +0 -0
- /package/build/assets/{canvas-ui-COgjltGz.js → canvas-ui-CC4EJo-H.js} +0 -0
- /package/build/assets/{checkmark-h7udgXMM.js → checkmark-ygQB1AtV.js} +0 -0
- /package/build/assets/{close-DLFb5kfv.js → close-BjSA0HWT.js} +0 -0
- /package/build/assets/{code-tag-DYlAhEQY.js → code-tag-D9aPPbOe.js} +0 -0
- /package/build/assets/{common-CxbUL3nR.js → common-CCuqQy_S.js} +0 -0
- /package/build/assets/{conversation-local-storage-F6zVMM--.js → conversation-local-storage-BDjWPg0Z.js} +0 -0
- /package/build/assets/{copy-BLmGeJcd.js → copy-Dce7sOvS.js} +0 -0
- /package/build/assets/{copy-D1YGjP-C.js → copy-iPJAncAj.js} +0 -0
- /package/build/assets/{dist-CodhvuAP.js → dist-D9PhjOaq.js} +0 -0
- /package/build/assets/{environment-switch-store-DkjlKWzN.js → environment-switch-store-DHfcz4M4.js} +0 -0
- /package/build/assets/{extension-module-card-classes-9V3J9J_b.js → extension-module-card-classes-BpebKiN6.js} +0 -0
- /package/build/assets/{external-link-lhdITPqq.js → external-link-CpPMXxrV.js} +0 -0
- /package/build/assets/{folder-Bk311brm.js → folder-BabbYnbF.js} +0 -0
- /package/build/assets/{format-time-delta-DhDbkD7V.js → format-time-delta-BkAmJEPT.js} +0 -0
- /package/build/assets/{get-language-from-path-DBqBsCWH.js → get-language-from-path-CPNnuVhI.js} +0 -0
- /package/build/assets/{git-status-mapper-DnL9OC8_.js → git-status-mapper-BIXK0AAG.js} +0 -0
- /package/build/assets/{iconBase-Dz51Zn5x.js → iconBase-Ch-fOe8B.js} +0 -0
- /package/build/assets/{link-external-CaBmUEs_.js → link-external-DfKQroKX.js} +0 -0
- /package/build/assets/{list-todo-CAtvkzcy.js → list-todo-6J6zc8oS.js} +0 -0
- /package/build/assets/{llm-subscription-DtsX5Lhg.js → llm-subscription-Bvu8BLXc.js} +0 -0
- /package/build/assets/{loader-circle-CsAsfLIs.js → loader-circle-DGsqG5qw.js} +0 -0
- /package/build/assets/{map-provider-BbIb12oh.js → map-provider-BSvXvVR0.js} +0 -0
- /package/build/assets/{middleware-DYHYNAnP.js → middleware-_izt7V6U.js} +0 -0
- /package/build/assets/{modal-backdrop-zVwfOJZr.js → modal-backdrop-B7H42xHG.js} +0 -0
- /package/build/assets/{navigation-context-DPs2G0X8.js → navigation-context-cvyvI1WA.js} +0 -0
- /package/build/assets/{openhands-logo-bcNw5bkY.js → openhands-logo-pEw0nKFP.js} +0 -0
- /package/build/assets/{pencil-CWhApFIT.js → pencil-DmSqWUA3.js} +0 -0
- /package/build/assets/{react-DPDgL6du.js → react-MKQOkha9.js} +0 -0
- /package/build/assets/{search-BgOCR7_c.js → search-B5D5EuSn.js} +0 -0
- /package/build/assets/{search-dIQ09UY2.js → search-vnYL5jwV.js} +0 -0
- /package/build/assets/{settings-gear-MXCyZW0x.js → settings-gear-BOwF59Bs.js} +0 -0
- /package/build/assets/{settings-section-header-context-COMOIaxV.js → settings-section-header-context-CGgHZXrf.js} +0 -0
- /package/build/assets/{skills-EqzxYBvT.js → skills-arUOHLcS.js} +0 -0
- /package/build/assets/{square-chevron-right-DE-JN-2Z.js → square-chevron-right-EizCGtgq.js} +0 -0
- /package/build/assets/{switch-skeleton-DqQwalyu.js → switch-skeleton-BjPRx1QD.js} +0 -0
- /package/build/assets/{terminal-Cgf___rK.js → terminal-a57bHgZs.js} +0 -0
- /package/build/assets/{trash-2-BU6BlW4i.js → trash-2-CF3hilrY.js} +0 -0
- /package/build/assets/{u-check-circle-BqoIxNz_.js → u-check-circle-WGqHdtfO.js} +0 -0
- /package/build/assets/{u-check-circle-half-MsShT8Ec.js → u-check-circle-half-LiwZkuFe.js} +0 -0
- /package/build/assets/{u-edit-DL5LgKon.js → u-edit-BwHepAPi.js} +0 -0
- /package/build/assets/{use-breakpoint-BP3lqLMx.js → use-breakpoint-B-O0lQ84.js} +0 -0
- /package/build/assets/{use-click-outside-element-D9BYdANT.js → use-click-outside-element-DLQIMQrz.js} +0 -0
- /package/build/assets/{use-is-authed-BezEyfeh.js → use-is-authed-BSeo4coy.js} +0 -0
- /package/build/assets/{use-onboarding-completion-C_Swglzp.js → use-onboarding-completion-C0hPNGpw.js} +0 -0
- /package/build/assets/{v4-DbCkTSoU.js → v4-q4yWTlMz.js} +0 -0
- /package/build/assets/{vendor~browser-By2MVv_N.js → vendor~browser-UwB1jbAZ.js} +0 -0
- /package/build/assets/{vendor~conversation-panel~conversation~alert-banner-CxfzCmkN.js → vendor~conversation-panel~conversation~alert-banner-DHDkknt5.js} +0 -0
- /package/build/assets/{vendor~index-home~home~conversation-panel~conversation-ChmYLVgz.js → vendor~index-home~home~conversation-panel~conversation-Bff9cq5J.js} +0 -0
- /package/build/assets/{vendor~module-D5a_AClf.js → vendor~module-D4DeFV4J.js} +0 -0
- /package/build/assets/{vendor~terminal-CnKZILnC.js → vendor~terminal-B7Eiak0-.js} +0 -0
- /package/build/assets/{x-ZE4iplpF.js → x-DQB_00VJ.js} +0 -0
- /package/build/assets/{x-mark-Batp6gXa.js → x-mark-B32XuEwS.js} +0 -0
|
@@ -5,119 +5,165 @@ import { retrieveAxiosErrorMessage as r } from "../utils/retrieve-axios-error-me
|
|
|
5
5
|
import { displayErrorToast as i, displaySuccessToast as a } from "../utils/custom-toast-handlers.js";
|
|
6
6
|
import { setTelemetryConsent as o } from "../services/telemetry.js";
|
|
7
7
|
import { DEFAULT_SETTINGS as s } from "../services/settings.js";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import g from "
|
|
17
|
-
import {
|
|
8
|
+
import { useLlmProfiles as c } from "../hooks/query/use-llm-profiles.js";
|
|
9
|
+
import { useSettings as l } from "../hooks/query/use-settings.js";
|
|
10
|
+
import { NavigationLink as u } from "../components/shared/navigation-link.js";
|
|
11
|
+
import { BrandButton as d } from "../components/features/settings/brand-button.js";
|
|
12
|
+
import { useSaveSettings as f } from "../hooks/mutation/use-save-settings.js";
|
|
13
|
+
import { SettingsSwitch as p } from "../components/features/settings/settings-switch.js";
|
|
14
|
+
import { SettingsInput as m } from "../components/features/settings/settings-input.js";
|
|
15
|
+
import { SettingsDropdownInput as h } from "../components/features/settings/settings-dropdown-input.js";
|
|
16
|
+
import { LanguageInput as g } from "../components/features/settings/app-settings/language-input.js";
|
|
17
|
+
import { ThemeInput as _ } from "../components/features/settings/app-settings/theme-input.js";
|
|
18
|
+
import { AppSettingsInputsSkeleton as v } from "../components/features/settings/app-settings/app-settings-inputs-skeleton.js";
|
|
19
|
+
import y from "react";
|
|
20
|
+
import { jsx as b, jsxs as x } from "react/jsx-runtime";
|
|
18
21
|
//#region src/routes/app-settings.tsx
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
var S = "__automatic__";
|
|
23
|
+
function C() {
|
|
24
|
+
let { t: C } = e("openhands"), { mutate: w, isPending: T } = f(), { data: E, isLoading: D } = l(), { data: O, isLoading: k } = c(), [A, j] = y.useState(!1), [M, N] = y.useState(!1), [P, F] = y.useState(!1), [I, L] = y.useState(!1), [R, z] = y.useState(!1), [B, V] = y.useState(void 0), H = y.useMemo(() => {
|
|
25
|
+
let e = E?.title_llm_profile ?? null;
|
|
26
|
+
return !e || !O || O.profiles.some((t) => t.name === e) ? e : null;
|
|
27
|
+
}, [O, E?.title_llm_profile]), U = B === void 0 ? H : B, W = y.useMemo(() => [{
|
|
28
|
+
key: S,
|
|
29
|
+
label: C(t.SETTINGS$TITLE_GENERATION_AUTOMATIC)
|
|
30
|
+
}, ...O?.profiles.map((e) => ({
|
|
31
|
+
key: e.name,
|
|
32
|
+
label: e.model ? C(t.SETTINGS$TITLE_GENERATION_PROFILE_OPTION, {
|
|
33
|
+
name: e.name,
|
|
34
|
+
model: e.model
|
|
35
|
+
}) : e.name
|
|
36
|
+
})) ?? []], [O?.profiles, C]), G = (e) => {
|
|
21
37
|
let c = e.get("language-input")?.toString(), l = n.find(({ label: e }) => e === c)?.value || s.language, u = e.get("enable-analytics-switch")?.toString() === "on";
|
|
22
|
-
|
|
38
|
+
w({
|
|
23
39
|
language: l,
|
|
24
40
|
user_consents_to_analytics: u,
|
|
25
41
|
enable_sound_notifications: e.get("enable-sound-notifications-switch")?.toString() === "on",
|
|
26
42
|
git_user_name: e.get("git-user-name-input")?.toString() || s.git_user_name,
|
|
27
|
-
git_user_email: e.get("git-user-email-input")?.toString() || s.git_user_email
|
|
43
|
+
git_user_email: e.get("git-user-email-input")?.toString() || s.git_user_email,
|
|
44
|
+
title_llm_profile: U
|
|
28
45
|
}, {
|
|
29
46
|
onSuccess: () => {
|
|
30
|
-
o(u ? "granted" : "denied"), a(
|
|
47
|
+
o(u ? "granted" : "denied"), a(C(t.SETTINGS$SAVED));
|
|
31
48
|
},
|
|
32
49
|
onError: (e) => {
|
|
33
|
-
i(r(e) ||
|
|
50
|
+
i(r(e) || C(t.ERROR$GENERIC));
|
|
34
51
|
},
|
|
35
52
|
onSettled: () => {
|
|
36
|
-
|
|
53
|
+
j(!1), N(!1), F(!1), L(!1), z(!1), V(void 0);
|
|
37
54
|
}
|
|
38
55
|
});
|
|
39
|
-
},
|
|
40
|
-
let t = n.find(({ label: t }) => t === e)?.label, r = n.find(({ value: e }) => e ===
|
|
41
|
-
|
|
42
|
-
},
|
|
43
|
-
|
|
44
|
-
},
|
|
45
|
-
|
|
46
|
-
},
|
|
47
|
-
let t =
|
|
48
|
-
|
|
49
|
-
},
|
|
50
|
-
let t =
|
|
51
|
-
|
|
52
|
-
},
|
|
53
|
-
return /* @__PURE__ */
|
|
56
|
+
}, K = (e) => {
|
|
57
|
+
let t = n.find(({ label: t }) => t === e)?.label, r = n.find(({ value: e }) => e === E?.language)?.label;
|
|
58
|
+
j(t !== r);
|
|
59
|
+
}, q = (e) => {
|
|
60
|
+
N(e !== (E?.user_consents_to_analytics ?? !0));
|
|
61
|
+
}, J = (e) => {
|
|
62
|
+
F(e !== !!E?.enable_sound_notifications);
|
|
63
|
+
}, Y = (e) => {
|
|
64
|
+
let t = E?.git_user_name;
|
|
65
|
+
L(e !== t);
|
|
66
|
+
}, X = (e) => {
|
|
67
|
+
let t = E?.git_user_email;
|
|
68
|
+
z(e !== t);
|
|
69
|
+
}, Z = !A && !M && !P && U === H && !I && !R, Q = !E || D || k || T;
|
|
70
|
+
return /* @__PURE__ */ x("form", {
|
|
54
71
|
"data-testid": "app-settings-screen",
|
|
55
|
-
action:
|
|
72
|
+
action: G,
|
|
56
73
|
className: "flex flex-col gap-6",
|
|
57
|
-
children: [
|
|
74
|
+
children: [Q && /* @__PURE__ */ b(v, {}), !Q && /* @__PURE__ */ x("div", {
|
|
58
75
|
className: "flex flex-col gap-6",
|
|
59
76
|
children: [
|
|
60
|
-
/* @__PURE__ */
|
|
77
|
+
/* @__PURE__ */ b(g, {
|
|
61
78
|
name: "language-input",
|
|
62
|
-
defaultKey:
|
|
63
|
-
onChange:
|
|
79
|
+
defaultKey: E.language,
|
|
80
|
+
onChange: K
|
|
64
81
|
}),
|
|
65
|
-
/* @__PURE__ */ _
|
|
66
|
-
/* @__PURE__ */
|
|
82
|
+
/* @__PURE__ */ b(_, {}),
|
|
83
|
+
/* @__PURE__ */ b(p, {
|
|
67
84
|
testId: "enable-analytics-switch",
|
|
68
85
|
name: "enable-analytics-switch",
|
|
69
|
-
defaultIsToggled:
|
|
70
|
-
onToggle:
|
|
71
|
-
children:
|
|
86
|
+
defaultIsToggled: E.user_consents_to_analytics ?? !0,
|
|
87
|
+
onToggle: q,
|
|
88
|
+
children: C(t.ANALYTICS$SEND_ANONYMOUS_DATA)
|
|
72
89
|
}),
|
|
73
|
-
/* @__PURE__ */
|
|
90
|
+
/* @__PURE__ */ b(p, {
|
|
74
91
|
testId: "enable-sound-notifications-switch",
|
|
75
92
|
name: "enable-sound-notifications-switch",
|
|
76
|
-
defaultIsToggled: !!
|
|
77
|
-
onToggle:
|
|
78
|
-
children:
|
|
93
|
+
defaultIsToggled: !!E.enable_sound_notifications,
|
|
94
|
+
onToggle: J,
|
|
95
|
+
children: C(t.SETTINGS$SOUND_NOTIFICATIONS)
|
|
79
96
|
}),
|
|
80
|
-
/* @__PURE__ */
|
|
97
|
+
/* @__PURE__ */ x("div", {
|
|
81
98
|
className: "border-t border-[var(--oh-border)] pt-6 mt-2",
|
|
82
99
|
children: [
|
|
83
|
-
/* @__PURE__ */
|
|
100
|
+
/* @__PURE__ */ b("h3", {
|
|
84
101
|
className: "text-lg font-medium mb-2",
|
|
85
|
-
children:
|
|
102
|
+
children: C(t.SETTINGS$CONVERSATION_TITLES)
|
|
86
103
|
}),
|
|
87
|
-
/* @__PURE__ */
|
|
104
|
+
/* @__PURE__ */ b("p", {
|
|
88
105
|
className: "mb-4 text-sm leading-5 text-tertiary-light",
|
|
89
|
-
children:
|
|
106
|
+
children: C(t.SETTINGS$TITLE_GENERATION_DESCRIPTION)
|
|
90
107
|
}),
|
|
91
|
-
/* @__PURE__ */
|
|
108
|
+
/* @__PURE__ */ b(h, {
|
|
109
|
+
testId: "title-llm-profile-input",
|
|
110
|
+
name: "title-llm-profile-input",
|
|
111
|
+
label: C(t.SETTINGS$TITLE_GENERATION_MODEL),
|
|
112
|
+
items: W,
|
|
113
|
+
selectedKey: U ?? S,
|
|
114
|
+
onSelectionChange: (e) => {
|
|
115
|
+
let t = e?.toString();
|
|
116
|
+
V(!t || t === S ? null : t);
|
|
117
|
+
}
|
|
118
|
+
}),
|
|
119
|
+
/* @__PURE__ */ b(u, {
|
|
120
|
+
to: "/settings/llm",
|
|
121
|
+
className: "mt-3 inline-block text-sm text-primary hover:underline",
|
|
122
|
+
children: C(t.SETTINGS$MANAGE_LLM_PROFILES)
|
|
123
|
+
})
|
|
124
|
+
]
|
|
125
|
+
}),
|
|
126
|
+
/* @__PURE__ */ x("div", {
|
|
127
|
+
className: "border-t border-[var(--oh-border)] pt-6 mt-2",
|
|
128
|
+
children: [
|
|
129
|
+
/* @__PURE__ */ b("h3", {
|
|
130
|
+
className: "text-lg font-medium mb-2",
|
|
131
|
+
children: C(t.SETTINGS$GIT_SETTINGS)
|
|
132
|
+
}),
|
|
133
|
+
/* @__PURE__ */ b("p", {
|
|
134
|
+
className: "mb-4 text-sm leading-5 text-tertiary-light",
|
|
135
|
+
children: C(t.SETTINGS$GIT_SETTINGS_DESCRIPTION)
|
|
136
|
+
}),
|
|
137
|
+
/* @__PURE__ */ x("div", {
|
|
92
138
|
className: "flex flex-col gap-6",
|
|
93
|
-
children: [/* @__PURE__ */
|
|
139
|
+
children: [/* @__PURE__ */ b(m, {
|
|
94
140
|
testId: "git-user-name-input",
|
|
95
141
|
name: "git-user-name-input",
|
|
96
142
|
type: "text",
|
|
97
|
-
label:
|
|
98
|
-
defaultValue:
|
|
99
|
-
onChange:
|
|
100
|
-
placeholder:
|
|
143
|
+
label: C(t.SETTINGS$GIT_USERNAME),
|
|
144
|
+
defaultValue: E.git_user_name || "",
|
|
145
|
+
onChange: Y,
|
|
146
|
+
placeholder: C(t.SETTINGS$GIT_USERNAME_PLACEHOLDER),
|
|
101
147
|
className: "w-full min-w-0"
|
|
102
|
-
}), /* @__PURE__ */
|
|
148
|
+
}), /* @__PURE__ */ b(m, {
|
|
103
149
|
testId: "git-user-email-input",
|
|
104
150
|
name: "git-user-email-input",
|
|
105
151
|
type: "email",
|
|
106
|
-
label:
|
|
107
|
-
defaultValue:
|
|
108
|
-
onChange:
|
|
109
|
-
placeholder:
|
|
152
|
+
label: C(t.SETTINGS$GIT_EMAIL),
|
|
153
|
+
defaultValue: E.git_user_email || "",
|
|
154
|
+
onChange: X,
|
|
155
|
+
placeholder: C(t.SETTINGS$GIT_EMAIL_PLACEHOLDER),
|
|
110
156
|
className: "w-full min-w-0"
|
|
111
157
|
})]
|
|
112
158
|
}),
|
|
113
|
-
/* @__PURE__ */
|
|
159
|
+
/* @__PURE__ */ b("div", {
|
|
114
160
|
className: "flex justify-start pt-4",
|
|
115
|
-
children: /* @__PURE__ */
|
|
161
|
+
children: /* @__PURE__ */ x(d, {
|
|
116
162
|
testId: "submit-button",
|
|
117
163
|
variant: "primary",
|
|
118
164
|
type: "submit",
|
|
119
|
-
isDisabled:
|
|
120
|
-
children: [!
|
|
165
|
+
isDisabled: T || Z,
|
|
166
|
+
children: [!T && C(t.SETTINGS$SAVE_CHANGES), T && C(t.SETTINGS$SAVING)]
|
|
121
167
|
})
|
|
122
168
|
})
|
|
123
169
|
]
|
|
@@ -127,6 +173,6 @@ function y() {
|
|
|
127
173
|
});
|
|
128
174
|
}
|
|
129
175
|
//#endregion
|
|
130
|
-
export {
|
|
176
|
+
export { C as default };
|
|
131
177
|
|
|
132
178
|
//# sourceMappingURL=app-settings.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-settings.js","names":[],"sources":["../../src/routes/app-settings.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { useSaveSettings } from \"#/hooks/mutation/use-save-settings\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { AvailableLanguages } from \"#/i18n\";\nimport { DEFAULT_SETTINGS } from \"#/services/settings\";\nimport { setTelemetryConsent } from \"#/services/telemetry\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { SettingsSwitch } from \"#/components/features/settings/settings-switch\";\nimport { SettingsInput } from \"#/components/features/settings/settings-input\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { LanguageInput } from \"#/components/features/settings/app-settings/language-input\";\nimport { ThemeInput } from \"#/components/features/settings/app-settings/theme-input\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport { AppSettingsInputsSkeleton } from \"#/components/features/settings/app-settings/app-settings-inputs-skeleton\";\n\nexport function AppSettingsScreen() {\n const { t } = useTranslation(\"openhands\");\n\n const { mutate: saveSettings, isPending } = useSaveSettings();\n const { data: settings, isLoading } = useSettings();\n\n const [languageInputHasChanged, setLanguageInputHasChanged] =\n React.useState(false);\n const [analyticsSwitchHasChanged, setAnalyticsSwitchHasChanged] =\n React.useState(false);\n const [\n soundNotificationsSwitchHasChanged,\n setSoundNotificationsSwitchHasChanged,\n ] = React.useState(false);\n const [gitUserNameHasChanged, setGitUserNameHasChanged] =\n React.useState(false);\n const [gitUserEmailHasChanged, setGitUserEmailHasChanged] =\n React.useState(false);\n\n const formAction = (formData: FormData) => {\n const languageLabel = formData.get(\"language-input\")?.toString();\n const languageValue = AvailableLanguages.find(\n ({ label }) => label === languageLabel,\n )?.value;\n const language = languageValue || DEFAULT_SETTINGS.language;\n\n const enableAnalytics =\n formData.get(\"enable-analytics-switch\")?.toString() === \"on\";\n const enableSoundNotifications =\n formData.get(\"enable-sound-notifications-switch\")?.toString() === \"on\";\n\n const gitUserName =\n formData.get(\"git-user-name-input\")?.toString() ||\n DEFAULT_SETTINGS.git_user_name;\n const gitUserEmail =\n formData.get(\"git-user-email-input\")?.toString() ||\n DEFAULT_SETTINGS.git_user_email;\n\n saveSettings(\n {\n language,\n user_consents_to_analytics: enableAnalytics,\n enable_sound_notifications: enableSoundNotifications,\n git_user_name: gitUserName,\n git_user_email: gitUserEmail,\n },\n {\n onSuccess: () => {\n void setTelemetryConsent(enableAnalytics ? \"granted\" : \"denied\");\n displaySuccessToast(t(I18nKey.SETTINGS$SAVED));\n },\n onError: (error) => {\n const errorMessage = retrieveAxiosErrorMessage(error);\n displayErrorToast(errorMessage || t(I18nKey.ERROR$GENERIC));\n },\n onSettled: () => {\n setLanguageInputHasChanged(false);\n setAnalyticsSwitchHasChanged(false);\n setSoundNotificationsSwitchHasChanged(false);\n setGitUserNameHasChanged(false);\n setGitUserEmailHasChanged(false);\n },\n },\n );\n };\n\n const checkIfLanguageInputHasChanged = (value: string) => {\n const selectedLanguage = AvailableLanguages.find(\n ({ label: langValue }) => langValue === value,\n )?.label;\n const currentLanguage = AvailableLanguages.find(\n ({ value: langValue }) => langValue === settings?.language,\n )?.label;\n\n setLanguageInputHasChanged(selectedLanguage !== currentLanguage);\n };\n\n const checkIfAnalyticsSwitchHasChanged = (checked: boolean) => {\n // Treat null as true since analytics is opt-in by default\n const currentAnalytics = settings?.user_consents_to_analytics ?? true;\n setAnalyticsSwitchHasChanged(checked !== currentAnalytics);\n };\n\n const checkIfSoundNotificationsSwitchHasChanged = (checked: boolean) => {\n const currentSoundNotifications = !!settings?.enable_sound_notifications;\n setSoundNotificationsSwitchHasChanged(\n checked !== currentSoundNotifications,\n );\n };\n\n const checkIfGitUserNameHasChanged = (value: string) => {\n const currentValue = settings?.git_user_name;\n setGitUserNameHasChanged(value !== currentValue);\n };\n\n const checkIfGitUserEmailHasChanged = (value: string) => {\n const currentValue = settings?.git_user_email;\n setGitUserEmailHasChanged(value !== currentValue);\n };\n\n const formIsClean =\n !languageInputHasChanged &&\n !analyticsSwitchHasChanged &&\n !soundNotificationsSwitchHasChanged &&\n !gitUserNameHasChanged &&\n !gitUserEmailHasChanged;\n\n const shouldBeLoading = !settings || isLoading || isPending;\n\n return (\n <form\n data-testid=\"app-settings-screen\"\n action={formAction}\n className=\"flex flex-col gap-6\"\n >\n {shouldBeLoading && <AppSettingsInputsSkeleton />}\n {!shouldBeLoading && (\n <div className=\"flex flex-col gap-6\">\n <LanguageInput\n name=\"language-input\"\n defaultKey={settings.language}\n onChange={checkIfLanguageInputHasChanged}\n />\n\n <ThemeInput />\n\n <SettingsSwitch\n testId=\"enable-analytics-switch\"\n name=\"enable-analytics-switch\"\n defaultIsToggled={settings.user_consents_to_analytics ?? true}\n onToggle={checkIfAnalyticsSwitchHasChanged}\n >\n {t(I18nKey.ANALYTICS$SEND_ANONYMOUS_DATA)}\n </SettingsSwitch>\n\n <SettingsSwitch\n testId=\"enable-sound-notifications-switch\"\n name=\"enable-sound-notifications-switch\"\n defaultIsToggled={!!settings.enable_sound_notifications}\n onToggle={checkIfSoundNotificationsSwitchHasChanged}\n >\n {t(I18nKey.SETTINGS$SOUND_NOTIFICATIONS)}\n </SettingsSwitch>\n\n <div className=\"border-t border-[var(--oh-border)] pt-6 mt-2\">\n <h3 className=\"text-lg font-medium mb-2\">\n {t(I18nKey.SETTINGS$GIT_SETTINGS)}\n </h3>\n <p className=\"mb-4 text-sm leading-5 text-tertiary-light\">\n {t(I18nKey.SETTINGS$GIT_SETTINGS_DESCRIPTION)}\n </p>\n <div className=\"flex flex-col gap-6\">\n <SettingsInput\n testId=\"git-user-name-input\"\n name=\"git-user-name-input\"\n type=\"text\"\n label={t(I18nKey.SETTINGS$GIT_USERNAME)}\n defaultValue={settings.git_user_name || \"\"}\n onChange={checkIfGitUserNameHasChanged}\n placeholder={t(I18nKey.SETTINGS$GIT_USERNAME_PLACEHOLDER)}\n className=\"w-full min-w-0\"\n />\n <SettingsInput\n testId=\"git-user-email-input\"\n name=\"git-user-email-input\"\n type=\"email\"\n label={t(I18nKey.SETTINGS$GIT_EMAIL)}\n defaultValue={settings.git_user_email || \"\"}\n onChange={checkIfGitUserEmailHasChanged}\n placeholder={t(I18nKey.SETTINGS$GIT_EMAIL_PLACEHOLDER)}\n className=\"w-full min-w-0\"\n />\n </div>\n <div className=\"flex justify-start pt-4\">\n <BrandButton\n testId=\"submit-button\"\n variant=\"primary\"\n type=\"submit\"\n isDisabled={isPending || formIsClean}\n >\n {!isPending && t(I18nKey.SETTINGS$SAVE_CHANGES)}\n {isPending && t(I18nKey.SETTINGS$SAVING)}\n </BrandButton>\n </div>\n </div>\n </div>\n )}\n </form>\n );\n}\n\nexport default AppSettingsScreen;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"app-settings.js","names":[],"sources":["../../src/routes/app-settings.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { useSaveSettings } from \"#/hooks/mutation/use-save-settings\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { AvailableLanguages } from \"#/i18n\";\nimport { DEFAULT_SETTINGS } from \"#/services/settings\";\nimport { setTelemetryConsent } from \"#/services/telemetry\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { SettingsSwitch } from \"#/components/features/settings/settings-switch\";\nimport { SettingsInput } from \"#/components/features/settings/settings-input\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { LanguageInput } from \"#/components/features/settings/app-settings/language-input\";\nimport { ThemeInput } from \"#/components/features/settings/app-settings/theme-input\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport { AppSettingsInputsSkeleton } from \"#/components/features/settings/app-settings/app-settings-inputs-skeleton\";\nimport { SettingsDropdownInput } from \"#/components/features/settings/settings-dropdown-input\";\nimport { NavigationLink } from \"#/components/shared/navigation-link\";\nimport { useLlmProfiles } from \"#/hooks/query/use-llm-profiles\";\n\nconst AUTOMATIC_TITLE_LLM_PROFILE_KEY = \"__automatic__\";\n\nexport function AppSettingsScreen() {\n const { t } = useTranslation(\"openhands\");\n\n const { mutate: saveSettings, isPending } = useSaveSettings();\n const { data: settings, isLoading } = useSettings();\n const { data: llmProfiles, isLoading: areLlmProfilesLoading } =\n useLlmProfiles();\n\n const [languageInputHasChanged, setLanguageInputHasChanged] =\n React.useState(false);\n const [analyticsSwitchHasChanged, setAnalyticsSwitchHasChanged] =\n React.useState(false);\n const [\n soundNotificationsSwitchHasChanged,\n setSoundNotificationsSwitchHasChanged,\n ] = React.useState(false);\n const [gitUserNameHasChanged, setGitUserNameHasChanged] =\n React.useState(false);\n const [gitUserEmailHasChanged, setGitUserEmailHasChanged] =\n React.useState(false);\n const [titleLlmProfileInput, setTitleLlmProfileInput] = React.useState<\n string | null | undefined\n >(undefined);\n\n const storedTitleLlmProfile = React.useMemo(() => {\n const preference = settings?.title_llm_profile ?? null;\n if (!preference || !llmProfiles) return preference;\n return llmProfiles.profiles.some((profile) => profile.name === preference)\n ? preference\n : null;\n }, [llmProfiles, settings?.title_llm_profile]);\n const selectedTitleLlmProfile =\n titleLlmProfileInput === undefined\n ? storedTitleLlmProfile\n : titleLlmProfileInput;\n const titleLlmProfileItems = React.useMemo(\n () => [\n {\n key: AUTOMATIC_TITLE_LLM_PROFILE_KEY,\n label: t(I18nKey.SETTINGS$TITLE_GENERATION_AUTOMATIC),\n },\n ...(llmProfiles?.profiles.map((profile) => ({\n key: profile.name,\n label: profile.model\n ? t(I18nKey.SETTINGS$TITLE_GENERATION_PROFILE_OPTION, {\n name: profile.name,\n model: profile.model,\n })\n : profile.name,\n })) ?? []),\n ],\n [llmProfiles?.profiles, t],\n );\n\n const formAction = (formData: FormData) => {\n const languageLabel = formData.get(\"language-input\")?.toString();\n const languageValue = AvailableLanguages.find(\n ({ label }) => label === languageLabel,\n )?.value;\n const language = languageValue || DEFAULT_SETTINGS.language;\n\n const enableAnalytics =\n formData.get(\"enable-analytics-switch\")?.toString() === \"on\";\n const enableSoundNotifications =\n formData.get(\"enable-sound-notifications-switch\")?.toString() === \"on\";\n\n const gitUserName =\n formData.get(\"git-user-name-input\")?.toString() ||\n DEFAULT_SETTINGS.git_user_name;\n const gitUserEmail =\n formData.get(\"git-user-email-input\")?.toString() ||\n DEFAULT_SETTINGS.git_user_email;\n\n saveSettings(\n {\n language,\n user_consents_to_analytics: enableAnalytics,\n enable_sound_notifications: enableSoundNotifications,\n git_user_name: gitUserName,\n git_user_email: gitUserEmail,\n title_llm_profile: selectedTitleLlmProfile,\n },\n {\n onSuccess: () => {\n void setTelemetryConsent(enableAnalytics ? \"granted\" : \"denied\");\n displaySuccessToast(t(I18nKey.SETTINGS$SAVED));\n },\n onError: (error) => {\n const errorMessage = retrieveAxiosErrorMessage(error);\n displayErrorToast(errorMessage || t(I18nKey.ERROR$GENERIC));\n },\n onSettled: () => {\n setLanguageInputHasChanged(false);\n setAnalyticsSwitchHasChanged(false);\n setSoundNotificationsSwitchHasChanged(false);\n setGitUserNameHasChanged(false);\n setGitUserEmailHasChanged(false);\n setTitleLlmProfileInput(undefined);\n },\n },\n );\n };\n\n const checkIfLanguageInputHasChanged = (value: string) => {\n const selectedLanguage = AvailableLanguages.find(\n ({ label: langValue }) => langValue === value,\n )?.label;\n const currentLanguage = AvailableLanguages.find(\n ({ value: langValue }) => langValue === settings?.language,\n )?.label;\n\n setLanguageInputHasChanged(selectedLanguage !== currentLanguage);\n };\n\n const checkIfAnalyticsSwitchHasChanged = (checked: boolean) => {\n // Treat null as true since analytics is opt-in by default\n const currentAnalytics = settings?.user_consents_to_analytics ?? true;\n setAnalyticsSwitchHasChanged(checked !== currentAnalytics);\n };\n\n const checkIfSoundNotificationsSwitchHasChanged = (checked: boolean) => {\n const currentSoundNotifications = !!settings?.enable_sound_notifications;\n setSoundNotificationsSwitchHasChanged(\n checked !== currentSoundNotifications,\n );\n };\n\n const checkIfGitUserNameHasChanged = (value: string) => {\n const currentValue = settings?.git_user_name;\n setGitUserNameHasChanged(value !== currentValue);\n };\n\n const checkIfGitUserEmailHasChanged = (value: string) => {\n const currentValue = settings?.git_user_email;\n setGitUserEmailHasChanged(value !== currentValue);\n };\n\n const formIsClean =\n !languageInputHasChanged &&\n !analyticsSwitchHasChanged &&\n !soundNotificationsSwitchHasChanged &&\n selectedTitleLlmProfile === storedTitleLlmProfile &&\n !gitUserNameHasChanged &&\n !gitUserEmailHasChanged;\n\n const shouldBeLoading =\n !settings || isLoading || areLlmProfilesLoading || isPending;\n\n return (\n <form\n data-testid=\"app-settings-screen\"\n action={formAction}\n className=\"flex flex-col gap-6\"\n >\n {shouldBeLoading && <AppSettingsInputsSkeleton />}\n {!shouldBeLoading && (\n <div className=\"flex flex-col gap-6\">\n <LanguageInput\n name=\"language-input\"\n defaultKey={settings.language}\n onChange={checkIfLanguageInputHasChanged}\n />\n\n <ThemeInput />\n\n <SettingsSwitch\n testId=\"enable-analytics-switch\"\n name=\"enable-analytics-switch\"\n defaultIsToggled={settings.user_consents_to_analytics ?? true}\n onToggle={checkIfAnalyticsSwitchHasChanged}\n >\n {t(I18nKey.ANALYTICS$SEND_ANONYMOUS_DATA)}\n </SettingsSwitch>\n\n <SettingsSwitch\n testId=\"enable-sound-notifications-switch\"\n name=\"enable-sound-notifications-switch\"\n defaultIsToggled={!!settings.enable_sound_notifications}\n onToggle={checkIfSoundNotificationsSwitchHasChanged}\n >\n {t(I18nKey.SETTINGS$SOUND_NOTIFICATIONS)}\n </SettingsSwitch>\n\n <div className=\"border-t border-[var(--oh-border)] pt-6 mt-2\">\n <h3 className=\"text-lg font-medium mb-2\">\n {t(I18nKey.SETTINGS$CONVERSATION_TITLES)}\n </h3>\n <p className=\"mb-4 text-sm leading-5 text-tertiary-light\">\n {t(I18nKey.SETTINGS$TITLE_GENERATION_DESCRIPTION)}\n </p>\n <SettingsDropdownInput\n testId=\"title-llm-profile-input\"\n name=\"title-llm-profile-input\"\n label={t(I18nKey.SETTINGS$TITLE_GENERATION_MODEL)}\n items={titleLlmProfileItems}\n selectedKey={\n selectedTitleLlmProfile ?? AUTOMATIC_TITLE_LLM_PROFILE_KEY\n }\n onSelectionChange={(key) => {\n const value = key?.toString();\n setTitleLlmProfileInput(\n !value || value === AUTOMATIC_TITLE_LLM_PROFILE_KEY\n ? null\n : value,\n );\n }}\n />\n <NavigationLink\n to=\"/settings/llm\"\n className=\"mt-3 inline-block text-sm text-primary hover:underline\"\n >\n {t(I18nKey.SETTINGS$MANAGE_LLM_PROFILES)}\n </NavigationLink>\n </div>\n\n <div className=\"border-t border-[var(--oh-border)] pt-6 mt-2\">\n <h3 className=\"text-lg font-medium mb-2\">\n {t(I18nKey.SETTINGS$GIT_SETTINGS)}\n </h3>\n <p className=\"mb-4 text-sm leading-5 text-tertiary-light\">\n {t(I18nKey.SETTINGS$GIT_SETTINGS_DESCRIPTION)}\n </p>\n <div className=\"flex flex-col gap-6\">\n <SettingsInput\n testId=\"git-user-name-input\"\n name=\"git-user-name-input\"\n type=\"text\"\n label={t(I18nKey.SETTINGS$GIT_USERNAME)}\n defaultValue={settings.git_user_name || \"\"}\n onChange={checkIfGitUserNameHasChanged}\n placeholder={t(I18nKey.SETTINGS$GIT_USERNAME_PLACEHOLDER)}\n className=\"w-full min-w-0\"\n />\n <SettingsInput\n testId=\"git-user-email-input\"\n name=\"git-user-email-input\"\n type=\"email\"\n label={t(I18nKey.SETTINGS$GIT_EMAIL)}\n defaultValue={settings.git_user_email || \"\"}\n onChange={checkIfGitUserEmailHasChanged}\n placeholder={t(I18nKey.SETTINGS$GIT_EMAIL_PLACEHOLDER)}\n className=\"w-full min-w-0\"\n />\n </div>\n <div className=\"flex justify-start pt-4\">\n <BrandButton\n testId=\"submit-button\"\n variant=\"primary\"\n type=\"submit\"\n isDisabled={isPending || formIsClean}\n >\n {!isPending && t(I18nKey.SETTINGS$SAVE_CHANGES)}\n {isPending && t(I18nKey.SETTINGS$SAVING)}\n </BrandButton>\n </div>\n </div>\n </div>\n )}\n </form>\n );\n}\n\nexport default AppSettingsScreen;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAuBA,IAAM,IAAkC;AAExC,SAAgB,IAAoB;CAClC,IAAM,EAAE,SAAM,EAAe,YAAY,EAEnC,EAAE,QAAQ,GAAc,iBAAc,GAAiB,EACvD,EAAE,MAAM,GAAU,iBAAc,GAAa,EAC7C,EAAE,MAAM,GAAa,WAAW,MACpC,GAAgB,EAEZ,CAAC,GAAyB,KAC9B,EAAM,SAAS,GAAM,EACjB,CAAC,GAA2B,KAChC,EAAM,SAAS,GAAM,EACjB,CACJ,GACA,KACE,EAAM,SAAS,GAAM,EACnB,CAAC,GAAuB,KAC5B,EAAM,SAAS,GAAM,EACjB,CAAC,GAAwB,KAC7B,EAAM,SAAS,GAAM,EACjB,CAAC,GAAsB,KAA2B,EAAM,SAE5D,KAAA,EAAU,EAEN,IAAwB,EAAM,cAAc;EAChD,IAAM,IAAa,GAAU,qBAAqB;AAElD,SADI,CAAC,KAAc,CAAC,KACb,EAAY,SAAS,MAAM,MAAY,EAAQ,SAAS,EAAW,GADlC,IAGpC;IACH,CAAC,GAAa,GAAU,kBAAkB,CAAC,EACxC,IACJ,MAAyB,KAAA,IACrB,IACA,GACA,IAAuB,EAAM,cAC3B,CACJ;EACE,KAAK;EACL,OAAO,EAAE,EAAQ,oCAAoC;EACtD,EACD,GAAI,GAAa,SAAS,KAAK,OAAa;EAC1C,KAAK,EAAQ;EACb,OAAO,EAAQ,QACX,EAAE,EAAQ,0CAA0C;GAClD,MAAM,EAAQ;GACd,OAAO,EAAQ;GAChB,CAAC,GACF,EAAQ;EACb,EAAE,IAAI,EAAE,CACV,EACD,CAAC,GAAa,UAAU,EAAE,CAC3B,EAEK,KAAc,MAAuB;EACzC,IAAM,IAAgB,EAAS,IAAI,iBAAiB,EAAE,UAAU,EAI1D,IAHgB,EAAmB,MACtC,EAAE,eAAY,MAAU,EAC1B,EAAE,SAC+B,EAAiB,UAE7C,IACJ,EAAS,IAAI,0BAA0B,EAAE,UAAU,KAAK;AAW1D,IACE;GACE;GACA,4BAA4B;GAC5B,4BAbF,EAAS,IAAI,oCAAoC,EAAE,UAAU,KAAK;GAchE,eAXF,EAAS,IAAI,sBAAsB,EAAE,UAAU,IAC/C,EAAiB;GAWf,gBATF,EAAS,IAAI,uBAAuB,EAAE,UAAU,IAChD,EAAiB;GASf,mBAAmB;GACpB,EACD;GACE,iBAAiB;AAEf,IADK,EAAoB,IAAkB,YAAY,SAAS,EAChE,EAAoB,EAAE,EAAQ,eAAe,CAAC;;GAEhD,UAAU,MAAU;AAElB,MADqB,EAA0B,EAC7B,IAAgB,EAAE,EAAQ,cAAc,CAAC;;GAE7D,iBAAiB;AAMf,IALA,EAA2B,GAAM,EACjC,EAA6B,GAAM,EACnC,EAAsC,GAAM,EAC5C,EAAyB,GAAM,EAC/B,EAA0B,GAAM,EAChC,EAAwB,KAAA,EAAU;;GAErC,CACF;IAGG,KAAkC,MAAkB;EACxD,IAAM,IAAmB,EAAmB,MACzC,EAAE,OAAO,QAAgB,MAAc,EACzC,EAAE,OACG,IAAkB,EAAmB,MACxC,EAAE,OAAO,QAAgB,MAAc,GAAU,SACnD,EAAE;AAEH,IAA2B,MAAqB,EAAgB;IAG5D,KAAoC,MAAqB;AAG7D,IAA6B,OADJ,GAAU,8BAA8B,IACP;IAGtD,KAA6C,MAAqB;AAEtE,IACE,MAAY,CAFqB,CAAC,GAAU,2BAG7C;IAGG,KAAgC,MAAkB;EACtD,IAAM,IAAe,GAAU;AAC/B,IAAyB,MAAU,EAAa;IAG5C,KAAiC,MAAkB;EACvD,IAAM,IAAe,GAAU;AAC/B,IAA0B,MAAU,EAAa;IAG7C,IACJ,CAAC,KACD,CAAC,KACD,CAAC,KACD,MAA4B,KAC5B,CAAC,KACD,CAAC,GAEG,IACJ,CAAC,KAAY,KAAa,KAAyB;AAErD,QACE,kBAAC,QAAD;EACE,eAAY;EACZ,QAAQ;EACR,WAAU;YAHZ,CAKG,KAAmB,kBAAC,GAAD,EAA6B,CAAA,EAChD,CAAC,KACA,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,GAAD;KACE,MAAK;KACL,YAAY,EAAS;KACrB,UAAU;KACV,CAAA;IAEF,kBAAC,GAAD,EAAc,CAAA;IAEd,kBAAC,GAAD;KACE,QAAO;KACP,MAAK;KACL,kBAAkB,EAAS,8BAA8B;KACzD,UAAU;eAET,EAAE,EAAQ,8BAA8B;KAC1B,CAAA;IAEjB,kBAAC,GAAD;KACE,QAAO;KACP,MAAK;KACL,kBAAkB,CAAC,CAAC,EAAS;KAC7B,UAAU;eAET,EAAE,EAAQ,6BAA6B;KACzB,CAAA;IAEjB,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAE,EAAQ,6BAA6B;OACrC,CAAA;MACL,kBAAC,KAAD;OAAG,WAAU;iBACV,EAAE,EAAQ,sCAAsC;OAC/C,CAAA;MACJ,kBAAC,GAAD;OACE,QAAO;OACP,MAAK;OACL,OAAO,EAAE,EAAQ,gCAAgC;OACjD,OAAO;OACP,aACE,KAA2B;OAE7B,oBAAoB,MAAQ;QAC1B,IAAM,IAAQ,GAAK,UAAU;AAC7B,UACE,CAAC,KAAS,MAAU,IAChB,OACA,EACL;;OAEH,CAAA;MACF,kBAAC,GAAD;OACE,IAAG;OACH,WAAU;iBAET,EAAE,EAAQ,6BAA6B;OACzB,CAAA;MACb;;IAEN,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAE,EAAQ,sBAAsB;OAC9B,CAAA;MACL,kBAAC,KAAD;OAAG,WAAU;iBACV,EAAE,EAAQ,kCAAkC;OAC3C,CAAA;MACJ,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QACE,QAAO;QACP,MAAK;QACL,MAAK;QACL,OAAO,EAAE,EAAQ,sBAAsB;QACvC,cAAc,EAAS,iBAAiB;QACxC,UAAU;QACV,aAAa,EAAE,EAAQ,kCAAkC;QACzD,WAAU;QACV,CAAA,EACF,kBAAC,GAAD;QACE,QAAO;QACP,MAAK;QACL,MAAK;QACL,OAAO,EAAE,EAAQ,mBAAmB;QACpC,cAAc,EAAS,kBAAkB;QACzC,UAAU;QACV,aAAa,EAAE,EAAQ,+BAA+B;QACtD,WAAU;QACV,CAAA,CACE;;MACN,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,GAAD;QACE,QAAO;QACP,SAAQ;QACR,MAAK;QACL,YAAY,KAAa;kBAJ3B,CAMG,CAAC,KAAa,EAAE,EAAQ,sBAAsB,EAC9C,KAAa,EAAE,EAAQ,gBAAgB,CAC5B;;OACV,CAAA;MACF;;IACF;KAEH"}
|
|
@@ -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(`../types/agent-state.cjs`),i=require(`../hooks/use-conversation-id.cjs`),a=require(`../stores/command-store.cjs`),o=require(`../stores/conversation-store.cjs`),s=require(`../stores/agent-store.cjs`),c=require(`../stores/conversation-state-store.cjs`),l=require(`../utils/custom-toast-handlers.cjs`),u=require(`../contexts/active-backend-context.cjs`),d=require(`../api/backend-registry/last-conversation-store.cjs`),f=require(`../stores/error-message-store.cjs`),p=require(`../api/cloud/conversation-service.api.cjs`),m=require(`../hooks/query/use-active-conversation.cjs`),h=require(`../wrapper/event-handler.cjs`),g=require(`../hooks/query/use-task-polling.cjs`),_=require(`../hooks/query/use-is-authed.cjs`),v=require(`../components/features/conversation/conversation-main/conversation-main.cjs`),y=require(`../components/features/conversation/conversation-main/conversation-mobile-panel-page.cjs`),b=require(`../contexts/websocket-provider-wrapper.cjs`);let x=require(`react`);x=e.__toESM(x,1);let S=require(`react/jsx-runtime`),C=require(`react-router`);function w(){let{t:e}=t.useTranslation(`openhands`),{conversationId:w}=i.useConversationId(),T=(0,C.useMatch)(`/conversations/:conversationId/panel`),{isTask:E,taskStatus:D,taskDetail:O}=g.
|
|
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(`../types/agent-state.cjs`),i=require(`../hooks/use-conversation-id.cjs`),a=require(`../stores/command-store.cjs`),o=require(`../stores/conversation-store.cjs`),s=require(`../stores/agent-store.cjs`),c=require(`../stores/conversation-state-store.cjs`),l=require(`../utils/custom-toast-handlers.cjs`),u=require(`../contexts/active-backend-context.cjs`),d=require(`../api/backend-registry/last-conversation-store.cjs`),f=require(`../stores/error-message-store.cjs`),p=require(`../api/cloud/conversation-service.api.cjs`),m=require(`../hooks/query/use-active-conversation.cjs`),h=require(`../wrapper/event-handler.cjs`),g=require(`../hooks/query/use-task-polling.cjs`),_=require(`../hooks/query/use-is-authed.cjs`),v=require(`../components/features/conversation/conversation-main/conversation-main.cjs`),y=require(`../components/features/conversation/conversation-main/conversation-mobile-panel-page.cjs`),b=require(`../contexts/websocket-provider-wrapper.cjs`);let x=require(`react`);x=e.__toESM(x,1);let S=require(`react/jsx-runtime`),C=require(`react-router`);function w(){let{t:e}=t.useTranslation(`openhands`),{conversationId:w}=i.useConversationId(),T=(0,C.useMatch)(`/conversations/:conversationId/panel`),{isTask:E,taskStatus:D,taskDetail:O}=g.useTaskPollingController(),k=u.useActiveBackend(),A=x.default.useRef(k.backend.id),j=x.default.useRef(k.orgId),M=A.current!==k.backend.id||j.current!==k.orgId,{data:N,isFetched:P}=m.useActiveConversation(),{data:F}=_.useIsAuthed(),{resetConversationState:I}=o.useConversationStore(),L=(0,C.useNavigate)(),R=(0,C.useLocation)(),z=a.useCommandStore(e=>e.clearTerminal),B=c.useConversationStateStore(e=>e.reset),V=s.useAgentStore(e=>e.setCurrentAgentState),H=f.useErrorMessageStore(e=>e.removeErrorMessage);x.default.useEffect(()=>{z(),I(),B(),V(r.AgentState.LOADING),H()},[w,z,I,B,V,H]),x.default.useEffect(()=>{if(E&&D===`ERROR`){l.displayErrorToast(O||e(n.I18nKey.CONVERSATION$FAILED_TO_START_FROM_TASK));let t=R.state?.resumedFromConversationId;L(t?`/conversations/${t}`:`/conversations`,{replace:!0})}},[E,D,O,e,L,R.state]),x.default.useEffect(()=>{!P||!F||M||N||(d.clearLastConversationId(k.backend.id,k.orgId),l.displayErrorToast(e(n.I18nKey.CONVERSATION$NOT_EXIST_OR_NO_PERMISSION)),L(`/conversations`))},[N,P,F,L,e,M,k.backend.id,k.orgId]),x.default.useEffect(()=>{M||w&&(w.startsWith(`task-`)||d.setLastConversationId(k.backend.id,k.orgId,w))},[w,M,k.backend.id,k.orgId]);let U=x.default.useRef(null);return x.default.useEffect(()=>{!P||!N||k.backend.kind===`cloud`&&N.sandbox_status===`PAUSED`&&N.sandbox_id&&U.current!==N.id&&(U.current=N.id,p.resumeCloudSandbox(N.sandbox_id).catch(()=>{l.displayErrorToast(e(n.I18nKey.CONVERSATION$FAILED_TO_START_FROM_TASK))}))},[P,N?.id,N?.sandbox_status,N?.sandbox_id,k.backend.kind,e]),M?null:(0,S.jsx)(b.WebSocketProviderWrapper,{conversationId:w,children:(0,S.jsx)(h.EventHandler,{children:(0,S.jsx)(`div`,{"data-testid":`app-route`,className:`flex h-full flex-col`,children:T?(0,S.jsx)(y.ConversationMobilePanelPage,{onNavigateBack:()=>L(`/conversations/${w}`)}):(0,S.jsx)(v.ConversationMain,{})})})})}function T(){return(0,S.jsx)(w,{})}exports.default=T;
|
|
2
2
|
//# sourceMappingURL=conversation.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation.cjs","names":[],"sources":["../../src/routes/conversation.tsx"],"sourcesContent":["import React from \"react\";\nimport { useNavigate, useLocation, useMatch } from \"react-router\";\nimport { useTranslation } from \"react-i18next\";\n\nimport { useConversationId } from \"#/hooks/use-conversation-id\";\nimport { useCommandStore } from \"#/stores/command-store\";\nimport { useConversationStore } from \"#/stores/conversation-store\";\nimport { useAgentStore } from \"#/stores/agent-store\";\nimport { useConversationStateStore } from \"#/stores/conversation-state-store\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport {\n clearLastConversationId,\n setLastConversationId,\n} from \"#/api/backend-registry/last-conversation-store\";\nimport { AgentState } from \"#/types/agent-state\";\n\nimport { EventHandler } from \"../wrapper/event-handler\";\n\nimport { useActiveConversation } from \"#/hooks/query/use-active-conversation\";\nimport { useTaskPolling } from \"#/hooks/query/use-task-polling\";\n\nimport { displayErrorToast } from \"#/utils/custom-toast-handlers\";\nimport { useIsAuthed } from \"#/hooks/query/use-is-authed\";\nimport { ConversationMain } from \"#/components/features/conversation/conversation-main/conversation-main\";\nimport { ConversationMobilePanelPage } from \"#/components/features/conversation/conversation-main/conversation-mobile-panel-page\";\n\nimport { WebSocketProviderWrapper } from \"#/contexts/websocket-provider-wrapper\";\nimport { useErrorMessageStore } from \"#/stores/error-message-store\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { resumeCloudSandbox } from \"#/api/cloud/conversation-service.api\";\n\nfunction AppContent() {\n const { t } = useTranslation(\"openhands\");\n const { conversationId } = useConversationId();\n const panelViewMatch = useMatch(\"/conversations/:conversationId/panel\");\n\n const { isTask, taskStatus, taskDetail } = useTaskPolling();\n\n // The conversationId in the URL belongs to whichever backend was\n // active when the route first mounted. If the user switches backends\n // while this route is still mounted, the id is meaningless under the\n // new backend — disable the active-conversation fetch (and its 404\n // toast) so we don't fire a request that the BackendSelector's\n // redirect will immediately navigate away from anyway. Mirrors the\n // same guard in `routes/automation-detail.tsx`.\n const active = useActiveBackend();\n const mountedBackendId = React.useRef(active.backend.id);\n const mountedOrgId = React.useRef(active.orgId);\n const backendChanged =\n mountedBackendId.current !== active.backend.id ||\n mountedOrgId.current !== active.orgId;\n\n const { data: conversation, isFetched } = useActiveConversation();\n const { data: isAuthed } = useIsAuthed();\n const { resetConversationState } = useConversationStore();\n const navigate = useNavigate();\n const location = useLocation();\n const clearTerminal = useCommandStore((state) => state.clearTerminal);\n const resetConversationRuntimeState = useConversationStateStore(\n (state) => state.reset,\n );\n const setCurrentAgentState = useAgentStore(\n (state) => state.setCurrentAgentState,\n );\n const removeErrorMessage = useErrorMessageStore(\n (state) => state.removeErrorMessage,\n );\n\n // Per-conversation UI/runtime resets. The event store is cleared separately,\n // inside ConversationWebSocketProvider, so the clear is ordered *before* the\n // preloaded-history re-seed (see the note there) — clearing it here would run\n // too late and wipe the freshly seeded history on a conversation switch.\n React.useEffect(() => {\n clearTerminal();\n resetConversationState();\n resetConversationRuntimeState();\n setCurrentAgentState(AgentState.LOADING);\n removeErrorMessage();\n }, [\n conversationId,\n clearTerminal,\n resetConversationState,\n resetConversationRuntimeState,\n setCurrentAgentState,\n removeErrorMessage,\n ]);\n\n React.useEffect(() => {\n if (isTask && taskStatus === \"ERROR\") {\n displayErrorToast(\n taskDetail || t(I18nKey.CONVERSATION$FAILED_TO_START_FROM_TASK),\n );\n // Navigate back to the original conversation when a resume task fails so\n // the user isn't stranded at the dead task-{id} URL. The resume effect's\n // ref prevents it from immediately retrying once we land there.\n const resumedFrom = (location.state as Record<string, unknown> | null)\n ?.resumedFromConversationId as string | undefined;\n navigate(\n resumedFrom ? `/conversations/${resumedFrom}` : \"/conversations\",\n { replace: true },\n );\n }\n }, [isTask, taskStatus, taskDetail, t, navigate, location.state]);\n\n React.useEffect(() => {\n if (!isFetched || !isAuthed) return;\n // The BackendSelector is in the middle of redirecting us away from\n // this route — don't toast/navigate based on a 404 that's just\n // \"this id doesn't exist on the new backend\".\n if (backendChanged) return;\n\n if (!conversation) {\n // Clear the per-backend \"last selected\" slot so the next switch\n // to this backend doesn't try to revisit a stale id.\n clearLastConversationId(active.backend.id, active.orgId);\n displayErrorToast(t(I18nKey.CONVERSATION$NOT_EXIST_OR_NO_PERMISSION));\n navigate(\"/conversations\");\n }\n }, [\n conversation,\n isFetched,\n isAuthed,\n navigate,\n t,\n backendChanged,\n active.backend.id,\n active.orgId,\n ]);\n\n // Remember the most recently selected conversation for the current\n // (backend, org) so flipping back to this backend later restores the\n // user to where they left off. Skip while a backend switch is in\n // flight: the id in the URL is from the previous backend and would\n // otherwise overwrite the new backend's memory.\n React.useEffect(() => {\n if (backendChanged) return;\n if (!conversationId) return;\n if (conversationId.startsWith(\"task-\")) return;\n setLastConversationId(active.backend.id, active.orgId, conversationId);\n }, [conversationId, backendChanged, active.backend.id, active.orgId]);\n\n // Cloud conversation resume: mirrors OpenHands' useSandboxRecovery.\n //\n // When the cloud API reports sandbox_status === \"PAUSED\" the sandbox is\n // sleeping. The correct wake-up call is POST /api/v1/sandboxes/{id}/resume\n // (a lightweight unpause). The previous approach — creating a new start task\n // via POST /api/v1/app-conversations — was wrong: it tries to provision a\n // fresh conversation in the sandbox and is subject to a 120-second cold-start\n // timeout that can fail. The resume endpoint simply unpauses the existing one.\n //\n // After calling resume we stay on the current URL. The 3-second refetch\n // interval in useActiveConversation (active while conversation_url is null)\n // polls until conversation_url populates, then the WebSocket connects.\n //\n // A ref guards against duplicate triggers per unique conversation.id within\n // the same route-mount lifetime.\n const resumeTriggeredForRef = React.useRef<string | null>(null);\n React.useEffect(() => {\n if (!isFetched || !conversation) return;\n if (active.backend.kind !== \"cloud\") return;\n if (conversation.sandbox_status !== \"PAUSED\") return; // only resume PAUSED sandboxes\n if (!conversation.sandbox_id) return; // no sandbox to resume\n if (resumeTriggeredForRef.current === conversation.id) return; // already sent\n\n resumeTriggeredForRef.current = conversation.id;\n\n resumeCloudSandbox(conversation.sandbox_id).catch(() => {\n displayErrorToast(t(I18nKey.CONVERSATION$FAILED_TO_START_FROM_TASK));\n });\n }, [\n isFetched,\n conversation?.id,\n conversation?.sandbox_status,\n conversation?.sandbox_id,\n active.backend.kind,\n t,\n ]);\n\n // A backend switch is in flight (BackendSelector flips the active backend\n // and redirects to /conversations on the next tick). The conversationId in\n // the URL belongs to the *previous* backend, so unmount the whole\n // conversation subtree now — before any per-conversation query (history,\n // metrics, sub-conversations, runtime info, …) re-fires against a backend\n // the id is foreign to. Those foreign fetches fail response validation and\n // surface \"agent server returned data this UI does not understand\". This is\n // deterministic regardless of the navigate-vs-setActive render race: React\n // re-renders this parent before its children, so returning null removes them\n // before they can issue the request.\n if (backendChanged) {\n return null;\n }\n\n const content = (\n <EventHandler>\n <div data-testid=\"app-route\" className=\"flex h-full flex-col\">\n {panelViewMatch ? (\n <ConversationMobilePanelPage\n onNavigateBack={() => navigate(`/conversations/${conversationId}`)}\n />\n ) : (\n <ConversationMain />\n )}\n </div>\n </EventHandler>\n );\n\n return (\n <WebSocketProviderWrapper conversationId={conversationId}>\n {content}\n </WebSocketProviderWrapper>\n );\n}\n\nexport function ConversationView() {\n return <AppContent />;\n}\n\nexport default ConversationView;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"conversation.cjs","names":[],"sources":["../../src/routes/conversation.tsx"],"sourcesContent":["import React from \"react\";\nimport { useNavigate, useLocation, useMatch } from \"react-router\";\nimport { useTranslation } from \"react-i18next\";\n\nimport { useConversationId } from \"#/hooks/use-conversation-id\";\nimport { useCommandStore } from \"#/stores/command-store\";\nimport { useConversationStore } from \"#/stores/conversation-store\";\nimport { useAgentStore } from \"#/stores/agent-store\";\nimport { useConversationStateStore } from \"#/stores/conversation-state-store\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport {\n clearLastConversationId,\n setLastConversationId,\n} from \"#/api/backend-registry/last-conversation-store\";\nimport { AgentState } from \"#/types/agent-state\";\n\nimport { EventHandler } from \"../wrapper/event-handler\";\n\nimport { useActiveConversation } from \"#/hooks/query/use-active-conversation\";\nimport { useTaskPollingController } from \"#/hooks/query/use-task-polling\";\n\nimport { displayErrorToast } from \"#/utils/custom-toast-handlers\";\nimport { useIsAuthed } from \"#/hooks/query/use-is-authed\";\nimport { ConversationMain } from \"#/components/features/conversation/conversation-main/conversation-main\";\nimport { ConversationMobilePanelPage } from \"#/components/features/conversation/conversation-main/conversation-mobile-panel-page\";\n\nimport { WebSocketProviderWrapper } from \"#/contexts/websocket-provider-wrapper\";\nimport { useErrorMessageStore } from \"#/stores/error-message-store\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { resumeCloudSandbox } from \"#/api/cloud/conversation-service.api\";\n\nfunction AppContent() {\n const { t } = useTranslation(\"openhands\");\n const { conversationId } = useConversationId();\n const panelViewMatch = useMatch(\"/conversations/:conversationId/panel\");\n\n const { isTask, taskStatus, taskDetail } = useTaskPollingController();\n\n // The conversationId in the URL belongs to whichever backend was\n // active when the route first mounted. If the user switches backends\n // while this route is still mounted, the id is meaningless under the\n // new backend — disable the active-conversation fetch (and its 404\n // toast) so we don't fire a request that the BackendSelector's\n // redirect will immediately navigate away from anyway. Mirrors the\n // same guard in `routes/automation-detail.tsx`.\n const active = useActiveBackend();\n const mountedBackendId = React.useRef(active.backend.id);\n const mountedOrgId = React.useRef(active.orgId);\n const backendChanged =\n mountedBackendId.current !== active.backend.id ||\n mountedOrgId.current !== active.orgId;\n\n const { data: conversation, isFetched } = useActiveConversation();\n const { data: isAuthed } = useIsAuthed();\n const { resetConversationState } = useConversationStore();\n const navigate = useNavigate();\n const location = useLocation();\n const clearTerminal = useCommandStore((state) => state.clearTerminal);\n const resetConversationRuntimeState = useConversationStateStore(\n (state) => state.reset,\n );\n const setCurrentAgentState = useAgentStore(\n (state) => state.setCurrentAgentState,\n );\n const removeErrorMessage = useErrorMessageStore(\n (state) => state.removeErrorMessage,\n );\n\n // Per-conversation UI/runtime resets. The event store is cleared separately,\n // inside ConversationWebSocketProvider, so the clear is ordered *before* the\n // preloaded-history re-seed (see the note there) — clearing it here would run\n // too late and wipe the freshly seeded history on a conversation switch.\n React.useEffect(() => {\n clearTerminal();\n resetConversationState();\n resetConversationRuntimeState();\n setCurrentAgentState(AgentState.LOADING);\n removeErrorMessage();\n }, [\n conversationId,\n clearTerminal,\n resetConversationState,\n resetConversationRuntimeState,\n setCurrentAgentState,\n removeErrorMessage,\n ]);\n\n React.useEffect(() => {\n if (isTask && taskStatus === \"ERROR\") {\n displayErrorToast(\n taskDetail || t(I18nKey.CONVERSATION$FAILED_TO_START_FROM_TASK),\n );\n // Navigate back to the original conversation when a resume task fails so\n // the user isn't stranded at the dead task-{id} URL. The resume effect's\n // ref prevents it from immediately retrying once we land there.\n const resumedFrom = (location.state as Record<string, unknown> | null)\n ?.resumedFromConversationId as string | undefined;\n navigate(\n resumedFrom ? `/conversations/${resumedFrom}` : \"/conversations\",\n { replace: true },\n );\n }\n }, [isTask, taskStatus, taskDetail, t, navigate, location.state]);\n\n React.useEffect(() => {\n if (!isFetched || !isAuthed) return;\n // The BackendSelector is in the middle of redirecting us away from\n // this route — don't toast/navigate based on a 404 that's just\n // \"this id doesn't exist on the new backend\".\n if (backendChanged) return;\n\n if (!conversation) {\n // Clear the per-backend \"last selected\" slot so the next switch\n // to this backend doesn't try to revisit a stale id.\n clearLastConversationId(active.backend.id, active.orgId);\n displayErrorToast(t(I18nKey.CONVERSATION$NOT_EXIST_OR_NO_PERMISSION));\n navigate(\"/conversations\");\n }\n }, [\n conversation,\n isFetched,\n isAuthed,\n navigate,\n t,\n backendChanged,\n active.backend.id,\n active.orgId,\n ]);\n\n // Remember the most recently selected conversation for the current\n // (backend, org) so flipping back to this backend later restores the\n // user to where they left off. Skip while a backend switch is in\n // flight: the id in the URL is from the previous backend and would\n // otherwise overwrite the new backend's memory.\n React.useEffect(() => {\n if (backendChanged) return;\n if (!conversationId) return;\n if (conversationId.startsWith(\"task-\")) return;\n setLastConversationId(active.backend.id, active.orgId, conversationId);\n }, [conversationId, backendChanged, active.backend.id, active.orgId]);\n\n // Cloud conversation resume: mirrors OpenHands' useSandboxRecovery.\n //\n // When the cloud API reports sandbox_status === \"PAUSED\" the sandbox is\n // sleeping. The correct wake-up call is POST /api/v1/sandboxes/{id}/resume\n // (a lightweight unpause). The previous approach — creating a new start task\n // via POST /api/v1/app-conversations — was wrong: it tries to provision a\n // fresh conversation in the sandbox and is subject to a 120-second cold-start\n // timeout that can fail. The resume endpoint simply unpauses the existing one.\n //\n // After calling resume we stay on the current URL. The 3-second refetch\n // interval in useActiveConversation (active while conversation_url is null)\n // polls until conversation_url populates, then the WebSocket connects.\n //\n // A ref guards against duplicate triggers per unique conversation.id within\n // the same route-mount lifetime.\n const resumeTriggeredForRef = React.useRef<string | null>(null);\n React.useEffect(() => {\n if (!isFetched || !conversation) return;\n if (active.backend.kind !== \"cloud\") return;\n if (conversation.sandbox_status !== \"PAUSED\") return; // only resume PAUSED sandboxes\n if (!conversation.sandbox_id) return; // no sandbox to resume\n if (resumeTriggeredForRef.current === conversation.id) return; // already sent\n\n resumeTriggeredForRef.current = conversation.id;\n\n resumeCloudSandbox(conversation.sandbox_id).catch(() => {\n displayErrorToast(t(I18nKey.CONVERSATION$FAILED_TO_START_FROM_TASK));\n });\n }, [\n isFetched,\n conversation?.id,\n conversation?.sandbox_status,\n conversation?.sandbox_id,\n active.backend.kind,\n t,\n ]);\n\n // A backend switch is in flight (BackendSelector flips the active backend\n // and redirects to /conversations on the next tick). The conversationId in\n // the URL belongs to the *previous* backend, so unmount the whole\n // conversation subtree now — before any per-conversation query (history,\n // metrics, sub-conversations, runtime info, …) re-fires against a backend\n // the id is foreign to. Those foreign fetches fail response validation and\n // surface \"agent server returned data this UI does not understand\". This is\n // deterministic regardless of the navigate-vs-setActive render race: React\n // re-renders this parent before its children, so returning null removes them\n // before they can issue the request.\n if (backendChanged) {\n return null;\n }\n\n const content = (\n <EventHandler>\n <div data-testid=\"app-route\" className=\"flex h-full flex-col\">\n {panelViewMatch ? (\n <ConversationMobilePanelPage\n onNavigateBack={() => navigate(`/conversations/${conversationId}`)}\n />\n ) : (\n <ConversationMain />\n )}\n </div>\n </EventHandler>\n );\n\n return (\n <WebSocketProviderWrapper conversationId={conversationId}>\n {content}\n </WebSocketProviderWrapper>\n );\n}\n\nexport function ConversationView() {\n return <AppContent />;\n}\n\nexport default ConversationView;\n"],"mappings":"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"}
|
|
@@ -13,7 +13,7 @@ import { useErrorMessageStore as f } from "../stores/error-message-store.js";
|
|
|
13
13
|
import { resumeCloudSandbox as p } from "../api/cloud/conversation-service.api.js";
|
|
14
14
|
import { useActiveConversation as m } from "../hooks/query/use-active-conversation.js";
|
|
15
15
|
import { EventHandler as h } from "../wrapper/event-handler.js";
|
|
16
|
-
import {
|
|
16
|
+
import { useTaskPollingController as g } from "../hooks/query/use-task-polling.js";
|
|
17
17
|
import { useIsAuthed as _ } from "../hooks/query/use-is-authed.js";
|
|
18
18
|
import { ConversationMain as v } from "../components/features/conversation/conversation-main/conversation-main.js";
|
|
19
19
|
import { ConversationMobilePanelPage as y } from "../components/features/conversation/conversation-main/conversation-mobile-panel-page.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation.js","names":[],"sources":["../../src/routes/conversation.tsx"],"sourcesContent":["import React from \"react\";\nimport { useNavigate, useLocation, useMatch } from \"react-router\";\nimport { useTranslation } from \"react-i18next\";\n\nimport { useConversationId } from \"#/hooks/use-conversation-id\";\nimport { useCommandStore } from \"#/stores/command-store\";\nimport { useConversationStore } from \"#/stores/conversation-store\";\nimport { useAgentStore } from \"#/stores/agent-store\";\nimport { useConversationStateStore } from \"#/stores/conversation-state-store\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport {\n clearLastConversationId,\n setLastConversationId,\n} from \"#/api/backend-registry/last-conversation-store\";\nimport { AgentState } from \"#/types/agent-state\";\n\nimport { EventHandler } from \"../wrapper/event-handler\";\n\nimport { useActiveConversation } from \"#/hooks/query/use-active-conversation\";\nimport { useTaskPolling } from \"#/hooks/query/use-task-polling\";\n\nimport { displayErrorToast } from \"#/utils/custom-toast-handlers\";\nimport { useIsAuthed } from \"#/hooks/query/use-is-authed\";\nimport { ConversationMain } from \"#/components/features/conversation/conversation-main/conversation-main\";\nimport { ConversationMobilePanelPage } from \"#/components/features/conversation/conversation-main/conversation-mobile-panel-page\";\n\nimport { WebSocketProviderWrapper } from \"#/contexts/websocket-provider-wrapper\";\nimport { useErrorMessageStore } from \"#/stores/error-message-store\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { resumeCloudSandbox } from \"#/api/cloud/conversation-service.api\";\n\nfunction AppContent() {\n const { t } = useTranslation(\"openhands\");\n const { conversationId } = useConversationId();\n const panelViewMatch = useMatch(\"/conversations/:conversationId/panel\");\n\n const { isTask, taskStatus, taskDetail } = useTaskPolling();\n\n // The conversationId in the URL belongs to whichever backend was\n // active when the route first mounted. If the user switches backends\n // while this route is still mounted, the id is meaningless under the\n // new backend — disable the active-conversation fetch (and its 404\n // toast) so we don't fire a request that the BackendSelector's\n // redirect will immediately navigate away from anyway. Mirrors the\n // same guard in `routes/automation-detail.tsx`.\n const active = useActiveBackend();\n const mountedBackendId = React.useRef(active.backend.id);\n const mountedOrgId = React.useRef(active.orgId);\n const backendChanged =\n mountedBackendId.current !== active.backend.id ||\n mountedOrgId.current !== active.orgId;\n\n const { data: conversation, isFetched } = useActiveConversation();\n const { data: isAuthed } = useIsAuthed();\n const { resetConversationState } = useConversationStore();\n const navigate = useNavigate();\n const location = useLocation();\n const clearTerminal = useCommandStore((state) => state.clearTerminal);\n const resetConversationRuntimeState = useConversationStateStore(\n (state) => state.reset,\n );\n const setCurrentAgentState = useAgentStore(\n (state) => state.setCurrentAgentState,\n );\n const removeErrorMessage = useErrorMessageStore(\n (state) => state.removeErrorMessage,\n );\n\n // Per-conversation UI/runtime resets. The event store is cleared separately,\n // inside ConversationWebSocketProvider, so the clear is ordered *before* the\n // preloaded-history re-seed (see the note there) — clearing it here would run\n // too late and wipe the freshly seeded history on a conversation switch.\n React.useEffect(() => {\n clearTerminal();\n resetConversationState();\n resetConversationRuntimeState();\n setCurrentAgentState(AgentState.LOADING);\n removeErrorMessage();\n }, [\n conversationId,\n clearTerminal,\n resetConversationState,\n resetConversationRuntimeState,\n setCurrentAgentState,\n removeErrorMessage,\n ]);\n\n React.useEffect(() => {\n if (isTask && taskStatus === \"ERROR\") {\n displayErrorToast(\n taskDetail || t(I18nKey.CONVERSATION$FAILED_TO_START_FROM_TASK),\n );\n // Navigate back to the original conversation when a resume task fails so\n // the user isn't stranded at the dead task-{id} URL. The resume effect's\n // ref prevents it from immediately retrying once we land there.\n const resumedFrom = (location.state as Record<string, unknown> | null)\n ?.resumedFromConversationId as string | undefined;\n navigate(\n resumedFrom ? `/conversations/${resumedFrom}` : \"/conversations\",\n { replace: true },\n );\n }\n }, [isTask, taskStatus, taskDetail, t, navigate, location.state]);\n\n React.useEffect(() => {\n if (!isFetched || !isAuthed) return;\n // The BackendSelector is in the middle of redirecting us away from\n // this route — don't toast/navigate based on a 404 that's just\n // \"this id doesn't exist on the new backend\".\n if (backendChanged) return;\n\n if (!conversation) {\n // Clear the per-backend \"last selected\" slot so the next switch\n // to this backend doesn't try to revisit a stale id.\n clearLastConversationId(active.backend.id, active.orgId);\n displayErrorToast(t(I18nKey.CONVERSATION$NOT_EXIST_OR_NO_PERMISSION));\n navigate(\"/conversations\");\n }\n }, [\n conversation,\n isFetched,\n isAuthed,\n navigate,\n t,\n backendChanged,\n active.backend.id,\n active.orgId,\n ]);\n\n // Remember the most recently selected conversation for the current\n // (backend, org) so flipping back to this backend later restores the\n // user to where they left off. Skip while a backend switch is in\n // flight: the id in the URL is from the previous backend and would\n // otherwise overwrite the new backend's memory.\n React.useEffect(() => {\n if (backendChanged) return;\n if (!conversationId) return;\n if (conversationId.startsWith(\"task-\")) return;\n setLastConversationId(active.backend.id, active.orgId, conversationId);\n }, [conversationId, backendChanged, active.backend.id, active.orgId]);\n\n // Cloud conversation resume: mirrors OpenHands' useSandboxRecovery.\n //\n // When the cloud API reports sandbox_status === \"PAUSED\" the sandbox is\n // sleeping. The correct wake-up call is POST /api/v1/sandboxes/{id}/resume\n // (a lightweight unpause). The previous approach — creating a new start task\n // via POST /api/v1/app-conversations — was wrong: it tries to provision a\n // fresh conversation in the sandbox and is subject to a 120-second cold-start\n // timeout that can fail. The resume endpoint simply unpauses the existing one.\n //\n // After calling resume we stay on the current URL. The 3-second refetch\n // interval in useActiveConversation (active while conversation_url is null)\n // polls until conversation_url populates, then the WebSocket connects.\n //\n // A ref guards against duplicate triggers per unique conversation.id within\n // the same route-mount lifetime.\n const resumeTriggeredForRef = React.useRef<string | null>(null);\n React.useEffect(() => {\n if (!isFetched || !conversation) return;\n if (active.backend.kind !== \"cloud\") return;\n if (conversation.sandbox_status !== \"PAUSED\") return; // only resume PAUSED sandboxes\n if (!conversation.sandbox_id) return; // no sandbox to resume\n if (resumeTriggeredForRef.current === conversation.id) return; // already sent\n\n resumeTriggeredForRef.current = conversation.id;\n\n resumeCloudSandbox(conversation.sandbox_id).catch(() => {\n displayErrorToast(t(I18nKey.CONVERSATION$FAILED_TO_START_FROM_TASK));\n });\n }, [\n isFetched,\n conversation?.id,\n conversation?.sandbox_status,\n conversation?.sandbox_id,\n active.backend.kind,\n t,\n ]);\n\n // A backend switch is in flight (BackendSelector flips the active backend\n // and redirects to /conversations on the next tick). The conversationId in\n // the URL belongs to the *previous* backend, so unmount the whole\n // conversation subtree now — before any per-conversation query (history,\n // metrics, sub-conversations, runtime info, …) re-fires against a backend\n // the id is foreign to. Those foreign fetches fail response validation and\n // surface \"agent server returned data this UI does not understand\". This is\n // deterministic regardless of the navigate-vs-setActive render race: React\n // re-renders this parent before its children, so returning null removes them\n // before they can issue the request.\n if (backendChanged) {\n return null;\n }\n\n const content = (\n <EventHandler>\n <div data-testid=\"app-route\" className=\"flex h-full flex-col\">\n {panelViewMatch ? (\n <ConversationMobilePanelPage\n onNavigateBack={() => navigate(`/conversations/${conversationId}`)}\n />\n ) : (\n <ConversationMain />\n )}\n </div>\n </EventHandler>\n );\n\n return (\n <WebSocketProviderWrapper conversationId={conversationId}>\n {content}\n </WebSocketProviderWrapper>\n );\n}\n\nexport function ConversationView() {\n return <AppContent />;\n}\n\nexport default ConversationView;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA+BA,SAAS,IAAa;CACpB,IAAM,EAAE,SAAM,EAAe,YAAY,EACnC,EAAE,sBAAmB,GAAmB,EACxC,IAAiB,EAAS,uCAAuC,EAEjE,EAAE,WAAQ,eAAY,kBAAe,GAAgB,EASrD,IAAS,GAAkB,EAC3B,IAAmB,EAAM,OAAO,EAAO,QAAQ,GAAG,EAClD,IAAe,EAAM,OAAO,EAAO,MAAM,EACzC,IACJ,EAAiB,YAAY,EAAO,QAAQ,MAC5C,EAAa,YAAY,EAAO,OAE5B,EAAE,MAAM,GAAc,iBAAc,GAAuB,EAC3D,EAAE,MAAM,MAAa,GAAa,EAClC,EAAE,8BAA2B,GAAsB,EACnD,IAAW,GAAa,EACxB,IAAW,GAAa,EACxB,IAAgB,GAAiB,MAAU,EAAM,cAAc,EAC/D,IAAgC,GACnC,MAAU,EAAM,MAClB,EACK,IAAuB,GAC1B,MAAU,EAAM,qBAClB,EACK,IAAqB,GACxB,MAAU,EAAM,mBAClB;AAoED,CA9DA,EAAM,gBAAgB;AAKpB,EAJA,GAAe,EACf,GAAwB,EACxB,GAA+B,EAC/B,EAAqB,EAAW,QAAQ,EACxC,GAAoB;IACnB;EACD;EACA;EACA;EACA;EACA;EACA;EACD,CAAC,EAEF,EAAM,gBAAgB;AACpB,MAAI,KAAU,MAAe,SAAS;AACpC,KACE,KAAc,EAAE,EAAQ,uCAAuC,CAChE;GAID,IAAM,IAAe,EAAS,OAC1B;AACJ,KACE,IAAc,kBAAkB,MAAgB,kBAChD,EAAE,SAAS,IAAM,CAClB;;IAEF;EAAC;EAAQ;EAAY;EAAY;EAAG;EAAU,EAAS;EAAM,CAAC,EAEjE,EAAM,gBAAgB;AAChB,GAAC,KAAa,CAAC,KAIf,KAEC,MAGH,EAAwB,EAAO,QAAQ,IAAI,EAAO,MAAM,EACxD,EAAkB,EAAE,EAAQ,wCAAwC,CAAC,EACrE,EAAS,iBAAiB;IAE3B;EACD;EACA;EACA;EACA;EACA;EACA;EACA,EAAO,QAAQ;EACf,EAAO;EACR,CAAC,EAOF,EAAM,gBAAgB;AAChB,OACC,MACD,EAAe,WAAW,QAAQ,IACtC,EAAsB,EAAO,QAAQ,IAAI,EAAO,OAAO,EAAe;IACrE;EAAC;EAAgB;EAAgB,EAAO,QAAQ;EAAI,EAAO;EAAM,CAAC;CAiBrE,IAAM,IAAwB,EAAM,OAAsB,KAAK;AAkD/D,QAjDA,EAAM,gBAAgB;AAChB,GAAC,KAAa,CAAC,KACf,EAAO,QAAQ,SAAS,WACxB,EAAa,mBAAmB,YAC/B,EAAa,cACd,EAAsB,YAAY,EAAa,OAEnD,EAAsB,UAAU,EAAa,IAE7C,EAAmB,EAAa,WAAW,CAAC,YAAY;AACtD,KAAkB,EAAE,EAAQ,uCAAuC,CAAC;IACpE;IACD;EACD;EACA,GAAc;EACd,GAAc;EACd,GAAc;EACd,EAAO,QAAQ;EACf;EACD,CAAC,EAYE,IACK,OAkBP,kBAAC,GAAD;EAA0C;YAd1C,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;GAAK,eAAY;GAAY,WAAU;aACpC,IACC,kBAAC,GAAD,EACE,sBAAsB,EAAS,kBAAkB,IAAiB,EAClE,CAAA,GAEF,kBAAC,GAAD,EAAoB,CAAA;GAElB,CAAA,EACO,CAKZ;EACwB,CAAA;;AAI/B,SAAgB,IAAmB;AACjC,QAAO,kBAAC,GAAD,EAAc,CAAA"}
|
|
1
|
+
{"version":3,"file":"conversation.js","names":[],"sources":["../../src/routes/conversation.tsx"],"sourcesContent":["import React from \"react\";\nimport { useNavigate, useLocation, useMatch } from \"react-router\";\nimport { useTranslation } from \"react-i18next\";\n\nimport { useConversationId } from \"#/hooks/use-conversation-id\";\nimport { useCommandStore } from \"#/stores/command-store\";\nimport { useConversationStore } from \"#/stores/conversation-store\";\nimport { useAgentStore } from \"#/stores/agent-store\";\nimport { useConversationStateStore } from \"#/stores/conversation-state-store\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport {\n clearLastConversationId,\n setLastConversationId,\n} from \"#/api/backend-registry/last-conversation-store\";\nimport { AgentState } from \"#/types/agent-state\";\n\nimport { EventHandler } from \"../wrapper/event-handler\";\n\nimport { useActiveConversation } from \"#/hooks/query/use-active-conversation\";\nimport { useTaskPollingController } from \"#/hooks/query/use-task-polling\";\n\nimport { displayErrorToast } from \"#/utils/custom-toast-handlers\";\nimport { useIsAuthed } from \"#/hooks/query/use-is-authed\";\nimport { ConversationMain } from \"#/components/features/conversation/conversation-main/conversation-main\";\nimport { ConversationMobilePanelPage } from \"#/components/features/conversation/conversation-main/conversation-mobile-panel-page\";\n\nimport { WebSocketProviderWrapper } from \"#/contexts/websocket-provider-wrapper\";\nimport { useErrorMessageStore } from \"#/stores/error-message-store\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { resumeCloudSandbox } from \"#/api/cloud/conversation-service.api\";\n\nfunction AppContent() {\n const { t } = useTranslation(\"openhands\");\n const { conversationId } = useConversationId();\n const panelViewMatch = useMatch(\"/conversations/:conversationId/panel\");\n\n const { isTask, taskStatus, taskDetail } = useTaskPollingController();\n\n // The conversationId in the URL belongs to whichever backend was\n // active when the route first mounted. If the user switches backends\n // while this route is still mounted, the id is meaningless under the\n // new backend — disable the active-conversation fetch (and its 404\n // toast) so we don't fire a request that the BackendSelector's\n // redirect will immediately navigate away from anyway. Mirrors the\n // same guard in `routes/automation-detail.tsx`.\n const active = useActiveBackend();\n const mountedBackendId = React.useRef(active.backend.id);\n const mountedOrgId = React.useRef(active.orgId);\n const backendChanged =\n mountedBackendId.current !== active.backend.id ||\n mountedOrgId.current !== active.orgId;\n\n const { data: conversation, isFetched } = useActiveConversation();\n const { data: isAuthed } = useIsAuthed();\n const { resetConversationState } = useConversationStore();\n const navigate = useNavigate();\n const location = useLocation();\n const clearTerminal = useCommandStore((state) => state.clearTerminal);\n const resetConversationRuntimeState = useConversationStateStore(\n (state) => state.reset,\n );\n const setCurrentAgentState = useAgentStore(\n (state) => state.setCurrentAgentState,\n );\n const removeErrorMessage = useErrorMessageStore(\n (state) => state.removeErrorMessage,\n );\n\n // Per-conversation UI/runtime resets. The event store is cleared separately,\n // inside ConversationWebSocketProvider, so the clear is ordered *before* the\n // preloaded-history re-seed (see the note there) — clearing it here would run\n // too late and wipe the freshly seeded history on a conversation switch.\n React.useEffect(() => {\n clearTerminal();\n resetConversationState();\n resetConversationRuntimeState();\n setCurrentAgentState(AgentState.LOADING);\n removeErrorMessage();\n }, [\n conversationId,\n clearTerminal,\n resetConversationState,\n resetConversationRuntimeState,\n setCurrentAgentState,\n removeErrorMessage,\n ]);\n\n React.useEffect(() => {\n if (isTask && taskStatus === \"ERROR\") {\n displayErrorToast(\n taskDetail || t(I18nKey.CONVERSATION$FAILED_TO_START_FROM_TASK),\n );\n // Navigate back to the original conversation when a resume task fails so\n // the user isn't stranded at the dead task-{id} URL. The resume effect's\n // ref prevents it from immediately retrying once we land there.\n const resumedFrom = (location.state as Record<string, unknown> | null)\n ?.resumedFromConversationId as string | undefined;\n navigate(\n resumedFrom ? `/conversations/${resumedFrom}` : \"/conversations\",\n { replace: true },\n );\n }\n }, [isTask, taskStatus, taskDetail, t, navigate, location.state]);\n\n React.useEffect(() => {\n if (!isFetched || !isAuthed) return;\n // The BackendSelector is in the middle of redirecting us away from\n // this route — don't toast/navigate based on a 404 that's just\n // \"this id doesn't exist on the new backend\".\n if (backendChanged) return;\n\n if (!conversation) {\n // Clear the per-backend \"last selected\" slot so the next switch\n // to this backend doesn't try to revisit a stale id.\n clearLastConversationId(active.backend.id, active.orgId);\n displayErrorToast(t(I18nKey.CONVERSATION$NOT_EXIST_OR_NO_PERMISSION));\n navigate(\"/conversations\");\n }\n }, [\n conversation,\n isFetched,\n isAuthed,\n navigate,\n t,\n backendChanged,\n active.backend.id,\n active.orgId,\n ]);\n\n // Remember the most recently selected conversation for the current\n // (backend, org) so flipping back to this backend later restores the\n // user to where they left off. Skip while a backend switch is in\n // flight: the id in the URL is from the previous backend and would\n // otherwise overwrite the new backend's memory.\n React.useEffect(() => {\n if (backendChanged) return;\n if (!conversationId) return;\n if (conversationId.startsWith(\"task-\")) return;\n setLastConversationId(active.backend.id, active.orgId, conversationId);\n }, [conversationId, backendChanged, active.backend.id, active.orgId]);\n\n // Cloud conversation resume: mirrors OpenHands' useSandboxRecovery.\n //\n // When the cloud API reports sandbox_status === \"PAUSED\" the sandbox is\n // sleeping. The correct wake-up call is POST /api/v1/sandboxes/{id}/resume\n // (a lightweight unpause). The previous approach — creating a new start task\n // via POST /api/v1/app-conversations — was wrong: it tries to provision a\n // fresh conversation in the sandbox and is subject to a 120-second cold-start\n // timeout that can fail. The resume endpoint simply unpauses the existing one.\n //\n // After calling resume we stay on the current URL. The 3-second refetch\n // interval in useActiveConversation (active while conversation_url is null)\n // polls until conversation_url populates, then the WebSocket connects.\n //\n // A ref guards against duplicate triggers per unique conversation.id within\n // the same route-mount lifetime.\n const resumeTriggeredForRef = React.useRef<string | null>(null);\n React.useEffect(() => {\n if (!isFetched || !conversation) return;\n if (active.backend.kind !== \"cloud\") return;\n if (conversation.sandbox_status !== \"PAUSED\") return; // only resume PAUSED sandboxes\n if (!conversation.sandbox_id) return; // no sandbox to resume\n if (resumeTriggeredForRef.current === conversation.id) return; // already sent\n\n resumeTriggeredForRef.current = conversation.id;\n\n resumeCloudSandbox(conversation.sandbox_id).catch(() => {\n displayErrorToast(t(I18nKey.CONVERSATION$FAILED_TO_START_FROM_TASK));\n });\n }, [\n isFetched,\n conversation?.id,\n conversation?.sandbox_status,\n conversation?.sandbox_id,\n active.backend.kind,\n t,\n ]);\n\n // A backend switch is in flight (BackendSelector flips the active backend\n // and redirects to /conversations on the next tick). The conversationId in\n // the URL belongs to the *previous* backend, so unmount the whole\n // conversation subtree now — before any per-conversation query (history,\n // metrics, sub-conversations, runtime info, …) re-fires against a backend\n // the id is foreign to. Those foreign fetches fail response validation and\n // surface \"agent server returned data this UI does not understand\". This is\n // deterministic regardless of the navigate-vs-setActive render race: React\n // re-renders this parent before its children, so returning null removes them\n // before they can issue the request.\n if (backendChanged) {\n return null;\n }\n\n const content = (\n <EventHandler>\n <div data-testid=\"app-route\" className=\"flex h-full flex-col\">\n {panelViewMatch ? (\n <ConversationMobilePanelPage\n onNavigateBack={() => navigate(`/conversations/${conversationId}`)}\n />\n ) : (\n <ConversationMain />\n )}\n </div>\n </EventHandler>\n );\n\n return (\n <WebSocketProviderWrapper conversationId={conversationId}>\n {content}\n </WebSocketProviderWrapper>\n );\n}\n\nexport function ConversationView() {\n return <AppContent />;\n}\n\nexport default ConversationView;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA+BA,SAAS,IAAa;CACpB,IAAM,EAAE,SAAM,EAAe,YAAY,EACnC,EAAE,sBAAmB,GAAmB,EACxC,IAAiB,EAAS,uCAAuC,EAEjE,EAAE,WAAQ,eAAY,kBAAe,GAA0B,EAS/D,IAAS,GAAkB,EAC3B,IAAmB,EAAM,OAAO,EAAO,QAAQ,GAAG,EAClD,IAAe,EAAM,OAAO,EAAO,MAAM,EACzC,IACJ,EAAiB,YAAY,EAAO,QAAQ,MAC5C,EAAa,YAAY,EAAO,OAE5B,EAAE,MAAM,GAAc,iBAAc,GAAuB,EAC3D,EAAE,MAAM,MAAa,GAAa,EAClC,EAAE,8BAA2B,GAAsB,EACnD,IAAW,GAAa,EACxB,IAAW,GAAa,EACxB,IAAgB,GAAiB,MAAU,EAAM,cAAc,EAC/D,IAAgC,GACnC,MAAU,EAAM,MAClB,EACK,IAAuB,GAC1B,MAAU,EAAM,qBAClB,EACK,IAAqB,GACxB,MAAU,EAAM,mBAClB;AAoED,CA9DA,EAAM,gBAAgB;AAKpB,EAJA,GAAe,EACf,GAAwB,EACxB,GAA+B,EAC/B,EAAqB,EAAW,QAAQ,EACxC,GAAoB;IACnB;EACD;EACA;EACA;EACA;EACA;EACA;EACD,CAAC,EAEF,EAAM,gBAAgB;AACpB,MAAI,KAAU,MAAe,SAAS;AACpC,KACE,KAAc,EAAE,EAAQ,uCAAuC,CAChE;GAID,IAAM,IAAe,EAAS,OAC1B;AACJ,KACE,IAAc,kBAAkB,MAAgB,kBAChD,EAAE,SAAS,IAAM,CAClB;;IAEF;EAAC;EAAQ;EAAY;EAAY;EAAG;EAAU,EAAS;EAAM,CAAC,EAEjE,EAAM,gBAAgB;AAChB,GAAC,KAAa,CAAC,KAIf,KAEC,MAGH,EAAwB,EAAO,QAAQ,IAAI,EAAO,MAAM,EACxD,EAAkB,EAAE,EAAQ,wCAAwC,CAAC,EACrE,EAAS,iBAAiB;IAE3B;EACD;EACA;EACA;EACA;EACA;EACA;EACA,EAAO,QAAQ;EACf,EAAO;EACR,CAAC,EAOF,EAAM,gBAAgB;AAChB,OACC,MACD,EAAe,WAAW,QAAQ,IACtC,EAAsB,EAAO,QAAQ,IAAI,EAAO,OAAO,EAAe;IACrE;EAAC;EAAgB;EAAgB,EAAO,QAAQ;EAAI,EAAO;EAAM,CAAC;CAiBrE,IAAM,IAAwB,EAAM,OAAsB,KAAK;AAkD/D,QAjDA,EAAM,gBAAgB;AAChB,GAAC,KAAa,CAAC,KACf,EAAO,QAAQ,SAAS,WACxB,EAAa,mBAAmB,YAC/B,EAAa,cACd,EAAsB,YAAY,EAAa,OAEnD,EAAsB,UAAU,EAAa,IAE7C,EAAmB,EAAa,WAAW,CAAC,YAAY;AACtD,KAAkB,EAAE,EAAQ,uCAAuC,CAAC;IACpE;IACD;EACD;EACA,GAAc;EACd,GAAc;EACd,GAAc;EACd,EAAO,QAAQ;EACf;EACD,CAAC,EAYE,IACK,OAkBP,kBAAC,GAAD;EAA0C;YAd1C,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;GAAK,eAAY;GAAY,WAAU;aACpC,IACC,kBAAC,GAAD,EACE,sBAAsB,EAAS,kBAAkB,IAAiB,EAClE,CAAA,GAEF,kBAAC,GAAD,EAAoB,CAAA;GAElB,CAAA,EACO,CAKZ;EACwB,CAAA;;AAI/B,SAAgB,IAAmB;AACjC,QAAO,kBAAC,GAAD,EAAc,CAAA"}
|
package/dist/routes/mcp.cjs
CHANGED
|
@@ -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/retrieve-axios-error-message.cjs`),i=require(`../utils/custom-toast-handlers.cjs`),a=require(`../utils/mcp-config.cjs`),o=require(`../hooks/query/use-settings.cjs`),s=require(`../components/features/settings/brand-button.cjs`),c=require(`../utils/settings-like-page-layout-classes.cjs`),l=require(`../components/features/skills/extensions-navigation.cjs`),u=require(`../components/shared/modals/confirmation-modal.cjs`),d=require(`../hooks/mutation/use-delete-mcp-server.cjs`),f=require(`../utils/mcp-marketplace-utils.cjs`),p=require(`../node_modules/@openhands/extensions/integrations/index.cjs`),m=require(`../utils/mcp-installed-servers.cjs`),h=require(`../components/features/mcp-page/installed-servers-section.cjs`),g=require(`../components/features/mcp-page/marketplace-section.cjs`),_=require(`../components/features/mcp-page/install-server-modal.cjs`),v=require(`../components/features/mcp-page/custom-server-editor.cjs`),y=require(`../components/features/mcp-page/mcp-toolbar.cjs`);require(`../components/features/mcp-page/index.cjs`);let b=require(`react`);b=e.__toESM(b,1);let x=require(`react/jsx-runtime`);function S(){let{t:e}=t.useTranslation(`openhands`),{data:S,isLoading:C}=o.useSettings(),{mutate:w,isPending:T}=d.useDeleteMcpServer(),[E,D]=b.default.useState(null),[O,k]=b.default.useState(null),[A,j]=b.default.useState(null),[M,N]=b.default.useState(``),[P,F]=b.default.useState(`all`),I=m.flattenMcpConfig(a.parseMcpConfig(S?.agent_settings?.mcp_config)),L=f.getMcpMarketplaceCatalog(p.default),R=I.filter(e=>f.installedServerMatchesQuery(e,f.findCatalogEntryForServer(e,L),M)),z=e=>{D(e)};return C||!S?(0,x.jsxs)(`div`,{"data-testid":`mcp-page`,className:`flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10`,children:[(0,x.jsx)(l.ExtensionsNavigation,{}),(0,x.jsx)(`div`,{className:`flex h-full flex-1 items-center justify-center px-4 md:px-0`,children:(0,x.jsx)(`div`,{className:`h-8 w-8 rounded-full border-2 border-transparent border-t-white animate-spin`})})]}):(0,x.jsxs)(`div`,{"data-testid":`mcp-page`,className:`flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10`,children:[(0,x.jsx)(l.ExtensionsNavigation,{}),(0,x.jsxs)(`main`,{className:c.settingsLikeMainScrollClassName,children:[(0,x.jsxs)(`div`,{className:`mx-auto flex w-full min-w-0 max-w-[800px] flex-col gap-6`,children:[(0,x.jsx)(`div`,{className:`min-w-0`,children:(0,x.jsxs)(`div`,{className:`flex items-start justify-between gap-4`,children:[(0,x.jsxs)(`div`,{className:`space-y-1`,children:[(0,x.jsx)(`h2`,{className:`text-xl font-medium leading-6 text-foreground`,children:e(n.I18nKey.SETTINGS$MCP_TITLE)}),(0,x.jsx)(`div`,{className:`max-w-2xl text-sm text-tertiary-light`,children:e(n.I18nKey.MCP$PAGE_DESCRIPTION)})]}),(0,x.jsx)(s.BrandButton,{type:`button`,variant:`secondary`,testId:`mcp-add-custom-server`,className:`flex-shrink-0 whitespace-nowrap`,onClick:()=>k({id:``,type:`sse`}),children:e(n.I18nKey.MCP$ADD_CUSTOM)})]})}),(0,x.jsx)(y.McpToolbar,{search:M,onSearchChange:N,sectionFilter:P,onSectionFilterChange:F}),P===`library`?null:(0,x.jsxs)(`section`,{className:`flex flex-col gap-3`,children:[(0,x.jsx)(`h2`,{className:`text-base font-semibold text-foreground`,children:e(n.I18nKey.MCP$INSTALLED_TITLE)}),(0,x.jsx)(h.InstalledServersSection,{servers:R,hasAnyInstalled:I.length>0,query:M,onEdit:e=>{k(e)},onDelete:e=>{let t=I.find(t=>t.id===e);t&&j(t)}})]}),P===`installed`?null:(0,x.jsx)(g.MarketplaceSection,{onSelect:z,onAdd:z,query:M})]}),E&&(0,x.jsx)(_.InstallServerModal,{entry:E,onClose:()=>D(null)}),O&&(0,x.jsx)(v.CustomServerEditor,{server:O,existingServers:I,onClose:()=>k(null)}),A&&(0,x.jsx)(u.ConfirmationModal,{text:e(n.I18nKey.SETTINGS$MCP_CONFIRM_DELETE),onCancel:()=>j(null),onConfirm:()=>{A&&w(A,{onSuccess:()=>{i.displaySuccessToast(e(n.I18nKey.MCP$REMOVE_SUCCESS)),j(null)},onError:t=>{i.displayErrorToast(r.retrieveAxiosErrorMessage(t)||e(n.I18nKey.ERROR$GENERIC)),j(null)}})},isConfirming:T})]})]})}exports.default=S;
|
|
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/retrieve-axios-error-message.cjs`),i=require(`../utils/custom-toast-handlers.cjs`),a=require(`../utils/mcp-config.cjs`),o=require(`../hooks/query/use-settings.cjs`),s=require(`../components/features/settings/brand-button.cjs`),c=require(`../utils/settings-like-page-layout-classes.cjs`),l=require(`../components/features/skills/extensions-navigation.cjs`),u=require(`../components/shared/modals/confirmation-modal.cjs`),d=require(`../hooks/mutation/use-delete-mcp-server.cjs`),f=require(`../utils/mcp-marketplace-utils.cjs`),p=require(`../node_modules/@openhands/extensions/integrations/index.cjs`),m=require(`../utils/mcp-installed-servers.cjs`),h=require(`../components/features/mcp-page/installed-servers-section.cjs`),g=require(`../components/features/mcp-page/marketplace-section.cjs`),_=require(`../components/features/mcp-page/install-server-modal.cjs`),v=require(`../components/features/mcp-page/custom-server-editor.cjs`),y=require(`../components/features/mcp-page/mcp-toolbar.cjs`);require(`../components/features/mcp-page/index.cjs`);let b=require(`react`);b=e.__toESM(b,1);let x=require(`react/jsx-runtime`);function S(){let{t:e}=t.useTranslation(`openhands`),{data:S,isLoading:C}=o.useSettings(),{mutate:w,isPending:T}=d.useDeleteMcpServer(),[E,D]=b.default.useState(null),[O,k]=b.default.useState(null),[A,j]=b.default.useState(null),[M,N]=b.default.useState(``),[P,F]=b.default.useState(`all`),I=m.flattenMcpConfig(a.parseMcpConfig(S?.agent_settings?.mcp_config)),L=f.getMcpMarketplaceCatalog(p.default),R=I.filter(e=>f.installedServerMatchesQuery(e,f.findCatalogEntryForServer(e,L),M)),z=e=>{D(e)};return C||!S?(0,x.jsxs)(`div`,{"data-testid":`mcp-page`,className:`flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10`,children:[(0,x.jsx)(l.ExtensionsNavigation,{}),(0,x.jsx)(`div`,{className:`flex h-full flex-1 items-center justify-center px-4 md:px-0`,children:(0,x.jsx)(`div`,{className:`h-8 w-8 rounded-full border-2 border-transparent border-t-white animate-spin`})})]}):(0,x.jsxs)(`div`,{"data-testid":`mcp-page`,className:`flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10`,children:[(0,x.jsx)(l.ExtensionsNavigation,{}),(0,x.jsxs)(`main`,{className:c.settingsLikeMainScrollClassName,children:[(0,x.jsxs)(`div`,{className:`mx-auto flex w-full min-w-0 max-w-[800px] flex-col gap-6`,children:[(0,x.jsx)(`div`,{className:`min-w-0`,children:(0,x.jsxs)(`div`,{className:`flex items-start justify-between gap-4`,children:[(0,x.jsxs)(`div`,{className:`space-y-1`,children:[(0,x.jsx)(`h2`,{className:`text-xl font-medium leading-6 text-foreground`,children:e(n.I18nKey.SETTINGS$MCP_TITLE)}),(0,x.jsx)(`div`,{className:`max-w-2xl text-sm text-tertiary-light`,children:e(n.I18nKey.MCP$PAGE_DESCRIPTION)})]}),(0,x.jsx)(s.BrandButton,{type:`button`,variant:`secondary`,testId:`mcp-add-custom-server`,className:`flex-shrink-0 whitespace-nowrap`,onClick:()=>k({id:``,type:`sse`}),children:e(n.I18nKey.MCP$ADD_CUSTOM)})]})}),(0,x.jsx)(y.McpToolbar,{search:M,onSearchChange:N,sectionFilter:P,onSectionFilterChange:F}),P===`library`?null:(0,x.jsxs)(`section`,{className:`flex flex-col gap-3`,children:[(0,x.jsx)(`h2`,{className:`text-base font-semibold text-foreground`,children:e(n.I18nKey.MCP$INSTALLED_TITLE)}),(0,x.jsx)(h.InstalledServersSection,{servers:R,hasAnyInstalled:I.length>0,query:M,onEdit:e=>{k(e)},onDelete:e=>{let t=I.find(t=>t.id===e);t&&j(t)}})]}),P===`installed`?null:(0,x.jsx)(g.MarketplaceSection,{onSelect:z,onAdd:z,query:M})]}),E&&(0,x.jsx)(_.InstallServerModal,{entry:E,existingServers:I,onClose:()=>D(null)}),O&&(0,x.jsx)(v.CustomServerEditor,{server:O,existingServers:I,onClose:()=>k(null)}),A&&(0,x.jsx)(u.ConfirmationModal,{text:e(n.I18nKey.SETTINGS$MCP_CONFIRM_DELETE),onCancel:()=>j(null),onConfirm:()=>{A&&w(A,{onSuccess:()=>{i.displaySuccessToast(e(n.I18nKey.MCP$REMOVE_SUCCESS)),j(null)},onError:t=>{i.displayErrorToast(r.retrieveAxiosErrorMessage(t)||e(n.I18nKey.ERROR$GENERIC)),j(null)}})},isConfirming:T})]})]})}exports.default=S;
|
|
2
2
|
//# sourceMappingURL=mcp.cjs.map
|
package/dist/routes/mcp.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.cjs","names":[],"sources":["../../src/routes/mcp.tsx"],"sourcesContent":["import React from \"react\";\nimport { AxiosError } from \"axios\";\nimport { ExtensionsNavigation } from \"#/components/features/skills/extensions-navigation\";\nimport { useTranslation } from \"react-i18next\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { ConfirmationModal } from \"#/components/shared/modals/confirmation-modal\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { useDeleteMcpServer } from \"#/hooks/mutation/use-delete-mcp-server\";\nimport { parseMcpConfig } from \"#/utils/mcp-config\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport { settingsLikeMainScrollClassName } from \"#/utils/settings-like-page-layout-classes\";\nimport {\n findCatalogEntryForServer,\n getMcpMarketplaceCatalog,\n installedServerMatchesQuery,\n} from \"#/utils/mcp-marketplace-utils\";\nimport {\n INTEGRATION_CATALOG as MCP_MARKETPLACE,\n type IntegrationCatalogEntry as MarketplaceEntry,\n} from \"@openhands/extensions/integrations\";\nimport { MCPServerConfig } from \"#/types/mcp-server\";\nimport { flattenMcpConfig } from \"#/utils/mcp-installed-servers\";\nimport {\n InstalledServersSection,\n McpToolbar,\n MarketplaceSection,\n InstallServerModal,\n CustomServerEditor,\n type McpSectionFilter,\n} from \"#/components/features/mcp-page\";\n\n// No ACP guard here (unlike `/settings` and `/settings/condenser`): MCP\n// servers configured via `agent_settings.mcp_config` are now forwarded to\n// the ACP subprocess at session creation, so this page is meaningful for\n// both OpenHands and ACP agents. The same editor and MCP settings storage\n// drive both kinds.\n\nexport default function MCPPage() {\n const { t } = useTranslation(\"openhands\");\n const { data: settings, isLoading } = useSettings();\n const { mutate: deleteMcpServer, isPending: isDeleting } =\n useDeleteMcpServer();\n\n const [installEntry, setInstallEntry] =\n React.useState<MarketplaceEntry | null>(null);\n const [editingServer, setEditingServer] =\n React.useState<MCPServerConfig | null>(null);\n const [serverToDelete, setServerToDelete] =\n React.useState<MCPServerConfig | null>(null);\n const [searchQuery, setSearchQuery] = React.useState(\"\");\n const [sectionFilter, setSectionFilter] =\n React.useState<McpSectionFilter>(\"all\");\n\n const mcpConfig = parseMcpConfig(settings?.agent_settings?.mcp_config);\n const allServers = flattenMcpConfig(mcpConfig);\n const mcpMarketplace = getMcpMarketplaceCatalog(MCP_MARKETPLACE);\n\n // Filter installed servers by the search query. We pair each server\n // with its catalog entry (if any) so the search can match friendly\n // names like \"Slack\" against a stdio server whose own `.name` is\n // just \"slack\".\n const filteredInstalledServers = allServers.filter((server) =>\n installedServerMatchesQuery(\n server,\n findCatalogEntryForServer(server, mcpMarketplace),\n searchQuery,\n ),\n );\n\n const handleMarketplaceInstall = (entry: MarketplaceEntry) => {\n setInstallEntry(entry);\n };\n\n const handleEdit = (server: MCPServerConfig) => {\n setEditingServer(server);\n };\n\n const handleDeleteClick = (serverId: string) => {\n const target = allServers.find((s) => s.id === serverId);\n if (target) setServerToDelete(target);\n };\n\n const handleConfirmDelete = () => {\n if (!serverToDelete) return;\n // Pass the full server config — useDeleteMcpServer re-resolves its\n // position against the fresh settings at mutation time, so a\n // background refresh between this click and confirm cannot point\n // us at the wrong index.\n deleteMcpServer(serverToDelete, {\n onSuccess: () => {\n displaySuccessToast(t(I18nKey.MCP$REMOVE_SUCCESS));\n setServerToDelete(null);\n },\n onError: (err) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n displayErrorToast(message || t(I18nKey.ERROR$GENERIC));\n setServerToDelete(null);\n },\n });\n };\n\n if (isLoading || !settings) {\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <div className=\"flex h-full flex-1 items-center justify-center px-4 md:px-0\">\n <div className=\"h-8 w-8 rounded-full border-2 border-transparent border-t-white animate-spin\" />\n </div>\n </div>\n );\n }\n\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <main className={settingsLikeMainScrollClassName}>\n <div className=\"mx-auto flex w-full min-w-0 max-w-[800px] flex-col gap-6\">\n <div className=\"min-w-0\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"space-y-1\">\n <h2 className=\"text-xl font-medium leading-6 text-foreground\">\n {t(I18nKey.SETTINGS$MCP_TITLE)}\n </h2>\n <div className=\"max-w-2xl text-sm text-tertiary-light\">\n {t(I18nKey.MCP$PAGE_DESCRIPTION)}\n </div>\n </div>\n <BrandButton\n type=\"button\"\n variant=\"secondary\"\n testId=\"mcp-add-custom-server\"\n className=\"flex-shrink-0 whitespace-nowrap\"\n onClick={() => setEditingServer({ id: \"\", type: \"sse\" })}\n >\n {t(I18nKey.MCP$ADD_CUSTOM)}\n </BrandButton>\n </div>\n </div>\n\n <McpToolbar\n search={searchQuery}\n onSearchChange={setSearchQuery}\n sectionFilter={sectionFilter}\n onSectionFilterChange={setSectionFilter}\n />\n\n {sectionFilter !== \"library\" ? (\n <section className=\"flex flex-col gap-3\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {t(I18nKey.MCP$INSTALLED_TITLE)}\n </h2>\n <InstalledServersSection\n servers={filteredInstalledServers}\n hasAnyInstalled={allServers.length > 0}\n query={searchQuery}\n onEdit={handleEdit}\n onDelete={handleDeleteClick}\n />\n </section>\n ) : null}\n\n {sectionFilter !== \"installed\" ? (\n <MarketplaceSection\n onSelect={handleMarketplaceInstall}\n onAdd={handleMarketplaceInstall}\n query={searchQuery}\n />\n ) : null}\n </div>\n\n {installEntry && (\n <InstallServerModal\n entry={installEntry}\n onClose={() => setInstallEntry(null)}\n />\n )}\n\n {/* Custom (or non-marketplace) server editor. The empty-id\n sentinel (`{ id: \"\", type: \"sse\" }`) means \"add new\". */}\n {editingServer && (\n <CustomServerEditor\n server={editingServer}\n existingServers={allServers}\n onClose={() => setEditingServer(null)}\n />\n )}\n\n {serverToDelete && (\n <ConfirmationModal\n text={t(I18nKey.SETTINGS$MCP_CONFIRM_DELETE)}\n onCancel={() => setServerToDelete(null)}\n onConfirm={handleConfirmDelete}\n isConfirming={isDeleting}\n />\n )}\n </main>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mcp.cjs","names":[],"sources":["../../src/routes/mcp.tsx"],"sourcesContent":["import React from \"react\";\nimport { AxiosError } from \"axios\";\nimport { ExtensionsNavigation } from \"#/components/features/skills/extensions-navigation\";\nimport { useTranslation } from \"react-i18next\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { ConfirmationModal } from \"#/components/shared/modals/confirmation-modal\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { useDeleteMcpServer } from \"#/hooks/mutation/use-delete-mcp-server\";\nimport { parseMcpConfig } from \"#/utils/mcp-config\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport { settingsLikeMainScrollClassName } from \"#/utils/settings-like-page-layout-classes\";\nimport {\n findCatalogEntryForServer,\n getMcpMarketplaceCatalog,\n installedServerMatchesQuery,\n} from \"#/utils/mcp-marketplace-utils\";\nimport {\n INTEGRATION_CATALOG as MCP_MARKETPLACE,\n type IntegrationCatalogEntry as MarketplaceEntry,\n} from \"@openhands/extensions/integrations\";\nimport { MCPServerConfig } from \"#/types/mcp-server\";\nimport { flattenMcpConfig } from \"#/utils/mcp-installed-servers\";\nimport {\n InstalledServersSection,\n McpToolbar,\n MarketplaceSection,\n InstallServerModal,\n CustomServerEditor,\n type McpSectionFilter,\n} from \"#/components/features/mcp-page\";\n\n// No ACP guard here (unlike `/settings` and `/settings/condenser`): MCP\n// servers configured via `agent_settings.mcp_config` are now forwarded to\n// the ACP subprocess at session creation, so this page is meaningful for\n// both OpenHands and ACP agents. The same editor and MCP settings storage\n// drive both kinds.\n\nexport default function MCPPage() {\n const { t } = useTranslation(\"openhands\");\n const { data: settings, isLoading } = useSettings();\n const { mutate: deleteMcpServer, isPending: isDeleting } =\n useDeleteMcpServer();\n\n const [installEntry, setInstallEntry] =\n React.useState<MarketplaceEntry | null>(null);\n const [editingServer, setEditingServer] =\n React.useState<MCPServerConfig | null>(null);\n const [serverToDelete, setServerToDelete] =\n React.useState<MCPServerConfig | null>(null);\n const [searchQuery, setSearchQuery] = React.useState(\"\");\n const [sectionFilter, setSectionFilter] =\n React.useState<McpSectionFilter>(\"all\");\n\n const mcpConfig = parseMcpConfig(settings?.agent_settings?.mcp_config);\n const allServers = flattenMcpConfig(mcpConfig);\n const mcpMarketplace = getMcpMarketplaceCatalog(MCP_MARKETPLACE);\n\n // Filter installed servers by the search query. We pair each server\n // with its catalog entry (if any) so the search can match friendly\n // names like \"Slack\" against a stdio server whose own `.name` is\n // just \"slack\".\n const filteredInstalledServers = allServers.filter((server) =>\n installedServerMatchesQuery(\n server,\n findCatalogEntryForServer(server, mcpMarketplace),\n searchQuery,\n ),\n );\n\n const handleMarketplaceInstall = (entry: MarketplaceEntry) => {\n setInstallEntry(entry);\n };\n\n const handleEdit = (server: MCPServerConfig) => {\n setEditingServer(server);\n };\n\n const handleDeleteClick = (serverId: string) => {\n const target = allServers.find((s) => s.id === serverId);\n if (target) setServerToDelete(target);\n };\n\n const handleConfirmDelete = () => {\n if (!serverToDelete) return;\n // Pass the full server config — useDeleteMcpServer re-resolves its\n // position against the fresh settings at mutation time, so a\n // background refresh between this click and confirm cannot point\n // us at the wrong index.\n deleteMcpServer(serverToDelete, {\n onSuccess: () => {\n displaySuccessToast(t(I18nKey.MCP$REMOVE_SUCCESS));\n setServerToDelete(null);\n },\n onError: (err) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n displayErrorToast(message || t(I18nKey.ERROR$GENERIC));\n setServerToDelete(null);\n },\n });\n };\n\n if (isLoading || !settings) {\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <div className=\"flex h-full flex-1 items-center justify-center px-4 md:px-0\">\n <div className=\"h-8 w-8 rounded-full border-2 border-transparent border-t-white animate-spin\" />\n </div>\n </div>\n );\n }\n\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <main className={settingsLikeMainScrollClassName}>\n <div className=\"mx-auto flex w-full min-w-0 max-w-[800px] flex-col gap-6\">\n <div className=\"min-w-0\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"space-y-1\">\n <h2 className=\"text-xl font-medium leading-6 text-foreground\">\n {t(I18nKey.SETTINGS$MCP_TITLE)}\n </h2>\n <div className=\"max-w-2xl text-sm text-tertiary-light\">\n {t(I18nKey.MCP$PAGE_DESCRIPTION)}\n </div>\n </div>\n <BrandButton\n type=\"button\"\n variant=\"secondary\"\n testId=\"mcp-add-custom-server\"\n className=\"flex-shrink-0 whitespace-nowrap\"\n onClick={() => setEditingServer({ id: \"\", type: \"sse\" })}\n >\n {t(I18nKey.MCP$ADD_CUSTOM)}\n </BrandButton>\n </div>\n </div>\n\n <McpToolbar\n search={searchQuery}\n onSearchChange={setSearchQuery}\n sectionFilter={sectionFilter}\n onSectionFilterChange={setSectionFilter}\n />\n\n {sectionFilter !== \"library\" ? (\n <section className=\"flex flex-col gap-3\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {t(I18nKey.MCP$INSTALLED_TITLE)}\n </h2>\n <InstalledServersSection\n servers={filteredInstalledServers}\n hasAnyInstalled={allServers.length > 0}\n query={searchQuery}\n onEdit={handleEdit}\n onDelete={handleDeleteClick}\n />\n </section>\n ) : null}\n\n {sectionFilter !== \"installed\" ? (\n <MarketplaceSection\n onSelect={handleMarketplaceInstall}\n onAdd={handleMarketplaceInstall}\n query={searchQuery}\n />\n ) : null}\n </div>\n\n {installEntry && (\n <InstallServerModal\n entry={installEntry}\n existingServers={allServers}\n onClose={() => setInstallEntry(null)}\n />\n )}\n\n {/* Custom (or non-marketplace) server editor. The empty-id\n sentinel (`{ id: \"\", type: \"sse\" }`) means \"add new\". */}\n {editingServer && (\n <CustomServerEditor\n server={editingServer}\n existingServers={allServers}\n onClose={() => setEditingServer(null)}\n />\n )}\n\n {serverToDelete && (\n <ConfirmationModal\n text={t(I18nKey.SETTINGS$MCP_CONFIRM_DELETE)}\n onCancel={() => setServerToDelete(null)}\n onConfirm={handleConfirmDelete}\n isConfirming={isDeleting}\n />\n )}\n </main>\n </div>\n );\n}\n"],"mappings":"oxCA0CA,SAAwB,GAAU,CAChC,GAAM,CAAE,KAAM,EAAA,eAAe,YAAY,CACnC,CAAE,KAAM,EAAU,aAAc,EAAA,aAAa,CAC7C,CAAE,OAAQ,EAAiB,UAAW,GAC1C,EAAA,oBAAoB,CAEhB,CAAC,EAAc,GACnB,EAAA,QAAM,SAAkC,KAAK,CACzC,CAAC,EAAe,GACpB,EAAA,QAAM,SAAiC,KAAK,CACxC,CAAC,EAAgB,GACrB,EAAA,QAAM,SAAiC,KAAK,CACxC,CAAC,EAAa,GAAkB,EAAA,QAAM,SAAS,GAAG,CAClD,CAAC,EAAe,GACpB,EAAA,QAAM,SAA2B,MAAM,CAGnC,EAAa,EAAA,iBADD,EAAA,eAAe,GAAU,gBAAgB,WACvB,CAAU,CACxC,EAAiB,EAAA,yBAAyB,EAAA,QAAgB,CAM1D,EAA2B,EAAW,OAAQ,GAClD,EAAA,4BACE,EACA,EAAA,0BAA0B,EAAQ,EAAe,CACjD,EACD,CACF,CAEK,EAA4B,GAA4B,CAC5D,EAAgB,EAAM,EA6CxB,OAdI,GAAa,CAAC,GAEd,EAAA,EAAA,MAAC,MAAD,CACE,cAAY,WACZ,UAAU,iEAFZ,EAIE,EAAA,EAAA,KAAC,EAAA,qBAAD,EAAwB,CAAA,EACxB,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,wEACb,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,+EAAiF,CAAA,CAC5F,CAAA,CACF,IAKR,EAAA,EAAA,MAAC,MAAD,CACE,cAAY,WACZ,UAAU,iEAFZ,EAIE,EAAA,EAAA,KAAC,EAAA,qBAAD,EAAwB,CAAA,EACxB,EAAA,EAAA,MAAC,OAAD,CAAM,UAAW,EAAA,yCAAjB,EACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,oEAAf,EACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,oBACb,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,kDAAf,EACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,qBAAf,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,yDACX,EAAE,EAAA,QAAQ,mBAAmB,CAC3B,CAAA,EACL,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,iDACZ,EAAE,EAAA,QAAQ,qBAAqB,CAC5B,CAAA,CACF,IACN,EAAA,EAAA,KAAC,EAAA,YAAD,CACE,KAAK,SACL,QAAQ,YACR,OAAO,wBACP,UAAU,kCACV,YAAe,EAAiB,CAAE,GAAI,GAAI,KAAM,MAAO,CAAC,UAEvD,EAAE,EAAA,QAAQ,eAAe,CACd,CAAA,CACV,GACF,CAAA,EAEN,EAAA,EAAA,KAAC,EAAA,WAAD,CACE,OAAQ,EACR,eAAgB,EACD,gBACf,sBAAuB,EACvB,CAAA,CAED,IAAkB,UAaf,MAZF,EAAA,EAAA,MAAC,UAAD,CAAS,UAAU,+BAAnB,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,mDACX,EAAE,EAAA,QAAQ,oBAAoB,CAC5B,CAAA,EACL,EAAA,EAAA,KAAC,EAAA,wBAAD,CACE,QAAS,EACT,gBAAiB,EAAW,OAAS,EACrC,MAAO,EACP,OAxFM,GAA4B,CAC9C,EAAiB,EAAO,EAwFZ,SArFa,GAAqB,CAC9C,IAAM,EAAS,EAAW,KAAM,GAAM,EAAE,KAAO,EAAS,CACpD,GAAQ,EAAkB,EAAO,EAoFzB,CAAA,CACM,GAGX,IAAkB,YAMf,MALF,EAAA,EAAA,KAAC,EAAA,mBAAD,CACE,SAAU,EACV,MAAO,EACP,MAAO,EACP,CAAA,CAEA,GAEL,IACC,EAAA,EAAA,KAAC,EAAA,mBAAD,CACE,MAAO,EACP,gBAAiB,EACjB,YAAe,EAAgB,KAAK,CACpC,CAAA,CAKH,IACC,EAAA,EAAA,KAAC,EAAA,mBAAD,CACE,OAAQ,EACR,gBAAiB,EACjB,YAAe,EAAiB,KAAK,CACrC,CAAA,CAGH,IACC,EAAA,EAAA,KAAC,EAAA,kBAAD,CACE,KAAM,EAAE,EAAA,QAAQ,4BAA4B,CAC5C,aAAgB,EAAkB,KAAK,CACvC,cApHwB,CAC3B,GAKL,EAAgB,EAAgB,CAC9B,cAAiB,CACf,EAAA,oBAAoB,EAAE,EAAA,QAAQ,mBAAmB,CAAC,CAClD,EAAkB,KAAK,EAEzB,QAAU,GAAQ,CAEhB,EAAA,kBADgB,EAAA,0BAA0B,EACxB,EAAW,EAAE,EAAA,QAAQ,cAAc,CAAC,CACtD,EAAkB,KAAK,EAE1B,CAAC,EAqGM,aAAc,EACd,CAAA,CAEC,GACH"}
|