@openhands/agent-canvas 1.17.0 → 1.19.0
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/acp-providers-BQ4o4vqy.js +1 -0
- package/build/assets/active-backend-context-BsLfwrXB.js +2 -0
- package/build/assets/{agent-context-settings-CJUrcBut.js → agent-context-settings-D9i6ezoJ.js} +1 -1
- package/build/assets/{agent-profiles-service.api-Biieml2L.js → agent-profiles-service.api-U-9YzDFU.js} +1 -1
- package/build/assets/agent-profiles-settings-D-bUV2PX.js +1 -0
- package/build/assets/agent-server-client-options-EHB23gyx.js +1 -0
- package/build/assets/agent-server-config-C_x8Otd9.js +1 -0
- package/build/assets/agent-server-conversation-service.api-BaVQ6NpE.js +88 -0
- package/build/assets/agent-settings-BZJHtaIK.js +2 -0
- package/build/assets/agent-settings-D4snDd6u.js +1 -0
- package/build/assets/alert-banner-BkVt_8Or.js +1 -0
- package/build/assets/{api-error-message-Ve79qDcN.js → api-error-message-BXo0lCI5.js} +1 -1
- package/build/assets/api-key-entry-screen-fAIld-n7.js +1 -0
- package/build/assets/app-settings-DITbrM2u.js +1 -0
- package/build/assets/automation-detail-DawHmaOl.js +3 -0
- package/build/assets/automation-disabled-reason-DtgC8Ppt.js +1 -0
- package/build/assets/{automation-export-DxY47m3T.js → automation-export-Kv6e0bHx.js} +1 -1
- package/build/assets/automation-git-sync-Dd98G_Oz.js +1 -0
- package/build/assets/automation-setup-route-Cdc109ZD.js +3 -0
- package/build/assets/{automation-templates-4C4PM8K7.js → automation-templates-Xhr-FDAB.js} +1 -1
- package/build/assets/automations-list-BeP1LuzQ.js +1 -0
- package/build/assets/{back-nav-button-B8tH0BEp.js → back-nav-button-DWNiN277.js} +1 -1
- package/build/assets/backend-form-modal-DeaUJIik.js +1 -0
- package/build/assets/backend-synced-settings-badge-Br85iWIY.js +1 -0
- package/build/assets/badge-Cdnei7Ly.js +1 -0
- package/build/assets/{base-modal-DTULovNc.js → base-modal-Ds7grR67.js} +1 -1
- package/build/assets/{bot-CLMxGFaq.js → bot-ByolqPEr.js} +1 -1
- package/build/assets/{brand-button-DxPO4Lf8.js → brand-button-mQq2Ld1I.js} +1 -1
- package/build/assets/browser-Bfum8fkE.js +46 -0
- package/build/assets/browser-tab-CmYT4j_r.js +1 -0
- package/build/assets/canvas-extension-page-CokKSVRG.js +1 -0
- package/build/assets/canvas-extensions-BoQEYG-2.js +1 -0
- package/build/assets/{canvas-extensions-runtime-DdnkgJXV.js → canvas-extensions-runtime-Du2M5iEX.js} +1 -1
- package/build/assets/{chat-send-button-B3SFSIg5.js → chat-send-button-DM3JgMc2.js} +1 -1
- package/build/assets/check-Bo8s5Ylg.js +1 -0
- package/build/assets/chevron-down-Cr6Fn_wS.js +1 -0
- package/build/assets/chevron-right-CfdfRn-8.js +1 -0
- package/build/assets/circle-check-5pH3qCji.js +1 -0
- package/build/assets/circle-plus-check-toggle-BbYBiUwv.js +1 -0
- package/build/assets/{cloud-funnel-analytics-BQanUEEC.js → cloud-funnel-analytics-D02kgq1s.js} +1 -1
- package/build/assets/{cog-VBlRo6iw.js → cog-Dy1eWbSZ.js} +1 -1
- package/build/assets/command-menu-mehU3Evb.js +1 -0
- package/build/assets/commits-tab-DhQW8CXi.js +1 -0
- package/build/assets/{condenser-settings-eVKFMvap.js → condenser-settings-eRk6Fkx6.js} +1 -1
- package/build/assets/confirmation-modal-BmVt_c0I.js +1 -0
- package/build/assets/{context-menu-list-item-DDROe12Z.js → context-menu-list-item-lx2zk9G7.js} +1 -1
- package/build/assets/{conversation-BnjJSFf5.js → conversation-BOj0ENI6.js} +8 -8
- package/build/assets/conversation-SouWlGvs.js +1 -0
- package/build/assets/conversation-panel-SouWlGvs.js +1 -0
- package/build/assets/conversation-state-store-C6YncQNo.js +1 -0
- package/build/assets/conversation-store-DC-JlJuq.js +6 -0
- package/build/assets/{conversation-tab-empty-state-DKlzAz5c.js → conversation-tab-empty-state-DIhwCC2J.js} +1 -1
- package/build/assets/copy-to-clipboard-button-DVNXLylP.js +1 -0
- package/build/assets/device-verify-LP-x7nra.js +1 -0
- package/build/assets/{dropdown-classes-B9kJVDIk.js → dropdown-classes-goDldkiu.js} +1 -1
- package/build/assets/edit-automation-modal-BJJR9wSW.js +1 -0
- package/build/assets/empty-state-Cd-TFe7i.js +1 -0
- package/build/assets/{entry.client-Ds8LVp-E.js → entry.client-CJdjIvMZ.js} +2 -2
- package/build/assets/enum-filter-dropdown-pocrz9AL.js +1 -0
- package/build/assets/environment-switch-overlay-Dwe78wRl.js +1 -0
- package/build/assets/error-state-SuWwztxV.js +1 -0
- package/build/assets/extensions-hub-O0esK3Er.js +1 -0
- package/build/assets/extensions-navigation-CgCVSXje.js +1 -0
- package/build/assets/{external-link-DQtv7eTh.js → external-link-Bd7Tga-1.js} +1 -1
- package/build/assets/files-tab-B_6t8ljw.js +1 -0
- package/build/assets/{form-control-classes-B-z85REi.js → form-control-classes-lQfLxzH4.js} +1 -1
- package/build/assets/format-model-name-Dfh9Udrx.js +1 -0
- package/build/assets/get-git-path-Bp5rsUkl.js +1 -0
- package/build/assets/git-repo-dropdown-CbD0_LPN.js +1 -0
- package/build/assets/git-repo-dropdown-DPQVumZg.js +1 -0
- package/build/assets/highlighted-source-view-Bp0sgK-f.js +1 -0
- package/build/assets/home-BghzJd-D.js +1 -0
- package/build/assets/home-CXZ8zawS.js +1 -0
- package/build/assets/home-automation-run-tooltip-BdpCckKO.js +1 -0
- package/build/assets/home-store-DNQpfIEO.js +1 -0
- package/build/assets/hooks-service-DkxnQa4N.js +1 -0
- package/build/assets/index-home-Ca6Q5CtT.js +1 -0
- package/build/assets/info-BcajzHn1.js +1 -0
- package/build/assets/install-server-modal-DvxxYKia.js +1 -0
- package/build/assets/{key-CfXbJa8w.js → key-CwTE6XJj.js} +1 -1
- package/build/assets/launch-jsRGPRBx.js +1 -0
- package/build/assets/link-external-B4gx3EeM.js +1 -0
- package/build/assets/list-filter-B8PQk3RA.js +1 -0
- package/build/assets/{list-todo-ByXMdY4W.js → list-todo-Caa8E1X_.js} +1 -1
- package/build/assets/llm-not-configured-banner-DMdL1vaX.js +27 -0
- package/build/assets/llm-settings-dkQ5Oq7W.js +1 -0
- package/build/assets/llm-settings-lNDerSlu.js +1 -0
- package/build/assets/{llm-subscription-service-aDNBQ7Gq.js → llm-subscription-service-BiQaZbvv.js} +1 -1
- package/build/assets/loader-circle-BxJgk73D.js +1 -0
- package/build/assets/{loading-spinner-DfHI77BA.js → loading-spinner-DK1sAwVg.js} +1 -1
- package/build/assets/manage-backends-modal-DqCJohsX.js +1 -0
- package/build/assets/manifest-ff93dc8c.js +1 -0
- package/build/assets/manifest-subpage-layout-sxuPqfUr.js +1 -0
- package/build/assets/{map-provider-DXvssjw9.js → map-provider-iRs80q_6.js} +1 -1
- package/build/assets/markdown-renderer-BH5pqDuJ.js +8 -0
- package/build/assets/mcp-BtaJDXnP.js +1 -0
- package/build/assets/mcp-installed-servers-Br4ZLsjr.js +1 -0
- package/build/assets/mcp-marketplace-utils-BwEnDYqm.js +1 -0
- package/build/assets/mcp-page-DwbnQpVs.js +9 -0
- package/build/assets/messages-DmFJlW6c.js +41 -0
- package/build/assets/{modal-body-DJw4xBki.js → modal-body-DBweM2EN.js} +1 -1
- package/build/assets/{modal-classes-Dg0ngBPO.js → modal-classes-jvG85nkU.js} +1 -1
- package/build/assets/modal-close-button-BrM5fNnn.js +1 -0
- package/build/assets/{mouse-pointer-click-DEhsSUpu.js → mouse-pointer-click-BXlRN92t.js} +1 -1
- package/build/assets/onboarding-CQ8T6T0U.js +1 -0
- package/build/assets/onboarding-modal-CnliiaSN.js +1 -0
- package/build/assets/{organization-service.api-Cyg1Tn03.js → organization-service.api-DmFUEmu5.js} +1 -1
- package/build/assets/parse-git-remote-url-BG8pcKL8.js +1 -0
- package/build/assets/{pencil-D5c47kyN.js → pencil-q-ihqDYv.js} +1 -1
- package/build/assets/{pin-C7vMagvf.js → pin-BdroVQdN.js} +1 -1
- package/build/assets/planner-tab-CXph_C9F.js +1 -0
- package/build/assets/{plug-CeaqeF6u.js → plug-7ACOEbMs.js} +1 -1
- package/build/assets/{plugins-management-service-Bh_pBuf-.js → plugins-management-service-CcEpfNKz.js} +1 -1
- package/build/assets/plus-C2e21TFC.js +1 -0
- package/build/assets/{profiles-service.api-BbOK0EkF.js → profiles-service.api-DdF_4Zhe.js} +1 -1
- package/build/assets/providers-BWRnl31s.js +1 -0
- package/build/assets/proxy-DbEf3Nqr.js +1 -0
- package/build/assets/{puzzle-DdAqbUrb.js → puzzle-LJYnuxKe.js} +1 -1
- package/build/assets/react-BX7IV650.js +1 -0
- package/build/assets/recommended-automations-launcher-r0oI91HN.js +1 -0
- package/build/assets/{refresh-cw-DEQdPCpH.js → refresh-cw-BtdC3T8P.js} +1 -1
- package/build/assets/root-j2fFRlWS.js +2 -0
- package/build/assets/root-layout-CfGgm2lo.js +2 -0
- package/build/assets/root-sEWn3ha1.css +1 -0
- package/build/assets/schema-field-c3Ncgm4x.js +1 -0
- package/build/assets/sdk-section-page-DFEiuiFQ.js +1 -0
- package/build/assets/secret-form-WXXNFqTM.js +1 -0
- package/build/assets/{secrets-service-Cr8g8xuv.js → secrets-service-DU6wh3wX.js} +1 -1
- package/build/assets/secrets-settings-BEqbPvjy.js +1 -0
- package/build/assets/settings-DjaSQwFh.js +1 -0
- package/build/assets/settings-dropdown-input-BRR2OZwi.js +1 -0
- package/build/assets/settings-index-DHv4XFcM.js +1 -0
- package/build/assets/settings-input-Cm4VxUon.js +1 -0
- package/build/assets/{settings-list-classes-Ds4jPBHK.js → settings-list-classes-CaUfKZ33.js} +1 -1
- package/build/assets/settings-modal-djXuAnBO.js +1 -0
- package/build/assets/settings-nav-DFb3hBMr.js +16 -0
- package/build/assets/{settings-service.api-9_xdv_mh.js → settings-service.api-Q9lKW1TX.js} +1 -1
- package/build/assets/settings-switch-seaSJc7t.js +1 -0
- package/build/assets/{settings-utils-8GIIgOQL.js → settings-utils-BTaaRhLZ.js} +1 -1
- package/build/assets/shared-conversation-x3rxVCon.js +1 -0
- package/build/assets/{shield-check-DO7wa_eu.js → shield-check-C3Rl0NF8.js} +1 -1
- package/build/assets/{sidebar-layout-EPfWxk11.js → sidebar-layout-B6mcvvdV.js} +1 -1
- package/build/assets/sidebar-mobile-menu-toggle-CEqS8KnA.js +1 -0
- package/build/assets/{sidebar-nav-link-_t4_Ef-9.js → sidebar-nav-link-BTHX11LG.js} +1 -1
- package/build/assets/{sidebar-onboarding-checklist-storage-DbDX-Wvj.js → sidebar-onboarding-checklist-storage-BP1kzn6p.js} +1 -1
- package/build/assets/sidebar-store-DAZVH-DR.js +1 -0
- package/build/assets/skill-card-pill-row-TD39nfP3.js +1 -0
- package/build/assets/{skill-filter-BBeZ4JEP.js → skill-filter-CdBbbwjm.js} +2 -2
- package/build/assets/{skill-icon-badge-BDhQ-tQ0.js → skill-icon-badge-vUEp7gsC.js} +1 -1
- package/build/assets/skill-scope-BTRBQt0-.js +1 -0
- package/build/assets/skills-plugins-k1tUNAw4.js +1 -0
- package/build/assets/skills-settings-CENviPT7.js +1 -0
- package/build/assets/{styled-tooltip-Pd22BIvr.js → styled-tooltip-DVAlWYnL.js} +1 -1
- package/build/assets/task-list-tab-BLKF_x9f.js +1 -0
- package/build/assets/{terminal-onXx0_Qz.js → terminal-Ckbnqb23.js} +1 -1
- package/build/assets/{toggle-switch-lwQtxDcm.js → toggle-switch-DeiG9Mf6.js} +1 -1
- package/build/assets/{trash-2-ZhKuTLiz.js → trash-2-Bb40zQzs.js} +1 -1
- package/build/assets/trash-CXN2R54L.js +1 -0
- package/build/assets/{triangle-alert-BajLPpQg.js → triangle-alert-DEdu-b_L.js} +1 -1
- package/build/assets/{typography-HLLg_FAn.js → typography-NarNyelM.js} +1 -1
- package/build/assets/usage-tab-Drd3O006.js +1 -0
- package/build/assets/use-acp-credential-form-CJ5wPsQm.js +1 -0
- package/build/assets/{use-activate-agent-profile-BLKML6vQ.js → use-activate-agent-profile-iQZ0U3qV.js} +1 -1
- package/build/assets/use-agent-profiles-LCvb5OXT.js +1 -0
- package/build/assets/{use-automation-health-BZkQNEA8.js → use-automation-health-DdgSa8sA.js} +1 -1
- package/build/assets/{use-automation-permissions-B_RpvL-s.js → use-automation-permissions-D3kEeieu.js} +1 -1
- package/build/assets/{use-automations-Cg0PDIZr.js → use-automations-CEubcYTD.js} +1 -1
- package/build/assets/{use-can-manage-org-profiles-BbN6KfDr.js → use-can-manage-org-profiles-CB8ybxFK.js} +1 -1
- package/build/assets/{use-canvas-extensions-CFUpHat6.js → use-canvas-extensions-BMacwi2v.js} +1 -1
- package/build/assets/{use-cloud-current-user-id-Dk0rjr63.js → use-cloud-current-user-id-BEKRd6XZ.js} +1 -1
- package/build/assets/{use-config-DpafU_QP.js → use-config-3WYcJsgC.js} +1 -1
- package/build/assets/{use-create-conversation-1YgmAHt-.js → use-create-conversation-Be-eVpFp.js} +1 -1
- package/build/assets/use-create-secret-Bk9ZxTjl.js +1 -0
- package/build/assets/use-free-models-Ci3FkKEm.js +1 -0
- package/build/assets/{use-get-secrets-CQ4b0qK8.js → use-get-secrets-fqS0kxt6.js} +1 -1
- package/build/assets/use-is-authed-A2Yinlt0.js +1 -0
- package/build/assets/{use-launch-skill-in-chat-DeYa1tFM.js → use-launch-skill-in-chat-QbXDhiHr.js} +1 -1
- package/build/assets/use-llm-configured-B71ZEVg2.js +1 -0
- package/build/assets/use-llm-profiles-xtCBMbef.js +1 -0
- package/build/assets/{use-manifest-capabilities-AOWGcu0j.js → use-manifest-capabilities-Bso6A_-A.js} +1 -1
- package/build/assets/{use-onboarding-completion-CoINurkm.js → use-onboarding-completion-CEgjL02y.js} +1 -1
- package/build/assets/{use-pinned-home-route-D6krwXjy.js → use-pinned-home-route-pK4IlJ-p.js} +1 -1
- package/build/assets/{use-plugins-marketplace-mLsIDhBv.js → use-plugins-marketplace-B8-ZEB34.js} +1 -1
- package/build/assets/use-save-agent-profile-D7hJuW_u.js +1 -0
- package/build/assets/{use-save-settings-3U5K9-8x.js → use-save-settings-CikTu5xV.js} +1 -1
- package/build/assets/{use-settings-Dn00UISA.js → use-settings-BWIH5EuN.js} +1 -1
- package/build/assets/use-settings-nav-items-DSKwLDnd.js +1 -0
- package/build/assets/use-tracking-ChnSFChv.js +3 -0
- package/build/assets/{use-user-conversation-ZWlXtbZb.js → use-user-conversation-C_l65DqW.js} +1 -1
- package/build/assets/{useInfiniteQuery-BzrRqjLg.js → useInfiniteQuery-CtSRG7uW.js} +1 -1
- package/build/assets/{useMutation-CJuK90oc.js → useMutation-Cszf8mKy.js} +1 -1
- package/build/assets/useQueries-pUohFMSP.js +1 -0
- package/build/assets/useQuery-DAAacS7O.js +1 -0
- package/build/assets/useTranslation-CCgUjPJF.js +1 -0
- package/build/assets/utils-D-gOfhmN.js +1 -0
- package/build/assets/{vendor~conversation-panel~conversation-4eJ0tml3.js → vendor~conversation-panel~conversation-C22sJuWZ.js} +1 -1
- package/build/assets/vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~b0x1wrp2-D6owle9R.js +2 -0
- package/build/assets/vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~czjee3a3-BXXGJNDU.js +185 -0
- package/build/assets/vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~ew9ih1s8-40UR63Gt.js +1 -0
- package/build/assets/{vendor~index-home~home~conversation-panel~conversation-CSFLzmTN.js → vendor~index-home~home~conversation-panel~conversation-UTl7gUo9.js} +1 -1
- package/build/assets/{vendor~root-layout-n8XCEXG8.js → vendor~root-layout-CcdIqs-C.js} +1 -1
- package/build/assets/{vendor~root-layout~conversation-panel~conversation-3Idg1_U3.js → vendor~root-layout~conversation-panel~conversation-C3EBV3kp.js} +1 -1
- package/build/assets/vendor~root-layout~conversation-panel~conversation~skills-settings~automations-list~shared-~bovqqk8e-BCe0JJVy.js +1 -0
- package/build/assets/{vendor~root-layout~index-home~home~conversation-panel~conversation-DgQ564nC.js → vendor~root-layout~index-home~home~conversation-panel~conversation-BGGbPcYh.js} +1 -1
- package/build/assets/vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~inibp4qe-BFRW8wt-.js +48 -0
- package/build/assets/{vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~skills-setti~eo2nf80n-BPjI-atc.js → vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~skills-setti~eo2nf80n-3eJ4ExtV.js} +1 -1
- package/build/assets/{verification-settings-u2POabjH.js → verification-settings-PKtoIUUY.js} +1 -1
- package/build/assets/{wrench-CkgI4rxA.js → wrench-B8Wg_nbp.js} +1 -1
- package/build/assets/{x-By6qCmtY.js → x-CX8lVGwm.js} +1 -1
- package/build/index.html +4 -4
- package/build/locales/ar/openhands.json +16 -2
- package/build/locales/ca/openhands.json +16 -2
- package/build/locales/de/openhands.json +16 -2
- package/build/locales/en/openhands.json +16 -2
- package/build/locales/es/openhands.json +16 -2
- package/build/locales/fr/openhands.json +16 -2
- package/build/locales/it/openhands.json +16 -2
- package/build/locales/ja/openhands.json +16 -2
- package/build/locales/ko-KR/openhands.json +16 -2
- package/build/locales/no/openhands.json +16 -2
- package/build/locales/pt/openhands.json +16 -2
- package/build/locales/tr/openhands.json +16 -2
- package/build/locales/uk/openhands.json +16 -2
- package/build/locales/zh-CN/openhands.json +16 -2
- package/build/locales/zh-TW/openhands.json +16 -2
- package/config/defaults.json +3 -3
- package/dist/api/cloud/organization-service.api.cjs.map +1 -1
- package/dist/api/cloud/organization-service.api.d.ts +9 -1
- package/dist/api/cloud/organization-service.api.js.map +1 -1
- package/dist/api/config-service/config-service.api.cjs +1 -1
- package/dist/api/config-service/config-service.api.cjs.map +1 -1
- package/dist/api/config-service/config-service.api.js +6 -2
- package/dist/api/config-service/config-service.api.js.map +1 -1
- package/dist/api/config-service/config-service.types.d.ts +13 -0
- package/dist/components/conversation-events/chat/event-content-helpers/get-skill-ready-content.cjs +3 -3
- package/dist/components/conversation-events/chat/event-content-helpers/get-skill-ready-content.cjs.map +1 -1
- package/dist/components/conversation-events/chat/event-content-helpers/get-skill-ready-content.js +12 -16
- package/dist/components/conversation-events/chat/event-content-helpers/get-skill-ready-content.js.map +1 -1
- package/dist/components/features/automations/automation-card.cjs +1 -1
- package/dist/components/features/automations/automation-card.cjs.map +1 -1
- package/dist/components/features/automations/automation-card.js +39 -38
- package/dist/components/features/automations/automation-card.js.map +1 -1
- package/dist/components/features/automations/automation-list-row.cjs +1 -1
- package/dist/components/features/automations/automation-list-row.cjs.map +1 -1
- package/dist/components/features/automations/automation-list-row.js +73 -72
- package/dist/components/features/automations/automation-list-row.js.map +1 -1
- package/dist/components/features/automations/build-automation-menu-items.cjs +1 -1
- package/dist/components/features/automations/build-automation-menu-items.cjs.map +1 -1
- package/dist/components/features/automations/build-automation-menu-items.d.ts +3 -1
- package/dist/components/features/automations/build-automation-menu-items.js +12 -11
- package/dist/components/features/automations/build-automation-menu-items.js.map +1 -1
- package/dist/components/features/automations/detail/configuration-section.d.ts +7 -1
- package/dist/components/features/automations/detail/detail-header.d.ts +8 -5
- package/dist/components/features/automations/detail/disabled-reason-banner.d.ts +16 -0
- 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 +112 -112
- package/dist/components/features/backends/backend-selector.js.map +1 -1
- package/dist/components/features/chat/components/chat-input-llm-profile-picker.cjs +1 -1
- package/dist/components/features/chat/components/chat-input-llm-profile-picker.cjs.map +1 -1
- package/dist/components/features/chat/components/chat-input-llm-profile-picker.js +62 -61
- package/dist/components/features/chat/components/chat-input-llm-profile-picker.js.map +1 -1
- package/dist/components/features/chat/model-messages.cjs +1 -1
- package/dist/components/features/chat/model-messages.cjs.map +1 -1
- package/dist/components/features/chat/model-messages.js +27 -26
- package/dist/components/features/chat/model-messages.js.map +1 -1
- package/dist/components/features/conversation-panel/budget-display.cjs +1 -1
- package/dist/components/features/conversation-panel/budget-display.cjs.map +1 -1
- package/dist/components/features/conversation-panel/budget-display.d.ts +1 -2
- package/dist/components/features/conversation-panel/budget-display.js +12 -19
- package/dist/components/features/conversation-panel/budget-display.js.map +1 -1
- package/dist/components/features/conversation-panel/conversation-card/conversation-card-footer.cjs +1 -1
- package/dist/components/features/conversation-panel/conversation-card/conversation-card-footer.cjs.map +1 -1
- package/dist/components/features/conversation-panel/conversation-card/conversation-card-footer.js +45 -44
- package/dist/components/features/conversation-panel/conversation-card/conversation-card-footer.js.map +1 -1
- package/dist/components/features/home/featured-automations/build-home-automation-menu-items.d.ts +1 -2
- package/dist/components/features/home/featured-automations/build-pinned-automation-menu-items.d.ts +0 -1
- package/dist/components/features/home/featured-automations/home-automation-run-tooltip.cjs +1 -1
- package/dist/components/features/home/featured-automations/home-automation-run-tooltip.cjs.map +1 -1
- package/dist/components/features/home/featured-automations/home-automation-run-tooltip.js +38 -29
- package/dist/components/features/home/featured-automations/home-automation-run-tooltip.js.map +1 -1
- package/dist/components/features/images/image-lightbox.cjs +2 -0
- package/dist/components/features/images/image-lightbox.cjs.map +1 -0
- package/dist/components/features/images/image-lightbox.d.ts +11 -0
- package/dist/components/features/images/image-lightbox.js +37 -0
- package/dist/components/features/images/image-lightbox.js.map +1 -0
- package/dist/components/features/images/image-preview.cjs +1 -1
- package/dist/components/features/images/image-preview.cjs.map +1 -1
- package/dist/components/features/images/image-preview.d.ts +2 -1
- package/dist/components/features/images/image-preview.js +33 -13
- package/dist/components/features/images/image-preview.js.map +1 -1
- package/dist/components/features/onboarding/steps/setup-llm-step.d.ts +3 -4
- package/dist/components/features/settings/agent-profiles/profile-scope-list.d.ts +20 -0
- package/dist/components/features/settings/cloud-settings-link.cjs +1 -1
- package/dist/components/features/settings/cloud-settings-link.cjs.map +1 -1
- package/dist/components/features/settings/cloud-settings-link.d.ts +3 -1
- package/dist/components/features/settings/cloud-settings-link.js +22 -21
- package/dist/components/features/settings/cloud-settings-link.js.map +1 -1
- 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 +2 -1
- package/dist/components/features/settings/llm-profiles/profile-row.cjs +1 -1
- package/dist/components/features/settings/llm-profiles/profile-row.js +1 -1
- package/dist/components/features/sidebar/sidebar-rail-body.cjs +1 -1
- package/dist/components/features/sidebar/sidebar-rail-body.cjs.map +1 -1
- package/dist/components/features/sidebar/sidebar-rail-body.d.ts +2 -1
- package/dist/components/features/sidebar/sidebar-rail-body.js +143 -142
- package/dist/components/features/sidebar/sidebar-rail-body.js.map +1 -1
- package/dist/components/features/sidebar/sidebar.cjs +1 -1
- package/dist/components/features/sidebar/sidebar.cjs.map +1 -1
- package/dist/components/features/sidebar/sidebar.js +28 -27
- package/dist/components/features/sidebar/sidebar.js.map +1 -1
- package/dist/components/providers/agent-server-ui-providers.cjs +1 -1
- package/dist/components/providers/agent-server-ui-providers.cjs.map +1 -1
- package/dist/components/providers/agent-server-ui-providers.js +33 -29
- package/dist/components/providers/agent-server-ui-providers.js.map +1 -1
- package/dist/components/shared/buttons/remove-button.cjs +1 -1
- package/dist/components/shared/buttons/remove-button.cjs.map +1 -1
- package/dist/components/shared/buttons/remove-button.d.ts +2 -1
- package/dist/components/shared/buttons/remove-button.js +2 -1
- package/dist/components/shared/buttons/remove-button.js.map +1 -1
- package/dist/components/shared/free-models-note.cjs +2 -0
- package/dist/components/shared/free-models-note.cjs.map +1 -0
- package/dist/components/shared/free-models-note.d.ts +3 -0
- package/dist/components/shared/free-models-note.js +20 -0
- package/dist/components/shared/free-models-note.js.map +1 -0
- package/dist/components/shared/modals/settings/model-selector.cjs +1 -1
- package/dist/components/shared/modals/settings/model-selector.cjs.map +1 -1
- package/dist/components/shared/modals/settings/model-selector.js +102 -112
- package/dist/components/shared/modals/settings/model-selector.js.map +1 -1
- package/dist/config/defaults.cjs +1 -1
- package/dist/config/defaults.cjs.map +1 -1
- package/dist/config/defaults.js +3 -3
- package/dist/config/defaults.js.map +1 -1
- package/dist/constants/acp-providers.cjs +1 -1
- package/dist/constants/acp-providers.cjs.map +1 -1
- package/dist/constants/acp-providers.d.ts +7 -0
- package/dist/constants/acp-providers.js +20 -16
- package/dist/constants/acp-providers.js.map +1 -1
- package/dist/constants/profile-scope.d.ts +21 -0
- package/dist/hooks/chat/use-slash-command.cjs +1 -1
- package/dist/hooks/chat/use-slash-command.cjs.map +1 -1
- package/dist/hooks/chat/use-slash-command.js +63 -62
- package/dist/hooks/chat/use-slash-command.js.map +1 -1
- package/dist/hooks/query/use-automation-sdk-version.cjs +1 -1
- package/dist/hooks/query/use-automation-sdk-version.cjs.map +1 -1
- package/dist/hooks/query/use-automation-sdk-version.js +3 -1
- package/dist/hooks/query/use-automation-sdk-version.js.map +1 -1
- package/dist/hooks/query/use-free-models.cjs +2 -0
- package/dist/hooks/query/use-free-models.cjs.map +1 -0
- package/dist/hooks/query/use-free-models.d.ts +23 -0
- package/dist/hooks/query/use-free-models.js +67 -0
- package/dist/hooks/query/use-free-models.js.map +1 -0
- package/dist/hooks/query/use-local-git-info.cjs.map +1 -1
- package/dist/hooks/query/use-local-git-info.js.map +1 -1
- package/dist/hooks/query/use-provider-models.cjs +1 -1
- package/dist/hooks/query/use-provider-models.cjs.map +1 -1
- package/dist/hooks/query/use-provider-models.js +34 -25
- package/dist/hooks/query/use-provider-models.js.map +1 -1
- package/dist/hooks/query/use-search-providers.cjs +1 -1
- package/dist/hooks/query/use-search-providers.cjs.map +1 -1
- package/dist/hooks/query/use-search-providers.js +31 -19
- package/dist/hooks/query/use-search-providers.js.map +1 -1
- package/dist/hooks/use-drag-resize.cjs +1 -1
- package/dist/hooks/use-drag-resize.cjs.map +1 -1
- package/dist/hooks/use-drag-resize.js +8 -9
- package/dist/hooks/use-drag-resize.js.map +1 -1
- package/dist/hooks/use-home-automation-actions.cjs +1 -1
- package/dist/hooks/use-home-automation-actions.cjs.map +1 -1
- package/dist/hooks/use-home-automation-actions.d.ts +1 -2
- package/dist/hooks/use-home-automation-actions.js +0 -1
- package/dist/hooks/use-home-automation-actions.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 +16 -2
- 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 +255 -17
- package/dist/i18n/translation.js.map +1 -1
- package/dist/locales/ar/openhands.json +16 -2
- package/dist/locales/ca/openhands.json +16 -2
- package/dist/locales/de/openhands.json +16 -2
- package/dist/locales/en/openhands.json +16 -2
- package/dist/locales/es/openhands.json +16 -2
- package/dist/locales/fr/openhands.json +16 -2
- package/dist/locales/it/openhands.json +16 -2
- package/dist/locales/ja/openhands.json +16 -2
- package/dist/locales/ko-KR/openhands.json +16 -2
- package/dist/locales/no/openhands.json +16 -2
- package/dist/locales/pt/openhands.json +16 -2
- package/dist/locales/tr/openhands.json +16 -2
- package/dist/locales/uk/openhands.json +16 -2
- package/dist/locales/zh-CN/openhands.json +16 -2
- package/dist/locales/zh-TW/openhands.json +16 -2
- package/dist/manifests/manifest-validation.cjs +1 -1
- package/dist/manifests/manifest-validation.cjs.map +1 -1
- package/dist/manifests/manifest-validation.js +2 -2
- package/dist/manifests/manifest-validation.js.map +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/agent-server-compatibility.cjs +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/agent-server-compatibility.cjs.map +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/agent-server-compatibility.js +15 -8
- package/dist/node_modules/@openhands/typescript-client/dist/client/agent-server-compatibility.js.map +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/bash-client.cjs +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/bash-client.cjs.map +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/bash-client.js +11 -13
- package/dist/node_modules/@openhands/typescript-client/dist/client/bash-client.js.map +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/conversation-client.cjs +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/conversation-client.cjs.map +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/conversation-client.js +6 -0
- package/dist/node_modules/@openhands/typescript-client/dist/client/conversation-client.js.map +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/desktop-client.cjs +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/desktop-client.cjs.map +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/desktop-client.js +3 -6
- package/dist/node_modules/@openhands/typescript-client/dist/client/desktop-client.js.map +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/file-client.cjs +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/file-client.cjs.map +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/file-client.js +9 -12
- package/dist/node_modules/@openhands/typescript-client/dist/client/file-client.js.map +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/runtime-transport.cjs +2 -0
- package/dist/node_modules/@openhands/typescript-client/dist/client/runtime-transport.cjs.map +1 -0
- package/dist/node_modules/@openhands/typescript-client/dist/client/runtime-transport.js +41 -0
- package/dist/node_modules/@openhands/typescript-client/dist/client/runtime-transport.js.map +1 -0
- package/dist/node_modules/@openhands/typescript-client/dist/client/vscode-client.cjs +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/vscode-client.cjs.map +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/vscode-client.js +3 -6
- package/dist/node_modules/@openhands/typescript-client/dist/client/vscode-client.js.map +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/clients.cjs +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/clients.js +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.cjs +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.cjs.map +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.js +199 -61
- package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.js.map +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/workspace/remote-workspace.cjs +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/workspace/remote-workspace.cjs.map +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/workspace/remote-workspace.js +9 -8
- package/dist/node_modules/@openhands/typescript-client/dist/workspace/remote-workspace.js.map +1 -1
- package/dist/package.cjs +1 -1
- package/dist/package.cjs.map +1 -1
- package/dist/package.js +2 -2
- package/dist/package.js.map +1 -1
- package/dist/routes/agent-settings.d.ts +5 -0
- package/dist/routes/app-settings.cjs +1 -1
- package/dist/routes/app-settings.cjs.map +1 -1
- package/dist/routes/app-settings.js +52 -47
- package/dist/routes/app-settings.js.map +1 -1
- package/dist/routes/llm-settings.cjs +1 -1
- package/dist/routes/llm-settings.cjs.map +1 -1
- package/dist/routes/llm-settings.js +137 -145
- package/dist/routes/llm-settings.js.map +1 -1
- package/dist/stores/free-models-store.cjs +2 -0
- package/dist/stores/free-models-store.cjs.map +1 -0
- package/dist/stores/free-models-store.d.ts +30 -0
- package/dist/stores/free-models-store.js +22 -0
- package/dist/stores/free-models-store.js.map +1 -0
- package/dist/types/automation.cjs.map +1 -1
- package/dist/types/automation.d.ts +23 -1
- package/dist/types/automation.js.map +1 -1
- package/dist/utils/automation-disabled-reason.cjs +2 -0
- package/dist/utils/automation-disabled-reason.cjs.map +1 -0
- package/dist/utils/automation-disabled-reason.d.ts +32 -0
- package/dist/utils/automation-disabled-reason.js +19 -0
- package/dist/utils/automation-disabled-reason.js.map +1 -0
- package/dist/utils/format-model-name.cjs +1 -1
- package/dist/utils/format-model-name.cjs.map +1 -1
- package/dist/utils/format-model-name.d.ts +27 -6
- package/dist/utils/format-model-name.js +14 -6
- package/dist/utils/format-model-name.js.map +1 -1
- package/dist/utils/parse-git-remote-url.cjs +1 -1
- package/dist/utils/parse-git-remote-url.cjs.map +1 -1
- package/dist/utils/parse-git-remote-url.d.ts +5 -1
- package/dist/utils/parse-git-remote-url.js +20 -13
- package/dist/utils/parse-git-remote-url.js.map +1 -1
- package/package.json +2 -2
- package/scripts/check-sdk-version-sync.mjs +79 -8
- package/scripts/dev-safe.mjs +1 -1
- package/scripts/static-server.mjs +24 -7
- package/build/assets/acp-providers-DrjNsPOH.js +0 -1
- package/build/assets/active-backend-context-rZiLJRUc.js +0 -2
- package/build/assets/agent-profiles-settings-x6RvPsq7.js +0 -1
- package/build/assets/agent-server-client-options-BikiNwTa.js +0 -1
- package/build/assets/agent-server-conversation-service.api-DYFsNHKf.js +0 -88
- package/build/assets/agent-settings-BJyovpJ_.js +0 -1
- package/build/assets/agent-settings-CpY3zObk.js +0 -2
- package/build/assets/alert-banner-vARz1idS.js +0 -1
- package/build/assets/api-key-entry-screen-CsMuBhoP.js +0 -1
- package/build/assets/app-settings-BaJ7nfHt.js +0 -1
- package/build/assets/automation-detail-CVoGDrKq.js +0 -3
- package/build/assets/automation-git-sync-CRMP9Bbm.js +0 -1
- package/build/assets/automation-setup-route-072beLz1.js +0 -3
- package/build/assets/automations-list-xuqTSQL4.js +0 -1
- package/build/assets/backend-form-modal-0aJmWdsa.js +0 -1
- package/build/assets/backend-synced-settings-badge-B7rKWBir.js +0 -1
- package/build/assets/badge-CcGx2TaV.js +0 -1
- package/build/assets/browser-C-_qBasq.js +0 -46
- package/build/assets/browser-tab-DZanIw5m.js +0 -1
- package/build/assets/canvas-extension-page-o_cWgE9B.js +0 -1
- package/build/assets/canvas-extensions-DSgNlCha.js +0 -1
- package/build/assets/check-fDEfgSzj.js +0 -1
- package/build/assets/chevron-down-CFrWHqu8.js +0 -1
- package/build/assets/chevron-right-C5roOrJu.js +0 -1
- package/build/assets/circle-check-ClTzJTdb.js +0 -1
- package/build/assets/circle-plus-check-toggle-Fr-h-mbL.js +0 -1
- package/build/assets/command-menu-BT3Ia5Ru.js +0 -1
- package/build/assets/commits-tab-2jhtaohl.js +0 -1
- package/build/assets/confirmation-modal-gIFHeZt6.js +0 -1
- package/build/assets/conversation-DZ578rOX.js +0 -1
- package/build/assets/conversation-panel-DZ578rOX.js +0 -1
- package/build/assets/conversation-state-store-D1_G_9I-.js +0 -1
- package/build/assets/conversation-store-DVVfkCsk.js +0 -6
- package/build/assets/copy-to-clipboard-button-B3w0X7WH.js +0 -1
- package/build/assets/device-verify-BfkCzyFB.js +0 -1
- package/build/assets/edit-automation-modal-BwhJ39JT.js +0 -1
- package/build/assets/empty-state-RZz0OfnY.js +0 -1
- package/build/assets/enum-filter-dropdown-C4pW0ORd.js +0 -1
- package/build/assets/environment-switch-overlay-P2ZAuzov.js +0 -1
- package/build/assets/error-state-B_5cgNPJ.js +0 -1
- package/build/assets/extensions-hub-DsaUr4ca.js +0 -1
- package/build/assets/extensions-navigation-CRMZd-FE.js +0 -1
- package/build/assets/files-tab-CCgAcVdc.js +0 -1
- package/build/assets/format-model-name-CasAP3nd.js +0 -1
- package/build/assets/get-git-path-EHrSDxTM.js +0 -1
- package/build/assets/git-repo-dropdown-D2WEQ97X.js +0 -1
- package/build/assets/git-repo-dropdown-DVeCUUXG.js +0 -1
- package/build/assets/highlighted-source-view-DjHO3SdW.js +0 -1
- package/build/assets/home-BorS_vdS.js +0 -1
- package/build/assets/home-aIMbHw5M.js +0 -1
- package/build/assets/home-automation-run-tooltip-CpHNFiFl.js +0 -1
- package/build/assets/home-store-DyXz0w6d.js +0 -1
- package/build/assets/hooks-service-C6dpRtZM.js +0 -1
- package/build/assets/index-home-zKFuKK2B.js +0 -1
- package/build/assets/info-CTIdjttz.js +0 -1
- package/build/assets/install-server-modal-DUiZMc8u.js +0 -1
- package/build/assets/kebab-menu-item-content-mm04SBD3.js +0 -1
- package/build/assets/launch-BSIf9KEg.js +0 -1
- package/build/assets/link-external-BNZzCM1I.js +0 -1
- package/build/assets/list-filter-CNpqTWVY.js +0 -1
- package/build/assets/llm-not-configured-banner-z_QRSeV0.js +0 -27
- package/build/assets/llm-settings-B-5AHMiX.js +0 -1
- package/build/assets/llm-settings-B3SjHDmA.js +0 -1
- package/build/assets/loader-circle-Dex47vVW.js +0 -1
- package/build/assets/manage-backends-modal-q1NdFisr.js +0 -1
- package/build/assets/manifest-8920b615.js +0 -1
- package/build/assets/manifest-subpage-layout-BQQy5ipR.js +0 -1
- package/build/assets/markdown-renderer-rivLvYh-.js +0 -8
- package/build/assets/mcp-CEXDhQWn.js +0 -1
- package/build/assets/mcp-marketplace-utils-Cn_NIMWM.js +0 -1
- package/build/assets/mcp-page-LGYIICMG.js +0 -9
- package/build/assets/messages-DUSeANAh.js +0 -41
- package/build/assets/modal-close-button-B9j4nasm.js +0 -1
- package/build/assets/onboarding-BjFebfs5.js +0 -1
- package/build/assets/onboarding-modal-DDTjOpyd.js +0 -1
- package/build/assets/parse-git-remote-url-DpDM9bK6.js +0 -1
- package/build/assets/planner-tab-D8f2Y3rn.js +0 -1
- package/build/assets/plus-B3wvU06-.js +0 -1
- package/build/assets/providers-2gIIkz2N.js +0 -1
- package/build/assets/proxy-CBgMd2zf.js +0 -1
- package/build/assets/recommended-automations-launcher-YLAQTp4s.js +0 -1
- package/build/assets/root-Bye_XmEL.js +0 -2
- package/build/assets/root-Cnwwzgo0.css +0 -1
- package/build/assets/root-layout-CSAwxBGM.js +0 -2
- package/build/assets/schema-field-CK0xYNbO.js +0 -1
- package/build/assets/sdk-section-page-Da73Rs_o.js +0 -1
- package/build/assets/secret-form-CB2VwYYg.js +0 -1
- package/build/assets/secrets-settings-Bh0udeKv.js +0 -1
- package/build/assets/settings-DmyIgRxO.js +0 -1
- package/build/assets/settings-dropdown-input-DVpyD87C.js +0 -1
- package/build/assets/settings-index-BSJUFmjE.js +0 -1
- package/build/assets/settings-input-C0dd8Utu.js +0 -1
- package/build/assets/settings-modal-yStgEh2o.js +0 -1
- package/build/assets/settings-switch-B78Khmyz.js +0 -1
- package/build/assets/shared-conversation-DM96X4KV.js +0 -1
- package/build/assets/sidebar-mobile-menu-toggle-D5GR5xT9.js +0 -1
- package/build/assets/sidebar-store-CSDFK0W5.js +0 -1
- package/build/assets/skill-card-pill-row-989y15jV.js +0 -1
- package/build/assets/skill-scope-Dz3kPH3P.js +0 -1
- package/build/assets/skills-plugins-e3CYGdUJ.js +0 -1
- package/build/assets/skills-settings-3e-FuHw_.js +0 -1
- package/build/assets/task-list-tab-3Jg8ywch.js +0 -1
- package/build/assets/trash-B6OIe4yX.js +0 -1
- package/build/assets/usage-tab-Cm-9j3UK.js +0 -1
- package/build/assets/use-acp-credential-form-BARcvjYE.js +0 -1
- package/build/assets/use-agent-profiles-1P91KSXz.js +0 -1
- package/build/assets/use-create-secret-D8p9ybQj.js +0 -1
- package/build/assets/use-is-authed-BRPjCRKM.js +0 -1
- package/build/assets/use-llm-configured-DGm8FiRR.js +0 -1
- package/build/assets/use-llm-profiles-BTTtpW4z.js +0 -1
- package/build/assets/use-save-agent-profile-CxyO9YG-.js +0 -1
- package/build/assets/use-settings-nav-items-vrjxTqcu.js +0 -16
- package/build/assets/use-tracking-B9prBsrq.js +0 -3
- package/build/assets/useQueries-CykmpT-a.js +0 -1
- package/build/assets/useQuery-S6j94er1.js +0 -1
- package/build/assets/utils-BOco8mxR.js +0 -1
- package/build/assets/vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~b0x1wrp2-Z0lly3FE.js +0 -2
- package/build/assets/vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~czjee3a3-BfkNGovw.js +0 -185
- package/build/assets/vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~ew9ih1s8-DnDoaYNi.js +0 -1
- package/build/assets/vendor~root-layout~conversation-panel~conversation~skills-settings~automations-list~shared-~bovqqk8e-DkPlXWl9.js +0 -1
- package/build/assets/vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~inibp4qe-CnsDDzeE.js +0 -48
- package/build/assets/vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~iyia17eu-CV850oio.js +0 -1
|
@@ -1,55 +1,56 @@
|
|
|
1
1
|
import { useTranslation as e } from "../node_modules/react-i18next/dist/es/useTranslation.js";
|
|
2
2
|
import { I18nKey as t } from "../i18n/declaration.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { SettingsInput as
|
|
10
|
-
import { SettingsDropdownInput as
|
|
11
|
-
import { extractModelAndProvider as
|
|
12
|
-
import { HelpLink as
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
3
|
+
import { useActiveBackend as n } from "../contexts/active-backend-context.js";
|
|
4
|
+
import { DEFAULT_SETTINGS as r } from "../services/settings.js";
|
|
5
|
+
import { LLM_AUTH_TYPE_API_KEY as i, LLM_AUTH_TYPE_KEY as a, LLM_AUTH_TYPE_SUBSCRIPTION as o, LLM_SUBSCRIPTION_VENDOR_KEY as s, OPENAI_SUBSCRIPTION_VENDOR as c, resolveLlmAuthType as l } from "../constants/llm-subscription.js";
|
|
6
|
+
import { useSettings as u } from "../hooks/query/use-settings.js";
|
|
7
|
+
import { useDefaultModel as d, useFreeModels as ee } from "../hooks/query/use-free-models.js";
|
|
8
|
+
import { isFreeOpenHandsModel as te, isOpenHandsProviderModel as f } from "../utils/format-model-name.js";
|
|
9
|
+
import { SettingsInput as p } from "../components/features/settings/settings-input.js";
|
|
10
|
+
import { SettingsDropdownInput as m } from "../components/features/settings/settings-dropdown-input.js";
|
|
11
|
+
import { extractModelAndProvider as h } from "../utils/extract-model-and-provider.js";
|
|
12
|
+
import { HelpLink as g } from "../ui/help-link.js";
|
|
13
|
+
import { FreeOpenHandsModelsNote as ne } from "../components/shared/free-models-note.js";
|
|
14
|
+
import { ModelSelector as re } from "../components/shared/modals/settings/model-selector.js";
|
|
15
|
+
import { useAgentSettingsSchema as _ } from "../hooks/query/use-agent-settings-schema.js";
|
|
16
|
+
import { OpenAISubscriptionAuthCard as ie } from "../components/features/settings/llm-settings/openai-subscription-auth-card.js";
|
|
17
|
+
import { KeyStatusIcon as ae } from "../components/features/settings/key-status-icon.js";
|
|
18
|
+
import { inferInitialView as v } from "../utils/sdk-settings-schema.js";
|
|
19
|
+
import { SdkSectionPage as y } from "../components/features/settings/sdk-settings/sdk-section-page.js";
|
|
20
|
+
import { useProviderConnections as b } from "../hooks/query/use-provider-connections.js";
|
|
20
21
|
import "../components/features/settings/llm-profiles/index.js";
|
|
21
|
-
import { useOpenAISubscriptionModels as
|
|
22
|
-
import
|
|
23
|
-
import { Fragment as
|
|
22
|
+
import { useOpenAISubscriptionModels as oe } from "../hooks/query/use-llm-subscription-models.js";
|
|
23
|
+
import x from "react";
|
|
24
|
+
import { Fragment as S, jsx as C, jsxs as w } from "react/jsx-runtime";
|
|
24
25
|
//#region src/routes/llm-settings.tsx
|
|
25
|
-
var
|
|
26
|
+
var T = "llm.provider_connection_id", E = "__none__", D = new Set([
|
|
26
27
|
"llm.model",
|
|
27
28
|
"llm.api_key",
|
|
28
29
|
"llm.base_url",
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
]),
|
|
30
|
+
T,
|
|
31
|
+
a,
|
|
32
|
+
s
|
|
33
|
+
]), se = (e, t) => !e || !t ? null : `${e}/${t}`, O = (e, t) => e?.sections.flatMap((e) => e.fields).find((e) => e.key === t)?.default ?? null, k = {
|
|
33
34
|
openai: new Set(["https://api.openai.com", "https://api.openai.com/v1"]),
|
|
34
35
|
moonshot: new Set(["https://api.kimi.com/coding/v1"])
|
|
35
|
-
},
|
|
36
|
+
}, A = (e) => {
|
|
36
37
|
try {
|
|
37
38
|
let t = new URL(e), n = t.pathname.replace(/\/+$/, "") || "";
|
|
38
39
|
return `${t.origin}${n}`;
|
|
39
40
|
} catch {
|
|
40
41
|
return e.trim().replace(/\/+$/, "");
|
|
41
42
|
}
|
|
42
|
-
},
|
|
43
|
-
let n =
|
|
43
|
+
}, j = (e, t) => {
|
|
44
|
+
let n = A(t), { provider: r } = h(e);
|
|
44
45
|
if (r) {
|
|
45
|
-
let e =
|
|
46
|
+
let e = k[r];
|
|
46
47
|
if (e) return e.has(n);
|
|
47
48
|
}
|
|
48
|
-
return Object.values(
|
|
49
|
+
return Object.values(k).some((e) => e?.has(n));
|
|
49
50
|
};
|
|
50
|
-
function
|
|
51
|
+
function ce({ testId: n }) {
|
|
51
52
|
let { t: r } = e("openhands");
|
|
52
|
-
return /* @__PURE__ */
|
|
53
|
+
return /* @__PURE__ */ C(g, {
|
|
53
54
|
testId: n,
|
|
54
55
|
text: r(t.SETTINGS$OPENHANDS_API_KEY_HELP_TEXT),
|
|
55
56
|
linkText: r(t.SETTINGS$OPENHANDS_API_KEY_HELP_LINK),
|
|
@@ -60,207 +61,198 @@ function ie({ testId: n }) {
|
|
|
60
61
|
trailing: "."
|
|
61
62
|
});
|
|
62
63
|
}
|
|
63
|
-
function
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}), /* @__PURE__ */ T("span", { children: f })]
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
function F({ scope: n = "personal", onSaveSuccess: f, initialValueOverrides: g, markInitialOverridesDirty: M, embedded: N, hideSaveButton: F, suppressSuccessToast: I, onSaveControlChange: L, showProviderConnection: R }) {
|
|
74
|
-
let { t: z } = e("openhands"), { backend: B } = r(), V = B.kind === "cloud", { data: H } = x(), U = C.useMemo(() => R ? H ?? [] : [], [R, H]), { data: W } = d(n), { data: G } = v(W?.agent_settings_schema), oe = W?.agent_settings?.llm, K = u(g?.["llm.auth_type"] ?? oe?.auth_type), [q, J] = C.useState(K === s), { data: Y, isLoading: se, isFetching: ce } = S({ enabled: q }), X = q && !Y && (se || ce), Z = C.useRef(null), Q = C.useRef(null);
|
|
75
|
-
C.useEffect(() => {
|
|
76
|
-
K === "subscription" && J(!0);
|
|
77
|
-
}, [K]);
|
|
78
|
-
let $ = String(i.agent_settings?.llm?.model ?? ""), le = C.useCallback((e, t) => {
|
|
79
|
-
let n = y(e, t);
|
|
64
|
+
function M({ scope: h = "personal", onSaveSuccess: k, initialValueOverrides: A, markInitialOverridesDirty: M, embedded: N, hideSaveButton: P, suppressSuccessToast: F, onSaveControlChange: I, showProviderConnection: L }) {
|
|
65
|
+
let { t: R } = e("openhands"), { backend: z } = n(), B = z.kind === "cloud", { data: V } = b(), H = x.useMemo(() => L ? V ?? [] : [], [L, V]), { data: U } = u(h), { data: W } = _(U?.agent_settings_schema), le = U?.agent_settings?.llm, G = l(A?.["llm.auth_type"] ?? le?.auth_type), [K, q] = x.useState(G === o), { data: J, isLoading: ue, isFetching: de } = oe({ enabled: K }), Y = K && !J && (ue || de), X = x.useRef(null), Z = x.useRef(null);
|
|
66
|
+
x.useEffect(() => {
|
|
67
|
+
G === "subscription" && q(!0);
|
|
68
|
+
}, [G]);
|
|
69
|
+
let Q = ee(), $ = d() ?? String(r.agent_settings?.llm?.model ?? ""), fe = x.useCallback((e, t) => {
|
|
70
|
+
let n = v(e, t);
|
|
80
71
|
if (n !== "basic") return n;
|
|
81
72
|
let r = e.llm_model ?? "", i = e.llm_base_url?.trim() ?? "";
|
|
82
|
-
return i.length > 0 && !
|
|
83
|
-
}, []),
|
|
84
|
-
let d = typeof e["llm.model"] == "string" ? e["llm.model"] : "",
|
|
73
|
+
return i.length > 0 && !j(r, i) ? "all" : "basic";
|
|
74
|
+
}, []), pe = x.useCallback(({ values: e, isDisabled: n, view: r, onChange: u }) => {
|
|
75
|
+
let d = typeof e["llm.model"] == "string" ? e["llm.model"] : "", ee = typeof e["llm.base_url"] == "string" ? e["llm.base_url"] : "", h = f(d), _ = l(e[a]), v = _ === o, y = B && h && !v, b = n || v && Y, oe = J?.includes(d) ? d : J?.[0] ?? "", x = typeof e["llm.api_key"] == "string" ? e["llm.api_key"] : "", D = N ? x.length > 0 : !!U?.llm_api_key_set, O = typeof e["llm.provider_connection_id"] == "string" ? e[T] : "", k = !!O, A = L && !v && (k || H.length > 0), j = k && !H.some((e) => e.id === O), M = () => /* @__PURE__ */ C(m, {
|
|
85
76
|
testId: "llm-provider-connection-input",
|
|
86
|
-
name:
|
|
87
|
-
label:
|
|
77
|
+
name: T,
|
|
78
|
+
label: R(t.SETTINGS$PROVIDER_CONNECTION_SELECT_LABEL),
|
|
88
79
|
items: [
|
|
89
80
|
{
|
|
90
|
-
key:
|
|
91
|
-
label:
|
|
81
|
+
key: E,
|
|
82
|
+
label: R(t.SETTINGS$MCP_AUTH_MODE_NONE)
|
|
92
83
|
},
|
|
93
|
-
...
|
|
84
|
+
...H.map((e) => ({
|
|
94
85
|
key: e.id,
|
|
95
86
|
label: e.display_name
|
|
96
87
|
})),
|
|
97
|
-
...
|
|
98
|
-
key:
|
|
99
|
-
label:
|
|
88
|
+
...j ? [{
|
|
89
|
+
key: O,
|
|
90
|
+
label: O
|
|
100
91
|
}] : []
|
|
101
92
|
],
|
|
102
|
-
selectedKey:
|
|
93
|
+
selectedKey: O || E,
|
|
103
94
|
isClearable: !1,
|
|
104
95
|
isDisabled: n,
|
|
105
96
|
onSelectionChange: (e) => {
|
|
106
|
-
|
|
97
|
+
u(T, typeof e == "string" && e !== E ? e : "");
|
|
107
98
|
}
|
|
108
|
-
}),
|
|
99
|
+
}), P = (e, r, i) => /* @__PURE__ */ w(S, { children: [/* @__PURE__ */ C(p, {
|
|
109
100
|
testId: e,
|
|
110
|
-
label:
|
|
101
|
+
label: R(t.SETTINGS_FORM$API_KEY),
|
|
111
102
|
type: "password",
|
|
112
103
|
className: "w-full",
|
|
113
|
-
value:
|
|
114
|
-
placeholder:
|
|
115
|
-
onChange: (e) =>
|
|
104
|
+
value: x,
|
|
105
|
+
placeholder: D ? "<hidden>" : "",
|
|
106
|
+
onChange: (e) => u("llm.api_key", e),
|
|
116
107
|
isDisabled: n,
|
|
117
|
-
startContent:
|
|
118
|
-
}),
|
|
108
|
+
startContent: D ? /* @__PURE__ */ C(ae, { isSet: D }) : void 0
|
|
109
|
+
}), h ? /* @__PURE__ */ C(ce, { testId: i }) : /* @__PURE__ */ C(g, {
|
|
119
110
|
testId: r,
|
|
120
|
-
text:
|
|
121
|
-
linkText:
|
|
111
|
+
text: R(t.SETTINGS$DONT_KNOW_API_KEY),
|
|
112
|
+
linkText: R(t.SETTINGS$CLICK_FOR_INSTRUCTIONS),
|
|
122
113
|
href: "https://docs.openhands.dev/usage/local-setup#getting-an-api-key"
|
|
123
|
-
})] }),
|
|
124
|
-
let t = e === "subscription" ?
|
|
125
|
-
if (
|
|
126
|
-
|
|
127
|
-
let e =
|
|
128
|
-
|
|
114
|
+
})] }), F = (e) => {
|
|
115
|
+
let t = e === "subscription" ? o : i;
|
|
116
|
+
if (u(a, t), t === "subscription") {
|
|
117
|
+
q(!0), d && !J?.includes(d) && (X.current = d);
|
|
118
|
+
let e = Z.current && J?.includes(Z.current) ? Z.current : J?.[0];
|
|
119
|
+
u(s, c), !J?.includes(d) && e && u("llm.model", e);
|
|
129
120
|
return;
|
|
130
121
|
}
|
|
131
|
-
d &&
|
|
132
|
-
},
|
|
122
|
+
d && J?.includes(d) && (Z.current = d, u("llm.model", X.current ?? $));
|
|
123
|
+
}, I = () => /* @__PURE__ */ C(m, {
|
|
133
124
|
testId: "llm-auth-type-input",
|
|
134
|
-
name:
|
|
135
|
-
label:
|
|
125
|
+
name: a,
|
|
126
|
+
label: R(t.SETTINGS$LLM_AUTH_TYPE),
|
|
136
127
|
items: [{
|
|
137
|
-
key:
|
|
138
|
-
label:
|
|
128
|
+
key: i,
|
|
129
|
+
label: R(t.SETTINGS$LLM_AUTH_TYPE_API_KEY)
|
|
139
130
|
}, {
|
|
140
|
-
key:
|
|
141
|
-
label:
|
|
131
|
+
key: o,
|
|
132
|
+
label: R(t.SETTINGS$LLM_AUTH_TYPE_SUBSCRIPTION)
|
|
142
133
|
}],
|
|
143
|
-
selectedKey:
|
|
134
|
+
selectedKey: _,
|
|
144
135
|
isClearable: !1,
|
|
145
136
|
required: !0,
|
|
146
|
-
isDisabled:
|
|
147
|
-
onSelectionChange:
|
|
148
|
-
}),
|
|
137
|
+
isDisabled: b,
|
|
138
|
+
onSelectionChange: F
|
|
139
|
+
}), z = () => /* @__PURE__ */ w("div", {
|
|
149
140
|
className: "flex flex-col gap-6",
|
|
150
141
|
"data-testid": "llm-subscription-settings",
|
|
151
|
-
children: [/* @__PURE__ */
|
|
142
|
+
children: [/* @__PURE__ */ C(m, {
|
|
152
143
|
testId: "llm-subscription-model-input",
|
|
153
144
|
name: "llm.subscription_model",
|
|
154
|
-
label:
|
|
155
|
-
items: (
|
|
145
|
+
label: R(t.SETTINGS$SUBSCRIPTION_MODEL),
|
|
146
|
+
items: (J ?? []).map((e) => ({
|
|
156
147
|
key: e,
|
|
157
148
|
label: e
|
|
158
149
|
})),
|
|
159
|
-
selectedKey:
|
|
150
|
+
selectedKey: oe,
|
|
160
151
|
isClearable: !1,
|
|
161
152
|
required: !0,
|
|
162
|
-
isDisabled:
|
|
153
|
+
isDisabled: b || !J?.length,
|
|
163
154
|
onSelectionChange: (e) => {
|
|
164
|
-
let t = typeof e == "string" ? e :
|
|
165
|
-
t &&
|
|
155
|
+
let t = typeof e == "string" ? e : J?.[0];
|
|
156
|
+
t && u("llm.model", t);
|
|
166
157
|
}
|
|
167
|
-
}), /* @__PURE__ */
|
|
158
|
+
}), /* @__PURE__ */ C(ie, { isDisabled: n })]
|
|
168
159
|
});
|
|
169
|
-
return /* @__PURE__ */
|
|
160
|
+
return /* @__PURE__ */ C("div", {
|
|
170
161
|
className: "flex flex-col gap-6",
|
|
171
|
-
children: r === "basic" ? /* @__PURE__ */
|
|
162
|
+
children: r === "basic" ? /* @__PURE__ */ w("div", {
|
|
172
163
|
className: "flex flex-col gap-6",
|
|
173
164
|
"data-testid": "llm-settings-form-basic",
|
|
174
|
-
children: [
|
|
175
|
-
/* @__PURE__ */
|
|
165
|
+
children: [I(), v ? z() : /* @__PURE__ */ w(S, { children: [
|
|
166
|
+
/* @__PURE__ */ C(re, {
|
|
176
167
|
currentModel: d || void 0,
|
|
177
168
|
onChange: (e, t) => {
|
|
178
|
-
let n =
|
|
179
|
-
n &&
|
|
169
|
+
let n = se(e, t);
|
|
170
|
+
n && u("llm.model", n);
|
|
180
171
|
},
|
|
181
172
|
wrapperClassName: "!flex-col !gap-6",
|
|
182
173
|
isDisabled: n
|
|
183
174
|
}),
|
|
184
|
-
|
|
185
|
-
|
|
175
|
+
A ? M() : null,
|
|
176
|
+
k || y ? null : P("llm-api-key-input", "llm-api-key-help-anchor", "openhands-api-key-help")
|
|
186
177
|
] })]
|
|
187
|
-
}) : /* @__PURE__ */
|
|
178
|
+
}) : /* @__PURE__ */ w("div", {
|
|
188
179
|
className: "flex flex-col gap-6",
|
|
189
180
|
"data-testid": "llm-settings-form-advanced",
|
|
190
|
-
children: [
|
|
191
|
-
/* @__PURE__ */
|
|
181
|
+
children: [I(), v ? z() : /* @__PURE__ */ w(S, { children: [
|
|
182
|
+
/* @__PURE__ */ C(p, {
|
|
192
183
|
testId: "llm-custom-model-input",
|
|
193
|
-
label:
|
|
184
|
+
label: R(t.SETTINGS$CUSTOM_MODEL),
|
|
194
185
|
type: "text",
|
|
195
186
|
className: "w-full",
|
|
196
187
|
value: d,
|
|
197
188
|
placeholder: $,
|
|
198
|
-
onChange: (e) =>
|
|
189
|
+
onChange: (e) => u("llm.model", e),
|
|
199
190
|
isDisabled: n
|
|
200
191
|
}),
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
192
|
+
h && !k ? /* @__PURE__ */ C(S, { children: te(d, Q) ? /* @__PURE__ */ C(ne, { modelIds: Q }) : null }) : null,
|
|
193
|
+
A ? M() : null,
|
|
194
|
+
k || y ? null : /* @__PURE__ */ C(p, {
|
|
204
195
|
testId: "base-url-input",
|
|
205
|
-
label:
|
|
196
|
+
label: R(t.SETTINGS$BASE_URL),
|
|
206
197
|
type: "text",
|
|
207
198
|
className: "w-full",
|
|
208
|
-
value:
|
|
199
|
+
value: ee,
|
|
209
200
|
placeholder: "https://api.openai.com",
|
|
210
|
-
onChange: (e) =>
|
|
201
|
+
onChange: (e) => u("llm.base_url", e),
|
|
211
202
|
isDisabled: n
|
|
212
203
|
}),
|
|
213
|
-
|
|
204
|
+
k || y ? null : P("llm-api-key-input", "llm-api-key-help-anchor-advanced", "openhands-api-key-help-2")
|
|
214
205
|
] })]
|
|
215
206
|
})
|
|
216
207
|
});
|
|
217
208
|
}, [
|
|
218
|
-
|
|
219
|
-
|
|
209
|
+
H,
|
|
210
|
+
L,
|
|
220
211
|
$,
|
|
221
212
|
N,
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
W?.llm_api_key_set,
|
|
213
|
+
B,
|
|
214
|
+
Q,
|
|
225
215
|
Y,
|
|
226
|
-
|
|
227
|
-
|
|
216
|
+
U?.llm_api_key_set,
|
|
217
|
+
J,
|
|
218
|
+
R
|
|
219
|
+
]), me = x.useCallback((e, t) => {
|
|
228
220
|
let n = structuredClone(e.agent_settings_diff ?? {}), r = n.llm ?? {};
|
|
229
|
-
if (
|
|
230
|
-
r.auth_type =
|
|
231
|
-
let e = typeof r.model == "string" ? r.model : String(t.values["llm.model"] ?? ""), n =
|
|
232
|
-
if (!
|
|
233
|
-
r.model =
|
|
234
|
-
} else t.dirty["llm.auth_type"] && (r.auth_type =
|
|
221
|
+
if (l(t.values["llm.auth_type"]) === "subscription") {
|
|
222
|
+
r.auth_type = o, r.subscription_vendor = c;
|
|
223
|
+
let e = typeof r.model == "string" ? r.model : String(t.values["llm.model"] ?? ""), n = J?.[0];
|
|
224
|
+
if (!J?.includes(e) && !n) throw Error("Subscription models are not loaded yet.");
|
|
225
|
+
r.model = J?.includes(e) ? e : n, delete r.api_key, delete r.base_url;
|
|
226
|
+
} else t.dirty["llm.auth_type"] && (r.auth_type = i, r.subscription_vendor = null), t.view === "basic" && r.model !== void 0 && (r.base_url = O(W, "llm.base_url")), B && f(String(t.values["llm.model"] ?? "")) && (delete r.api_key, delete r.base_url);
|
|
235
227
|
return n.llm = r, { agent_settings_diff: n };
|
|
236
228
|
}, [
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
229
|
+
W,
|
|
230
|
+
J,
|
|
231
|
+
B
|
|
240
232
|
]);
|
|
241
|
-
return /* @__PURE__ */
|
|
242
|
-
scope:
|
|
233
|
+
return /* @__PURE__ */ C(y, {
|
|
234
|
+
scope: h,
|
|
243
235
|
settingsSources: [{
|
|
244
236
|
settingsSource: "agent_settings",
|
|
245
237
|
sectionKeys: ["llm"],
|
|
246
|
-
excludeKeys:
|
|
238
|
+
excludeKeys: D
|
|
247
239
|
}],
|
|
248
|
-
header:
|
|
249
|
-
buildPayload:
|
|
250
|
-
getInitialView:
|
|
240
|
+
header: pe,
|
|
241
|
+
buildPayload: me,
|
|
242
|
+
getInitialView: fe,
|
|
251
243
|
forceShowAdvancedView: !0,
|
|
252
244
|
allowAllView: !0,
|
|
253
|
-
onSaveSuccess:
|
|
254
|
-
initialValueOverrides:
|
|
245
|
+
onSaveSuccess: k,
|
|
246
|
+
initialValueOverrides: A,
|
|
255
247
|
markInitialOverridesDirty: M,
|
|
256
248
|
embedded: N,
|
|
257
|
-
hideSaveButton:
|
|
258
|
-
suppressSuccessToast:
|
|
259
|
-
onSaveControlChange:
|
|
249
|
+
hideSaveButton: P,
|
|
250
|
+
suppressSuccessToast: F,
|
|
251
|
+
onSaveControlChange: I,
|
|
260
252
|
testId: "llm-settings-screen"
|
|
261
253
|
});
|
|
262
254
|
}
|
|
263
255
|
//#endregion
|
|
264
|
-
export {
|
|
256
|
+
export { M as LlmSettingsScreen };
|
|
265
257
|
|
|
266
258
|
//# sourceMappingURL=llm-settings.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"llm-settings.js","names":[],"sources":["../../src/routes/llm-settings.tsx"],"sourcesContent":["import React from \"react\";\nimport { Info } from \"lucide-react\";\nimport { useTranslation } from \"react-i18next\";\nimport { ModelSelector } from \"#/components/shared/modals/settings/model-selector\";\nimport { useAgentSettingsSchema } from \"#/hooks/query/use-agent-settings-schema\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { SettingsInput } from \"#/components/features/settings/settings-input\";\nimport { SettingsDropdownInput } from \"#/components/features/settings/settings-dropdown-input\";\nimport { OpenAISubscriptionAuthCard } from \"#/components/features/settings/llm-settings/openai-subscription-auth-card\";\nimport { HelpLink } from \"#/ui/help-link\";\nimport { KeyStatusIcon } from \"#/components/features/settings/key-status-icon\";\nimport {\n SdkSectionHeaderProps,\n SdkSectionPage,\n SdkSectionSaveControl,\n} from \"#/components/features/settings/sdk-settings/sdk-section-page\";\nimport { LlmSettingsLocalView } from \"#/components/features/settings/llm-profiles\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { Settings, SettingsSchema, SettingsScope } from \"#/types/settings\";\nimport { extractModelAndProvider } from \"#/utils/extract-model-and-provider\";\nimport {\n inferInitialView,\n type SettingsFormValues,\n type SettingsView,\n} from \"#/utils/sdk-settings-schema\";\nimport { DEFAULT_SETTINGS } from \"#/services/settings\";\nimport {\n LLM_AUTH_TYPE_API_KEY,\n LLM_AUTH_TYPE_KEY,\n LLM_AUTH_TYPE_SUBSCRIPTION,\n LLM_SUBSCRIPTION_VENDOR_KEY,\n OPENAI_SUBSCRIPTION_VENDOR,\n resolveLlmAuthType,\n} from \"#/constants/llm-subscription\";\nimport { useOpenAISubscriptionModels } from \"#/hooks/query/use-llm-subscription-models\";\nimport { useProviderConnections } from \"#/hooks/query/use-provider-connections\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport {\n FREE_OPENHANDS_MODEL_NOTE,\n isFreeOpenHandsModel,\n isOpenHandsProviderModel,\n} from \"#/utils/format-model-name\";\n\n/** Form-values key for the shared provider connection a profile links to. */\nexport const LLM_PROVIDER_CONNECTION_KEY = \"llm.provider_connection_id\";\n\n/** Dropdown sentinel for \"no provider connection\" (an inline key is used). */\nconst NO_PROVIDER_CONNECTION = \"__none__\";\n\nconst LLM_EXCLUDED_KEYS = new Set([\n \"llm.model\",\n \"llm.api_key\",\n \"llm.base_url\",\n LLM_PROVIDER_CONNECTION_KEY,\n LLM_AUTH_TYPE_KEY,\n LLM_SUBSCRIPTION_VENDOR_KEY,\n]);\n\nconst buildModelId = (provider: string | null, model: string | null) => {\n if (!provider || !model) return null;\n return `${provider}/${model}`;\n};\n\nconst getSchemaFieldDefaultValue = (\n schema: SettingsSchema | null | undefined,\n fieldKey: string,\n) =>\n schema?.sections\n .flatMap((section) => section.fields)\n .find((field) => field.key === fieldKey)?.default ?? null;\n\nconst KNOWN_PROVIDER_DEFAULT_BASE_URLS: Partial<Record<string, Set<string>>> = {\n openai: new Set([\"https://api.openai.com\", \"https://api.openai.com/v1\"]),\n moonshot: new Set([\"https://api.kimi.com/coding/v1\"]),\n};\n\nconst normalizeBaseUrl = (baseUrl: string) => {\n try {\n const parsedUrl = new URL(baseUrl);\n const normalizedPath = parsedUrl.pathname.replace(/\\/+$/, \"\") || \"\";\n return `${parsedUrl.origin}${normalizedPath}`;\n } catch {\n return baseUrl.trim().replace(/\\/+$/, \"\");\n }\n};\n\nconst isProviderDefaultBaseUrl = (model: string, baseUrl: string) => {\n const normalizedBaseUrl = normalizeBaseUrl(baseUrl);\n const { provider } = extractModelAndProvider(model);\n\n if (provider) {\n const knownDefaults = KNOWN_PROVIDER_DEFAULT_BASE_URLS[provider];\n if (knownDefaults) {\n return knownDefaults.has(normalizedBaseUrl);\n }\n }\n\n return Object.values(KNOWN_PROVIDER_DEFAULT_BASE_URLS).some((knownDefaults) =>\n knownDefaults?.has(normalizedBaseUrl),\n );\n};\n\ninterface OpenHandsApiKeyHelpProps {\n testId: string;\n}\n\nfunction OpenHandsApiKeyHelp({ testId }: OpenHandsApiKeyHelpProps) {\n const { t } = useTranslation(\"openhands\");\n\n return (\n <HelpLink\n testId={testId}\n text={t(I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_TEXT)}\n linkText={t(I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_LINK)}\n href=\"https://app.all-hands.dev/settings/api-keys\"\n suffix={` ${t(I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_SUFFIX)}`}\n suffixLinkText={t(I18nKey.SETTINGS$SEE_HERE_FOR_MORE_DETAILS)}\n suffixLinkHref=\"https://docs.openhands.dev/usage/local-setup#getting-an-api-key\"\n trailing=\".\"\n />\n );\n}\n\nfunction OpenHandsFreeModelsNote() {\n return (\n <p\n data-testid=\"openhands-free-models-note\"\n className=\"flex items-start gap-2 text-xs text-warning\"\n >\n <Info className=\"mt-0.5 size-4 shrink-0 text-warning\" aria-hidden />\n <span>{FREE_OPENHANDS_MODEL_NOTE}</span>\n </p>\n );\n}\n\nexport function LlmSettingsScreen({\n scope = \"personal\",\n onSaveSuccess,\n initialValueOverrides,\n markInitialOverridesDirty,\n embedded,\n hideSaveButton,\n suppressSuccessToast,\n onSaveControlChange,\n showProviderConnection,\n}: {\n scope?: SettingsScope;\n /** Optional hook fired after a successful save (e.g. advance an onboarding step). */\n onSaveSuccess?: () => void;\n /** Forwarded to {@link SdkSectionPage}. */\n initialValueOverrides?: SettingsFormValues;\n /** Forwarded to {@link SdkSectionPage}. */\n markInitialOverridesDirty?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n embedded?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n hideSaveButton?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n suppressSuccessToast?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n onSaveControlChange?: (control: SdkSectionSaveControl) => void;\n /**\n * When true (the local profile editor), show a \"Provider connection\" selector\n * that links this profile to a shared connection. Only rendered when at least\n * one connection exists, so the form is unchanged until the user creates one.\n */\n showProviderConnection?: boolean;\n}) {\n const { t } = useTranslation(\"openhands\");\n\n const { backend } = useActiveBackend();\n const isCloud = backend.kind === \"cloud\";\n\n const { data: providerConnections } = useProviderConnections();\n const connectionOptions = React.useMemo(\n () => (showProviderConnection ? (providerConnections ?? []) : []),\n [showProviderConnection, providerConnections],\n );\n\n const { data: settings } = useSettings(scope);\n const { data: schema } = useAgentSettingsSchema(\n settings?.agent_settings_schema,\n );\n const persistedLlmSettings = settings?.agent_settings?.llm as\n | Record<string, unknown>\n | undefined;\n const initialAuthType = resolveLlmAuthType(\n initialValueOverrides?.[LLM_AUTH_TYPE_KEY] ??\n persistedLlmSettings?.auth_type,\n );\n const [enableSubscriptionModels, setEnableSubscriptionModels] =\n React.useState(initialAuthType === LLM_AUTH_TYPE_SUBSCRIPTION);\n const {\n data: subscriptionModels,\n isLoading: isSubscriptionModelsLoading,\n isFetching: isSubscriptionModelsFetching,\n } = useOpenAISubscriptionModels({ enabled: enableSubscriptionModels });\n const isWaitingForSubscriptionModels =\n enableSubscriptionModels &&\n !subscriptionModels &&\n (isSubscriptionModelsLoading || isSubscriptionModelsFetching);\n const lastApiKeyModelRef = React.useRef<string | null>(null);\n const lastSubscriptionModelRef = React.useRef<string | null>(null);\n\n React.useEffect(() => {\n if (initialAuthType === LLM_AUTH_TYPE_SUBSCRIPTION) {\n setEnableSubscriptionModels(true);\n }\n }, [initialAuthType]);\n\n const defaultModel = String(\n (DEFAULT_SETTINGS.agent_settings?.llm as Record<string, unknown>)?.model ??\n \"\",\n );\n\n const getInitialView = React.useCallback(\n (\n currentSettings: Settings,\n filteredSchema: SettingsSchema,\n ): SettingsView => {\n const schemaView = inferInitialView(currentSettings, filteredSchema);\n if (schemaView !== \"basic\") {\n return schemaView;\n }\n\n const currentModel = currentSettings.llm_model ?? \"\";\n const trimmedBaseUrl = currentSettings.llm_base_url?.trim() ?? \"\";\n const hasCustomBaseUrl =\n trimmedBaseUrl.length > 0 &&\n !isProviderDefaultBaseUrl(currentModel, trimmedBaseUrl);\n\n return hasCustomBaseUrl ? \"all\" : \"basic\";\n },\n [],\n );\n\n const buildHeader = React.useCallback(\n ({ values, isDisabled, view, onChange }: SdkSectionHeaderProps) => {\n const modelValue =\n typeof values[\"llm.model\"] === \"string\" ? values[\"llm.model\"] : \"\";\n const baseUrlValue =\n typeof values[\"llm.base_url\"] === \"string\"\n ? values[\"llm.base_url\"]\n : \"\";\n const showOpenHandsApiKeyHelp = isOpenHandsProviderModel(modelValue);\n const authType = resolveLlmAuthType(values[LLM_AUTH_TYPE_KEY]);\n const isSubscriptionAuth = authType === LLM_AUTH_TYPE_SUBSCRIPTION;\n // On cloud the OpenHands provider is backed by a server-minted LLM key,\n // so the inline API key / base URL inputs are not user-supplied. Local\n // mode still collects an api_key (the OpenHands provider can run against\n // a self-hosted endpoint there).\n const hideInlineCredentials =\n isCloud && showOpenHandsApiKeyHelp && !isSubscriptionAuth;\n const shouldDisableSubscriptionControls =\n isDisabled || (isSubscriptionAuth && isWaitingForSubscriptionModels);\n const subscriptionModelValue = subscriptionModels?.includes(modelValue)\n ? modelValue\n : (subscriptionModels?.[0] ?? \"\");\n\n const apiKeyValue =\n typeof values[\"llm.api_key\"] === \"string\" ? values[\"llm.api_key\"] : \"\";\n // For embedded profile forms (create/edit) the global\n // `llm_api_key_set` flag is misleading: a brand-new profile would show a\n // \"key set\" indicator just because some other profile has a key. Reflect\n // the form's own key state instead so create mode starts visibly unset.\n const apiKeyIsSet = embedded\n ? apiKeyValue.length > 0\n : Boolean(settings?.llm_api_key_set);\n\n // A profile linked to a provider connection reads its api_key / base_url\n // from that connection, so the inline key + base URL inputs are hidden.\n const connectionValue =\n typeof values[LLM_PROVIDER_CONNECTION_KEY] === \"string\"\n ? values[LLM_PROVIDER_CONNECTION_KEY]\n : \"\";\n const isLinkedToConnection = Boolean(connectionValue);\n // Show the selector whenever connections can be linked here. Include the\n // linked case so a profile pointing at an orphaned connection (its only\n // connection deleted, or the list still loading) still exposes a control\n // to unlink — otherwise the API key / base URL inputs stay hidden with no\n // way to recover.\n const showConnectionSelector =\n showProviderConnection &&\n !isSubscriptionAuth &&\n (isLinkedToConnection || connectionOptions.length > 0);\n // Surface an orphaned link (a selected id absent from the fetched list)\n // as its own option so the dropdown reflects it and can be cleared.\n const isOrphanedLink =\n isLinkedToConnection &&\n !connectionOptions.some((c) => c.id === connectionValue);\n\n const renderConnectionSelector = () => (\n <SettingsDropdownInput\n testId=\"llm-provider-connection-input\"\n name={LLM_PROVIDER_CONNECTION_KEY}\n label={t(I18nKey.SETTINGS$PROVIDER_CONNECTION_SELECT_LABEL)}\n items={[\n {\n key: NO_PROVIDER_CONNECTION,\n label: t(I18nKey.SETTINGS$MCP_AUTH_MODE_NONE),\n },\n ...connectionOptions.map((connection) => ({\n key: connection.id,\n label: connection.display_name,\n })),\n ...(isOrphanedLink\n ? [{ key: connectionValue, label: connectionValue }]\n : []),\n ]}\n selectedKey={connectionValue || NO_PROVIDER_CONNECTION}\n isClearable={false}\n isDisabled={isDisabled}\n onSelectionChange={(selectedKey) => {\n const next =\n typeof selectedKey === \"string\" &&\n selectedKey !== NO_PROVIDER_CONNECTION\n ? selectedKey\n : \"\";\n onChange(LLM_PROVIDER_CONNECTION_KEY, next);\n }}\n />\n );\n\n const renderApiKeyInput = (\n testId: string,\n helpTestId: string,\n openHandsHelpTestId: string,\n ) => (\n <>\n <SettingsInput\n testId={testId}\n label={t(I18nKey.SETTINGS_FORM$API_KEY)}\n type=\"password\"\n className=\"w-full\"\n value={apiKeyValue}\n // eslint-disable-next-line i18next/no-literal-string -- masked-key sentinel, not translatable\n placeholder={apiKeyIsSet ? \"<hidden>\" : \"\"}\n onChange={(value) => onChange(\"llm.api_key\", value)}\n isDisabled={isDisabled}\n startContent={\n apiKeyIsSet ? <KeyStatusIcon isSet={apiKeyIsSet} /> : undefined\n }\n />\n\n {/* The OpenHands provider's key lives in the OpenHands Cloud \"API\n Keys\" tab, so point users there instead of the generic docs page\n that covers both LLM and regular API keys. */}\n {showOpenHandsApiKeyHelp ? (\n <OpenHandsApiKeyHelp testId={openHandsHelpTestId} />\n ) : (\n <HelpLink\n testId={helpTestId}\n text={t(I18nKey.SETTINGS$DONT_KNOW_API_KEY)}\n linkText={t(I18nKey.SETTINGS$CLICK_FOR_INSTRUCTIONS)}\n href=\"https://docs.openhands.dev/usage/local-setup#getting-an-api-key\"\n />\n )}\n </>\n );\n\n const handleAuthTypeChange = (selectedKey: React.Key | null) => {\n const nextAuthType =\n selectedKey === LLM_AUTH_TYPE_SUBSCRIPTION\n ? LLM_AUTH_TYPE_SUBSCRIPTION\n : LLM_AUTH_TYPE_API_KEY;\n onChange(LLM_AUTH_TYPE_KEY, nextAuthType);\n\n if (nextAuthType === LLM_AUTH_TYPE_SUBSCRIPTION) {\n setEnableSubscriptionModels(true);\n if (modelValue && !subscriptionModels?.includes(modelValue)) {\n lastApiKeyModelRef.current = modelValue;\n }\n const restoredSubscriptionModel =\n lastSubscriptionModelRef.current &&\n subscriptionModels?.includes(lastSubscriptionModelRef.current)\n ? lastSubscriptionModelRef.current\n : subscriptionModels?.[0];\n onChange(LLM_SUBSCRIPTION_VENDOR_KEY, OPENAI_SUBSCRIPTION_VENDOR);\n if (\n !subscriptionModels?.includes(modelValue) &&\n restoredSubscriptionModel\n ) {\n onChange(\"llm.model\", restoredSubscriptionModel);\n }\n return;\n }\n\n if (modelValue && subscriptionModels?.includes(modelValue)) {\n lastSubscriptionModelRef.current = modelValue;\n onChange(\"llm.model\", lastApiKeyModelRef.current ?? defaultModel);\n }\n };\n\n const renderAuthTypeInput = () => (\n <SettingsDropdownInput\n testId=\"llm-auth-type-input\"\n name={LLM_AUTH_TYPE_KEY}\n label={t(I18nKey.SETTINGS$LLM_AUTH_TYPE)}\n items={[\n {\n key: LLM_AUTH_TYPE_API_KEY,\n label: t(I18nKey.SETTINGS$LLM_AUTH_TYPE_API_KEY),\n },\n {\n key: LLM_AUTH_TYPE_SUBSCRIPTION,\n label: t(I18nKey.SETTINGS$LLM_AUTH_TYPE_SUBSCRIPTION),\n },\n ]}\n selectedKey={authType}\n isClearable={false}\n required\n isDisabled={shouldDisableSubscriptionControls}\n onSelectionChange={handleAuthTypeChange}\n />\n );\n\n const renderSubscriptionSettings = () => (\n <div\n className=\"flex flex-col gap-6\"\n data-testid=\"llm-subscription-settings\"\n >\n <SettingsDropdownInput\n testId=\"llm-subscription-model-input\"\n name=\"llm.subscription_model\"\n label={t(I18nKey.SETTINGS$SUBSCRIPTION_MODEL)}\n items={(subscriptionModels ?? []).map((model) => ({\n key: model,\n label: model,\n }))}\n selectedKey={subscriptionModelValue}\n isClearable={false}\n required\n isDisabled={\n shouldDisableSubscriptionControls || !subscriptionModels?.length\n }\n onSelectionChange={(selectedKey) => {\n const nextModel =\n typeof selectedKey === \"string\"\n ? selectedKey\n : subscriptionModels?.[0];\n if (nextModel) {\n onChange(\"llm.model\", nextModel);\n }\n }}\n />\n <OpenAISubscriptionAuthCard isDisabled={isDisabled} />\n </div>\n );\n\n return (\n <div className=\"flex flex-col gap-6\">\n {view === \"basic\" ? (\n <div\n className=\"flex flex-col gap-6\"\n data-testid=\"llm-settings-form-basic\"\n >\n {renderAuthTypeInput()}\n\n {isSubscriptionAuth ? (\n renderSubscriptionSettings()\n ) : (\n <>\n <ModelSelector\n currentModel={modelValue || undefined}\n onChange={(provider, model) => {\n const nextModel = buildModelId(provider, model);\n if (nextModel) {\n onChange(\"llm.model\", nextModel);\n }\n }}\n wrapperClassName=\"!flex-col !gap-6\"\n isDisabled={isDisabled}\n />\n\n {showConnectionSelector ? renderConnectionSelector() : null}\n\n {isLinkedToConnection || hideInlineCredentials\n ? null\n : renderApiKeyInput(\n // eslint-disable-next-line i18next/no-literal-string -- DOM id, not user-facing\n \"llm-api-key-input\",\n // eslint-disable-next-line i18next/no-literal-string -- DOM id, not user-facing\n \"llm-api-key-help-anchor\",\n // eslint-disable-next-line i18next/no-literal-string -- DOM id, not user-facing\n \"openhands-api-key-help\",\n )}\n </>\n )}\n </div>\n ) : (\n <div\n className=\"flex flex-col gap-6\"\n data-testid=\"llm-settings-form-advanced\"\n >\n {renderAuthTypeInput()}\n\n {isSubscriptionAuth ? (\n renderSubscriptionSettings()\n ) : (\n <>\n <SettingsInput\n testId=\"llm-custom-model-input\"\n label={t(I18nKey.SETTINGS$CUSTOM_MODEL)}\n type=\"text\"\n className=\"w-full\"\n value={modelValue}\n placeholder={defaultModel}\n onChange={(value) => onChange(\"llm.model\", value)}\n isDisabled={isDisabled}\n />\n\n {showOpenHandsApiKeyHelp && !isLinkedToConnection ? (\n <>\n {isFreeOpenHandsModel(modelValue) ? (\n <OpenHandsFreeModelsNote />\n ) : null}\n </>\n ) : null}\n\n {showConnectionSelector ? renderConnectionSelector() : null}\n\n {isLinkedToConnection || hideInlineCredentials ? null : (\n <SettingsInput\n testId=\"base-url-input\"\n label={t(I18nKey.SETTINGS$BASE_URL)}\n type=\"text\"\n className=\"w-full\"\n value={baseUrlValue}\n // eslint-disable-next-line i18next/no-literal-string -- example value, not translatable\n placeholder=\"https://api.openai.com\"\n onChange={(value) => onChange(\"llm.base_url\", value)}\n isDisabled={isDisabled}\n />\n )}\n\n {isLinkedToConnection || hideInlineCredentials\n ? null\n : renderApiKeyInput(\n // eslint-disable-next-line i18next/no-literal-string -- DOM id, not user-facing\n \"llm-api-key-input\",\n // eslint-disable-next-line i18next/no-literal-string -- DOM id, not user-facing\n \"llm-api-key-help-anchor-advanced\",\n // eslint-disable-next-line i18next/no-literal-string -- DOM id, not user-facing\n \"openhands-api-key-help-2\",\n )}\n </>\n )}\n </div>\n )}\n </div>\n );\n },\n [\n connectionOptions,\n showProviderConnection,\n defaultModel,\n embedded,\n isCloud,\n isWaitingForSubscriptionModels,\n settings?.llm_api_key_set,\n subscriptionModels,\n t,\n ],\n );\n\n const buildPayload = React.useCallback(\n (\n defaultPayload: Record<string, unknown>,\n context: {\n values: Record<string, string | boolean>;\n dirty: Record<string, boolean>;\n view: SettingsView;\n },\n ) => {\n // defaultPayload is the wrapped diff (e.g.\n // `{ agent_settings_diff: { llm: { model: \"gpt-4\" } } }`); we only\n // mutate the inner `llm` object below.\n const agentSettings = structuredClone(\n (defaultPayload.agent_settings_diff as Record<string, unknown>) ?? {},\n );\n const llm = (agentSettings.llm ?? {}) as Record<string, unknown>;\n const authType = resolveLlmAuthType(context.values[LLM_AUTH_TYPE_KEY]);\n\n if (authType === LLM_AUTH_TYPE_SUBSCRIPTION) {\n llm.auth_type = LLM_AUTH_TYPE_SUBSCRIPTION;\n llm.subscription_vendor = OPENAI_SUBSCRIPTION_VENDOR;\n const model =\n typeof llm.model === \"string\"\n ? llm.model\n : String(context.values[\"llm.model\"] ?? \"\");\n const fallbackSubscriptionModel = subscriptionModels?.[0];\n if (\n !subscriptionModels?.includes(model) &&\n !fallbackSubscriptionModel\n ) {\n throw new Error(\"Subscription models are not loaded yet.\");\n }\n llm.model = subscriptionModels?.includes(model)\n ? model\n : fallbackSubscriptionModel;\n delete llm.api_key;\n delete llm.base_url;\n } else {\n if (context.dirty[LLM_AUTH_TYPE_KEY]) {\n llm.auth_type = LLM_AUTH_TYPE_API_KEY;\n llm.subscription_vendor = null;\n }\n if (context.view === \"basic\" && llm.model !== undefined) {\n llm.base_url = getSchemaFieldDefaultValue(schema, \"llm.base_url\");\n }\n // On cloud the OpenHands provider uses a server-minted LLM key, so\n // never send an inline api_key / base_url — let the backend attach its\n // own credential. (Local mode still collects an inline key.)\n if (\n isCloud &&\n isOpenHandsProviderModel(String(context.values[\"llm.model\"] ?? \"\"))\n ) {\n delete llm.api_key;\n delete llm.base_url;\n }\n }\n\n agentSettings.llm = llm;\n return { agent_settings_diff: agentSettings };\n },\n [schema, subscriptionModels, isCloud],\n );\n\n return (\n <SdkSectionPage\n scope={scope}\n settingsSources={[\n {\n settingsSource: \"agent_settings\",\n sectionKeys: [\"llm\"],\n excludeKeys: LLM_EXCLUDED_KEYS,\n },\n ]}\n header={buildHeader}\n buildPayload={buildPayload}\n getInitialView={getInitialView}\n forceShowAdvancedView\n allowAllView\n onSaveSuccess={onSaveSuccess}\n initialValueOverrides={initialValueOverrides}\n markInitialOverridesDirty={markInitialOverridesDirty}\n embedded={embedded}\n hideSaveButton={hideSaveButton}\n suppressSuccessToast={suppressSuccessToast}\n onSaveControlChange={onSaveControlChange}\n testId=\"llm-settings-screen\"\n />\n );\n}\n\n/**\n * Default export for the route renders the LLM-profile management view for both\n * backend types. Both manage the LLM through named profiles — local via the\n * agent-server (`/api/profiles`), cloud via the app-server\n * (`/api/v1/settings/profiles`) — and the view is backend-agnostic because it\n * goes through ProfilesService, which routes per active backend.\n *\n * The LlmSettingsScreen component is also exported for embedded use cases\n * (e.g., onboarding, the profile create/edit form).\n *\n * Note: This is a route file, only the router should import the default export.\n * Other consumers should use the named export `LlmSettingsScreen` for embedded\n * use cases.\n */\nexport default function LlmSettingsRoute() {\n return <LlmSettingsLocalView />;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA4CA,IAAa,IAA8B,8BAGrC,IAAyB,YAEzB,IAAoB,IAAI,IAAI;CAChC;CACA;CACA;CACA;CACA;CACA;AACF,CAAC,GAEK,KAAgB,GAAyB,MACzC,CAAC,KAAY,CAAC,IAAc,OACzB,GAAG,EAAS,GAAG,KAGlB,KACJ,GACA,MAEA,GAAQ,SACL,SAAS,MAAY,EAAQ,MAAM,EACnC,MAAM,MAAU,EAAM,QAAQ,CAAQ,GAAG,WAAW,MAEnD,IAAyE;CAC7E,QAAQ,IAAI,IAAI,CAAC,0BAA0B,2BAA2B,CAAC;CACvE,UAAU,IAAI,IAAI,CAAC,gCAAgC,CAAC;AACtD,GAEM,KAAoB,MAAoB;CAC5C,IAAI;EACF,IAAM,IAAY,IAAI,IAAI,CAAO,GAC3B,IAAiB,EAAU,SAAS,QAAQ,QAAQ,EAAE,KAAK;EACjE,OAAO,GAAG,EAAU,SAAS;CAC/B,QAAQ;EACN,OAAO,EAAQ,KAAK,EAAE,QAAQ,QAAQ,EAAE;CAC1C;AACF,GAEM,KAA4B,GAAe,MAAoB;CACnE,IAAM,IAAoB,EAAiB,CAAO,GAC5C,EAAE,gBAAa,EAAwB,CAAK;CAElD,IAAI,GAAU;EACZ,IAAM,IAAgB,EAAiC;EACvD,IAAI,GACF,OAAO,EAAc,IAAI,CAAiB;CAE9C;CAEA,OAAO,OAAO,OAAO,CAAgC,EAAE,MAAM,MAC3D,GAAe,IAAI,CAAiB,CACtC;AACF;AAMA,SAAS,GAAoB,EAAE,aAAoC;CACjE,IAAM,EAAE,SAAM,EAAe,WAAW;CAExC,OACE,kBAAC,GAAD;EACU;EACR,MAAM,EAAE,EAAQ,oCAAoC;EACpD,UAAU,EAAE,EAAQ,oCAAoC;EACxD,MAAK;EACL,QAAQ,IAAI,EAAE,EAAQ,sCAAsC;EAC5D,gBAAgB,EAAE,EAAQ,kCAAkC;EAC5D,gBAAe;EACf,UAAS;CACV,CAAA;AAEL;AAEA,SAAS,KAA0B;CACjC,OACE,kBAAC,KAAD;EACE,eAAY;EACZ,WAAU;YAFZ,CAIE,kBAAC,GAAD;GAAM,WAAU;GAAsC,eAAA;EAAa,CAAA,GACnE,kBAAC,QAAD,EAAA,UAAO,EAAgC,CAAA,CACtC;;AAEP;AAEA,SAAgB,EAAkB,EAChC,WAAQ,YACR,kBACA,0BACA,8BACA,aACA,mBACA,yBACA,wBACA,6BAuBC;CACD,IAAM,EAAE,SAAM,EAAe,WAAW,GAElC,EAAE,eAAY,EAAiB,GAC/B,IAAU,EAAQ,SAAS,SAE3B,EAAE,MAAM,MAAwB,EAAuB,GACvD,IAAoB,EAAM,cACvB,IAA0B,KAAuB,CAAC,IAAK,CAAC,GAC/D,CAAC,GAAwB,CAAmB,CAC9C,GAEM,EAAE,MAAM,MAAa,EAAY,CAAK,GACtC,EAAE,MAAM,MAAW,EACvB,GAAU,qBACZ,GACM,KAAuB,GAAU,gBAAgB,KAGjD,IAAkB,EACtB,IAAA,oBACE,IAAsB,SAC1B,GACM,CAAC,GAA0B,KAC/B,EAAM,SAAS,MAAoB,CAA0B,GACzD,EACJ,MAAM,GACN,WAAW,IACX,YAAY,OACV,EAA4B,EAAE,SAAS,EAAyB,CAAC,GAC/D,IACJ,KACA,CAAC,MACA,MAA+B,KAC5B,IAAqB,EAAM,OAAsB,IAAI,GACrD,IAA2B,EAAM,OAAsB,IAAI;CAEjE,EAAM,gBAAgB;EACpB,AAAI,MAAA,kBACF,EAA4B,EAAI;CAEpC,GAAG,CAAC,CAAe,CAAC;CAEpB,IAAM,IAAe,OAClB,EAAiB,gBAAgB,KAAiC,SACjE,EACJ,GAEM,KAAiB,EAAM,aAEzB,GACA,MACiB;EACjB,IAAM,IAAa,EAAiB,GAAiB,CAAc;EACnE,IAAI,MAAe,SACjB,OAAO;EAGT,IAAM,IAAe,EAAgB,aAAa,IAC5C,IAAiB,EAAgB,cAAc,KAAK,KAAK;EAK/D,OAHE,EAAe,SAAS,KACxB,CAAC,EAAyB,GAAc,CAAc,IAE9B,QAAQ;CACpC,GACA,CAAC,CACH,GAEM,KAAc,EAAM,aACvB,EAAE,WAAQ,eAAY,SAAM,kBAAsC;EACjE,IAAM,IACJ,OAAO,EAAO,gBAAiB,WAAW,EAAO,eAAe,IAC5D,IACJ,OAAO,EAAO,mBAAoB,WAC9B,EAAO,kBACP,IACA,IAA0B,EAAyB,CAAU,GAC7D,IAAW,EAAmB,EAAO,EAAkB,GACvD,IAAqB,MAAa,GAKlC,IACJ,KAAW,KAA2B,CAAC,GACnC,IACJ,KAAe,KAAsB,GACjC,IAAyB,GAAoB,SAAS,CAAU,IAClE,IACC,IAAqB,MAAM,IAE1B,IACJ,OAAO,EAAO,kBAAmB,WAAW,EAAO,iBAAiB,IAKhE,IAAc,IAChB,EAAY,SAAS,IACrB,EAAQ,GAAU,iBAIhB,IACJ,OAAO,EAAA,iCAAwC,WAC3C,EAAO,KACP,IACA,IAAuB,EAAQ,GAM/B,IACJ,KACA,CAAC,MACA,KAAwB,EAAkB,SAAS,IAGhD,IACJ,KACA,CAAC,EAAkB,MAAM,MAAM,EAAE,OAAO,CAAe,GAEnD,UACJ,kBAAC,GAAD;GACE,QAAO;GACP,MAAM;GACN,OAAO,EAAE,EAAQ,yCAAyC;GAC1D,OAAO;IACL;KACE,KAAK;KACL,OAAO,EAAE,EAAQ,2BAA2B;IAC9C;IACA,GAAG,EAAkB,KAAK,OAAgB;KACxC,KAAK,EAAW;KAChB,OAAO,EAAW;IACpB,EAAE;IACF,GAAI,IACA,CAAC;KAAE,KAAK;KAAiB,OAAO;IAAgB,CAAC,IACjD,CAAC;GACP;GACA,aAAa,KAAmB;GAChC,aAAa;GACD;GACZ,oBAAoB,MAAgB;IAMlC,EAAS,GAJP,OAAO,KAAgB,YACvB,MAAgB,IACZ,IACA,EACoC;GAC5C;EACD,CAAA,GAGG,KACJ,GACA,GACA,MAEA,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;GACU;GACR,OAAO,EAAE,EAAQ,qBAAqB;GACtC,MAAK;GACL,WAAU;GACV,OAAO;GAEP,aAAa,IAAc,aAAa;GACxC,WAAW,MAAU,EAAS,eAAe,CAAK;GACtC;GACZ,cACE,IAAc,kBAAC,IAAD,EAAe,OAAO,EAAc,CAAA,IAAI,KAAA;EAEzD,CAAA,GAKA,IACC,kBAAC,IAAD,EAAqB,QAAQ,EAAsB,CAAA,IAEnD,kBAAC,GAAD;GACE,QAAQ;GACR,MAAM,EAAE,EAAQ,0BAA0B;GAC1C,UAAU,EAAE,EAAQ,+BAA+B;GACnD,MAAK;EACN,CAAA,CAEH,EAAA,CAAA,GAGE,KAAwB,MAAkC;GAC9D,IAAM,IACJ,MAAA,iBACI,IACA;GAGN,IAFA,EAAS,GAAmB,CAAY,GAEpC,MAAA,gBAA6C;IAE/C,AADA,EAA4B,EAAI,GAC5B,KAAc,CAAC,GAAoB,SAAS,CAAU,MACxD,EAAmB,UAAU;IAE/B,IAAM,IACJ,EAAyB,WACzB,GAAoB,SAAS,EAAyB,OAAO,IACzD,EAAyB,UACzB,IAAqB;IAE3B,AADA,EAAS,GAA6B,CAA0B,GAE9D,CAAC,GAAoB,SAAS,CAAU,KACxC,KAEA,EAAS,aAAa,CAAyB;IAEjD;GACF;GAEA,AAAI,KAAc,GAAoB,SAAS,CAAU,MACvD,EAAyB,UAAU,GACnC,EAAS,aAAa,EAAmB,WAAW,CAAY;EAEpE,GAEM,UACJ,kBAAC,GAAD;GACE,QAAO;GACP,MAAM;GACN,OAAO,EAAE,EAAQ,sBAAsB;GACvC,OAAO,CACL;IACE,KAAK;IACL,OAAO,EAAE,EAAQ,8BAA8B;GACjD,GACA;IACE,KAAK;IACL,OAAO,EAAE,EAAQ,mCAAmC;GACtD,CACF;GACA,aAAa;GACb,aAAa;GACb,UAAA;GACA,YAAY;GACZ,mBAAmB;EACpB,CAAA,GAGG,UACJ,kBAAC,OAAD;GACE,WAAU;GACV,eAAY;aAFd,CAIE,kBAAC,GAAD;IACE,QAAO;IACP,MAAK;IACL,OAAO,EAAE,EAAQ,2BAA2B;IAC5C,QAAQ,KAAsB,CAAC,GAAG,KAAK,OAAW;KAChD,KAAK;KACL,OAAO;IACT,EAAE;IACF,aAAa;IACb,aAAa;IACb,UAAA;IACA,YACE,KAAqC,CAAC,GAAoB;IAE5D,oBAAoB,MAAgB;KAClC,IAAM,IACJ,OAAO,KAAgB,WACnB,IACA,IAAqB;KAC3B,AAAI,KACF,EAAS,aAAa,CAAS;IAEnC;GACD,CAAA,GACD,kBAAC,IAAD,EAAwC,cAAa,CAAA,CAClD;;EAGP,OACE,kBAAC,OAAD;GAAK,WAAU;aACZ,MAAS,UACR,kBAAC,OAAD;IACE,WAAU;IACV,eAAY;cAFd,CAIG,EAAoB,GAEpB,IACC,EAA2B,IAE3B,kBAAA,GAAA,EAAA,UAAA;KACE,kBAAC,IAAD;MACE,cAAc,KAAc,KAAA;MAC5B,WAAW,GAAU,MAAU;OAC7B,IAAM,IAAY,EAAa,GAAU,CAAK;OAC9C,AAAI,KACF,EAAS,aAAa,CAAS;MAEnC;MACA,kBAAiB;MACL;KACb,CAAA;KAEA,IAAyB,EAAyB,IAAI;KAEtD,KAAwB,IACrB,OACA,EAEE,qBAEA,2BAEA,wBACF;IACJ,EAAA,CAAA,CAED;QAEL,kBAAC,OAAD;IACE,WAAU;IACV,eAAY;cAFd,CAIG,EAAoB,GAEpB,IACC,EAA2B,IAE3B,kBAAA,GAAA,EAAA,UAAA;KACE,kBAAC,GAAD;MACE,QAAO;MACP,OAAO,EAAE,EAAQ,qBAAqB;MACtC,MAAK;MACL,WAAU;MACV,OAAO;MACP,aAAa;MACb,WAAW,MAAU,EAAS,aAAa,CAAK;MACpC;KACb,CAAA;KAEA,KAA2B,CAAC,IAC3B,kBAAA,GAAA,EAAA,UACG,GAAqB,CAAU,IAC9B,kBAAC,IAAD,CAA0B,CAAA,IACxB,KACJ,CAAA,IACA;KAEH,IAAyB,EAAyB,IAAI;KAEtD,KAAwB,IAAwB,OAC/C,kBAAC,GAAD;MACE,QAAO;MACP,OAAO,EAAE,EAAQ,iBAAiB;MAClC,MAAK;MACL,WAAU;MACV,OAAO;MAEP,aAAY;MACZ,WAAW,MAAU,EAAS,gBAAgB,CAAK;MACvC;KACb,CAAA;KAGF,KAAwB,IACrB,OACA,EAEE,qBAEA,oCAEA,0BACF;IACJ,EAAA,CAAA,CAED;;EAEJ,CAAA;CAET,GACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA,GAAU;EACV;EACA;CACF,CACF,GAEM,KAAe,EAAM,aAEvB,GACA,MAKG;EAIH,IAAM,IAAgB,gBACnB,EAAe,uBAAmD,CAAC,CACtE,GACM,IAAO,EAAc,OAAO,CAAC;EAGnC,IAFiB,EAAmB,EAAQ,OAAA,gBAExC,MAAA,gBAAyC;GAE3C,AADA,EAAI,YAAY,GAChB,EAAI,sBAAsB;GAC1B,IAAM,IACJ,OAAO,EAAI,SAAU,WACjB,EAAI,QACJ,OAAO,EAAQ,OAAO,gBAAgB,EAAE,GACxC,IAA4B,IAAqB;GACvD,IACE,CAAC,GAAoB,SAAS,CAAK,KACnC,CAAC,GAED,MAAU,MAAM,yCAAyC;GAM3D,AAJA,EAAI,QAAQ,GAAoB,SAAS,CAAK,IAC1C,IACA,GACJ,OAAO,EAAI,SACX,OAAO,EAAI;EACb,OAWE,AAVI,EAAQ,MAAA,qBACV,EAAI,YAAY,GAChB,EAAI,sBAAsB,OAExB,EAAQ,SAAS,WAAW,EAAI,UAAU,KAAA,MAC5C,EAAI,WAAW,EAA2B,GAAQ,cAAc,IAMhE,KACA,EAAyB,OAAO,EAAQ,OAAO,gBAAgB,EAAE,CAAC,MAElE,OAAO,EAAI,SACX,OAAO,EAAI;EAKf,OADA,EAAc,MAAM,GACb,EAAE,qBAAqB,EAAc;CAC9C,GACA;EAAC;EAAQ;EAAoB;CAAO,CACtC;CAEA,OACE,kBAAC,GAAD;EACS;EACP,iBAAiB,CACf;GACE,gBAAgB;GAChB,aAAa,CAAC,KAAK;GACnB,aAAa;EACf,CACF;EACA,QAAQ;EACM;EACE;EAChB,uBAAA;EACA,cAAA;EACe;EACQ;EACI;EACjB;EACM;EACM;EACD;EACrB,QAAO;CACR,CAAA;AAEL"}
|
|
1
|
+
{"version":3,"file":"llm-settings.js","names":[],"sources":["../../src/routes/llm-settings.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { ModelSelector } from \"#/components/shared/modals/settings/model-selector\";\nimport { useAgentSettingsSchema } from \"#/hooks/query/use-agent-settings-schema\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { SettingsInput } from \"#/components/features/settings/settings-input\";\nimport { SettingsDropdownInput } from \"#/components/features/settings/settings-dropdown-input\";\nimport { OpenAISubscriptionAuthCard } from \"#/components/features/settings/llm-settings/openai-subscription-auth-card\";\nimport { HelpLink } from \"#/ui/help-link\";\nimport { KeyStatusIcon } from \"#/components/features/settings/key-status-icon\";\nimport {\n SdkSectionHeaderProps,\n SdkSectionPage,\n SdkSectionSaveControl,\n} from \"#/components/features/settings/sdk-settings/sdk-section-page\";\nimport { LlmSettingsLocalView } from \"#/components/features/settings/llm-profiles\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { Settings, SettingsSchema, SettingsScope } from \"#/types/settings\";\nimport { extractModelAndProvider } from \"#/utils/extract-model-and-provider\";\nimport {\n inferInitialView,\n type SettingsFormValues,\n type SettingsView,\n} from \"#/utils/sdk-settings-schema\";\nimport { DEFAULT_SETTINGS } from \"#/services/settings\";\nimport {\n LLM_AUTH_TYPE_API_KEY,\n LLM_AUTH_TYPE_KEY,\n LLM_AUTH_TYPE_SUBSCRIPTION,\n LLM_SUBSCRIPTION_VENDOR_KEY,\n OPENAI_SUBSCRIPTION_VENDOR,\n resolveLlmAuthType,\n} from \"#/constants/llm-subscription\";\nimport { useOpenAISubscriptionModels } from \"#/hooks/query/use-llm-subscription-models\";\nimport { useProviderConnections } from \"#/hooks/query/use-provider-connections\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport { useDefaultModel, useFreeModels } from \"#/hooks/query/use-free-models\";\nimport {\n isFreeOpenHandsModel,\n isOpenHandsProviderModel,\n} from \"#/utils/format-model-name\";\nimport { FreeOpenHandsModelsNote } from \"#/components/shared/free-models-note\";\n\n/** Form-values key for the shared provider connection a profile links to. */\nexport const LLM_PROVIDER_CONNECTION_KEY = \"llm.provider_connection_id\";\n\n/** Dropdown sentinel for \"no provider connection\" (an inline key is used). */\nconst NO_PROVIDER_CONNECTION = \"__none__\";\n\nconst LLM_EXCLUDED_KEYS = new Set([\n \"llm.model\",\n \"llm.api_key\",\n \"llm.base_url\",\n LLM_PROVIDER_CONNECTION_KEY,\n LLM_AUTH_TYPE_KEY,\n LLM_SUBSCRIPTION_VENDOR_KEY,\n]);\n\nconst buildModelId = (provider: string | null, model: string | null) => {\n if (!provider || !model) return null;\n return `${provider}/${model}`;\n};\n\nconst getSchemaFieldDefaultValue = (\n schema: SettingsSchema | null | undefined,\n fieldKey: string,\n) =>\n schema?.sections\n .flatMap((section) => section.fields)\n .find((field) => field.key === fieldKey)?.default ?? null;\n\nconst KNOWN_PROVIDER_DEFAULT_BASE_URLS: Partial<Record<string, Set<string>>> = {\n openai: new Set([\"https://api.openai.com\", \"https://api.openai.com/v1\"]),\n moonshot: new Set([\"https://api.kimi.com/coding/v1\"]),\n};\n\nconst normalizeBaseUrl = (baseUrl: string) => {\n try {\n const parsedUrl = new URL(baseUrl);\n const normalizedPath = parsedUrl.pathname.replace(/\\/+$/, \"\") || \"\";\n return `${parsedUrl.origin}${normalizedPath}`;\n } catch {\n return baseUrl.trim().replace(/\\/+$/, \"\");\n }\n};\n\nconst isProviderDefaultBaseUrl = (model: string, baseUrl: string) => {\n const normalizedBaseUrl = normalizeBaseUrl(baseUrl);\n const { provider } = extractModelAndProvider(model);\n\n if (provider) {\n const knownDefaults = KNOWN_PROVIDER_DEFAULT_BASE_URLS[provider];\n if (knownDefaults) {\n return knownDefaults.has(normalizedBaseUrl);\n }\n }\n\n return Object.values(KNOWN_PROVIDER_DEFAULT_BASE_URLS).some((knownDefaults) =>\n knownDefaults?.has(normalizedBaseUrl),\n );\n};\n\ninterface OpenHandsApiKeyHelpProps {\n testId: string;\n}\n\nfunction OpenHandsApiKeyHelp({ testId }: OpenHandsApiKeyHelpProps) {\n const { t } = useTranslation(\"openhands\");\n\n return (\n <HelpLink\n testId={testId}\n text={t(I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_TEXT)}\n linkText={t(I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_LINK)}\n href=\"https://app.all-hands.dev/settings/api-keys\"\n suffix={` ${t(I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_SUFFIX)}`}\n suffixLinkText={t(I18nKey.SETTINGS$SEE_HERE_FOR_MORE_DETAILS)}\n suffixLinkHref=\"https://docs.openhands.dev/usage/local-setup#getting-an-api-key\"\n trailing=\".\"\n />\n );\n}\n\nexport function LlmSettingsScreen({\n scope = \"personal\",\n onSaveSuccess,\n initialValueOverrides,\n markInitialOverridesDirty,\n embedded,\n hideSaveButton,\n suppressSuccessToast,\n onSaveControlChange,\n showProviderConnection,\n}: {\n scope?: SettingsScope;\n /** Optional hook fired after a successful save (e.g. advance an onboarding step). */\n onSaveSuccess?: () => void;\n /** Forwarded to {@link SdkSectionPage}. */\n initialValueOverrides?: SettingsFormValues;\n /** Forwarded to {@link SdkSectionPage}. */\n markInitialOverridesDirty?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n embedded?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n hideSaveButton?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n suppressSuccessToast?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n onSaveControlChange?: (control: SdkSectionSaveControl) => void;\n /**\n * When true (the local profile editor), show a \"Provider connection\" selector\n * that links this profile to a shared connection. Only rendered when at least\n * one connection exists, so the form is unchanged until the user creates one.\n */\n showProviderConnection?: boolean;\n}) {\n const { t } = useTranslation(\"openhands\");\n\n const { backend } = useActiveBackend();\n const isCloud = backend.kind === \"cloud\";\n\n const { data: providerConnections } = useProviderConnections();\n const connectionOptions = React.useMemo(\n () => (showProviderConnection ? (providerConnections ?? []) : []),\n [showProviderConnection, providerConnections],\n );\n\n const { data: settings } = useSettings(scope);\n const { data: schema } = useAgentSettingsSchema(\n settings?.agent_settings_schema,\n );\n const persistedLlmSettings = settings?.agent_settings?.llm as\n | Record<string, unknown>\n | undefined;\n const initialAuthType = resolveLlmAuthType(\n initialValueOverrides?.[LLM_AUTH_TYPE_KEY] ??\n persistedLlmSettings?.auth_type,\n );\n const [enableSubscriptionModels, setEnableSubscriptionModels] =\n React.useState(initialAuthType === LLM_AUTH_TYPE_SUBSCRIPTION);\n const {\n data: subscriptionModels,\n isLoading: isSubscriptionModelsLoading,\n isFetching: isSubscriptionModelsFetching,\n } = useOpenAISubscriptionModels({ enabled: enableSubscriptionModels });\n const isWaitingForSubscriptionModels =\n enableSubscriptionModels &&\n !subscriptionModels &&\n (isSubscriptionModelsLoading || isSubscriptionModelsFetching);\n const lastApiKeyModelRef = React.useRef<string | null>(null);\n const lastSubscriptionModelRef = React.useRef<string | null>(null);\n\n React.useEffect(() => {\n if (initialAuthType === LLM_AUTH_TYPE_SUBSCRIPTION) {\n setEnableSubscriptionModels(true);\n }\n }, [initialAuthType]);\n\n const freeModels = useFreeModels();\n const dbDefaultModel = useDefaultModel();\n\n // Prefer the DB-driven default (cloud) and fall back to the bundled default\n // when the backend exposes none (e.g. the local agent-server).\n const defaultModel =\n dbDefaultModel ??\n String(\n (DEFAULT_SETTINGS.agent_settings?.llm as Record<string, unknown>)\n ?.model ?? \"\",\n );\n\n const getInitialView = React.useCallback(\n (\n currentSettings: Settings,\n filteredSchema: SettingsSchema,\n ): SettingsView => {\n const schemaView = inferInitialView(currentSettings, filteredSchema);\n if (schemaView !== \"basic\") {\n return schemaView;\n }\n\n const currentModel = currentSettings.llm_model ?? \"\";\n const trimmedBaseUrl = currentSettings.llm_base_url?.trim() ?? \"\";\n const hasCustomBaseUrl =\n trimmedBaseUrl.length > 0 &&\n !isProviderDefaultBaseUrl(currentModel, trimmedBaseUrl);\n\n return hasCustomBaseUrl ? \"all\" : \"basic\";\n },\n [],\n );\n\n const buildHeader = React.useCallback(\n ({ values, isDisabled, view, onChange }: SdkSectionHeaderProps) => {\n const modelValue =\n typeof values[\"llm.model\"] === \"string\" ? values[\"llm.model\"] : \"\";\n const baseUrlValue =\n typeof values[\"llm.base_url\"] === \"string\"\n ? values[\"llm.base_url\"]\n : \"\";\n const showOpenHandsApiKeyHelp = isOpenHandsProviderModel(modelValue);\n const authType = resolveLlmAuthType(values[LLM_AUTH_TYPE_KEY]);\n const isSubscriptionAuth = authType === LLM_AUTH_TYPE_SUBSCRIPTION;\n // On cloud the OpenHands provider is backed by a server-minted LLM key,\n // so the inline API key / base URL inputs are not user-supplied. Local\n // mode still collects an api_key (the OpenHands provider can run against\n // a self-hosted endpoint there).\n const hideInlineCredentials =\n isCloud && showOpenHandsApiKeyHelp && !isSubscriptionAuth;\n const shouldDisableSubscriptionControls =\n isDisabled || (isSubscriptionAuth && isWaitingForSubscriptionModels);\n const subscriptionModelValue = subscriptionModels?.includes(modelValue)\n ? modelValue\n : (subscriptionModels?.[0] ?? \"\");\n\n const apiKeyValue =\n typeof values[\"llm.api_key\"] === \"string\" ? values[\"llm.api_key\"] : \"\";\n // For embedded profile forms (create/edit) the global\n // `llm_api_key_set` flag is misleading: a brand-new profile would show a\n // \"key set\" indicator just because some other profile has a key. Reflect\n // the form's own key state instead so create mode starts visibly unset.\n const apiKeyIsSet = embedded\n ? apiKeyValue.length > 0\n : Boolean(settings?.llm_api_key_set);\n\n // A profile linked to a provider connection reads its api_key / base_url\n // from that connection, so the inline key + base URL inputs are hidden.\n const connectionValue =\n typeof values[LLM_PROVIDER_CONNECTION_KEY] === \"string\"\n ? values[LLM_PROVIDER_CONNECTION_KEY]\n : \"\";\n const isLinkedToConnection = Boolean(connectionValue);\n // Show the selector whenever connections can be linked here. Include the\n // linked case so a profile pointing at an orphaned connection (its only\n // connection deleted, or the list still loading) still exposes a control\n // to unlink — otherwise the API key / base URL inputs stay hidden with no\n // way to recover.\n const showConnectionSelector =\n showProviderConnection &&\n !isSubscriptionAuth &&\n (isLinkedToConnection || connectionOptions.length > 0);\n // Surface an orphaned link (a selected id absent from the fetched list)\n // as its own option so the dropdown reflects it and can be cleared.\n const isOrphanedLink =\n isLinkedToConnection &&\n !connectionOptions.some((c) => c.id === connectionValue);\n\n const renderConnectionSelector = () => (\n <SettingsDropdownInput\n testId=\"llm-provider-connection-input\"\n name={LLM_PROVIDER_CONNECTION_KEY}\n label={t(I18nKey.SETTINGS$PROVIDER_CONNECTION_SELECT_LABEL)}\n items={[\n {\n key: NO_PROVIDER_CONNECTION,\n label: t(I18nKey.SETTINGS$MCP_AUTH_MODE_NONE),\n },\n ...connectionOptions.map((connection) => ({\n key: connection.id,\n label: connection.display_name,\n })),\n ...(isOrphanedLink\n ? [{ key: connectionValue, label: connectionValue }]\n : []),\n ]}\n selectedKey={connectionValue || NO_PROVIDER_CONNECTION}\n isClearable={false}\n isDisabled={isDisabled}\n onSelectionChange={(selectedKey) => {\n const next =\n typeof selectedKey === \"string\" &&\n selectedKey !== NO_PROVIDER_CONNECTION\n ? selectedKey\n : \"\";\n onChange(LLM_PROVIDER_CONNECTION_KEY, next);\n }}\n />\n );\n\n const renderApiKeyInput = (\n testId: string,\n helpTestId: string,\n openHandsHelpTestId: string,\n ) => (\n <>\n <SettingsInput\n testId={testId}\n label={t(I18nKey.SETTINGS_FORM$API_KEY)}\n type=\"password\"\n className=\"w-full\"\n value={apiKeyValue}\n // eslint-disable-next-line i18next/no-literal-string -- masked-key sentinel, not translatable\n placeholder={apiKeyIsSet ? \"<hidden>\" : \"\"}\n onChange={(value) => onChange(\"llm.api_key\", value)}\n isDisabled={isDisabled}\n startContent={\n apiKeyIsSet ? <KeyStatusIcon isSet={apiKeyIsSet} /> : undefined\n }\n />\n\n {/* The OpenHands provider's key lives in the OpenHands Cloud \"API\n Keys\" tab, so point users there instead of the generic docs page\n that covers both LLM and regular API keys. */}\n {showOpenHandsApiKeyHelp ? (\n <OpenHandsApiKeyHelp testId={openHandsHelpTestId} />\n ) : (\n <HelpLink\n testId={helpTestId}\n text={t(I18nKey.SETTINGS$DONT_KNOW_API_KEY)}\n linkText={t(I18nKey.SETTINGS$CLICK_FOR_INSTRUCTIONS)}\n href=\"https://docs.openhands.dev/usage/local-setup#getting-an-api-key\"\n />\n )}\n </>\n );\n\n const handleAuthTypeChange = (selectedKey: React.Key | null) => {\n const nextAuthType =\n selectedKey === LLM_AUTH_TYPE_SUBSCRIPTION\n ? LLM_AUTH_TYPE_SUBSCRIPTION\n : LLM_AUTH_TYPE_API_KEY;\n onChange(LLM_AUTH_TYPE_KEY, nextAuthType);\n\n if (nextAuthType === LLM_AUTH_TYPE_SUBSCRIPTION) {\n setEnableSubscriptionModels(true);\n if (modelValue && !subscriptionModels?.includes(modelValue)) {\n lastApiKeyModelRef.current = modelValue;\n }\n const restoredSubscriptionModel =\n lastSubscriptionModelRef.current &&\n subscriptionModels?.includes(lastSubscriptionModelRef.current)\n ? lastSubscriptionModelRef.current\n : subscriptionModels?.[0];\n onChange(LLM_SUBSCRIPTION_VENDOR_KEY, OPENAI_SUBSCRIPTION_VENDOR);\n if (\n !subscriptionModels?.includes(modelValue) &&\n restoredSubscriptionModel\n ) {\n onChange(\"llm.model\", restoredSubscriptionModel);\n }\n return;\n }\n\n if (modelValue && subscriptionModels?.includes(modelValue)) {\n lastSubscriptionModelRef.current = modelValue;\n onChange(\"llm.model\", lastApiKeyModelRef.current ?? defaultModel);\n }\n };\n\n const renderAuthTypeInput = () => (\n <SettingsDropdownInput\n testId=\"llm-auth-type-input\"\n name={LLM_AUTH_TYPE_KEY}\n label={t(I18nKey.SETTINGS$LLM_AUTH_TYPE)}\n items={[\n {\n key: LLM_AUTH_TYPE_API_KEY,\n label: t(I18nKey.SETTINGS$LLM_AUTH_TYPE_API_KEY),\n },\n {\n key: LLM_AUTH_TYPE_SUBSCRIPTION,\n label: t(I18nKey.SETTINGS$LLM_AUTH_TYPE_SUBSCRIPTION),\n },\n ]}\n selectedKey={authType}\n isClearable={false}\n required\n isDisabled={shouldDisableSubscriptionControls}\n onSelectionChange={handleAuthTypeChange}\n />\n );\n\n const renderSubscriptionSettings = () => (\n <div\n className=\"flex flex-col gap-6\"\n data-testid=\"llm-subscription-settings\"\n >\n <SettingsDropdownInput\n testId=\"llm-subscription-model-input\"\n name=\"llm.subscription_model\"\n label={t(I18nKey.SETTINGS$SUBSCRIPTION_MODEL)}\n items={(subscriptionModels ?? []).map((model) => ({\n key: model,\n label: model,\n }))}\n selectedKey={subscriptionModelValue}\n isClearable={false}\n required\n isDisabled={\n shouldDisableSubscriptionControls || !subscriptionModels?.length\n }\n onSelectionChange={(selectedKey) => {\n const nextModel =\n typeof selectedKey === \"string\"\n ? selectedKey\n : subscriptionModels?.[0];\n if (nextModel) {\n onChange(\"llm.model\", nextModel);\n }\n }}\n />\n <OpenAISubscriptionAuthCard isDisabled={isDisabled} />\n </div>\n );\n\n return (\n <div className=\"flex flex-col gap-6\">\n {view === \"basic\" ? (\n <div\n className=\"flex flex-col gap-6\"\n data-testid=\"llm-settings-form-basic\"\n >\n {renderAuthTypeInput()}\n\n {isSubscriptionAuth ? (\n renderSubscriptionSettings()\n ) : (\n <>\n <ModelSelector\n currentModel={modelValue || undefined}\n onChange={(provider, model) => {\n const nextModel = buildModelId(provider, model);\n if (nextModel) {\n onChange(\"llm.model\", nextModel);\n }\n }}\n wrapperClassName=\"!flex-col !gap-6\"\n isDisabled={isDisabled}\n />\n\n {showConnectionSelector ? renderConnectionSelector() : null}\n\n {isLinkedToConnection || hideInlineCredentials\n ? null\n : renderApiKeyInput(\n // eslint-disable-next-line i18next/no-literal-string -- DOM id, not user-facing\n \"llm-api-key-input\",\n // eslint-disable-next-line i18next/no-literal-string -- DOM id, not user-facing\n \"llm-api-key-help-anchor\",\n // eslint-disable-next-line i18next/no-literal-string -- DOM id, not user-facing\n \"openhands-api-key-help\",\n )}\n </>\n )}\n </div>\n ) : (\n <div\n className=\"flex flex-col gap-6\"\n data-testid=\"llm-settings-form-advanced\"\n >\n {renderAuthTypeInput()}\n\n {isSubscriptionAuth ? (\n renderSubscriptionSettings()\n ) : (\n <>\n <SettingsInput\n testId=\"llm-custom-model-input\"\n label={t(I18nKey.SETTINGS$CUSTOM_MODEL)}\n type=\"text\"\n className=\"w-full\"\n value={modelValue}\n placeholder={defaultModel}\n onChange={(value) => onChange(\"llm.model\", value)}\n isDisabled={isDisabled}\n />\n\n {showOpenHandsApiKeyHelp && !isLinkedToConnection ? (\n <>\n {isFreeOpenHandsModel(modelValue, freeModels) ? (\n <FreeOpenHandsModelsNote modelIds={freeModels} />\n ) : null}\n </>\n ) : null}\n\n {showConnectionSelector ? renderConnectionSelector() : null}\n\n {isLinkedToConnection || hideInlineCredentials ? null : (\n <SettingsInput\n testId=\"base-url-input\"\n label={t(I18nKey.SETTINGS$BASE_URL)}\n type=\"text\"\n className=\"w-full\"\n value={baseUrlValue}\n // eslint-disable-next-line i18next/no-literal-string -- example value, not translatable\n placeholder=\"https://api.openai.com\"\n onChange={(value) => onChange(\"llm.base_url\", value)}\n isDisabled={isDisabled}\n />\n )}\n\n {isLinkedToConnection || hideInlineCredentials\n ? null\n : renderApiKeyInput(\n // eslint-disable-next-line i18next/no-literal-string -- DOM id, not user-facing\n \"llm-api-key-input\",\n // eslint-disable-next-line i18next/no-literal-string -- DOM id, not user-facing\n \"llm-api-key-help-anchor-advanced\",\n // eslint-disable-next-line i18next/no-literal-string -- DOM id, not user-facing\n \"openhands-api-key-help-2\",\n )}\n </>\n )}\n </div>\n )}\n </div>\n );\n },\n [\n connectionOptions,\n showProviderConnection,\n defaultModel,\n embedded,\n isCloud,\n freeModels,\n isWaitingForSubscriptionModels,\n settings?.llm_api_key_set,\n subscriptionModels,\n t,\n ],\n );\n\n const buildPayload = React.useCallback(\n (\n defaultPayload: Record<string, unknown>,\n context: {\n values: Record<string, string | boolean>;\n dirty: Record<string, boolean>;\n view: SettingsView;\n },\n ) => {\n // defaultPayload is the wrapped diff (e.g.\n // `{ agent_settings_diff: { llm: { model: \"gpt-4\" } } }`); we only\n // mutate the inner `llm` object below.\n const agentSettings = structuredClone(\n (defaultPayload.agent_settings_diff as Record<string, unknown>) ?? {},\n );\n const llm = (agentSettings.llm ?? {}) as Record<string, unknown>;\n const authType = resolveLlmAuthType(context.values[LLM_AUTH_TYPE_KEY]);\n\n if (authType === LLM_AUTH_TYPE_SUBSCRIPTION) {\n llm.auth_type = LLM_AUTH_TYPE_SUBSCRIPTION;\n llm.subscription_vendor = OPENAI_SUBSCRIPTION_VENDOR;\n const model =\n typeof llm.model === \"string\"\n ? llm.model\n : String(context.values[\"llm.model\"] ?? \"\");\n const fallbackSubscriptionModel = subscriptionModels?.[0];\n if (\n !subscriptionModels?.includes(model) &&\n !fallbackSubscriptionModel\n ) {\n throw new Error(\"Subscription models are not loaded yet.\");\n }\n llm.model = subscriptionModels?.includes(model)\n ? model\n : fallbackSubscriptionModel;\n delete llm.api_key;\n delete llm.base_url;\n } else {\n if (context.dirty[LLM_AUTH_TYPE_KEY]) {\n llm.auth_type = LLM_AUTH_TYPE_API_KEY;\n llm.subscription_vendor = null;\n }\n if (context.view === \"basic\" && llm.model !== undefined) {\n llm.base_url = getSchemaFieldDefaultValue(schema, \"llm.base_url\");\n }\n // On cloud the OpenHands provider uses a server-minted LLM key, so\n // never send an inline api_key / base_url — let the backend attach its\n // own credential. (Local mode still collects an inline key.)\n if (\n isCloud &&\n isOpenHandsProviderModel(String(context.values[\"llm.model\"] ?? \"\"))\n ) {\n delete llm.api_key;\n delete llm.base_url;\n }\n }\n\n agentSettings.llm = llm;\n return { agent_settings_diff: agentSettings };\n },\n [schema, subscriptionModels, isCloud],\n );\n\n return (\n <SdkSectionPage\n scope={scope}\n settingsSources={[\n {\n settingsSource: \"agent_settings\",\n sectionKeys: [\"llm\"],\n excludeKeys: LLM_EXCLUDED_KEYS,\n },\n ]}\n header={buildHeader}\n buildPayload={buildPayload}\n getInitialView={getInitialView}\n forceShowAdvancedView\n allowAllView\n onSaveSuccess={onSaveSuccess}\n initialValueOverrides={initialValueOverrides}\n markInitialOverridesDirty={markInitialOverridesDirty}\n embedded={embedded}\n hideSaveButton={hideSaveButton}\n suppressSuccessToast={suppressSuccessToast}\n onSaveControlChange={onSaveControlChange}\n testId=\"llm-settings-screen\"\n />\n );\n}\n\n/**\n * Default export for the route renders the LLM-profile management view for both\n * backend types. Both manage the LLM through named profiles — local via the\n * agent-server (`/api/profiles`), cloud via the app-server\n * (`/api/v1/settings/profiles`) — and the view is backend-agnostic because it\n * goes through ProfilesService, which routes per active backend.\n *\n * The LlmSettingsScreen component is also exported for embedded use cases\n * (e.g., onboarding, the profile create/edit form).\n *\n * Note: This is a route file, only the router should import the default export.\n * Other consumers should use the named export `LlmSettingsScreen` for embedded\n * use cases.\n */\nexport default function LlmSettingsRoute() {\n return <LlmSettingsLocalView />;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
require("../_virtual/_rolldown/runtime.cjs");const e=require("../node_modules/zustand/esm/react.cjs");var t=new Set,n=e.create()(e=>({freeModels:t,defaultModel:null,defaultModelReady:!1,setFlags:t=>e({freeModels:t.freeModels,defaultModel:t.defaultModel,defaultModelReady:!0}),markDefaultModelReady:()=>e({defaultModelReady:!0}),resetFlags:()=>e({freeModels:t,defaultModel:null,defaultModelReady:!1})}));exports.useFreeModelsStore=n;
|
|
2
|
+
//# sourceMappingURL=free-models-store.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"free-models-store.cjs","names":[],"sources":["../../src/stores/free-models-store.ts"],"sourcesContent":["import { create } from \"zustand\";\nimport type { FreeModelSet } from \"#/utils/format-model-name\";\n\ninterface FreeModelsState {\n /**\n * DB-driven set of free ``provider/model`` ids (the same channel that carries\n * `verified`). Empty on backends without free metadata (e.g. the local\n * agent-server), so consumers uniformly treat \"not in set\" as paid.\n */\n freeModels: FreeModelSet;\n /** DB-driven default OpenHands model id (``openhands/<model>``), or null. */\n defaultModel: string | null;\n /** True once the backend flags query has settled at least once. */\n defaultModelReady: boolean;\n}\n\ninterface FreeModelsActions {\n /**\n * Replaces the DB-driven flags. Called once by the app-level hydrator\n * ({@link useHydrateFreeModels}) after the backend model list is fetched, so\n * leaf components can read the flags synchronously via zustand selectors\n * without needing a QueryClientProvider in scope.\n */\n setFlags: (flags: {\n freeModels: FreeModelSet;\n defaultModel: string | null;\n }) => void;\n markDefaultModelReady: () => void;\n resetFlags: () => void;\n}\n\ntype FreeModelsStore = FreeModelsState & FreeModelsActions;\n\nconst EMPTY_FREE_MODELS: FreeModelSet = new Set<string>();\n\nexport const useFreeModelsStore = create<FreeModelsStore>()((set) => ({\n freeModels: EMPTY_FREE_MODELS,\n defaultModel: null,\n defaultModelReady: false,\n setFlags: (flags) =>\n set({\n freeModels: flags.freeModels,\n defaultModel: flags.defaultModel,\n defaultModelReady: true,\n }),\n markDefaultModelReady: () => set({ defaultModelReady: true }),\n resetFlags: () =>\n set({\n freeModels: EMPTY_FREE_MODELS,\n defaultModel: null,\n defaultModelReady: false,\n }),\n}));\n"],"mappings":"sGAiCA,IAAM,EAAkC,IAAI,IAE/B,EAAqB,EAAA,OAAwB,EAAG,IAAS,CACpE,WAAY,EACZ,aAAc,KACd,kBAAmB,GACnB,SAAW,GACT,EAAI,CACF,WAAY,EAAM,WAClB,aAAc,EAAM,aACpB,kBAAmB,EACrB,CAAC,EACH,0BAA6B,EAAI,CAAE,kBAAmB,EAAK,CAAC,EAC5D,eACE,EAAI,CACF,WAAY,EACZ,aAAc,KACd,kBAAmB,EACrB,CAAC,CACL,EAAE"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { FreeModelSet } from "#/utils/format-model-name";
|
|
2
|
+
interface FreeModelsState {
|
|
3
|
+
/**
|
|
4
|
+
* DB-driven set of free ``provider/model`` ids (the same channel that carries
|
|
5
|
+
* `verified`). Empty on backends without free metadata (e.g. the local
|
|
6
|
+
* agent-server), so consumers uniformly treat "not in set" as paid.
|
|
7
|
+
*/
|
|
8
|
+
freeModels: FreeModelSet;
|
|
9
|
+
/** DB-driven default OpenHands model id (``openhands/<model>``), or null. */
|
|
10
|
+
defaultModel: string | null;
|
|
11
|
+
/** True once the backend flags query has settled at least once. */
|
|
12
|
+
defaultModelReady: boolean;
|
|
13
|
+
}
|
|
14
|
+
interface FreeModelsActions {
|
|
15
|
+
/**
|
|
16
|
+
* Replaces the DB-driven flags. Called once by the app-level hydrator
|
|
17
|
+
* ({@link useHydrateFreeModels}) after the backend model list is fetched, so
|
|
18
|
+
* leaf components can read the flags synchronously via zustand selectors
|
|
19
|
+
* without needing a QueryClientProvider in scope.
|
|
20
|
+
*/
|
|
21
|
+
setFlags: (flags: {
|
|
22
|
+
freeModels: FreeModelSet;
|
|
23
|
+
defaultModel: string | null;
|
|
24
|
+
}) => void;
|
|
25
|
+
markDefaultModelReady: () => void;
|
|
26
|
+
resetFlags: () => void;
|
|
27
|
+
}
|
|
28
|
+
type FreeModelsStore = FreeModelsState & FreeModelsActions;
|
|
29
|
+
export declare const useFreeModelsStore: import("zustand").UseBoundStore<import("zustand").StoreApi<FreeModelsStore>>;
|
|
30
|
+
export {};
|