@openhands/agent-canvas 1.12.0 → 1.14.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-BkL3HWa3.js → acp-providers-CYy8qA2z.js} +1 -1
- package/build/assets/active-backend-context-BZDG15C0.js +2 -0
- package/build/assets/{agent-context-settings-CzWS1DgR.js → agent-context-settings-DGWBBbcp.js} +1 -1
- package/build/assets/agent-profiles-settings-DrkGdf4_.js +1 -0
- package/build/assets/agent-server-conversation-service.api-DK56YPTs.js +86 -0
- package/build/assets/{agent-settings-D2J1dKVd.js → agent-settings-DfcSgkLD.js} +2 -2
- package/build/assets/agent-settings-Lrc5-twS.js +1 -0
- package/build/assets/{alert-banner-lrK-2_0Y.js → alert-banner-BgDHhL7b.js} +1 -1
- package/build/assets/api-error-message-BEIE_yD1.js +1 -0
- package/build/assets/{api-key-entry-screen-D70oJj2c.js → api-key-entry-screen-DaZnOlVo.js} +1 -1
- package/build/assets/{app-settings-D0OKHB3M.js → app-settings-BG5NAUbC.js} +1 -1
- package/build/assets/automation-detail-D4Hs831Z.js +3 -0
- package/build/assets/automation-export-n0X6FB0C.js +2 -0
- package/build/assets/automation-git-sync-CDrm8WV7.js +1 -0
- package/build/assets/automation-setup-route-CZCl4ONs.js +1 -0
- package/build/assets/{automation-templates-D9gs6ihu.js → automation-templates-DFF96AdL.js} +1 -1
- package/build/assets/automations-list-Bl-oGOrV.js +1 -0
- package/build/assets/{back-nav-button-B3pYwmUJ.js → back-nav-button-H_ThtDA0.js} +1 -1
- package/build/assets/{backend-form-modal-HwclKrUS.js → backend-form-modal-CbCemvHt.js} +1 -1
- package/build/assets/backend-not-configured-DP8KLNq_.js +1 -0
- package/build/assets/{backend-synced-settings-badge-YI3k09Wr.js → backend-synced-settings-badge-BBASWqsb.js} +1 -1
- package/build/assets/{badge-Dpn3-LTV.js → badge-B-51h-SW.js} +1 -1
- package/build/assets/{base-modal-3NmIOKDm.js → base-modal-BbjycA8X.js} +1 -1
- package/build/assets/bot-CGPCg03p.js +1 -0
- package/build/assets/{brand-button-CJcwjnfb.js → brand-button-Blxv5nww.js} +1 -1
- package/build/assets/browser-CuW0nWvh.js +7 -0
- package/build/assets/{browser-tab-4CPdj3J3.js → browser-tab-D5G0ORwt.js} +1 -1
- package/build/assets/{chat-send-button-B8n6-DQA.js → chat-send-button-BD2tii1r.js} +1 -1
- package/build/assets/check-DSuS-lyr.js +1 -0
- package/build/assets/chevron-down-CgGcmtE2.js +1 -0
- package/build/assets/circle-check-CG5-NPw7.js +1 -0
- package/build/assets/{circle-plus-check-toggle-BVzv5EkZ.js → circle-plus-check-toggle-ASbpB8vN.js} +1 -1
- package/build/assets/cloud-funnel-analytics-GlCUG0gk.js +1 -0
- package/build/assets/cog-CZiR80uT.js +1 -0
- package/build/assets/{combobox-caret-BlmRwiM8.js → combobox-caret-DvpEsh2O.js} +1 -1
- package/build/assets/{command-menu-BKOLj-TC.js → command-menu-DwUQzjYP.js} +1 -1
- package/build/assets/{condenser-settings-DLQogFnB.js → condenser-settings-BptcoiLA.js} +1 -1
- package/build/assets/{confirmation-modal-DAH0XtOp.js → confirmation-modal-CiEwxZAA.js} +1 -1
- package/build/assets/{context-menu-list-item-BQhmFVEK.js → context-menu-list-item-CdcamfM1.js} +1 -1
- package/build/assets/conversation-DREHj4nT.js +1 -0
- package/build/assets/conversation-DotRfiDz.js +90 -0
- package/build/assets/conversation-panel-DREHj4nT.js +1 -0
- package/build/assets/conversation-state-store-DMLtlHbE.js +1 -0
- package/build/assets/conversation-store-Blc5xysY.js +6 -0
- package/build/assets/{conversation-tab-empty-state-C9sfDOlt.js → conversation-tab-empty-state-D-puECpY.js} +1 -1
- package/build/assets/{copy-to-clipboard-button-DatoElj8.js → copy-to-clipboard-button-BGxcUbgy.js} +1 -1
- package/build/assets/{device-verify-BIjXeW9N.js → device-verify-CZJfWaJf.js} +1 -1
- package/build/assets/{dropdown-classes-zFW7qPSK.js → dropdown-classes-tLhpwtxS.js} +1 -1
- package/build/assets/{entry.client-EBn3ZtNP.js → entry.client-D8GnI6GZ.js} +2 -2
- package/build/assets/{enum-filter-dropdown-CctILg5t.js → enum-filter-dropdown-Fk8k60nk.js} +1 -1
- package/build/assets/{environment-switch-overlay-Cvmo6clk.js → environment-switch-overlay-DeztVYuL.js} +1 -1
- package/build/assets/{extensions-hub-BZ3HYztk.js → extensions-hub-Cd6GCYzq.js} +1 -1
- package/build/assets/{extensions-navigation-Bnx32WAb.js → extensions-navigation-C4sgZg-y.js} +1 -1
- package/build/assets/external-link-C0UpBgsE.js +1 -0
- package/build/assets/{file-text-RecuaId_.js → file-text-C6WYtNdV.js} +1 -1
- package/build/assets/files-tab-BW_qzyAm.js +1 -0
- package/build/assets/{form-control-classes-DLN3Qgub.js → form-control-classes-CGXBLcn1.js} +1 -1
- package/build/assets/format-model-name-BNPKVsIq.js +1 -0
- package/build/assets/format-relative-time-ZhQD4rsl.js +1 -0
- package/build/assets/git-provider-icon-CaQ1yLPi.js +1 -0
- package/build/assets/{git-repo-dropdown-B5VnMftu.js → git-repo-dropdown-CgXR6M_E.js} +1 -1
- package/build/assets/git-repo-dropdown-D2Uei3CO.js +1 -0
- package/build/assets/{highlighted-source-view-CgJfD5VT.js → highlighted-source-view-C_YOp8Fo.js} +1 -1
- package/build/assets/home-DNzzJcMP.js +1 -0
- package/build/assets/home-aCos-5vc.js +1 -0
- package/build/assets/{home-store-Cubdq0uP.js → home-store-DgzViC3f.js} +1 -1
- package/build/assets/index-home-DNzzJcMP.js +1 -0
- package/build/assets/info-CLoC1LRo.js +1 -0
- package/build/assets/install-server-modal-D7zIqNKz.js +1 -0
- package/build/assets/kebab-menu-item-content-DERMdnDv.js +1 -0
- package/build/assets/{launch-c4GEP8oo.js → launch-5PjKeLak.js} +1 -1
- package/build/assets/{list-todo-CheUtB7F.js → list-todo-BF049YaY.js} +1 -1
- package/build/assets/llm-not-configured-banner-BK9z5eS0.js +27 -0
- package/build/assets/llm-settings-BLAMK2tR.js +1 -0
- package/build/assets/llm-settings-BWsbarGM.js +1 -0
- package/build/assets/llm-subscription-service-SfnEV9Uc.js +1 -0
- package/build/assets/loader-circle-D7IagAyF.js +1 -0
- package/build/assets/{loading-spinner-CN3riY7k.js → loading-spinner-DBgXgra0.js} +1 -1
- package/build/assets/{manage-backends-modal-DTCME_Pu.js → manage-backends-modal-BTqNPhzc.js} +1 -1
- package/build/assets/manifest-abebca3c.js +1 -0
- package/build/assets/manifest-subpage-layout-Rn-glaxV.js +1 -0
- package/build/assets/{map-provider-7Bp2aih5.js → map-provider-BK4HnqYz.js} +1 -1
- package/build/assets/markdown-renderer-Cp6DlHQN.js +8 -0
- package/build/assets/{mcp-Da7wFU7A.js → mcp-BC-Ixn4T.js} +2 -2
- package/build/assets/mcp-marketplace-utils-BJWJgbB6.js +1 -0
- package/build/assets/messages-CzFKrzPG.js +40 -0
- package/build/assets/{modal-body-duRaxj_K.js → modal-body-BdKfD3Hl.js} +1 -1
- package/build/assets/{modal-classes-CLEXO6dj.js → modal-classes-D5_b5vMi.js} +1 -1
- package/build/assets/{modal-close-button-D0aT02hs.js → modal-close-button-objukxk_.js} +1 -1
- package/build/assets/{mouse-pointer-click-Px-dXWcS.js → mouse-pointer-click-C_gXyLyD.js} +1 -1
- package/build/assets/{npm-Cswluf6-.js → npm-CHVHV1MC.js} +1 -1
- package/build/assets/{onboarding-BKbTYlW1.js → onboarding-Diw0V51A.js} +1 -1
- package/build/assets/onboarding-modal-Da4yHzsA.js +1 -0
- package/build/assets/{organization-service.api-DK8csGvK.js → organization-service.api-BztSy69u.js} +1 -1
- package/build/assets/parse-git-remote-url-BkXN9jzl.js +1 -0
- package/build/assets/pencil-49avMHlD.js +1 -0
- package/build/assets/{planner-tab-D-mZ1I7n.js → planner-tab-CJiSpNax.js} +1 -1
- package/build/assets/{plugins-management-service-CywqyfLK.js → plugins-management-service-lHdNKWNU.js} +1 -1
- package/build/assets/plus-C0BagBpV.js +1 -0
- package/build/assets/profiles-service.api-BLr7FXec.js +1 -0
- package/build/assets/providers-CWXnb7S3.js +1 -0
- package/build/assets/{proxy-b4aqL4SX.js → proxy-DYDXxtje.js} +1 -1
- package/build/assets/{puzzle-B3v361yY.js → puzzle-Bt2B1rzf.js} +1 -1
- package/build/assets/recommended-automations-launcher-CcFMfJRR.js +1 -0
- package/build/assets/refresh-cw-nmcesifB.js +1 -0
- package/build/assets/root-CT4t7apy.css +1 -0
- package/build/assets/root-DnRgLKpU.js +2 -0
- package/build/assets/root-layout-2L9tr-BN.js +2 -0
- package/build/assets/{schema-field-Z-rMg9ti.js → schema-field-C59lVZTA.js} +1 -1
- package/build/assets/{sdk-section-page-m_cjygxR.js → sdk-section-page-BbBEQQjq.js} +1 -1
- package/build/assets/search-CYSDBczG.js +1 -0
- package/build/assets/secrets-service-BtsgYSlj.js +1 -0
- package/build/assets/secrets-settings-DJ0OKa4_.js +1 -0
- package/build/assets/{segmented-toggle-SmvsR3jW.js → segmented-toggle-DiVfTZuN.js} +1 -1
- package/build/assets/{settings-CZPGNens.js → settings-CDqL_Uqh.js} +1 -1
- package/build/assets/{settings-CWFxymAf.js → settings-DcNPxz0v.js} +1 -1
- package/build/assets/{settings-dropdown-input-TWIeiG02.js → settings-dropdown-input-Ba1UN5Du.js} +1 -1
- package/build/assets/{settings-index-Dtlegd6s.js → settings-index-Cz2cKt2K.js} +1 -1
- package/build/assets/{settings-input-D61Vzp9e.js → settings-input-CWUEHHvS.js} +1 -1
- package/build/assets/{settings-list-classes-sE0ASr1s.js → settings-list-classes-DdcLXDGn.js} +1 -1
- package/build/assets/{settings-modal-CalzJP2l.js → settings-modal-nEEK1Kh1.js} +1 -1
- package/build/assets/{settings-service.api-DfPYaxZJ.js → settings-service.api-3yAUFcaP.js} +1 -1
- package/build/assets/{settings-switch-Drt-rF5s.js → settings-switch-Dk9hChx1.js} +1 -1
- package/build/assets/{settings-utils-gw2ppAvw.js → settings-utils-CxjtCSB3.js} +1 -1
- package/build/assets/shared-conversation-DbAcrx3s.js +1 -0
- package/build/assets/shield-check-CiOTXxV2.js +1 -0
- package/build/assets/{sidebar-layout-Dxg6zc2K.js → sidebar-layout-lrfPooIB.js} +1 -1
- package/build/assets/{sidebar-mobile-menu-toggle-C6HpQ55l.js → sidebar-mobile-menu-toggle-KERXfNu1.js} +1 -1
- package/build/assets/{sidebar-nav-link-CxLoG-dG.js → sidebar-nav-link-B8lFD6Cb.js} +1 -1
- package/build/assets/{sidebar-store-BJeYY-E9.js → sidebar-store-u6pUpxJ7.js} +1 -1
- package/build/assets/{skill-card-pill-row-B_BYBONu.js → skill-card-pill-row-dGIUzr_b.js} +1 -1
- package/build/assets/{skill-icon-badge-CN41Hy9l.js → skill-icon-badge-kkOWZ89w.js} +1 -1
- package/build/assets/{skill-scope-Dt1V5X2p.js → skill-scope-DWN1PBPH.js} +1 -1
- package/build/assets/{skills-plugins-B-H0cCOP.js → skills-plugins-DFjH2Nq6.js} +1 -1
- package/build/assets/{skills-settings-DthdIDUb.js → skills-settings-DIHpl3ol.js} +2 -2
- package/build/assets/{sparkles-g7y3r-Ut.js → sparkles-ntyMLnbj.js} +1 -1
- package/build/assets/{styled-tooltip-C5C07RQC.js → styled-tooltip-B6JXcsmL.js} +1 -1
- package/build/assets/{task-list-tab-BTde81Iu.js → task-list-tab-aEJzEcHD.js} +1 -1
- package/build/assets/{terminal-DRrJo-cR.js → terminal-Dch7Ty5K.js} +1 -1
- package/build/assets/{toggle-switch-CIioisto.js → toggle-switch-B2MLKsgt.js} +1 -1
- package/build/assets/trash-2-yZnDM4Ji.js +1 -0
- package/build/assets/{typography-D9tiHct7.js → typography-DB5HoCk0.js} +1 -1
- package/build/assets/usage-tab-DrEtBmBT.js +1 -0
- package/build/assets/use-acp-credential-form-c8KXAa8A.js +1 -0
- package/build/assets/{use-activate-agent-profile-DrPzIKJF.js → use-activate-agent-profile-B0p34N3q.js} +1 -1
- package/build/assets/use-agent-profiles-CPIc6wLH.js +1 -0
- package/build/assets/{use-can-manage-org-profiles-BzE28H3x.js → use-can-manage-org-profiles-Dz_8Eqkv.js} +1 -1
- package/build/assets/{use-cloud-current-user-id-U6HPjy50.js → use-cloud-current-user-id-DvUVqCle.js} +1 -1
- package/build/assets/use-config-C3PO4TBw.js +1 -0
- package/build/assets/use-create-conversation-DVrA_uLD.js +1 -0
- package/build/assets/use-create-secret-DbBIpaCR.js +1 -0
- package/build/assets/use-get-secrets-6PBitf54.js +1 -0
- package/build/assets/use-has-permission-CQ31Cl8j.js +1 -0
- package/build/assets/use-is-authed-2UrDIziV.js +1 -0
- package/build/assets/use-is-creating-conversation-BvYpmb3v.js +1 -0
- package/build/assets/{use-launch-skill-in-chat-BcKNjxxd.js → use-launch-skill-in-chat-COnDpxCQ.js} +1 -1
- package/build/assets/use-llm-profiles-diZS4FiN.js +1 -0
- package/build/assets/use-manifest-capabilities-HIWCtIUm.js +1 -0
- package/build/assets/{use-onboarding-completion-6kWOW3ul.js → use-onboarding-completion-Bs8PcXik.js} +1 -1
- package/build/assets/{use-plugins-marketplace-CqkR8kLE.js → use-plugins-marketplace-BCuNLFsr.js} +1 -1
- package/build/assets/use-save-agent-profile-BaMNSpBV.js +1 -0
- package/build/assets/{use-save-settings-DIEurJ3D.js → use-save-settings-BahvC2Gw.js} +1 -1
- package/build/assets/{use-settings-BmLzQjnC.js → use-settings-C6ZxpBDX.js} +1 -1
- package/build/assets/{use-settings-nav-items-DV9qgeu7.js → use-settings-nav-items-Bqn69Ggw.js} +2 -2
- package/build/assets/use-tracking-Bhu7gk2y.js +3 -0
- package/build/assets/{use-user-conversation-Dt-W6uNw.js → use-user-conversation-BkNXpXrd.js} +1 -1
- package/build/assets/{useInfiniteQuery-DbCv0Jzd.js → useInfiniteQuery-c_OmS3lK.js} +1 -1
- package/build/assets/{useMutation-ChpkYxI5.js → useMutation-6ZsQCqAn.js} +1 -1
- package/build/assets/{useQueries-Cjv3E8_1.js → useQueries-xDrGlTO_.js} +1 -1
- package/build/assets/{useQuery-BCnzy4LX.js → useQuery-Bs5NFz2s.js} +1 -1
- package/build/assets/utils-DUD5ScdA.js +1 -0
- package/build/assets/{vendor~browser-DJ1pl_wn.js → vendor~browser-B-fae1JU.js} +14 -14
- package/build/assets/{vendor~entry.client-CgNUwtQL.js → vendor~entry.client-BFE7Llz9.js} +1 -1
- package/build/assets/{vendor~entry.client-zSIea5EO.js → vendor~entry.client-BaKt_PIp.js} +1 -1
- package/build/assets/{vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~kv3pap4j-oGvLV0dO.js → vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~kepq2zme-D87mAf6K.js} +3 -3
- package/build/assets/{vendor~files-tab-C87pjSpi.js → vendor~files-tab-B6POTS66.js} +1 -1
- package/build/assets/vendor~index-home~home~conversation-panel~conversation-53Q_U6uP.js +13 -0
- package/build/assets/vendor~root-layout-DeQACFVA.js +1 -0
- package/build/assets/{vendor~root-layout~conversation-panel~conversation-DEzjR4K7.js → vendor~root-layout~conversation-panel~conversation-bv7ooVgH.js} +1 -1
- package/build/assets/{vendor~root-layout~conversation-panel~conversation~skills-settings~automations-list~shared-~bovqqk8e-U-xdsAEx.js → vendor~root-layout~conversation-panel~conversation~skills-settings~automations-list~shared-~bovqqk8e-e8pX05xf.js} +1 -1
- package/build/assets/{vendor~root-layout~index-home~home~conversation-panel~conversation~shared-conversation-CQR5Sa0H.js → vendor~root-layout~index-home~home~conversation-panel~conversation~shared-conversation-BvS6PCK2.js} +1 -1
- package/build/assets/{vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~hjcjabwg-CuQhkiS7.js → vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~hjcjabwg-DOPLJMH9.js} +2 -2
- package/build/assets/{vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~gxu4j2ea-Cwhh3zLe.js → vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~iw7io29p-Dz8NQve5.js} +1 -1
- package/build/assets/{verification-settings-oi54wEc1.js → verification-settings-COueVXmM.js} +1 -1
- package/build/assets/{wrench-B1_H-tL1.js → wrench-C95ujnYo.js} +1 -1
- package/build/assets/x-86ZCfxKY.js +1 -0
- package/build/assets/zap-DRa-r-Tf.js +1 -0
- package/build/index.html +4 -4
- package/build/locales/ar/openhands.json +88 -3
- package/build/locales/ca/openhands.json +88 -3
- package/build/locales/de/openhands.json +88 -3
- package/build/locales/en/openhands.json +88 -3
- package/build/locales/es/openhands.json +88 -3
- package/build/locales/fr/openhands.json +88 -3
- package/build/locales/it/openhands.json +88 -3
- package/build/locales/ja/openhands.json +88 -3
- package/build/locales/ko-KR/openhands.json +88 -3
- package/build/locales/no/openhands.json +88 -3
- package/build/locales/pt/openhands.json +88 -3
- package/build/locales/tr/openhands.json +88 -3
- package/build/locales/uk/openhands.json +88 -3
- package/build/locales/zh-CN/openhands.json +88 -3
- package/build/locales/zh-TW/openhands.json +88 -3
- package/config/defaults.json +3 -3
- package/dist/api/agent-server-compatibility.cjs +1 -1
- package/dist/api/agent-server-compatibility.cjs.map +1 -1
- package/dist/api/agent-server-compatibility.js +1 -1
- package/dist/api/agent-server-compatibility.js.map +1 -1
- package/dist/api/automation-service/automation-service.api.cjs +1 -1
- package/dist/api/automation-service/automation-service.api.cjs.map +1 -1
- package/dist/api/automation-service/automation-service.api.d.ts +10 -0
- package/dist/api/automation-service/automation-service.api.js +42 -0
- package/dist/api/automation-service/automation-service.api.js.map +1 -1
- package/dist/api/cloud/conversation-service.api.cjs +1 -1
- package/dist/api/cloud/conversation-service.api.cjs.map +1 -1
- package/dist/api/cloud/conversation-service.api.d.ts +9 -0
- package/dist/api/cloud/conversation-service.api.js +11 -1
- package/dist/api/cloud/conversation-service.api.js.map +1 -1
- package/dist/api/conversation-service/agent-server-conversation-service.api.cjs +1 -1
- package/dist/api/conversation-service/agent-server-conversation-service.api.cjs.map +1 -1
- package/dist/api/conversation-service/agent-server-conversation-service.api.d.ts +24 -1
- package/dist/api/conversation-service/agent-server-conversation-service.api.js +116 -97
- package/dist/api/conversation-service/agent-server-conversation-service.api.js.map +1 -1
- package/dist/api/llm-balance-service.cjs +2 -0
- package/dist/api/llm-balance-service.cjs.map +1 -0
- package/dist/api/llm-balance-service.d.ts +33 -0
- package/dist/api/llm-balance-service.js +53 -0
- package/dist/api/llm-balance-service.js.map +1 -0
- package/dist/api/llm-subscription-service.cjs +1 -1
- package/dist/api/llm-subscription-service.cjs.map +1 -1
- package/dist/api/llm-subscription-service.js +42 -34
- package/dist/api/llm-subscription-service.js.map +1 -1
- package/dist/api/profiles-service/profiles-service.api.cjs +1 -1
- package/dist/api/profiles-service/profiles-service.api.cjs.map +1 -1
- package/dist/api/profiles-service/profiles-service.api.d.ts +15 -2
- package/dist/api/profiles-service/profiles-service.api.js +25 -2
- package/dist/api/profiles-service/profiles-service.api.js.map +1 -1
- package/dist/api/secrets-service.cjs +1 -1
- package/dist/api/secrets-service.cjs.map +1 -1
- package/dist/api/secrets-service.d.ts +5 -0
- package/dist/api/secrets-service.js +12 -6
- package/dist/api/secrets-service.js.map +1 -1
- package/dist/components/conversation/index.cjs +1 -1
- package/dist/components/conversation/index.d.ts +0 -1
- package/dist/components/conversation/index.js +0 -1
- package/dist/components/conversation-events/chat/event-content-helpers/get-event-content.cjs +1 -1
- package/dist/components/conversation-events/chat/event-content-helpers/get-event-content.cjs.map +1 -1
- package/dist/components/conversation-events/chat/event-content-helpers/get-event-content.js +1 -1
- package/dist/components/conversation-events/chat/event-content-helpers/get-event-content.js.map +1 -1
- package/dist/components/conversation-events/chat/event-message-components/generic-event-message-wrapper.cjs +1 -1
- package/dist/components/conversation-events/chat/event-message-components/generic-event-message-wrapper.cjs.map +1 -1
- package/dist/components/conversation-events/chat/event-message-components/generic-event-message-wrapper.js +24 -23
- package/dist/components/conversation-events/chat/event-message-components/generic-event-message-wrapper.js.map +1 -1
- package/dist/components/conversation-events/chat/event-message-components/index.d.ts +0 -1
- package/dist/components/conversation-events/chat/group-events.cjs +1 -1
- package/dist/components/conversation-events/chat/group-events.cjs.map +1 -1
- package/dist/components/conversation-events/chat/group-events.d.ts +3 -3
- package/dist/components/conversation-events/chat/group-events.js +27 -26
- package/dist/components/conversation-events/chat/group-events.js.map +1 -1
- package/dist/components/features/automations/git-sync/git-sync-activity-row.d.ts +15 -0
- package/dist/components/features/automations/git-sync/git-sync-config-form.d.ts +13 -0
- package/dist/components/features/automations/git-sync/git-sync-error-banner.d.ts +6 -0
- package/dist/components/features/automations/git-sync/git-sync-not-local-state.d.ts +1 -0
- package/dist/components/features/automations/git-sync/git-sync-overview-section.d.ts +12 -0
- package/dist/components/features/automations/git-sync/git-sync-skeleton.d.ts +1 -0
- package/dist/components/features/automations/git-sync/git-sync-status-pill.d.ts +7 -0
- package/dist/components/features/automations/git-sync/git-sync-unsupported-state.d.ts +7 -0
- package/dist/components/features/automations/recommended-automations-section.d.ts +7 -0
- package/dist/components/features/automations/responder-deployment-modal.d.ts +2 -1
- package/dist/components/features/chat/chat-interface.cjs +2 -2
- package/dist/components/features/chat/chat-interface.cjs.map +1 -1
- package/dist/components/features/chat/chat-interface.js +177 -176
- package/dist/components/features/chat/chat-interface.js.map +1 -1
- package/dist/components/features/chat/components/chat-input-actions.cjs +1 -1
- package/dist/components/features/chat/components/chat-input-actions.cjs.map +1 -1
- package/dist/components/features/chat/components/chat-input-actions.js +123 -118
- package/dist/components/features/chat/components/chat-input-actions.js.map +1 -1
- package/dist/components/features/chat/components/chat-input-grip.cjs +1 -1
- package/dist/components/features/chat/components/chat-input-grip.cjs.map +1 -1
- package/dist/components/features/chat/components/chat-input-grip.d.ts +2 -1
- package/dist/components/features/chat/components/chat-input-grip.js +7 -7
- package/dist/components/features/chat/components/chat-input-grip.js.map +1 -1
- package/dist/components/features/chat/components/context-window-meter.cjs +2 -0
- package/dist/components/features/chat/components/context-window-meter.cjs.map +1 -0
- package/dist/components/features/chat/components/context-window-meter.d.ts +2 -0
- package/dist/components/features/chat/components/context-window-meter.js +131 -0
- package/dist/components/features/chat/components/context-window-meter.js.map +1 -0
- package/dist/components/features/chat/components/context-window-ring.cjs +2 -0
- package/dist/components/features/chat/components/context-window-ring.cjs.map +1 -0
- package/dist/components/features/chat/components/context-window-ring.d.ts +26 -0
- package/dist/components/features/chat/components/context-window-ring.js +45 -0
- package/dist/components/features/chat/components/context-window-ring.js.map +1 -0
- package/dist/components/features/chat/custom-chat-input.cjs +1 -1
- package/dist/components/features/chat/custom-chat-input.cjs.map +1 -1
- package/dist/components/features/chat/custom-chat-input.js +68 -67
- package/dist/components/features/chat/custom-chat-input.js.map +1 -1
- package/dist/components/features/chat/error-message-banner.cjs +1 -1
- package/dist/components/features/chat/error-message-banner.cjs.map +1 -1
- package/dist/components/features/chat/error-message-banner.d.ts +3 -1
- package/dist/components/features/chat/error-message-banner.js +64 -58
- package/dist/components/features/chat/error-message-banner.js.map +1 -1
- package/dist/components/features/chat/path-component.cjs +1 -1
- package/dist/components/features/chat/path-component.cjs.map +1 -1
- package/dist/components/features/chat/path-component.js +9 -6
- package/dist/components/features/chat/path-component.js.map +1 -1
- package/dist/components/features/chat/plan-preview.cjs +1 -1
- package/dist/components/features/chat/plan-preview.js +4 -4
- package/dist/components/features/chat/tool-visualizers/file-editor/file-editor.cjs +1 -1
- package/dist/components/features/chat/tool-visualizers/file-editor/file-editor.cjs.map +1 -1
- package/dist/components/features/chat/tool-visualizers/file-editor/file-editor.d.ts +0 -8
- package/dist/components/features/chat/tool-visualizers/file-editor/file-editor.js +92 -50
- package/dist/components/features/chat/tool-visualizers/file-editor/file-editor.js.map +1 -1
- package/dist/components/features/chat/tool-visualizers/primitives/file-path-chip.cjs +1 -1
- package/dist/components/features/chat/tool-visualizers/primitives/file-path-chip.cjs.map +1 -1
- package/dist/components/features/chat/tool-visualizers/primitives/file-path-chip.d.ts +7 -2
- package/dist/components/features/chat/tool-visualizers/primitives/file-path-chip.js +15 -9
- package/dist/components/features/chat/tool-visualizers/primitives/file-path-chip.js.map +1 -1
- package/dist/components/features/chat/tool-visualizers/primitives/markdown-file-preview.cjs +2 -0
- package/dist/components/features/chat/tool-visualizers/primitives/markdown-file-preview.cjs.map +1 -0
- package/dist/components/features/chat/tool-visualizers/primitives/markdown-file-preview.d.ts +20 -0
- package/dist/components/features/chat/tool-visualizers/primitives/markdown-file-preview.js +76 -0
- package/dist/components/features/chat/tool-visualizers/primitives/markdown-file-preview.js.map +1 -0
- package/dist/components/features/controls/server-status-context-menu.cjs +1 -1
- package/dist/components/features/controls/server-status-context-menu.cjs.map +1 -1
- package/dist/components/features/controls/server-status-context-menu.d.ts +5 -3
- package/dist/components/features/controls/server-status-context-menu.js +8 -8
- package/dist/components/features/controls/server-status-context-menu.js.map +1 -1
- package/dist/components/features/conversation/conversation-name-context-menu.cjs +1 -1
- package/dist/components/features/conversation/conversation-name-context-menu.cjs.map +1 -1
- package/dist/components/features/conversation/conversation-name-context-menu.js +58 -61
- package/dist/components/features/conversation/conversation-name-context-menu.js.map +1 -1
- package/dist/components/features/conversation/conversation-name-with-status.cjs +1 -1
- package/dist/components/features/conversation/conversation-name-with-status.cjs.map +1 -1
- package/dist/components/features/conversation/conversation-name-with-status.js +74 -46
- package/dist/components/features/conversation/conversation-name-with-status.js.map +1 -1
- package/dist/components/features/conversation/conversation-name.cjs +1 -1
- package/dist/components/features/conversation/conversation-name.cjs.map +1 -1
- package/dist/components/features/conversation/conversation-name.js +69 -71
- package/dist/components/features/conversation/conversation-name.js.map +1 -1
- package/dist/components/features/conversation/conversation-tabs/conversation-tab-content/conversation-tab-content.cjs +1 -1
- package/dist/components/features/conversation/conversation-tabs/conversation-tab-content/conversation-tab-content.cjs.map +1 -1
- package/dist/components/features/conversation/conversation-tabs/conversation-tab-content/conversation-tab-content.js +7 -6
- package/dist/components/features/conversation/conversation-tabs/conversation-tab-content/conversation-tab-content.js.map +1 -1
- package/dist/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.cjs +1 -1
- package/dist/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.cjs.map +1 -1
- package/dist/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.js +92 -86
- package/dist/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.js.map +1 -1
- package/dist/components/features/conversation/conversation-tabs/conversation-tabs.cjs +1 -1
- package/dist/components/features/conversation/conversation-tabs/conversation-tabs.cjs.map +1 -1
- package/dist/components/features/conversation/conversation-tabs/conversation-tabs.js +81 -71
- package/dist/components/features/conversation/conversation-tabs/conversation-tabs.js.map +1 -1
- package/dist/components/features/conversation/metrics-modal/cost-section.cjs +1 -1
- package/dist/components/features/conversation/metrics-modal/cost-section.cjs.map +1 -1
- package/dist/components/features/conversation/metrics-modal/cost-section.js +6 -6
- package/dist/components/features/conversation/metrics-modal/cost-section.js.map +1 -1
- package/dist/components/features/conversation/metrics-modal/metric-row.cjs +1 -1
- package/dist/components/features/conversation/metrics-modal/metric-row.cjs.map +1 -1
- package/dist/components/features/conversation/metrics-modal/metric-row.d.ts +2 -1
- package/dist/components/features/conversation/metrics-modal/metric-row.js +10 -9
- package/dist/components/features/conversation/metrics-modal/metric-row.js.map +1 -1
- package/dist/components/features/conversation/metrics-modal/usage-section.cjs +1 -1
- package/dist/components/features/conversation/metrics-modal/usage-section.cjs.map +1 -1
- package/dist/components/features/conversation/metrics-modal/usage-section.js +2 -1
- package/dist/components/features/conversation/metrics-modal/usage-section.js.map +1 -1
- package/dist/components/features/conversation/usage-panel/compact-context-button.cjs +2 -0
- package/dist/components/features/conversation/usage-panel/compact-context-button.cjs.map +1 -0
- package/dist/components/features/conversation/usage-panel/compact-context-button.d.ts +16 -0
- package/dist/components/features/conversation/usage-panel/compact-context-button.js +59 -0
- package/dist/components/features/conversation/usage-panel/compact-context-button.js.map +1 -0
- package/dist/components/features/conversation/usage-panel/context-meter.cjs +2 -0
- package/dist/components/features/conversation/usage-panel/context-meter.cjs.map +1 -0
- package/dist/components/features/conversation/usage-panel/context-meter.d.ts +19 -0
- package/dist/components/features/conversation/usage-panel/context-meter.js +46 -0
- package/dist/components/features/conversation/usage-panel/context-meter.js.map +1 -0
- package/dist/components/features/conversation/usage-panel/provider-balance-card.cjs +2 -0
- package/dist/components/features/conversation/usage-panel/provider-balance-card.cjs.map +1 -0
- package/dist/components/features/conversation/usage-panel/provider-balance-card.d.ts +7 -0
- package/dist/components/features/conversation/usage-panel/provider-balance-card.js +57 -0
- package/dist/components/features/conversation/usage-panel/provider-balance-card.js.map +1 -0
- package/dist/components/features/conversation/usage-panel/usage-panel.cjs +2 -0
- package/dist/components/features/conversation/usage-panel/usage-panel.cjs.map +1 -0
- package/dist/components/features/conversation/usage-panel/usage-panel.d.ts +9 -0
- package/dist/components/features/conversation/usage-panel/usage-panel.js +68 -0
- package/dist/components/features/conversation/usage-panel/usage-panel.js.map +1 -0
- 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.js +10 -13
- package/dist/components/features/conversation-panel/budget-display.js.map +1 -1
- package/dist/components/features/conversation-panel/budget-progress-bar.cjs +1 -1
- package/dist/components/features/conversation-panel/budget-progress-bar.cjs.map +1 -1
- package/dist/components/features/conversation-panel/budget-progress-bar.js +2 -2
- package/dist/components/features/conversation-panel/budget-progress-bar.js.map +1 -1
- package/dist/components/features/conversation-panel/compact-conversation-row.cjs +1 -1
- package/dist/components/features/conversation-panel/compact-conversation-row.js +6 -6
- package/dist/components/features/conversation-panel/confirm-archive-modal.cjs +2 -0
- package/dist/components/features/conversation-panel/confirm-archive-modal.cjs.map +1 -0
- package/dist/components/features/conversation-panel/confirm-archive-modal.d.ts +8 -0
- package/dist/components/features/conversation-panel/confirm-archive-modal.js +48 -0
- package/dist/components/features/conversation-panel/confirm-archive-modal.js.map +1 -0
- package/dist/components/features/conversation-panel/conversation-card/conversation-card-actions.cjs +1 -1
- package/dist/components/features/conversation-panel/conversation-card/conversation-card-actions.cjs.map +1 -1
- package/dist/components/features/conversation-panel/conversation-card/conversation-card-actions.d.ts +3 -1
- package/dist/components/features/conversation-panel/conversation-card/conversation-card-actions.js +39 -34
- package/dist/components/features/conversation-panel/conversation-card/conversation-card-actions.js.map +1 -1
- package/dist/components/features/conversation-panel/conversation-card/conversation-card-context-menu.cjs +1 -1
- package/dist/components/features/conversation-panel/conversation-card/conversation-card-context-menu.cjs.map +1 -1
- package/dist/components/features/conversation-panel/conversation-card/conversation-card-context-menu.d.ts +3 -1
- package/dist/components/features/conversation-panel/conversation-card/conversation-card-context-menu.js +104 -80
- package/dist/components/features/conversation-panel/conversation-card/conversation-card-context-menu.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.d.ts +7 -1
- package/dist/components/features/conversation-panel/conversation-card/conversation-card-footer.js +25 -17
- package/dist/components/features/conversation-panel/conversation-card/conversation-card-footer.js.map +1 -1
- package/dist/components/features/conversation-panel/conversation-card/conversation-card.cjs +1 -1
- package/dist/components/features/conversation-panel/conversation-card/conversation-card.cjs.map +1 -1
- package/dist/components/features/conversation-panel/conversation-card/conversation-card.d.ts +9 -1
- package/dist/components/features/conversation-panel/conversation-card/conversation-card.js +94 -84
- package/dist/components/features/conversation-panel/conversation-card/conversation-card.js.map +1 -1
- package/dist/components/features/conversation-panel/conversation-group-folder-list.cjs +1 -1
- package/dist/components/features/conversation-panel/conversation-group-folder-list.cjs.map +1 -1
- package/dist/components/features/conversation-panel/conversation-group-folder-list.d.ts +2 -1
- package/dist/components/features/conversation-panel/conversation-group-folder-list.js +32 -31
- package/dist/components/features/conversation-panel/conversation-group-folder-list.js.map +1 -1
- package/dist/components/features/conversation-panel/conversation-group-folder-row.cjs +1 -1
- package/dist/components/features/conversation-panel/conversation-group-folder-row.cjs.map +1 -1
- package/dist/components/features/conversation-panel/conversation-group-folder-row.d.ts +2 -1
- package/dist/components/features/conversation-panel/conversation-group-folder-row.js +27 -26
- package/dist/components/features/conversation-panel/conversation-group-folder-row.js.map +1 -1
- package/dist/components/features/conversation-panel/conversation-panel-filter-menu.cjs +1 -1
- package/dist/components/features/conversation-panel/conversation-panel-filter-menu.cjs.map +1 -1
- package/dist/components/features/conversation-panel/conversation-panel-filter-menu.d.ts +3 -1
- package/dist/components/features/conversation-panel/conversation-panel-filter-menu.js +116 -106
- package/dist/components/features/conversation-panel/conversation-panel-filter-menu.js.map +1 -1
- package/dist/components/features/conversation-panel/conversation-panel-list-helpers.cjs +1 -1
- package/dist/components/features/conversation-panel/conversation-panel-list-helpers.cjs.map +1 -1
- package/dist/components/features/conversation-panel/conversation-panel-list-helpers.d.ts +27 -0
- package/dist/components/features/conversation-panel/conversation-panel-list-helpers.js +69 -46
- package/dist/components/features/conversation-panel/conversation-panel-list-helpers.js.map +1 -1
- package/dist/components/features/conversation-panel/conversation-panel.cjs +1 -1
- package/dist/components/features/conversation-panel/conversation-panel.cjs.map +1 -1
- package/dist/components/features/conversation-panel/conversation-panel.js +240 -175
- package/dist/components/features/conversation-panel/conversation-panel.js.map +1 -1
- package/dist/components/features/files-tab/file-content-viewer.cjs +1 -1
- package/dist/components/features/files-tab/file-content-viewer.cjs.map +1 -1
- package/dist/components/features/files-tab/file-content-viewer.js +22 -25
- package/dist/components/features/files-tab/file-content-viewer.js.map +1 -1
- package/dist/components/features/markdown/markdown-table-scroll.cjs +1 -1
- package/dist/components/features/markdown/markdown-table-scroll.cjs.map +1 -1
- package/dist/components/features/markdown/markdown-table-scroll.js +2 -2
- package/dist/components/features/markdown/markdown-table-scroll.js.map +1 -1
- package/dist/components/features/onboarding/steps/setup-llm-step.d.ts +10 -7
- package/dist/components/shared/buttons/conversation-confirmation-buttons.cjs +1 -1
- package/dist/components/shared/buttons/conversation-confirmation-buttons.cjs.map +1 -1
- package/dist/components/shared/buttons/conversation-confirmation-buttons.js +2 -2
- package/dist/components/shared/buttons/conversation-confirmation-buttons.js.map +1 -1
- package/dist/components/shared/modals/confirmation-modals/base-modal.cjs +1 -1
- package/dist/components/shared/modals/confirmation-modals/base-modal.cjs.map +1 -1
- package/dist/components/shared/modals/confirmation-modals/base-modal.js +1 -1
- package/dist/components/shared/modals/confirmation-modals/base-modal.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/llm-balance.cjs +2 -0
- package/dist/constants/llm-balance.cjs.map +1 -0
- package/dist/constants/llm-balance.d.ts +13 -0
- package/dist/constants/llm-balance.js +6 -0
- package/dist/constants/llm-balance.js.map +1 -0
- package/dist/contexts/conversation-websocket-context.cjs +2 -2
- package/dist/contexts/conversation-websocket-context.cjs.map +1 -1
- package/dist/contexts/conversation-websocket-context.js +227 -219
- package/dist/contexts/conversation-websocket-context.js.map +1 -1
- package/dist/hooks/chat/use-grip-resize.cjs +1 -1
- package/dist/hooks/chat/use-grip-resize.cjs.map +1 -1
- package/dist/hooks/chat/use-grip-resize.d.ts +1 -0
- package/dist/hooks/chat/use-grip-resize.js +39 -30
- package/dist/hooks/chat/use-grip-resize.js.map +1 -1
- package/dist/hooks/mutation/use-condense-conversation.cjs +2 -0
- package/dist/hooks/mutation/use-condense-conversation.cjs.map +1 -0
- package/dist/hooks/mutation/use-condense-conversation.d.ts +12 -0
- package/dist/hooks/mutation/use-condense-conversation.js +17 -0
- package/dist/hooks/mutation/use-condense-conversation.js.map +1 -0
- package/dist/hooks/mutation/use-create-conversation.cjs +1 -1
- package/dist/hooks/mutation/use-create-conversation.cjs.map +1 -1
- package/dist/hooks/mutation/use-create-conversation.js +30 -21
- package/dist/hooks/mutation/use-create-conversation.js.map +1 -1
- package/dist/hooks/mutation/use-new-conversation-command.cjs +1 -1
- package/dist/hooks/mutation/use-new-conversation-command.cjs.map +1 -1
- package/dist/hooks/mutation/use-new-conversation-command.js +1 -1
- package/dist/hooks/mutation/use-new-conversation-command.js.map +1 -1
- package/dist/hooks/query/use-commit-changes.cjs +1 -1
- package/dist/hooks/query/use-commit-changes.js +4 -4
- package/dist/hooks/query/use-conversation-metrics.cjs +1 -1
- package/dist/hooks/query/use-conversation-metrics.cjs.map +1 -1
- package/dist/hooks/query/use-conversation-metrics.js +1 -1
- package/dist/hooks/query/use-conversation-metrics.js.map +1 -1
- package/dist/hooks/query/use-git-sync.d.ts +19 -0
- package/dist/hooks/query/use-llm-balance.cjs +2 -0
- package/dist/hooks/query/use-llm-balance.cjs.map +1 -0
- package/dist/hooks/query/use-llm-balance.d.ts +10 -0
- package/dist/hooks/query/use-llm-balance.js +24 -0
- package/dist/hooks/query/use-llm-balance.js.map +1 -0
- 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 +1 -1
- package/dist/hooks/query/use-search-providers.js.map +1 -1
- package/dist/hooks/query/use-task-polling.cjs +1 -1
- package/dist/hooks/query/use-task-polling.cjs.map +1 -1
- package/dist/hooks/query/use-task-polling.js +12 -10
- package/dist/hooks/query/use-task-polling.js.map +1 -1
- package/dist/hooks/query/use-unified-get-git-changes.cjs +1 -1
- package/dist/hooks/query/use-unified-get-git-changes.js +4 -4
- package/dist/hooks/query/use-unified-git-commits.cjs +1 -1
- package/dist/hooks/query/use-unified-git-commits.js +4 -4
- package/dist/hooks/query/use-unified-git-diff.cjs +1 -1
- package/dist/hooks/query/use-unified-git-diff.js +4 -4
- package/dist/hooks/query/use-workspace-files.cjs +1 -1
- package/dist/hooks/query/use-workspace-files.cjs.map +1 -1
- package/dist/hooks/query/use-workspace-files.d.ts +14 -4
- package/dist/hooks/query/use-workspace-files.js +45 -32
- package/dist/hooks/query/use-workspace-files.js.map +1 -1
- package/dist/hooks/use-await-context-compaction.cjs +2 -0
- package/dist/hooks/use-await-context-compaction.cjs.map +1 -0
- package/dist/hooks/use-await-context-compaction.d.ts +38 -0
- package/dist/hooks/use-await-context-compaction.js +61 -0
- package/dist/hooks/use-await-context-compaction.js.map +1 -0
- package/dist/hooks/use-compact-context-action.cjs +2 -0
- package/dist/hooks/use-compact-context-action.cjs.map +1 -0
- package/dist/hooks/use-compact-context-action.d.ts +10 -0
- package/dist/hooks/use-compact-context-action.js +61 -0
- package/dist/hooks/use-compact-context-action.js.map +1 -0
- package/dist/hooks/use-context-window-usage.cjs +2 -0
- package/dist/hooks/use-context-window-usage.cjs.map +1 -0
- package/dist/hooks/use-context-window-usage.d.ts +5 -0
- package/dist/hooks/use-context-window-usage.js +20 -0
- package/dist/hooks/use-context-window-usage.js.map +1 -0
- package/dist/hooks/use-conversation-name-context-menu.cjs +1 -1
- package/dist/hooks/use-conversation-name-context-menu.cjs.map +1 -1
- package/dist/hooks/use-conversation-name-context-menu.d.ts +0 -3
- package/dist/hooks/use-conversation-name-context-menu.js +54 -57
- package/dist/hooks/use-conversation-name-context-menu.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.d.ts +8 -0
- package/dist/hooks/use-drag-resize.js +21 -18
- package/dist/hooks/use-drag-resize.js.map +1 -1
- package/dist/hooks/use-live-conversation-metrics.cjs +2 -0
- package/dist/hooks/use-live-conversation-metrics.cjs.map +1 -0
- package/dist/hooks/use-live-conversation-metrics.d.ts +18 -0
- package/dist/hooks/use-live-conversation-metrics.js +37 -0
- package/dist/hooks/use-live-conversation-metrics.js.map +1 -0
- package/dist/hooks/use-responder-url-secret.d.ts +5 -0
- package/dist/hooks/use-select-conversation-tab.cjs +1 -1
- package/dist/hooks/use-select-conversation-tab.cjs.map +1 -1
- package/dist/hooks/use-select-conversation-tab.js +2 -2
- package/dist/hooks/use-select-conversation-tab.js.map +1 -1
- package/dist/hooks/use-tracking.cjs +1 -1
- package/dist/hooks/use-tracking.cjs.map +1 -1
- package/dist/hooks/use-tracking.d.ts +6 -0
- package/dist/hooks/use-tracking.js +6 -0
- package/dist/hooks/use-tracking.js.map +1 -1
- package/dist/i18n/declaration.cjs +1 -1
- package/dist/i18n/declaration.cjs.map +1 -1
- package/dist/i18n/declaration.d.ts +86 -1
- package/dist/i18n/declaration.js +1 -1
- package/dist/i18n/declaration.js.map +1 -1
- package/dist/i18n/translation.cjs +2 -2
- package/dist/i18n/translation.cjs.map +1 -1
- package/dist/i18n/translation.js +1475 -30
- package/dist/i18n/translation.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +28 -29
- package/dist/lib/index.cjs +1 -1
- package/dist/lib/index.js +0 -1
- package/dist/locales/ar/openhands.json +88 -3
- package/dist/locales/ca/openhands.json +88 -3
- package/dist/locales/de/openhands.json +88 -3
- package/dist/locales/en/openhands.json +88 -3
- package/dist/locales/es/openhands.json +88 -3
- package/dist/locales/fr/openhands.json +88 -3
- package/dist/locales/it/openhands.json +88 -3
- package/dist/locales/ja/openhands.json +88 -3
- package/dist/locales/ko-KR/openhands.json +88 -3
- package/dist/locales/no/openhands.json +88 -3
- package/dist/locales/pt/openhands.json +88 -3
- package/dist/locales/tr/openhands.json +88 -3
- package/dist/locales/uk/openhands.json +88 -3
- package/dist/locales/zh-CN/openhands.json +88 -3
- package/dist/locales/zh-TW/openhands.json +88 -3
- package/dist/node_modules/@microlink/react-json-view/dist/main.cjs +5 -5
- package/dist/node_modules/@microlink/react-json-view/dist/main.cjs.map +1 -1
- package/dist/node_modules/@microlink/react-json-view/dist/main.js +5194 -5187
- package/dist/node_modules/@microlink/react-json-view/dist/main.js.map +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/desktop-client.cjs +2 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/desktop-client.cjs.map +1 -0
- package/dist/node_modules/@openhands/typescript-client/dist/client/desktop-client.js +21 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/desktop-client.js.map +1 -0
- package/dist/node_modules/@openhands/typescript-client/dist/client/hooks-client.cjs +2 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/hooks-client.cjs.map +1 -0
- package/dist/node_modules/@openhands/typescript-client/dist/client/hooks-client.js +22 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/hooks-client.js.map +1 -0
- package/dist/node_modules/@openhands/typescript-client/dist/client/meta-profiles-client.cjs +2 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/meta-profiles-client.cjs.map +1 -0
- package/dist/node_modules/@openhands/typescript-client/dist/client/meta-profiles-client.js +33 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/meta-profiles-client.js.map +1 -0
- package/dist/node_modules/@openhands/typescript-client/dist/client/openhands-client.cjs +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/openhands-client.cjs.map +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/openhands-client.js +56 -22
- package/dist/node_modules/@openhands/typescript-client/dist/client/openhands-client.js.map +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/profiles-client.cjs +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/profiles-client.cjs.map +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/profiles-client.js +3 -0
- package/dist/node_modules/@openhands/typescript-client/dist/client/profiles-client.js.map +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/shared-client.cjs +2 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/shared-client.cjs.map +1 -0
- package/dist/node_modules/@openhands/typescript-client/dist/client/shared-client.js +31 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/shared-client.js.map +1 -0
- package/dist/node_modules/@openhands/typescript-client/dist/client/sub-agents-client.cjs +2 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/sub-agents-client.cjs.map +1 -0
- package/dist/node_modules/@openhands/typescript-client/dist/client/sub-agents-client.js +21 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/sub-agents-client.js.map +1 -0
- package/dist/node_modules/@openhands/typescript-client/dist/client/tool-client.cjs +2 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/tool-client.cjs.map +1 -0
- package/dist/node_modules/@openhands/typescript-client/dist/client/tool-client.js +21 -1
- package/dist/node_modules/@openhands/typescript-client/dist/client/tool-client.js.map +1 -0
- package/dist/node_modules/@openhands/typescript-client/dist/conversation/local-conversation.cjs.map +1 -1
- package/dist/node_modules/@openhands/typescript-client/dist/conversation/local-conversation.js.map +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 +9 -5
- package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.js.map +1 -1
- package/dist/node_modules/i18next-http-backend/esm/index.cjs +1 -1
- package/dist/node_modules/i18next-http-backend/esm/index.cjs.map +1 -1
- package/dist/node_modules/i18next-http-backend/esm/index.js +2 -2
- package/dist/node_modules/i18next-http-backend/esm/index.js.map +1 -1
- package/dist/node_modules/lucide-react/dist/esm/icons/archive-restore.cjs +2 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/archive-restore.cjs.map +1 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/archive-restore.js +31 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/archive-restore.js.map +1 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/archive.cjs +2 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/archive.cjs.map +1 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/archive.js +23 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/archive.js.map +1 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/circle-alert.cjs +2 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/circle-alert.cjs.map +1 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/circle-alert.js +27 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/circle-alert.js.map +1 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/gauge.cjs +2 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/gauge.cjs.map +1 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/gauge.js +12 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/gauge.js.map +1 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/minimize.cjs +2 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/minimize.cjs.map +1 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/minimize.js +23 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/minimize.js.map +1 -0
- package/dist/node_modules/zustand/esm/middleware.cjs +3 -3
- package/dist/node_modules/zustand/esm/middleware.cjs.map +1 -1
- package/dist/node_modules/zustand/esm/middleware.js +33 -31
- package/dist/node_modules/zustand/esm/middleware.js.map +1 -1
- package/dist/package.cjs +1 -1
- package/dist/package.cjs.map +1 -1
- package/dist/package.js +17 -16
- package/dist/package.js.map +1 -1
- package/dist/routes/files-tab.cjs +1 -1
- package/dist/routes/files-tab.js +11 -11
- package/dist/routes/files-tab.js.map +1 -1
- package/dist/routes/usage-tab.cjs +2 -0
- package/dist/routes/usage-tab.cjs.map +1 -0
- package/dist/routes/usage-tab.d.ts +2 -0
- package/dist/routes/usage-tab.js +10 -0
- package/dist/routes/usage-tab.js.map +1 -0
- package/dist/services/child-conversation-launch.cjs +1 -1
- package/dist/services/child-conversation-launch.cjs.map +1 -1
- package/dist/services/child-conversation-launch.js +11 -5
- package/dist/services/child-conversation-launch.js.map +1 -1
- package/dist/services/settings.cjs +1 -1
- package/dist/services/settings.cjs.map +1 -1
- package/dist/services/settings.js +2 -2
- package/dist/services/settings.js.map +1 -1
- package/dist/services/telemetry.cjs +1 -1
- package/dist/services/telemetry.cjs.map +1 -1
- package/dist/services/telemetry.js +47 -51
- package/dist/services/telemetry.js.map +1 -1
- package/dist/stores/archived-conversations-store.cjs +2 -0
- package/dist/stores/archived-conversations-store.cjs.map +1 -0
- package/dist/stores/archived-conversations-store.d.ts +24 -0
- package/dist/stores/archived-conversations-store.js +33 -0
- package/dist/stores/archived-conversations-store.js.map +1 -0
- package/dist/stores/conversation-panel-preferences-store.cjs +1 -1
- package/dist/stores/conversation-panel-preferences-store.cjs.map +1 -1
- package/dist/stores/conversation-panel-preferences-store.d.ts +3 -0
- package/dist/stores/conversation-panel-preferences-store.js +4 -0
- package/dist/stores/conversation-panel-preferences-store.js.map +1 -1
- package/dist/stores/conversation-store.cjs.map +1 -1
- package/dist/stores/conversation-store.d.ts +1 -1
- package/dist/stores/conversation-store.js.map +1 -1
- package/dist/stores/error-message-store.cjs +1 -1
- package/dist/stores/error-message-store.cjs.map +1 -1
- package/dist/stores/error-message-store.d.ts +3 -1
- package/dist/stores/error-message-store.js +5 -3
- package/dist/stores/error-message-store.js.map +1 -1
- package/dist/stores/metrics-store.cjs +1 -1
- package/dist/stores/metrics-store.cjs.map +1 -1
- package/dist/stores/metrics-store.d.ts +1 -0
- package/dist/stores/metrics-store.js +7 -4
- package/dist/stores/metrics-store.js.map +1 -1
- package/dist/types/agent-server/core/events/condensation-event.d.ts +3 -0
- package/dist/types/agent-server/core/events/conversation-state-event.d.ts +4 -6
- package/dist/types/agent-server/type-guards.cjs +1 -1
- package/dist/types/agent-server/type-guards.cjs.map +1 -1
- package/dist/types/agent-server/type-guards.d.ts +5 -0
- package/dist/types/agent-server/type-guards.js +3 -3
- package/dist/types/agent-server/type-guards.js.map +1 -1
- package/dist/types/git-sync.d.ts +51 -0
- package/dist/utils/conversation-local-storage.cjs +1 -1
- package/dist/utils/conversation-local-storage.cjs.map +1 -1
- package/dist/utils/conversation-local-storage.js +2 -1
- package/dist/utils/conversation-local-storage.js.map +1 -1
- package/dist/utils/error-handler.cjs +1 -1
- package/dist/utils/error-handler.cjs.map +1 -1
- package/dist/utils/error-handler.d.ts +3 -2
- package/dist/utils/error-handler.js +18 -5
- package/dist/utils/error-handler.js.map +1 -1
- 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 +1 -0
- package/dist/utils/format-model-name.js +1 -0
- package/dist/utils/format-model-name.js.map +1 -1
- package/dist/utils/format-token-count.cjs +2 -0
- package/dist/utils/format-token-count.cjs.map +1 -0
- package/dist/utils/format-token-count.d.ts +3 -0
- package/dist/utils/format-token-count.js +19 -0
- package/dist/utils/format-token-count.js.map +1 -0
- package/dist/utils/hover-reveal-classes.cjs +2 -0
- package/dist/utils/hover-reveal-classes.cjs.map +1 -0
- package/dist/utils/hover-reveal-classes.d.ts +34 -0
- package/dist/utils/hover-reveal-classes.js +41 -0
- package/dist/utils/hover-reveal-classes.js.map +1 -0
- package/dist/utils/is-markdown-file-path.cjs +2 -0
- package/dist/utils/is-markdown-file-path.cjs.map +1 -0
- package/dist/utils/is-markdown-file-path.d.ts +4 -0
- package/dist/utils/is-markdown-file-path.js +14 -0
- package/dist/utils/is-markdown-file-path.js.map +1 -0
- package/dist/utils/mcp-marketplace-utils.cjs +1 -1
- package/dist/utils/mcp-marketplace-utils.cjs.map +1 -1
- package/dist/utils/mcp-marketplace-utils.d.ts +7 -0
- package/dist/utils/mcp-marketplace-utils.js +19 -16
- package/dist/utils/mcp-marketplace-utils.js.map +1 -1
- package/dist/utils/transcript-export/index.cjs +3 -3
- package/dist/utils/transcript-export/index.cjs.map +1 -1
- package/dist/utils/transcript-export/index.js +12 -12
- package/dist/utils/transcript-export/index.js.map +1 -1
- package/dist/utils/transcript-export/load-complete-events.cjs +1 -1
- package/dist/utils/transcript-export/load-complete-events.cjs.map +1 -1
- package/dist/utils/transcript-export/load-complete-events.js +25 -17
- package/dist/utils/transcript-export/load-complete-events.js.map +1 -1
- package/dist/utils/workspace-relative-path.cjs +2 -0
- package/dist/utils/workspace-relative-path.cjs.map +1 -0
- package/dist/utils/workspace-relative-path.d.ts +10 -0
- package/dist/utils/workspace-relative-path.js +22 -0
- package/dist/utils/workspace-relative-path.js.map +1 -0
- package/package.json +17 -16
- package/scripts/check-sdk-version-sync.mjs +6 -6
- package/scripts/check-translation-completeness.cjs +3 -0
- package/scripts/dev-process-utils.mjs +6 -1
- package/scripts/dev-safe.mjs +57 -2
- package/scripts/dev-with-automation.mjs +98 -9
- package/build/assets/active-backend-context-B_bg5h9O.js +0 -2
- package/build/assets/agent-profiles-settings-hd2cAIZM.js +0 -1
- package/build/assets/agent-server-conversation-service.api-BheU4HX3.js +0 -86
- package/build/assets/agent-settings-D_SVrWhI.js +0 -1
- package/build/assets/automation-detail-C0SxWTnQ.js +0 -3
- package/build/assets/automation-export-BjQa_fT6.js +0 -2
- package/build/assets/automation-setup-route-BzCNpljP.js +0 -1
- package/build/assets/automations-list-dZg8zOCl.js +0 -1
- package/build/assets/bot-DuN83i3p.js +0 -1
- package/build/assets/browser--eoQOo4M.js +0 -6
- package/build/assets/check-DLOKoFU9.js +0 -1
- package/build/assets/chevron-down-CnIbtM6i.js +0 -1
- package/build/assets/circle-check-CxCYJrpZ.js +0 -1
- package/build/assets/cloud-funnel-analytics-CcSez21r.js +0 -1
- package/build/assets/conversation-Cmyw9bFh.js +0 -90
- package/build/assets/conversation-CvoGZ5vC.js +0 -1
- package/build/assets/conversation-panel-CvoGZ5vC.js +0 -1
- package/build/assets/conversation-state-store-CtgILxWF.js +0 -1
- package/build/assets/conversation-store-B8Eahyeg.js +0 -6
- package/build/assets/external-link-zWbg5KXS.js +0 -1
- package/build/assets/files-tab-D5zuU5TY.js +0 -1
- package/build/assets/format-model-name-BN_rx1Y3.js +0 -1
- package/build/assets/format-relative-time-BerVamGl.js +0 -1
- package/build/assets/git-provider-icon-zuKz2cwo.js +0 -1
- package/build/assets/git-repo-dropdown-Bo7ciSNX.js +0 -1
- package/build/assets/home-DqyeeFA_.js +0 -1
- package/build/assets/home-Y0aDou-a.js +0 -1
- package/build/assets/index-home-DqyeeFA_.js +0 -1
- package/build/assets/info-C9lpK5pw.js +0 -1
- package/build/assets/install-server-modal-DW6dSyGr.js +0 -1
- package/build/assets/kebab-menu-item-content-CKydZrbH.js +0 -1
- package/build/assets/llm-not-configured-banner-DCE_0B4I.js +0 -27
- package/build/assets/llm-settings-8eWBF3Ij.js +0 -1
- package/build/assets/llm-settings-D9ko42Pi.js +0 -1
- package/build/assets/llm-subscription-service-B3K-97lP.js +0 -1
- package/build/assets/loader-circle-C5AnEN8r.js +0 -1
- package/build/assets/manifest-e1c3bc3b.js +0 -1
- package/build/assets/manifest-subpage-layout-Ds7G5GZ8.js +0 -1
- package/build/assets/markdown-renderer-DzvgdZey.js +0 -8
- package/build/assets/mcp-marketplace-utils-DSLou4n7.js +0 -1
- package/build/assets/messages-B2l0qLVk.js +0 -40
- package/build/assets/onboarding-modal-DrrGlEQq.js +0 -1
- package/build/assets/pencil-Bl3GWhgq.js +0 -1
- package/build/assets/plus-CtzlyAoF.js +0 -1
- package/build/assets/profiles-service.api-vcE_jJCe.js +0 -1
- package/build/assets/providers-CdrPPm0z.js +0 -1
- package/build/assets/recommended-automations-launcher-DIYgUdMm.js +0 -1
- package/build/assets/refresh-cw-B9GhC3QC.js +0 -1
- package/build/assets/root-CBBi6IAe.js +0 -2
- package/build/assets/root-CRK9fOFd.css +0 -1
- package/build/assets/root-layout-BFN2rCOy.js +0 -2
- package/build/assets/search-CYaiKHRp.js +0 -1
- package/build/assets/secrets-service-BHF4fxML.js +0 -1
- package/build/assets/secrets-settings-aBGXtQhX.js +0 -1
- package/build/assets/shared-conversation-BIAcuORk.js +0 -1
- package/build/assets/shield-check-D2cpEpv3.js +0 -1
- package/build/assets/trash-2-CzDVN-Iw.js +0 -1
- package/build/assets/use-acp-credential-form-DGyo0QvL.js +0 -1
- package/build/assets/use-agent-profiles-B37XWDLq.js +0 -1
- package/build/assets/use-config-DapX3pjC.js +0 -1
- package/build/assets/use-create-conversation-CRf1dCm5.js +0 -1
- package/build/assets/use-create-secret-DcpT3RPw.js +0 -1
- package/build/assets/use-is-authed-Bka89Xmm.js +0 -1
- package/build/assets/use-is-creating-conversation-CVefC9Ns.js +0 -1
- package/build/assets/use-llm-profiles-CHxqoHiN.js +0 -1
- package/build/assets/use-manifest-capabilities-zihHDbMW.js +0 -1
- package/build/assets/use-save-agent-profile-CH9_EXQG.js +0 -1
- package/build/assets/use-tracking-salbPJxT.js +0 -3
- package/build/assets/utils-DPQfkd-7.js +0 -1
- package/build/assets/vendor~index-home~home~conversation-panel~conversation-DiXf0dkj.js +0 -13
- package/build/assets/x-RYDBg-e2.js +0 -1
- package/build/assets/zap-tbKDzCe3.js +0 -1
- package/dist/api/cloud/suggestions-service.api.d.ts +0 -8
- package/dist/api/suggestions-service/suggestions-service.api.d.ts +0 -11
- package/dist/components/conversation-events/chat/event-message-components/observation-pair-event-message.d.ts +0 -7
- package/dist/components/conversation-events/index.d.ts +0 -1
- package/dist/components/features/automations/metadata-chip.d.ts +0 -6
- package/dist/components/features/chat/task-tracking/status-badge.d.ts +0 -5
- package/dist/components/features/chat/task-tracking/status-icon.d.ts +0 -5
- package/dist/components/features/chat/task-tracking/task-list-section.d.ts +0 -10
- package/dist/components/features/controls/tools.d.ts +0 -2
- package/dist/components/features/conversation/metrics-modal/context-window-section.cjs +0 -2
- package/dist/components/features/conversation/metrics-modal/context-window-section.cjs.map +0 -1
- package/dist/components/features/conversation/metrics-modal/context-window-section.d.ts +0 -6
- package/dist/components/features/conversation/metrics-modal/context-window-section.js +0 -46
- package/dist/components/features/conversation/metrics-modal/context-window-section.js.map +0 -1
- package/dist/components/features/conversation/metrics-modal/empty-state.cjs +0 -2
- package/dist/components/features/conversation/metrics-modal/empty-state.cjs.map +0 -1
- package/dist/components/features/conversation/metrics-modal/empty-state.d.ts +0 -1
- package/dist/components/features/conversation/metrics-modal/empty-state.js +0 -18
- package/dist/components/features/conversation/metrics-modal/empty-state.js.map +0 -1
- package/dist/components/features/conversation/metrics-modal/metrics-modal-header.cjs +0 -2
- package/dist/components/features/conversation/metrics-modal/metrics-modal-header.cjs.map +0 -1
- package/dist/components/features/conversation/metrics-modal/metrics-modal-header.d.ts +0 -5
- package/dist/components/features/conversation/metrics-modal/metrics-modal-header.js +0 -20
- package/dist/components/features/conversation/metrics-modal/metrics-modal-header.js.map +0 -1
- package/dist/components/features/conversation/metrics-modal/metrics-modal.cjs +0 -2
- package/dist/components/features/conversation/metrics-modal/metrics-modal.cjs.map +0 -1
- package/dist/components/features/conversation/metrics-modal/metrics-modal.d.ts +0 -6
- package/dist/components/features/conversation/metrics-modal/metrics-modal.js +0 -57
- package/dist/components/features/conversation/metrics-modal/metrics-modal.js.map +0 -1
- package/dist/components/features/conversation-panel/new-conversation-button.d.ts +0 -23
- package/dist/components/features/home/home-header/guide-message.d.ts +0 -1
- package/dist/components/features/home/home-header/home-header.d.ts +0 -1
- package/dist/components/features/home/new-conversation/create-conversation-button.d.ts +0 -1
- package/dist/components/features/home/new-conversation/new-conversation.d.ts +0 -1
- package/dist/components/features/home/new-conversation.d.ts +0 -1
- package/dist/components/features/home/tasks/task-card.d.ts +0 -6
- package/dist/components/features/home/tasks/task-group.d.ts +0 -7
- package/dist/components/features/home/tasks/task-issue-number.d.ts +0 -6
- package/dist/components/features/home/tasks/task-item-title.d.ts +0 -1
- package/dist/components/features/home/tasks/task-suggestions-skeleton.d.ts +0 -1
- package/dist/components/features/home/tasks/task-suggestions.d.ts +0 -6
- package/dist/components/features/settings/agent-server-onboarding.d.ts +0 -10
- package/dist/components/features/settings/mcp-settings/mcp-server-list-item.d.ts +0 -6
- package/dist/components/features/settings/mcp-settings/mcp-server-list.d.ts +0 -8
- package/dist/hooks/query/use-suggested-tasks.d.ts +0 -1
- package/dist/hooks/use-should-show-user-features.d.ts +0 -1
- package/dist/icons/u-credit-card.cjs +0 -2
- package/dist/icons/u-credit-card.cjs.map +0 -1
- package/dist/icons/u-credit-card.js +0 -21
- package/dist/icons/u-credit-card.js.map +0 -1
- package/dist/ui/card-title.d.ts +0 -16
- package/dist/ui/card.d.ts +0 -14
- package/dist/utils/group-suggested-tasks.d.ts +0 -7
- /package/build/assets/{vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~cy4jtuc2-rfV8mQ9m.js → vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~dcc51rps-rfV8mQ9m.js} +0 -0
- /package/build/assets/{vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~lq5hicxx-cHFhpUBq.js → vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~ox0jfsa0-cHFhpUBq.js} +0 -0
- /package/build/assets/{vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~skills-setti~9pstowjp-BOVIFA_g.js → vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~skills-setti~eo2nf80n-BOVIFA_g.js} +0 -0
- /package/build/assets/{vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~skills-setti~ht43enc2-C0JXQb_q.js → vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~skills-setti~jz4f6vo2-C0JXQb_q.js} +0 -0
package/dist/routes/files-tab.js
CHANGED
|
@@ -7,13 +7,13 @@ import { useFilesTabStore as a } from "../stores/files-tab-store.js";
|
|
|
7
7
|
import o from "../icons/link-external.js";
|
|
8
8
|
import { SegmentedToggle as s } from "../components/features/files-tab/segmented-toggle.js";
|
|
9
9
|
import { NoFileSelectedMessage as c } from "../components/features/files-tab/no-file-selected-message.js";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
10
|
+
import { useWorkspaceFiles as l } from "../hooks/query/use-workspace-files.js";
|
|
11
|
+
import { useWorkspaceMutationCounter as u, withWorkspaceCacheBuster as ee } from "../stores/use-workspace-mutation-counter.js";
|
|
12
|
+
import { useWorkspaceFileContent as te } from "../hooks/query/use-workspace-file-content.js";
|
|
13
|
+
import { useHasAttachedSource as ne } from "../hooks/use-has-attached-source.js";
|
|
14
|
+
import { useHasGitCommits as re } from "../hooks/query/use-has-git-commits.js";
|
|
15
|
+
import { useAutoRefreshFilesOnEdit as d } from "../hooks/use-auto-refresh-files-on-edit.js";
|
|
16
|
+
import { useUnifiedGetGitChanges as f } from "../hooks/query/use-unified-get-git-changes.js";
|
|
17
17
|
import { sortFilesByPriority as ie } from "../utils/file-priority.js";
|
|
18
18
|
import { FileQuickRow as p } from "../components/features/files-tab/file-quick-row.js";
|
|
19
19
|
import { FileTreeView as m } from "../components/features/files-tab/file-tree-view.js";
|
|
@@ -27,10 +27,10 @@ import { Fragment as C, jsx as w, jsxs as T } from "react/jsx-runtime";
|
|
|
27
27
|
//#region src/routes/files-tab.tsx
|
|
28
28
|
function E() {
|
|
29
29
|
let { t: E } = e("openhands");
|
|
30
|
-
|
|
31
|
-
let { hasAttachedSource: D, isLoading: O } =
|
|
30
|
+
d();
|
|
31
|
+
let { hasAttachedSource: D, isLoading: O } = ne(), { hasCommits: k } = re({ enabled: D }), { conversationId: A } = n(), { state: j, setFilesTabDiffView: M, setFilesTabContentViewMode: N } = r(A ?? ""), P = (D || O) && k !== !1, F = j.filesTabDiffView ?? P, I = j.filesTabContentViewMode, { isSuccess: oe, isUnsupported: L } = _(), R = oe && !L, [z, B] = S(!1), V = F ? "on" : "off";
|
|
32
32
|
z && R && (V = "commits");
|
|
33
|
-
let [H, U] = S(!1), W =
|
|
33
|
+
let [H, U] = S(!1), W = l(), G = ae(() => W.data ?? [], [W.data]), K = a((e) => e.selectedPath), q = a((e) => e.selectedConversationId), J = a((e) => e.setSelectedPath), Y = q === A ? K : null, X = b((e) => J(e, A), [A, J]), se = te(Y), ce = u((e) => e.count), Z = ee(se.data?.staticUrl ?? null, ce);
|
|
34
34
|
x(() => {
|
|
35
35
|
q !== A && J(null, A);
|
|
36
36
|
}, [
|
|
@@ -47,7 +47,7 @@ function E() {
|
|
|
47
47
|
A,
|
|
48
48
|
J
|
|
49
49
|
]);
|
|
50
|
-
let Q = i(), { refetch: le, isFetching: $ } =
|
|
50
|
+
let Q = i(), { refetch: le, isFetching: $ } = f(), ue = () => {
|
|
51
51
|
le(), Q.invalidateQueries({ queryKey: ["workspace-files"] }), Q.invalidateQueries({ queryKey: ["workspace-file-content"] }), Q.invalidateQueries({ queryKey: ["git_commits"] });
|
|
52
52
|
};
|
|
53
53
|
return /* @__PURE__ */ T("main", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files-tab.js","names":[],"sources":["../../src/routes/files-tab.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { useQueryClient } from \"@tanstack/react-query\";\n\nimport { NoFileSelectedMessage } from \"#/components/features/files-tab/no-file-selected-message\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { useFilesTabStore } from \"#/stores/files-tab-store\";\nimport { useWorkspaceFiles } from \"#/hooks/query/use-workspace-files\";\nimport { useWorkspaceFileContent } from \"#/hooks/query/use-workspace-file-content\";\nimport { useHasAttachedSource } from \"#/hooks/use-has-attached-source\";\nimport { useHasGitCommits } from \"#/hooks/query/use-has-git-commits\";\nimport { useAutoRefreshFilesOnEdit } from \"#/hooks/use-auto-refresh-files-on-edit\";\nimport { useUnifiedGetGitChanges } from \"#/hooks/query/use-unified-get-git-changes\";\nimport { useOptionalConversationId } from \"#/hooks/use-conversation-id\";\nimport { useConversationLocalStorageState } from \"#/utils/conversation-local-storage\";\nimport {\n useWorkspaceMutationCounter,\n withWorkspaceCacheBuster,\n} from \"#/stores/use-workspace-mutation-counter\";\nimport { sortFilesByPriority } from \"#/utils/file-priority\";\nimport { FileQuickRow } from \"#/components/features/files-tab/file-quick-row\";\nimport { FileTreeView } from \"#/components/features/files-tab/file-tree-view\";\nimport { FileContentViewer } from \"#/components/features/files-tab/file-content-viewer\";\nimport { SegmentedToggle } from \"#/components/features/files-tab/segmented-toggle\";\nimport type { ViewMode } from \"#/components/features/files-tab/view-mode\";\nimport RefreshIcon from \"#/icons/u-refresh.svg?react\";\nimport LinkExternalIcon from \"#/icons/link-external.svg?react\";\nimport { useUnifiedGitCommits } from \"#/hooks/query/use-unified-git-commits\";\nimport GitChanges from \"./changes-tab\";\nimport GitCommits from \"./commits-tab\";\n\nfunction FilesTab() {\n const { t } = useTranslation(\"openhands\");\n\n // Keep the list / content / diff caches fresh as the agent writes files.\n useAutoRefreshFilesOnEdit();\n\n const { hasAttachedSource, isLoading: isAttachedSourceLoading } =\n useHasAttachedSource();\n // A workspace with zero commits has no diff base to compare against, so\n // the diff view would just be empty / misleading. Only probe when we\n // already believe the user attached a source — saves a workspace round\n // trip on every plain (no-attachment) conversation.\n const { hasCommits } = useHasGitCommits({ enabled: hasAttachedSource });\n\n // Diff view defaults to ON when the user attached a source (repo or\n // local workspace) *and* there's at least one commit, OFF otherwise\n // (no attachment, or attachment with no commits yet).\n //\n // While the attachment / commit probes are still resolving we stay\n // optimistic — most attached conversations live in a real repo, so\n // defaulting to diff during the brief loading window avoids a\n // \"files → diff\" flash on initial load. We only flip to files-view\n // once `hasAttachedSource` *or* `hasCommits` definitively resolves\n // false. The user's persisted choice always wins.\n const { conversationId } = useOptionalConversationId();\n const {\n state: persistedState,\n setFilesTabDiffView,\n setFilesTabContentViewMode,\n } = useConversationLocalStorageState(conversationId ?? \"\");\n\n const diffViewDefault =\n (hasAttachedSource || isAttachedSourceLoading) && hasCommits !== false;\n const diffViewEnabled = persistedState.filesTabDiffView ?? diffViewDefault;\n const contentViewMode = persistedState.filesTabContentViewMode;\n\n // Commit history gets a third toggle segment, offered only when the\n // agent server supports the commits API (older servers 404 → the toggle\n // stays two-way and the tab looks exactly as it did before). The\n // selection is session-local; the persisted diff/files preference is\n // untouched so falling out of the commits view restores it.\n const { isSuccess: commitsIsSuccess, isUnsupported: commitsUnsupported } =\n useUnifiedGitCommits();\n const showCommitsOption = commitsIsSuccess && !commitsUnsupported;\n const [commitsViewSelected, setCommitsViewSelected] = useState(false);\n let activeView: \"on\" | \"off\" | \"commits\" = diffViewEnabled ? \"on\" : \"off\";\n if (commitsViewSelected && showCommitsOption) activeView = \"commits\";\n\n // Collapsed by default — the quick-access pill row at the top is usually\n // enough; the user can expand the tree on demand.\n const [isTreeVisible, setIsTreeVisible] = useState(false);\n\n const filesQuery = useWorkspaceFiles();\n const paths = useMemo(() => filesQuery.data ?? [], [filesQuery.data]);\n\n const storedSelectedPath = useFilesTabStore((s) => s.selectedPath);\n const selectedConversationId = useFilesTabStore(\n (s) => s.selectedConversationId,\n );\n const setSelectedPath = useFilesTabStore((s) => s.setSelectedPath);\n\n // A selection is scoped to the conversation it was made in. Ignore a path\n // that belongs to a different conversation so we never try to open a file\n // that only exists in the previous conversation's workspace (issue #1350).\n // The auto-select effect below then picks this conversation's top file.\n const selectedPath =\n selectedConversationId === conversationId ? storedSelectedPath : null;\n\n // Tag every selection with the active conversation so it can't leak into\n // the next one. FileQuickRow / FileTreeView call this with just the path.\n const handleSelectFile = useCallback(\n (path: string) => setSelectedPath(path, conversationId),\n [conversationId, setSelectedPath],\n );\n\n // Pre-fetch the selected file's content here too so the toolbar's\n // \"open in new window\" link can reach for its `staticUrl`. react-query\n // dedupes against `FileContentViewer`'s identical call, so this costs\n // nothing extra.\n const selectedFileContent = useWorkspaceFileContent(selectedPath);\n const mutationCounter = useWorkspaceMutationCounter((state) => state.count);\n const selectedFileStaticUrl = withWorkspaceCacheBuster(\n selectedFileContent.data?.staticUrl ?? null,\n mutationCounter,\n );\n\n useEffect(() => {\n if (selectedConversationId === conversationId) return;\n setSelectedPath(null, conversationId);\n }, [selectedConversationId, conversationId, setSelectedPath]);\n\n // Auto-select the highest-priority file the first time we load the list,\n // so users see something useful immediately.\n useEffect(() => {\n if (selectedPath || paths.length === 0) return;\n const [first] = sortFilesByPriority(paths);\n if (first) setSelectedPath(first, conversationId);\n }, [paths, selectedPath, conversationId, setSelectedPath]);\n\n // Refresh button: covers the diff view (git changes) and the file viewer\n // (workspace listing + cached file contents). Lives in this toolbar — not\n // in the outer ConversationTabs bar — so it sits with the other\n // files-tab-local controls.\n const queryClient = useQueryClient();\n const { refetch: refetchGitChanges, isFetching: isFetchingGitChanges } =\n useUnifiedGetGitChanges();\n const refreshFiles = () => {\n refetchGitChanges();\n queryClient.invalidateQueries({ queryKey: [\"workspace-files\"] });\n queryClient.invalidateQueries({ queryKey: [\"workspace-file-content\"] });\n queryClient.invalidateQueries({ queryKey: [\"git_commits\"] });\n };\n\n return (\n <main\n className=\"h-full w-full flex flex-col items-stretch\"\n data-testid=\"files-tab\"\n >\n {/* Top toolbar: diff/files + rich/plain toggles (left-aligned) plus\n the refresh button on the right. */}\n <div className=\"flex items-center gap-3 px-3 py-1.5 border-b border-[var(--oh-border)]\">\n <SegmentedToggle<\"on\" | \"off\" | \"commits\">\n ariaLabel={t(I18nKey.FILES$DIFF_VIEW)}\n testId=\"files-tab-diff-toggle\"\n value={activeView}\n options={[\n { value: \"on\", label: t(I18nKey.FILES$DIFF_VIEW) },\n ...(showCommitsOption\n ? [\n {\n value: \"commits\" as const,\n label: t(I18nKey.DIFF_VIEWER$COMMITS),\n },\n ]\n : []),\n { value: \"off\", label: t(I18nKey.COMMON$FILES) },\n ]}\n onChange={(value) => {\n if (value === \"commits\") {\n setCommitsViewSelected(true);\n } else {\n setCommitsViewSelected(false);\n setFilesTabDiffView(value === \"on\");\n }\n }}\n />\n\n {activeView === \"off\" && (\n <SegmentedToggle<ViewMode>\n ariaLabel={t(I18nKey.FILES$RICH)}\n testId=\"files-tab-content-mode-toggle\"\n value={contentViewMode}\n options={[\n { value: \"rich\", label: t(I18nKey.FILES$RICH) },\n { value: \"plain\", label: t(I18nKey.FILES$PLAIN) },\n ]}\n onChange={setFilesTabContentViewMode}\n />\n )}\n\n <div className=\"ml-auto flex items-center gap-1\">\n {/* Open the currently-selected file in a new browser tab. Only\n meaningful while we're showing a file (not the diff view) and\n we've resolved its staticUrl from the workspace fileserver. */}\n {activeView === \"off\" && selectedFileStaticUrl && (\n <a\n href={selectedFileStaticUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={t(I18nKey.FILES$OPEN_IN_NEW_WINDOW)}\n title={t(I18nKey.FILES$OPEN_IN_NEW_WINDOW)}\n data-testid=\"files-tab-open-in-new-window\"\n className=\"flex items-center justify-center w-[26px] py-1 rounded-[7px] hover:bg-[var(--oh-interactive-hover)] cursor-pointer text-white\"\n >\n <LinkExternalIcon width={14} height={14} />\n </a>\n )}\n <button\n type=\"button\"\n onClick={refreshFiles}\n disabled={isFetchingGitChanges}\n aria-label={t(I18nKey.FILES$REFRESH)}\n title={t(I18nKey.FILES$REFRESH)}\n data-testid=\"files-tab-refresh\"\n className=\"flex items-center justify-center w-[26px] py-1 rounded-[7px] hover:enabled:bg-[var(--oh-interactive-hover)] cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n <RefreshIcon\n width={12.75}\n height={15}\n color=\"#ffffff\"\n className={isFetchingGitChanges ? \"animate-spin\" : \"\"}\n />\n </button>\n </div>\n </div>\n\n {activeView === \"on\" && (\n <div className=\"flex-1 min-h-0\">\n <GitChanges />\n </div>\n )}\n {activeView === \"commits\" && (\n <div className=\"flex-1 min-h-0\">\n <GitCommits />\n </div>\n )}\n {activeView === \"off\" && (\n <div className=\"flex flex-1 flex-col min-h-0\">\n {filesQuery.isLoading ? (\n <div className=\"flex flex-1 items-center justify-center text-sm text-[var(--oh-muted)]\">\n {t(I18nKey.FILES$LOADING_FILES)}\n </div>\n ) : (\n <>\n <FileQuickRow\n paths={paths}\n selectedPath={selectedPath}\n onSelectFile={handleSelectFile}\n isTreeVisible={isTreeVisible}\n onToggleTree={() => setIsTreeVisible((prev) => !prev)}\n />\n <div className=\"flex h-full min-h-0 flex-1\">\n {isTreeVisible && (\n <aside\n className=\"w-56 shrink-0 border-r border-[var(--oh-border)] overflow-y-auto custom-scrollbar-always\"\n data-testid=\"files-tab-tree\"\n >\n <FileTreeView\n paths={paths}\n selectedPath={selectedPath}\n onSelectFile={handleSelectFile}\n />\n </aside>\n )}\n <section\n className=\"flex h-full min-h-0 min-w-0 flex-1 flex-col\"\n data-testid=\"files-tab-content\"\n >\n {selectedPath ? (\n <FileContentViewer\n path={selectedPath}\n viewMode={contentViewMode}\n />\n ) : (\n <NoFileSelectedMessage />\n )}\n </section>\n </div>\n </>\n )}\n </div>\n )}\n </main>\n );\n}\n\nexport default FilesTab;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"files-tab.js","names":[],"sources":["../../src/routes/files-tab.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { useQueryClient } from \"@tanstack/react-query\";\n\nimport { NoFileSelectedMessage } from \"#/components/features/files-tab/no-file-selected-message\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { useFilesTabStore } from \"#/stores/files-tab-store\";\nimport { useWorkspaceFiles } from \"#/hooks/query/use-workspace-files\";\nimport { useWorkspaceFileContent } from \"#/hooks/query/use-workspace-file-content\";\nimport { useHasAttachedSource } from \"#/hooks/use-has-attached-source\";\nimport { useHasGitCommits } from \"#/hooks/query/use-has-git-commits\";\nimport { useAutoRefreshFilesOnEdit } from \"#/hooks/use-auto-refresh-files-on-edit\";\nimport { useUnifiedGetGitChanges } from \"#/hooks/query/use-unified-get-git-changes\";\nimport { useOptionalConversationId } from \"#/hooks/use-conversation-id\";\nimport { useConversationLocalStorageState } from \"#/utils/conversation-local-storage\";\nimport {\n useWorkspaceMutationCounter,\n withWorkspaceCacheBuster,\n} from \"#/stores/use-workspace-mutation-counter\";\nimport { sortFilesByPriority } from \"#/utils/file-priority\";\nimport { FileQuickRow } from \"#/components/features/files-tab/file-quick-row\";\nimport { FileTreeView } from \"#/components/features/files-tab/file-tree-view\";\nimport { FileContentViewer } from \"#/components/features/files-tab/file-content-viewer\";\nimport { SegmentedToggle } from \"#/components/features/files-tab/segmented-toggle\";\nimport type { ViewMode } from \"#/components/features/files-tab/view-mode\";\nimport RefreshIcon from \"#/icons/u-refresh.svg?react\";\nimport LinkExternalIcon from \"#/icons/link-external.svg?react\";\nimport { useUnifiedGitCommits } from \"#/hooks/query/use-unified-git-commits\";\nimport GitChanges from \"./changes-tab\";\nimport GitCommits from \"./commits-tab\";\n\nfunction FilesTab() {\n const { t } = useTranslation(\"openhands\");\n\n // Keep the list / content / diff caches fresh as the agent writes files.\n useAutoRefreshFilesOnEdit();\n\n const { hasAttachedSource, isLoading: isAttachedSourceLoading } =\n useHasAttachedSource();\n // A workspace with zero commits has no diff base to compare against, so\n // the diff view would just be empty / misleading. Only probe when we\n // already believe the user attached a source — saves a workspace round\n // trip on every plain (no-attachment) conversation.\n const { hasCommits } = useHasGitCommits({ enabled: hasAttachedSource });\n\n // Diff view defaults to ON when the user attached a source (repo or\n // local workspace) *and* there's at least one commit, OFF otherwise\n // (no attachment, or attachment with no commits yet).\n //\n // While the attachment / commit probes are still resolving we stay\n // optimistic — most attached conversations live in a real repo, so\n // defaulting to diff during the brief loading window avoids a\n // \"files → diff\" flash on initial load. We only flip to files-view\n // once `hasAttachedSource` *or* `hasCommits` definitively resolves\n // false. The user's persisted choice always wins.\n const { conversationId } = useOptionalConversationId();\n const {\n state: persistedState,\n setFilesTabDiffView,\n setFilesTabContentViewMode,\n } = useConversationLocalStorageState(conversationId ?? \"\");\n\n const diffViewDefault =\n (hasAttachedSource || isAttachedSourceLoading) && hasCommits !== false;\n const diffViewEnabled = persistedState.filesTabDiffView ?? diffViewDefault;\n const contentViewMode = persistedState.filesTabContentViewMode;\n\n // Commit history gets a third toggle segment, offered only when the\n // agent server supports the commits API (older servers 404 → the toggle\n // stays two-way and the tab looks exactly as it did before). The\n // selection is session-local; the persisted diff/files preference is\n // untouched so falling out of the commits view restores it.\n const { isSuccess: commitsIsSuccess, isUnsupported: commitsUnsupported } =\n useUnifiedGitCommits();\n const showCommitsOption = commitsIsSuccess && !commitsUnsupported;\n const [commitsViewSelected, setCommitsViewSelected] = useState(false);\n let activeView: \"on\" | \"off\" | \"commits\" = diffViewEnabled ? \"on\" : \"off\";\n if (commitsViewSelected && showCommitsOption) activeView = \"commits\";\n\n // Collapsed by default — the quick-access pill row at the top is usually\n // enough; the user can expand the tree on demand.\n const [isTreeVisible, setIsTreeVisible] = useState(false);\n\n const filesQuery = useWorkspaceFiles();\n const paths = useMemo(() => filesQuery.data ?? [], [filesQuery.data]);\n\n const storedSelectedPath = useFilesTabStore((s) => s.selectedPath);\n const selectedConversationId = useFilesTabStore(\n (s) => s.selectedConversationId,\n );\n const setSelectedPath = useFilesTabStore((s) => s.setSelectedPath);\n\n // A selection is scoped to the conversation it was made in. Ignore a path\n // that belongs to a different conversation so we never try to open a file\n // that only exists in the previous conversation's workspace (issue #1350).\n // The auto-select effect below then picks this conversation's top file.\n const selectedPath =\n selectedConversationId === conversationId ? storedSelectedPath : null;\n\n // Tag every selection with the active conversation so it can't leak into\n // the next one. FileQuickRow / FileTreeView call this with just the path.\n const handleSelectFile = useCallback(\n (path: string) => setSelectedPath(path, conversationId),\n [conversationId, setSelectedPath],\n );\n\n // Pre-fetch the selected file's content here too so the toolbar's\n // \"open in new window\" link can reach for its `staticUrl`. react-query\n // dedupes against `FileContentViewer`'s identical call, so this costs\n // nothing extra.\n const selectedFileContent = useWorkspaceFileContent(selectedPath);\n const mutationCounter = useWorkspaceMutationCounter((state) => state.count);\n const selectedFileStaticUrl = withWorkspaceCacheBuster(\n selectedFileContent.data?.staticUrl ?? null,\n mutationCounter,\n );\n\n useEffect(() => {\n if (selectedConversationId === conversationId) return;\n setSelectedPath(null, conversationId);\n }, [selectedConversationId, conversationId, setSelectedPath]);\n\n // Auto-select the highest-priority file the first time we load the list,\n // so users see something useful immediately.\n useEffect(() => {\n if (selectedPath || paths.length === 0) return;\n const [first] = sortFilesByPriority(paths);\n if (first) setSelectedPath(first, conversationId);\n }, [paths, selectedPath, conversationId, setSelectedPath]);\n\n // Refresh button: covers the diff view (git changes) and the file viewer\n // (workspace listing + cached file contents). Lives in this toolbar — not\n // in the outer ConversationTabs bar — so it sits with the other\n // files-tab-local controls.\n const queryClient = useQueryClient();\n const { refetch: refetchGitChanges, isFetching: isFetchingGitChanges } =\n useUnifiedGetGitChanges();\n const refreshFiles = () => {\n refetchGitChanges();\n queryClient.invalidateQueries({ queryKey: [\"workspace-files\"] });\n queryClient.invalidateQueries({ queryKey: [\"workspace-file-content\"] });\n queryClient.invalidateQueries({ queryKey: [\"git_commits\"] });\n };\n\n return (\n <main\n className=\"h-full w-full flex flex-col items-stretch\"\n data-testid=\"files-tab\"\n >\n {/* Top toolbar: diff/files + rich/plain toggles (left-aligned) plus\n the refresh button on the right. */}\n <div className=\"flex items-center gap-3 px-3 py-1.5 border-b border-[var(--oh-border)]\">\n <SegmentedToggle<\"on\" | \"off\" | \"commits\">\n ariaLabel={t(I18nKey.FILES$DIFF_VIEW)}\n testId=\"files-tab-diff-toggle\"\n value={activeView}\n options={[\n { value: \"on\", label: t(I18nKey.FILES$DIFF_VIEW) },\n ...(showCommitsOption\n ? [\n {\n value: \"commits\" as const,\n label: t(I18nKey.DIFF_VIEWER$COMMITS),\n },\n ]\n : []),\n { value: \"off\", label: t(I18nKey.COMMON$FILES) },\n ]}\n onChange={(value) => {\n if (value === \"commits\") {\n setCommitsViewSelected(true);\n } else {\n setCommitsViewSelected(false);\n setFilesTabDiffView(value === \"on\");\n }\n }}\n />\n\n {activeView === \"off\" && (\n <SegmentedToggle<ViewMode>\n ariaLabel={t(I18nKey.FILES$RICH)}\n testId=\"files-tab-content-mode-toggle\"\n value={contentViewMode}\n options={[\n { value: \"rich\", label: t(I18nKey.FILES$RICH) },\n { value: \"plain\", label: t(I18nKey.FILES$PLAIN) },\n ]}\n onChange={setFilesTabContentViewMode}\n />\n )}\n\n <div className=\"ml-auto flex items-center gap-1\">\n {/* Open the currently-selected file in a new browser tab. Only\n meaningful while we're showing a file (not the diff view) and\n we've resolved its staticUrl from the workspace fileserver. */}\n {activeView === \"off\" && selectedFileStaticUrl && (\n <a\n href={selectedFileStaticUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={t(I18nKey.FILES$OPEN_IN_NEW_WINDOW)}\n title={t(I18nKey.FILES$OPEN_IN_NEW_WINDOW)}\n data-testid=\"files-tab-open-in-new-window\"\n className=\"flex items-center justify-center w-[26px] py-1 rounded-[7px] hover:bg-[var(--oh-interactive-hover)] cursor-pointer text-white\"\n >\n <LinkExternalIcon width={14} height={14} />\n </a>\n )}\n <button\n type=\"button\"\n onClick={refreshFiles}\n disabled={isFetchingGitChanges}\n aria-label={t(I18nKey.FILES$REFRESH)}\n title={t(I18nKey.FILES$REFRESH)}\n data-testid=\"files-tab-refresh\"\n className=\"flex items-center justify-center w-[26px] py-1 rounded-[7px] hover:enabled:bg-[var(--oh-interactive-hover)] cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n <RefreshIcon\n width={12.75}\n height={15}\n color=\"#ffffff\"\n className={isFetchingGitChanges ? \"animate-spin\" : \"\"}\n />\n </button>\n </div>\n </div>\n\n {activeView === \"on\" && (\n <div className=\"flex-1 min-h-0\">\n <GitChanges />\n </div>\n )}\n {activeView === \"commits\" && (\n <div className=\"flex-1 min-h-0\">\n <GitCommits />\n </div>\n )}\n {activeView === \"off\" && (\n <div className=\"flex flex-1 flex-col min-h-0\">\n {filesQuery.isLoading ? (\n <div className=\"flex flex-1 items-center justify-center text-sm text-[var(--oh-muted)]\">\n {t(I18nKey.FILES$LOADING_FILES)}\n </div>\n ) : (\n <>\n <FileQuickRow\n paths={paths}\n selectedPath={selectedPath}\n onSelectFile={handleSelectFile}\n isTreeVisible={isTreeVisible}\n onToggleTree={() => setIsTreeVisible((prev) => !prev)}\n />\n <div className=\"flex h-full min-h-0 flex-1\">\n {isTreeVisible && (\n <aside\n className=\"w-56 shrink-0 border-r border-[var(--oh-border)] overflow-y-auto custom-scrollbar-always\"\n data-testid=\"files-tab-tree\"\n >\n <FileTreeView\n paths={paths}\n selectedPath={selectedPath}\n onSelectFile={handleSelectFile}\n />\n </aside>\n )}\n <section\n className=\"flex h-full min-h-0 min-w-0 flex-1 flex-col\"\n data-testid=\"files-tab-content\"\n >\n {selectedPath ? (\n <FileContentViewer\n path={selectedPath}\n viewMode={contentViewMode}\n />\n ) : (\n <NoFileSelectedMessage />\n )}\n </section>\n </div>\n </>\n )}\n </div>\n )}\n </main>\n );\n}\n\nexport default FilesTab;\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage-tab.cjs","names":[],"sources":["../../src/routes/usage-tab.tsx"],"sourcesContent":["import { UsagePanel } from \"#/components/features/conversation/usage-panel/usage-panel\";\n\nfunction UsageTab() {\n return <UsagePanel />;\n}\n\nexport default UsageTab;\n"],"mappings":"mKAEA,SAAS,GAAW,CAClB,OAAO,EAAA,EAAA,KAAC,EAAA,WAAD,CAAa,CAAA,CACtB"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { UsagePanel as e } from "../components/features/conversation/usage-panel/usage-panel.js";
|
|
2
|
+
import { jsx as t } from "react/jsx-runtime";
|
|
3
|
+
//#region src/routes/usage-tab.tsx
|
|
4
|
+
function n() {
|
|
5
|
+
return /* @__PURE__ */ t(e, {});
|
|
6
|
+
}
|
|
7
|
+
//#endregion
|
|
8
|
+
export { n as default };
|
|
9
|
+
|
|
10
|
+
//# sourceMappingURL=usage-tab.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage-tab.js","names":[],"sources":["../../src/routes/usage-tab.tsx"],"sourcesContent":["import { UsagePanel } from \"#/components/features/conversation/usage-panel/usage-panel\";\n\nfunction UsageTab() {\n return <UsagePanel />;\n}\n\nexport default UsageTab;\n"],"mappings":";;;AAEA,SAAS,IAAW;CAClB,OAAO,kBAAC,GAAD,CAAa,CAAA;AACtB"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
require("../_virtual/_rolldown/runtime.cjs");const e=require("../i18n/declaration.cjs"),t=require("../api/agent-server-compatibility.cjs"),n=require("../utils/base-path.cjs"),r=require("../i18n/index.cjs"),i=require("../utils/custom-toast-handlers.cjs"),a=require("../constants/child-conversation.cjs"),o=require("../stores/goal-store.cjs"),s=require("../api/conversation-metadata-store.cjs"),c=require("../api/cloud/conversation-service.api.cjs"),l=require("../api/conversation-service/agent-server-conversation-service.api.cjs");var u=3e3,d=18e4,f=`openhands-child-conversation-launches:`,p=(e,t)=>({status:`error`,error:e,guidance:t}),m=e=>e.map(e=>`"${e}"`).join(` or `),h=e=>e?.trim()||null;function g(e){let t=e.target;if(!a.CHILD_CONVERSATION_TARGETS.includes(t))return{ok:!1,failure:p(`Unknown target ${JSON.stringify(e.target)}.`,`\`target\` must be exactly ${m(a.CHILD_CONVERSATION_TARGETS)}. Nothing was launched — call ${a.LAUNCH_CHILD_CONVERSATION_TOOL_NAME} again with a valid target.`)};let n=h(e.task);if(!n)return{ok:!1,failure:p("`task` is empty.","`task` must be a self-contained brief: the child conversation cannot see this one, so state the goal, constraints and expected output.")};let r=h(e.repository),i=h(e.branch),o=h(e.isolation);return t===`local`&&(r||i)?{ok:!1,failure:p('`repository`/`branch` were passed with target="local".','A local child always runs in this conversation\'s workspace. Drop `repository` and `branch`, or use target="cloud" to run against a repository in a Cloud sandbox.')}:t===`cloud`&&o?{ok:!1,failure:p('`isolation` was passed with target="cloud".','Cloud children always run in their own isolated sandbox. Drop `isolation`, or use target="local" to choose between "worktree" and "shared".')}:i&&!r?{ok:!1,failure:p("`branch` was passed without `repository`.",'Pass `repository` as "owner/repo" alongside `branch`, or drop `branch` to use the repository\'s default branch.')}:o&&!a.CHILD_CONVERSATION_ISOLATIONS.includes(o)?{ok:!1,failure:p(`Unknown isolation ${JSON.stringify(e.isolation)}.`,`\`isolation\` must be exactly ${m(a.CHILD_CONVERSATION_ISOLATIONS)}. Nothing was launched — call ${a.LAUNCH_CHILD_CONVERSATION_TOOL_NAME} again with a valid isolation.`)}:{ok:!0,params:{target:t,task:n,title:h(e.title),repository:r,branch:i,isolation:o??`worktree`}}}function _(e,t){let n=`${f}${e}`,r=[];try{let e=window.localStorage.getItem(n),t=e?JSON.parse(e):null;Array.isArray(t)&&(r=t.filter(e=>typeof e==`string`))}catch{}if(r.includes(t))return!1;try{window.localStorage.setItem(n,JSON.stringify([...r,t]))}catch{}return!0}function v(e){let t=n.buildAgentCanvasPath(e);return typeof window>`u`?t:new URL(t,window.location.origin).toString()}function y(){let e=t.getCachedAgentServerVersion();if(!e)return null;let n=t.compareAgentServerVersions(e,a.MIN_AGENT_SERVER_VERSION_FOR_PARENT_LINK);return n===null||n>=0?null:`Agent server ${e} does not persist parent/child conversation links (needs ${a.MIN_AGENT_SERVER_VERSION_FOR_PARENT_LINK}); the child was created but is not linked to this conversation.`}var b=e=>!!(e?.selected_repository||e?.selected_workspace),x=`The child was launched in this conversation's directory instead, so it can see work in progress here and the two agents may conflict over the same files.`;async function S(e,t){let n=await l.default.resolveConversationWorkingDir(t),r=s.getStoredConversationMetadata(t),i=i=>l.default.createConversation(e.task,
|
|
1
|
+
require("../_virtual/_rolldown/runtime.cjs");const e=require("../i18n/declaration.cjs"),t=require("../api/agent-server-compatibility.cjs"),n=require("../utils/base-path.cjs"),r=require("../i18n/index.cjs"),i=require("../utils/custom-toast-handlers.cjs"),a=require("../constants/child-conversation.cjs"),o=require("../stores/goal-store.cjs"),s=require("../api/conversation-metadata-store.cjs"),c=require("../api/cloud/conversation-service.api.cjs"),l=require("../api/conversation-service/agent-server-conversation-service.api.cjs");var u=3e3,d=18e4,f=`openhands-child-conversation-launches:`,p=(e,t)=>({status:`error`,error:e,guidance:t}),m=e=>e.map(e=>`"${e}"`).join(` or `),h=e=>e?.trim()||null;function g(e){let t=e.target;if(!a.CHILD_CONVERSATION_TARGETS.includes(t))return{ok:!1,failure:p(`Unknown target ${JSON.stringify(e.target)}.`,`\`target\` must be exactly ${m(a.CHILD_CONVERSATION_TARGETS)}. Nothing was launched — call ${a.LAUNCH_CHILD_CONVERSATION_TOOL_NAME} again with a valid target.`)};let n=h(e.task);if(!n)return{ok:!1,failure:p("`task` is empty.","`task` must be a self-contained brief: the child conversation cannot see this one, so state the goal, constraints and expected output.")};let r=h(e.repository),i=h(e.branch),o=h(e.isolation);return t===`local`&&(r||i)?{ok:!1,failure:p('`repository`/`branch` were passed with target="local".','A local child always runs in this conversation\'s workspace. Drop `repository` and `branch`, or use target="cloud" to run against a repository in a Cloud sandbox.')}:t===`cloud`&&o?{ok:!1,failure:p('`isolation` was passed with target="cloud".','Cloud children always run in their own isolated sandbox. Drop `isolation`, or use target="local" to choose between "worktree" and "shared".')}:i&&!r?{ok:!1,failure:p("`branch` was passed without `repository`.",'Pass `repository` as "owner/repo" alongside `branch`, or drop `branch` to use the repository\'s default branch.')}:o&&!a.CHILD_CONVERSATION_ISOLATIONS.includes(o)?{ok:!1,failure:p(`Unknown isolation ${JSON.stringify(e.isolation)}.`,`\`isolation\` must be exactly ${m(a.CHILD_CONVERSATION_ISOLATIONS)}. Nothing was launched — call ${a.LAUNCH_CHILD_CONVERSATION_TOOL_NAME} again with a valid isolation.`)}:{ok:!0,params:{target:t,task:n,title:h(e.title),repository:r,branch:i,isolation:o??`worktree`}}}function _(e,t){let n=`${f}${e}`,r=[];try{let e=window.localStorage.getItem(n),t=e?JSON.parse(e):null;Array.isArray(t)&&(r=t.filter(e=>typeof e==`string`))}catch{}if(r.includes(t))return!1;try{window.localStorage.setItem(n,JSON.stringify([...r,t]))}catch{}return!0}function v(e){let t=n.buildAgentCanvasPath(e);return typeof window>`u`?t:new URL(t,window.location.origin).toString()}function y(){let e=t.getCachedAgentServerVersion();if(!e)return null;let n=t.compareAgentServerVersions(e,a.MIN_AGENT_SERVER_VERSION_FOR_PARENT_LINK);return n===null||n>=0?null:`Agent server ${e} does not persist parent/child conversation links (needs ${a.MIN_AGENT_SERVER_VERSION_FOR_PARENT_LINK}); the child was created but is not linked to this conversation.`}var b=e=>!!(e?.selected_repository||e?.selected_workspace),x=`The child was launched in this conversation's directory instead, so it can see work in progress here and the two agents may conflict over the same files.`;async function S(e,t){let n=await l.default.resolveConversationWorkingDir(t),r=s.getStoredConversationMetadata(t),i=i=>l.default.createConversation({initialUserMsg:e.task,metadata:r?{selected_repository:r.selected_repository,selected_branch:r.selected_branch,git_provider:r.git_provider}:null,workingDirOverride:n,workspaceMode:i===`shared`?`local_repo`:`new_worktree`,parentConversationId:t}),a=e.isolation,o=null;a===`worktree`&&!b(r)&&(a=`shared`,o=`This conversation's workspace is a scratch directory with no commits, which git cannot cut a worktree from. ${x}`);let c;try{c=await i(a)}catch(e){if(a!==`worktree`)throw e;try{c=await i(`shared`)}catch{throw e}a=`shared`,o=`Creating a git worktree in this conversation's workspace failed (${e instanceof Error?e.message:String(e)}). ${x}`}let u=c.app_conversation_id??c.id;e.title&&await l.default.updateConversationTitle(u,e.title).catch(()=>void 0);let d=y();return{status:`launched`,target:`local`,conversation_id:u,url:v(`/conversations/${u}`),initial_status:c.status,title:e.title,workspace:n,isolation:a,...o?{isolation_note:o}:{},parent_link:!d,...d?{parent_link_note:d}:{}}}var C=e=>new Promise(t=>{setTimeout(t,e)});async function w(e,t){let n=Date.now()+d,r=e;for(;!r.app_conversation_id&&r.status!==`ERROR`&&!(Date.now()>=n);){await C(u);let e=await c.getCloudAppConversationStartTask(r.id,t).catch(()=>null);if(!e)break;r=e}return r}async function T(e,t){let n=c.pickCloudBackendForLaunch();if(!n)return p(`No OpenHands Cloud backend is connected in Agent Canvas.`,`Ask the user to connect OpenHands Cloud from the backend picker, then call this tool again — or relaunch now with target="local".`);let r=s.getStoredConversationMetadata(t),i=await w(await c.createCloudAppConversation({initial_message:{role:`user`,content:[{type:`text`,text:e.task}]},title:e.title,selected_repository:e.repository??r?.selected_repository??null,selected_branch:e.branch??null,git_provider:e.repository?null:r?.git_provider??null,parent_conversation_id:null},n),n);if(i.status===`ERROR`)return p(i.detail||`The Cloud conversation failed to start.`,`The Cloud sandbox could not be provisioned. Report this to the user; you can retry, or fall back to target="local".`);let a=i.app_conversation_id;return{status:`launched`,target:`cloud`,conversation_id:a,url:a?`${n.host.replace(/\/$/,``)}/conversations/${a}`:null,initial_status:i.status,title:e.title,start_task_id:i.id,backend:n.name,parent_link:!1,parent_link_note:`This conversation runs on the local agent server, so OpenHands Cloud has no parent to link the child to.`}}async function E(t,n){n.status===`error`?i.displayErrorToast(r.default.t(e.I18nKey.CHILD_CONVERSATION$LAUNCH_FAILED,{error:n.error})):n.url&&i.displaySuccessToastWithLink(r.default.t(n.target===`cloud`?e.I18nKey.CHILD_CONVERSATION$LAUNCHED_CLOUD:e.I18nKey.CHILD_CONVERSATION$LAUNCHED_LOCAL),r.default.t(e.I18nKey.CHILD_CONVERSATION$OPEN),n.url),!o.useGoalStore.getState().statusByConversation[t]?.active&&await l.default.sendMessage(t,{role:`user`,content:[{type:`text`,text:`${a.CHILD_CONVERSATION_RESULT_PREFIX}${JSON.stringify(n)}`}]})}async function D(e,t,n){if(!_(t,n))return;let r=g(e),i;if(!r.ok)i=r.failure;else try{i=r.params.target===`cloud`?await T(r.params,t):await S(r.params,t)}catch(e){i=p(e instanceof Error?e.message:String(e),`The launch request failed. Report the error to the user; retry only if the cause looks transient.`)}await E(t,i).catch(e=>{console.warn(`[${a.LAUNCH_CHILD_CONVERSATION_TOOL_NAME}] Failed to report the launch result:`,e)})}exports.handleLaunchChildConversationAction=D;
|
|
2
2
|
//# sourceMappingURL=child-conversation-launch.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"child-conversation-launch.cjs","names":[],"sources":["../../src/services/child-conversation-launch.ts"],"sourcesContent":["import i18n from \"#/i18n\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport {\n compareAgentServerVersions,\n getCachedAgentServerVersion,\n} from \"#/api/agent-server-compatibility\";\nimport {\n createCloudAppConversation,\n getCloudAppConversationStartTask,\n pickCloudBackendForLaunch,\n} from \"#/api/cloud/conversation-service.api\";\nimport type { Backend } from \"#/api/backend-registry/types\";\nimport {\n getStoredConversationMetadata,\n type ConversationMetadata,\n} from \"#/api/conversation-metadata-store\";\nimport AgentServerConversationService from \"#/api/conversation-service/agent-server-conversation-service.api\";\nimport type { AppConversationStartTask } from \"#/api/conversation-service/agent-server-conversation-service.types\";\nimport {\n CHILD_CONVERSATION_ISOLATIONS,\n CHILD_CONVERSATION_RESULT_PREFIX,\n CHILD_CONVERSATION_TARGETS,\n LAUNCH_CHILD_CONVERSATION_TOOL_NAME,\n MIN_AGENT_SERVER_VERSION_FOR_PARENT_LINK,\n type ChildConversationIsolation,\n type ChildConversationTarget,\n} from \"#/constants/child-conversation\";\nimport { useGoalStore } from \"#/stores/goal-store\";\nimport type { LaunchChildConversationAction } from \"#/types/agent-server/core\";\nimport { buildAgentCanvasPath } from \"#/utils/base-path\";\nimport {\n displayErrorToast,\n displaySuccessToastWithLink,\n} from \"#/utils/custom-toast-handlers\";\n\n/** Cadence and ceiling for waiting on a Cloud sandbox to expose its id. */\nconst CLOUD_START_POLL_INTERVAL_MS = 3_000;\nconst CLOUD_START_POLL_TIMEOUT_MS = 180_000;\n\nconst LEDGER_STORAGE_KEY_PREFIX = \"openhands-child-conversation-launches:\";\n\ninterface LaunchSuccess {\n status: \"launched\";\n target: ChildConversationTarget;\n conversation_id: string | null;\n url: string | null;\n initial_status: string;\n title: string | null;\n /** Local only: the directory the child inherited from this conversation. */\n workspace?: string;\n /** Local only: which isolation mode was actually applied. */\n isolation?: ChildConversationIsolation;\n /**\n * Present when the applied isolation is not the one that was asked for,\n * explaining why and what it means for the child.\n */\n isolation_note?: string;\n /** Cloud only: poll this if `conversation_id` is still null. */\n start_task_id?: string;\n /** Cloud only: which connected Cloud backend the child was launched on. */\n backend?: string;\n /** Whether the parent/child link was persisted server-side. */\n parent_link: boolean;\n /** Present when `parent_link` is false, explaining why. */\n parent_link_note?: string;\n}\n\ninterface LaunchFailure {\n status: \"error\";\n error: string;\n guidance: string;\n}\n\nexport type LaunchChildConversationResult = LaunchSuccess | LaunchFailure;\n\ninterface ValidatedParams {\n target: ChildConversationTarget;\n task: string;\n title: string | null;\n repository: string | null;\n branch: string | null;\n isolation: ChildConversationIsolation;\n}\n\nconst failure = (error: string, guidance: string): LaunchFailure => ({\n status: \"error\",\n error,\n guidance,\n});\n\nconst quoted = (values: readonly string[]) =>\n values.map((value) => `\"${value}\"`).join(\" or \");\n\nconst blankToNull = (value: string | null | undefined) => {\n const trimmed = value?.trim();\n return trimmed ? trimmed : null;\n};\n\n/**\n * Validate what the agent-server cannot.\n *\n * The tool's JSON Schema is turned into a pydantic model with `extra=\"forbid\"`,\n * so unknown/misspelled parameter names, missing required parameters and wrong\n * types already fail server-side with a corrective message. `enum` is the gap:\n * the SDK advertises it to the LLM but drops it when building the model, so a\n * misspelled `target` reaches us intact and must be rejected here. The\n * cross-target rules (cloud-only / local-only parameters) are ours to enforce\n * too, since a schema cannot express them.\n */\nfunction validateLaunchParams(\n action: LaunchChildConversationAction,\n):\n | { ok: true; params: ValidatedParams }\n | { ok: false; failure: LaunchFailure } {\n const target = action.target as ChildConversationTarget;\n if (!CHILD_CONVERSATION_TARGETS.includes(target)) {\n return {\n ok: false,\n failure: failure(\n `Unknown target ${JSON.stringify(action.target)}.`,\n `\\`target\\` must be exactly ${quoted(CHILD_CONVERSATION_TARGETS)}. Nothing was launched — call ${LAUNCH_CHILD_CONVERSATION_TOOL_NAME} again with a valid target.`,\n ),\n };\n }\n\n const task = blankToNull(action.task);\n if (!task) {\n return {\n ok: false,\n failure: failure(\n \"`task` is empty.\",\n \"`task` must be a self-contained brief: the child conversation cannot see this one, so state the goal, constraints and expected output.\",\n ),\n };\n }\n\n const repository = blankToNull(action.repository);\n const branch = blankToNull(action.branch);\n const isolation = blankToNull(\n action.isolation,\n ) as ChildConversationIsolation | null;\n\n if (target === \"local\" && (repository || branch)) {\n return {\n ok: false,\n failure: failure(\n '`repository`/`branch` were passed with target=\"local\".',\n 'A local child always runs in this conversation\\'s workspace. Drop `repository` and `branch`, or use target=\"cloud\" to run against a repository in a Cloud sandbox.',\n ),\n };\n }\n\n if (target === \"cloud\" && isolation) {\n return {\n ok: false,\n failure: failure(\n '`isolation` was passed with target=\"cloud\".',\n 'Cloud children always run in their own isolated sandbox. Drop `isolation`, or use target=\"local\" to choose between \"worktree\" and \"shared\".',\n ),\n };\n }\n\n if (branch && !repository) {\n return {\n ok: false,\n failure: failure(\n \"`branch` was passed without `repository`.\",\n 'Pass `repository` as \"owner/repo\" alongside `branch`, or drop `branch` to use the repository\\'s default branch.',\n ),\n };\n }\n\n if (isolation && !CHILD_CONVERSATION_ISOLATIONS.includes(isolation)) {\n return {\n ok: false,\n failure: failure(\n `Unknown isolation ${JSON.stringify(action.isolation)}.`,\n `\\`isolation\\` must be exactly ${quoted(CHILD_CONVERSATION_ISOLATIONS)}. Nothing was launched — call ${LAUNCH_CHILD_CONVERSATION_TOOL_NAME} again with a valid isolation.`,\n ),\n };\n }\n\n return {\n ok: true,\n params: {\n target,\n task,\n title: blankToNull(action.title),\n repository,\n branch,\n isolation: isolation ?? \"worktree\",\n },\n };\n}\n\n/**\n * Remember which tool calls have already been acted on.\n *\n * Unlike the Canvas UI tool, a launch is not idempotent: replaying its\n * ActionEvent (a socket reconnect that falls back to `resend_mode: \"all\"`, or a\n * REST/WebSocket race after a reload) would start a second — on Cloud, billable\n * — conversation. Claim the tool call before any network work so a replay that\n * arrives mid-flight is dropped too.\n */\nfunction claimToolCall(parentConversationId: string, toolCallId: string) {\n const key = `${LEDGER_STORAGE_KEY_PREFIX}${parentConversationId}`;\n let handled: string[] = [];\n try {\n const raw = window.localStorage.getItem(key);\n const parsed: unknown = raw ? JSON.parse(raw) : null;\n if (Array.isArray(parsed)) {\n handled = parsed.filter((id): id is string => typeof id === \"string\");\n }\n } catch {\n // A corrupt ledger must not block the launch; start a fresh one.\n }\n\n if (handled.includes(toolCallId)) return false;\n\n try {\n window.localStorage.setItem(key, JSON.stringify([...handled, toolCallId]));\n } catch {\n // Storage full or unavailable — proceed, accepting replay risk over never\n // launching at all.\n }\n return true;\n}\n\nfunction absoluteCanvasUrl(path: string) {\n const canvasPath = buildAgentCanvasPath(path);\n if (typeof window === \"undefined\") return canvasPath;\n return new URL(canvasPath, window.location.origin).toString();\n}\n\n/**\n * `parent_conversation_id` on the local start request landed in agent-server\n * 1.37.1. Older servers ignore unknown fields, so the child is created without\n * the link — report that rather than letting the agent assume a relationship\n * that does not exist.\n */\nfunction localParentLinkNote(): string | null {\n const version = getCachedAgentServerVersion();\n if (!version) return null;\n const comparison = compareAgentServerVersions(\n version,\n MIN_AGENT_SERVER_VERSION_FOR_PARENT_LINK,\n );\n if (comparison === null || comparison >= 0) return null;\n return `Agent server ${version} does not persist parent/child conversation links (needs ${MIN_AGENT_SERVER_VERSION_FOR_PARENT_LINK}); the child was created but is not linked to this conversation.`;\n}\n\n/**\n * Whether the parent's workspace can host a git worktree.\n *\n * A conversation started without a repository or an attached workspace runs in\n * a scratch directory that is `git init`-ed but never committed to. `git\n * worktree add` cannot branch from an unborn HEAD, and the agent-server raises\n * the resulting error straight out of its start-conversation handler as a 500,\n * so asking for a worktree there fails the whole launch. Conversation metadata\n * is only persisted when a repository or an explicit workspace was chosen (see\n * `createConversation`), so its absence pinpoints exactly those scratch\n * workspaces. Anything else is attempted and falls back on failure, because the\n * frontend cannot inspect the workspace's git state directly.\n */\nconst parentSupportsWorktree = (\n metadata: ConversationMetadata | null,\n): boolean => !!(metadata?.selected_repository || metadata?.selected_workspace);\n\nconst SHARED_FALLBACK_CONSEQUENCE =\n \"The child was launched in this conversation's directory instead, so it can see work in progress here and the two agents may conflict over the same files.\";\n\nasync function launchLocalChild(\n params: ValidatedParams,\n parentConversationId: string,\n): Promise<LaunchChildConversationResult> {\n // The agent-server rejects a parent whose workspace differs from the child's,\n // so the child requests the parent's own directory. `worktree` then carves an\n // isolated worktree out of it, which is what keeps siblings from colliding.\n const workspace =\n await AgentServerConversationService.resolveConversationWorkingDir(\n parentConversationId,\n );\n const parentMetadata = getStoredConversationMetadata(parentConversationId);\n\n const createChild = (isolation: ChildConversationIsolation) =>\n AgentServerConversationService.createConversation(\n params.task,\n undefined,\n undefined,\n parentMetadata\n ? {\n selected_repository: parentMetadata.selected_repository,\n selected_branch: parentMetadata.selected_branch,\n git_provider: parentMetadata.git_provider,\n }\n : null,\n workspace,\n isolation === \"shared\" ? \"local_repo\" : \"new_worktree\",\n parentConversationId,\n );\n\n let isolation = params.isolation;\n let isolationNote: string | null = null;\n\n if (isolation === \"worktree\" && !parentSupportsWorktree(parentMetadata)) {\n isolation = \"shared\";\n isolationNote = `This conversation's workspace is a scratch directory with no commits, which git cannot cut a worktree from. ${SHARED_FALLBACK_CONSEQUENCE}`;\n }\n\n let startTask;\n try {\n startTask = await createChild(isolation);\n } catch (worktreeError) {\n if (isolation !== \"worktree\") throw worktreeError;\n // Creating the worktree is the one part of a local launch that can fail on\n // an otherwise healthy workspace, so retry without it rather than losing\n // the launch. Anything else fails both attempts and is reported as-is.\n try {\n startTask = await createChild(\"shared\");\n } catch {\n throw worktreeError;\n }\n isolation = \"shared\";\n isolationNote = `Creating a git worktree in this conversation's workspace failed (${worktreeError instanceof Error ? worktreeError.message : String(worktreeError)}). ${SHARED_FALLBACK_CONSEQUENCE}`;\n }\n\n const conversationId = startTask.app_conversation_id ?? startTask.id;\n\n if (params.title) {\n // Local start requests carry no title — only `autotitle`. Best effort: a\n // failed rename must not fail the launch.\n await AgentServerConversationService.updateConversationTitle(\n conversationId,\n params.title,\n ).catch(() => undefined);\n }\n\n const parentLinkNote = localParentLinkNote();\n return {\n status: \"launched\",\n target: \"local\",\n conversation_id: conversationId,\n url: absoluteCanvasUrl(`/conversations/${conversationId}`),\n initial_status: startTask.status,\n title: params.title,\n workspace,\n isolation,\n ...(isolationNote ? { isolation_note: isolationNote } : {}),\n parent_link: !parentLinkNote,\n ...(parentLinkNote ? { parent_link_note: parentLinkNote } : {}),\n };\n}\n\nconst delay = (ms: number) =>\n new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n\n/**\n * Wait for the Cloud start task to expose its conversation id.\n *\n * The Cloud API provisions a sandbox asynchronously and only fills in\n * `app_conversation_id` once the task reaches READY, so without this the agent\n * would get a result with no conversation to open. Bounded: on timeout the\n * caller reports the still-provisioning task instead of hanging.\n */\nasync function waitForCloudConversationId(\n task: AppConversationStartTask,\n backend: Backend,\n): Promise<AppConversationStartTask> {\n const deadline = Date.now() + CLOUD_START_POLL_TIMEOUT_MS;\n let latest = task;\n while (!latest.app_conversation_id && latest.status !== \"ERROR\") {\n if (Date.now() >= deadline) break;\n\n await delay(CLOUD_START_POLL_INTERVAL_MS);\n\n const next = await getCloudAppConversationStartTask(\n latest.id,\n backend,\n ).catch(() => null);\n if (!next) break;\n latest = next;\n }\n return latest;\n}\n\nasync function launchCloudChild(\n params: ValidatedParams,\n parentConversationId: string,\n): Promise<LaunchChildConversationResult> {\n const backend = pickCloudBackendForLaunch();\n if (!backend) {\n return failure(\n \"No OpenHands Cloud backend is connected in Agent Canvas.\",\n 'Ask the user to connect OpenHands Cloud from the backend picker, then call this tool again — or relaunch now with target=\"local\".',\n );\n }\n\n const parentMetadata = getStoredConversationMetadata(parentConversationId);\n const startTask = await createCloudAppConversation(\n {\n initial_message: {\n role: \"user\",\n content: [{ type: \"text\", text: params.task }],\n },\n title: params.title,\n // Fall back to this conversation's repository so a bare `target: \"cloud\"`\n // call still lands the child on the code the user is working on. The\n // provider only travels with the inherited repository — it may not apply\n // to one the agent named itself.\n selected_repository:\n params.repository ?? parentMetadata?.selected_repository ?? null,\n selected_branch: params.branch ?? null,\n git_provider: params.repository\n ? null\n : (parentMetadata?.git_provider ?? null),\n // The parent runs on the local agent-server, so its id means nothing to\n // Cloud. Sending it would only hide the child from the Cloud\n // conversation list, which filters out anything with a parent.\n parent_conversation_id: null,\n },\n backend,\n );\n\n const settled = await waitForCloudConversationId(startTask, backend);\n if (settled.status === \"ERROR\") {\n return failure(\n settled.detail || \"The Cloud conversation failed to start.\",\n 'The Cloud sandbox could not be provisioned. Report this to the user; you can retry, or fall back to target=\"local\".',\n );\n }\n\n const conversationId = settled.app_conversation_id;\n return {\n status: \"launched\",\n target: \"cloud\",\n conversation_id: conversationId,\n url: conversationId\n ? `${backend.host.replace(/\\/$/, \"\")}/conversations/${conversationId}`\n : null,\n initial_status: settled.status,\n title: params.title,\n start_task_id: settled.id,\n backend: backend.name,\n // Cloud children of a local parent carry no server-side link; see above.\n parent_link: false,\n parent_link_note:\n \"This conversation runs on the local agent server, so OpenHands Cloud has no parent to link the child to.\",\n };\n}\n\n/**\n * Hand the outcome back to the agent and the user.\n *\n * Client tools are acknowledged by the agent-server before the browser does any\n * work, so a message is the only way to give the agent the child's id or tell\n * it how to fix a malformed call. `sendMessage` runs the agent, which is what\n * makes it relay the result to the user in its next turn.\n */\nasync function reportLaunchResult(\n parentConversationId: string,\n result: LaunchChildConversationResult,\n) {\n if (result.status === \"error\") {\n displayErrorToast(\n i18n.t(I18nKey.CHILD_CONVERSATION$LAUNCH_FAILED, {\n error: result.error,\n }),\n );\n } else if (result.url) {\n displaySuccessToastWithLink(\n i18n.t(\n result.target === \"cloud\"\n ? I18nKey.CHILD_CONVERSATION$LAUNCHED_CLOUD\n : I18nKey.CHILD_CONVERSATION$LAUNCHED_LOCAL,\n ),\n i18n.t(I18nKey.CHILD_CONVERSATION$OPEN),\n result.url,\n );\n }\n\n // The agent-server cancels an active `/goal` loop on any inbound message, so\n // a launch must not silently end one. The toast above still tells the user\n // what happened.\n const goalStatus =\n useGoalStore.getState().statusByConversation[parentConversationId];\n if (goalStatus?.active) return;\n\n await AgentServerConversationService.sendMessage(parentConversationId, {\n role: \"user\",\n content: [\n {\n type: \"text\",\n text: `${CHILD_CONVERSATION_RESULT_PREFIX}${JSON.stringify(result)}`,\n },\n ],\n });\n}\n\n/**\n * Execute a `launch_child_conversation` tool call.\n *\n * Never rejects: every failure is turned into corrective guidance for the\n * agent, because the agent-server has already told it the call succeeded.\n */\nexport async function handleLaunchChildConversationAction(\n action: LaunchChildConversationAction,\n parentConversationId: string,\n toolCallId: string,\n): Promise<void> {\n if (!claimToolCall(parentConversationId, toolCallId)) return;\n\n const validation = validateLaunchParams(action);\n let result: LaunchChildConversationResult;\n if (!validation.ok) {\n result = validation.failure;\n } else {\n try {\n result =\n validation.params.target === \"cloud\"\n ? await launchCloudChild(validation.params, parentConversationId)\n : await launchLocalChild(validation.params, parentConversationId);\n } catch (error) {\n result = failure(\n error instanceof Error ? error.message : String(error),\n \"The launch request failed. Report the error to the user; retry only if the cause looks transient.\",\n );\n }\n }\n\n await reportLaunchResult(parentConversationId, result).catch((error) => {\n console.warn(\n `[${LAUNCH_CHILD_CONVERSATION_TOOL_NAME}] Failed to report the launch result:`,\n error,\n );\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"child-conversation-launch.cjs","names":[],"sources":["../../src/services/child-conversation-launch.ts"],"sourcesContent":["import i18n from \"#/i18n\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport {\n compareAgentServerVersions,\n getCachedAgentServerVersion,\n} from \"#/api/agent-server-compatibility\";\nimport {\n createCloudAppConversation,\n getCloudAppConversationStartTask,\n pickCloudBackendForLaunch,\n} from \"#/api/cloud/conversation-service.api\";\nimport type { Backend } from \"#/api/backend-registry/types\";\nimport {\n getStoredConversationMetadata,\n type ConversationMetadata,\n} from \"#/api/conversation-metadata-store\";\nimport AgentServerConversationService from \"#/api/conversation-service/agent-server-conversation-service.api\";\nimport type { AppConversationStartTask } from \"#/api/conversation-service/agent-server-conversation-service.types\";\nimport {\n CHILD_CONVERSATION_ISOLATIONS,\n CHILD_CONVERSATION_RESULT_PREFIX,\n CHILD_CONVERSATION_TARGETS,\n LAUNCH_CHILD_CONVERSATION_TOOL_NAME,\n MIN_AGENT_SERVER_VERSION_FOR_PARENT_LINK,\n type ChildConversationIsolation,\n type ChildConversationTarget,\n} from \"#/constants/child-conversation\";\nimport { useGoalStore } from \"#/stores/goal-store\";\nimport type { LaunchChildConversationAction } from \"#/types/agent-server/core\";\nimport { buildAgentCanvasPath } from \"#/utils/base-path\";\nimport {\n displayErrorToast,\n displaySuccessToastWithLink,\n} from \"#/utils/custom-toast-handlers\";\n\n/** Cadence and ceiling for waiting on a Cloud sandbox to expose its id. */\nconst CLOUD_START_POLL_INTERVAL_MS = 3_000;\nconst CLOUD_START_POLL_TIMEOUT_MS = 180_000;\n\nconst LEDGER_STORAGE_KEY_PREFIX = \"openhands-child-conversation-launches:\";\n\ninterface LaunchSuccess {\n status: \"launched\";\n target: ChildConversationTarget;\n conversation_id: string | null;\n url: string | null;\n initial_status: string;\n title: string | null;\n /** Local only: the directory the child inherited from this conversation. */\n workspace?: string;\n /** Local only: which isolation mode was actually applied. */\n isolation?: ChildConversationIsolation;\n /**\n * Present when the applied isolation is not the one that was asked for,\n * explaining why and what it means for the child.\n */\n isolation_note?: string;\n /** Cloud only: poll this if `conversation_id` is still null. */\n start_task_id?: string;\n /** Cloud only: which connected Cloud backend the child was launched on. */\n backend?: string;\n /** Whether the parent/child link was persisted server-side. */\n parent_link: boolean;\n /** Present when `parent_link` is false, explaining why. */\n parent_link_note?: string;\n}\n\ninterface LaunchFailure {\n status: \"error\";\n error: string;\n guidance: string;\n}\n\nexport type LaunchChildConversationResult = LaunchSuccess | LaunchFailure;\n\ninterface ValidatedParams {\n target: ChildConversationTarget;\n task: string;\n title: string | null;\n repository: string | null;\n branch: string | null;\n isolation: ChildConversationIsolation;\n}\n\nconst failure = (error: string, guidance: string): LaunchFailure => ({\n status: \"error\",\n error,\n guidance,\n});\n\nconst quoted = (values: readonly string[]) =>\n values.map((value) => `\"${value}\"`).join(\" or \");\n\nconst blankToNull = (value: string | null | undefined) => {\n const trimmed = value?.trim();\n return trimmed ? trimmed : null;\n};\n\n/**\n * Validate what the agent-server cannot.\n *\n * The tool's JSON Schema is turned into a pydantic model with `extra=\"forbid\"`,\n * so unknown/misspelled parameter names, missing required parameters and wrong\n * types already fail server-side with a corrective message. `enum` is the gap:\n * the SDK advertises it to the LLM but drops it when building the model, so a\n * misspelled `target` reaches us intact and must be rejected here. The\n * cross-target rules (cloud-only / local-only parameters) are ours to enforce\n * too, since a schema cannot express them.\n */\nfunction validateLaunchParams(\n action: LaunchChildConversationAction,\n):\n | { ok: true; params: ValidatedParams }\n | { ok: false; failure: LaunchFailure } {\n const target = action.target as ChildConversationTarget;\n if (!CHILD_CONVERSATION_TARGETS.includes(target)) {\n return {\n ok: false,\n failure: failure(\n `Unknown target ${JSON.stringify(action.target)}.`,\n `\\`target\\` must be exactly ${quoted(CHILD_CONVERSATION_TARGETS)}. Nothing was launched — call ${LAUNCH_CHILD_CONVERSATION_TOOL_NAME} again with a valid target.`,\n ),\n };\n }\n\n const task = blankToNull(action.task);\n if (!task) {\n return {\n ok: false,\n failure: failure(\n \"`task` is empty.\",\n \"`task` must be a self-contained brief: the child conversation cannot see this one, so state the goal, constraints and expected output.\",\n ),\n };\n }\n\n const repository = blankToNull(action.repository);\n const branch = blankToNull(action.branch);\n const isolation = blankToNull(\n action.isolation,\n ) as ChildConversationIsolation | null;\n\n if (target === \"local\" && (repository || branch)) {\n return {\n ok: false,\n failure: failure(\n '`repository`/`branch` were passed with target=\"local\".',\n 'A local child always runs in this conversation\\'s workspace. Drop `repository` and `branch`, or use target=\"cloud\" to run against a repository in a Cloud sandbox.',\n ),\n };\n }\n\n if (target === \"cloud\" && isolation) {\n return {\n ok: false,\n failure: failure(\n '`isolation` was passed with target=\"cloud\".',\n 'Cloud children always run in their own isolated sandbox. Drop `isolation`, or use target=\"local\" to choose between \"worktree\" and \"shared\".',\n ),\n };\n }\n\n if (branch && !repository) {\n return {\n ok: false,\n failure: failure(\n \"`branch` was passed without `repository`.\",\n 'Pass `repository` as \"owner/repo\" alongside `branch`, or drop `branch` to use the repository\\'s default branch.',\n ),\n };\n }\n\n if (isolation && !CHILD_CONVERSATION_ISOLATIONS.includes(isolation)) {\n return {\n ok: false,\n failure: failure(\n `Unknown isolation ${JSON.stringify(action.isolation)}.`,\n `\\`isolation\\` must be exactly ${quoted(CHILD_CONVERSATION_ISOLATIONS)}. Nothing was launched — call ${LAUNCH_CHILD_CONVERSATION_TOOL_NAME} again with a valid isolation.`,\n ),\n };\n }\n\n return {\n ok: true,\n params: {\n target,\n task,\n title: blankToNull(action.title),\n repository,\n branch,\n isolation: isolation ?? \"worktree\",\n },\n };\n}\n\n/**\n * Remember which tool calls have already been acted on.\n *\n * Unlike the Canvas UI tool, a launch is not idempotent: replaying its\n * ActionEvent (a socket reconnect that falls back to `resend_mode: \"all\"`, or a\n * REST/WebSocket race after a reload) would start a second — on Cloud, billable\n * — conversation. Claim the tool call before any network work so a replay that\n * arrives mid-flight is dropped too.\n */\nfunction claimToolCall(parentConversationId: string, toolCallId: string) {\n const key = `${LEDGER_STORAGE_KEY_PREFIX}${parentConversationId}`;\n let handled: string[] = [];\n try {\n const raw = window.localStorage.getItem(key);\n const parsed: unknown = raw ? JSON.parse(raw) : null;\n if (Array.isArray(parsed)) {\n handled = parsed.filter((id): id is string => typeof id === \"string\");\n }\n } catch {\n // A corrupt ledger must not block the launch; start a fresh one.\n }\n\n if (handled.includes(toolCallId)) return false;\n\n try {\n window.localStorage.setItem(key, JSON.stringify([...handled, toolCallId]));\n } catch {\n // Storage full or unavailable — proceed, accepting replay risk over never\n // launching at all.\n }\n return true;\n}\n\nfunction absoluteCanvasUrl(path: string) {\n const canvasPath = buildAgentCanvasPath(path);\n if (typeof window === \"undefined\") return canvasPath;\n return new URL(canvasPath, window.location.origin).toString();\n}\n\n/**\n * `parent_conversation_id` on the local start request landed in agent-server\n * 1.37.1. Older servers ignore unknown fields, so the child is created without\n * the link — report that rather than letting the agent assume a relationship\n * that does not exist.\n */\nfunction localParentLinkNote(): string | null {\n const version = getCachedAgentServerVersion();\n if (!version) return null;\n const comparison = compareAgentServerVersions(\n version,\n MIN_AGENT_SERVER_VERSION_FOR_PARENT_LINK,\n );\n if (comparison === null || comparison >= 0) return null;\n return `Agent server ${version} does not persist parent/child conversation links (needs ${MIN_AGENT_SERVER_VERSION_FOR_PARENT_LINK}); the child was created but is not linked to this conversation.`;\n}\n\n/**\n * Whether the parent's workspace can host a git worktree.\n *\n * A conversation started without a repository or an attached workspace runs in\n * a scratch directory that is `git init`-ed but never committed to. `git\n * worktree add` cannot branch from an unborn HEAD, and the agent-server raises\n * the resulting error straight out of its start-conversation handler as a 500,\n * so asking for a worktree there fails the whole launch. Conversation metadata\n * is only persisted when a repository or an explicit workspace was chosen (see\n * `createConversation`), so its absence pinpoints exactly those scratch\n * workspaces. Anything else is attempted and falls back on failure, because the\n * frontend cannot inspect the workspace's git state directly.\n */\nconst parentSupportsWorktree = (\n metadata: ConversationMetadata | null,\n): boolean => !!(metadata?.selected_repository || metadata?.selected_workspace);\n\nconst SHARED_FALLBACK_CONSEQUENCE =\n \"The child was launched in this conversation's directory instead, so it can see work in progress here and the two agents may conflict over the same files.\";\n\nasync function launchLocalChild(\n params: ValidatedParams,\n parentConversationId: string,\n): Promise<LaunchChildConversationResult> {\n // The agent-server rejects a parent whose workspace differs from the child's,\n // so the child requests the parent's own directory. `worktree` then carves an\n // isolated worktree out of it, which is what keeps siblings from colliding.\n const workspace =\n await AgentServerConversationService.resolveConversationWorkingDir(\n parentConversationId,\n );\n const parentMetadata = getStoredConversationMetadata(parentConversationId);\n\n const createChild = (isolation: ChildConversationIsolation) =>\n AgentServerConversationService.createConversation({\n initialUserMsg: params.task,\n metadata: parentMetadata\n ? {\n selected_repository: parentMetadata.selected_repository,\n selected_branch: parentMetadata.selected_branch,\n git_provider: parentMetadata.git_provider,\n }\n : null,\n workingDirOverride: workspace,\n workspaceMode: isolation === \"shared\" ? \"local_repo\" : \"new_worktree\",\n parentConversationId,\n });\n\n let isolation = params.isolation;\n let isolationNote: string | null = null;\n\n if (isolation === \"worktree\" && !parentSupportsWorktree(parentMetadata)) {\n isolation = \"shared\";\n isolationNote = `This conversation's workspace is a scratch directory with no commits, which git cannot cut a worktree from. ${SHARED_FALLBACK_CONSEQUENCE}`;\n }\n\n let startTask;\n try {\n startTask = await createChild(isolation);\n } catch (worktreeError) {\n if (isolation !== \"worktree\") throw worktreeError;\n // Creating the worktree is the one part of a local launch that can fail on\n // an otherwise healthy workspace, so retry without it rather than losing\n // the launch. Anything else fails both attempts and is reported as-is.\n try {\n startTask = await createChild(\"shared\");\n } catch {\n throw worktreeError;\n }\n isolation = \"shared\";\n isolationNote = `Creating a git worktree in this conversation's workspace failed (${worktreeError instanceof Error ? worktreeError.message : String(worktreeError)}). ${SHARED_FALLBACK_CONSEQUENCE}`;\n }\n\n const conversationId = startTask.app_conversation_id ?? startTask.id;\n\n if (params.title) {\n // Local start requests carry no title — only `autotitle`. Best effort: a\n // failed rename must not fail the launch.\n await AgentServerConversationService.updateConversationTitle(\n conversationId,\n params.title,\n ).catch(() => undefined);\n }\n\n const parentLinkNote = localParentLinkNote();\n return {\n status: \"launched\",\n target: \"local\",\n conversation_id: conversationId,\n url: absoluteCanvasUrl(`/conversations/${conversationId}`),\n initial_status: startTask.status,\n title: params.title,\n workspace,\n isolation,\n ...(isolationNote ? { isolation_note: isolationNote } : {}),\n parent_link: !parentLinkNote,\n ...(parentLinkNote ? { parent_link_note: parentLinkNote } : {}),\n };\n}\n\nconst delay = (ms: number) =>\n new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n\n/**\n * Wait for the Cloud start task to expose its conversation id.\n *\n * The Cloud API provisions a sandbox asynchronously and only fills in\n * `app_conversation_id` once the task reaches READY, so without this the agent\n * would get a result with no conversation to open. Bounded: on timeout the\n * caller reports the still-provisioning task instead of hanging.\n */\nasync function waitForCloudConversationId(\n task: AppConversationStartTask,\n backend: Backend,\n): Promise<AppConversationStartTask> {\n const deadline = Date.now() + CLOUD_START_POLL_TIMEOUT_MS;\n let latest = task;\n while (!latest.app_conversation_id && latest.status !== \"ERROR\") {\n if (Date.now() >= deadline) break;\n\n await delay(CLOUD_START_POLL_INTERVAL_MS);\n\n const next = await getCloudAppConversationStartTask(\n latest.id,\n backend,\n ).catch(() => null);\n if (!next) break;\n latest = next;\n }\n return latest;\n}\n\nasync function launchCloudChild(\n params: ValidatedParams,\n parentConversationId: string,\n): Promise<LaunchChildConversationResult> {\n const backend = pickCloudBackendForLaunch();\n if (!backend) {\n return failure(\n \"No OpenHands Cloud backend is connected in Agent Canvas.\",\n 'Ask the user to connect OpenHands Cloud from the backend picker, then call this tool again — or relaunch now with target=\"local\".',\n );\n }\n\n const parentMetadata = getStoredConversationMetadata(parentConversationId);\n const startTask = await createCloudAppConversation(\n {\n initial_message: {\n role: \"user\",\n content: [{ type: \"text\", text: params.task }],\n },\n title: params.title,\n // Fall back to this conversation's repository so a bare `target: \"cloud\"`\n // call still lands the child on the code the user is working on. The\n // provider only travels with the inherited repository — it may not apply\n // to one the agent named itself.\n selected_repository:\n params.repository ?? parentMetadata?.selected_repository ?? null,\n selected_branch: params.branch ?? null,\n git_provider: params.repository\n ? null\n : (parentMetadata?.git_provider ?? null),\n // The parent runs on the local agent-server, so its id means nothing to\n // Cloud. Sending it would only hide the child from the Cloud\n // conversation list, which filters out anything with a parent.\n parent_conversation_id: null,\n },\n backend,\n );\n\n const settled = await waitForCloudConversationId(startTask, backend);\n if (settled.status === \"ERROR\") {\n return failure(\n settled.detail || \"The Cloud conversation failed to start.\",\n 'The Cloud sandbox could not be provisioned. Report this to the user; you can retry, or fall back to target=\"local\".',\n );\n }\n\n const conversationId = settled.app_conversation_id;\n return {\n status: \"launched\",\n target: \"cloud\",\n conversation_id: conversationId,\n url: conversationId\n ? `${backend.host.replace(/\\/$/, \"\")}/conversations/${conversationId}`\n : null,\n initial_status: settled.status,\n title: params.title,\n start_task_id: settled.id,\n backend: backend.name,\n // Cloud children of a local parent carry no server-side link; see above.\n parent_link: false,\n parent_link_note:\n \"This conversation runs on the local agent server, so OpenHands Cloud has no parent to link the child to.\",\n };\n}\n\n/**\n * Hand the outcome back to the agent and the user.\n *\n * Client tools are acknowledged by the agent-server before the browser does any\n * work, so a message is the only way to give the agent the child's id or tell\n * it how to fix a malformed call. `sendMessage` runs the agent, which is what\n * makes it relay the result to the user in its next turn.\n */\nasync function reportLaunchResult(\n parentConversationId: string,\n result: LaunchChildConversationResult,\n) {\n if (result.status === \"error\") {\n displayErrorToast(\n i18n.t(I18nKey.CHILD_CONVERSATION$LAUNCH_FAILED, {\n error: result.error,\n }),\n );\n } else if (result.url) {\n displaySuccessToastWithLink(\n i18n.t(\n result.target === \"cloud\"\n ? I18nKey.CHILD_CONVERSATION$LAUNCHED_CLOUD\n : I18nKey.CHILD_CONVERSATION$LAUNCHED_LOCAL,\n ),\n i18n.t(I18nKey.CHILD_CONVERSATION$OPEN),\n result.url,\n );\n }\n\n // The agent-server cancels an active `/goal` loop on any inbound message, so\n // a launch must not silently end one. The toast above still tells the user\n // what happened.\n const goalStatus =\n useGoalStore.getState().statusByConversation[parentConversationId];\n if (goalStatus?.active) return;\n\n await AgentServerConversationService.sendMessage(parentConversationId, {\n role: \"user\",\n content: [\n {\n type: \"text\",\n text: `${CHILD_CONVERSATION_RESULT_PREFIX}${JSON.stringify(result)}`,\n },\n ],\n });\n}\n\n/**\n * Execute a `launch_child_conversation` tool call.\n *\n * Never rejects: every failure is turned into corrective guidance for the\n * agent, because the agent-server has already told it the call succeeded.\n */\nexport async function handleLaunchChildConversationAction(\n action: LaunchChildConversationAction,\n parentConversationId: string,\n toolCallId: string,\n): Promise<void> {\n if (!claimToolCall(parentConversationId, toolCallId)) return;\n\n const validation = validateLaunchParams(action);\n let result: LaunchChildConversationResult;\n if (!validation.ok) {\n result = validation.failure;\n } else {\n try {\n result =\n validation.params.target === \"cloud\"\n ? await launchCloudChild(validation.params, parentConversationId)\n : await launchLocalChild(validation.params, parentConversationId);\n } catch (error) {\n result = failure(\n error instanceof Error ? error.message : String(error),\n \"The launch request failed. Report the error to the user; retry only if the cause looks transient.\",\n );\n }\n }\n\n await reportLaunchResult(parentConversationId, result).catch((error) => {\n console.warn(\n `[${LAUNCH_CHILD_CONVERSATION_TOOL_NAME}] Failed to report the launch result:`,\n error,\n );\n });\n}\n"],"mappings":"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"}
|
|
@@ -74,11 +74,17 @@ function D() {
|
|
|
74
74
|
}
|
|
75
75
|
var O = (e) => !!(e?.selected_repository || e?.selected_workspace), k = "The child was launched in this conversation's directory instead, so it can see work in progress here and the two agents may conflict over the same files.";
|
|
76
76
|
async function A(e, t) {
|
|
77
|
-
let n = await _.resolveConversationWorkingDir(t), r = p(t), i = (i) => _.createConversation(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
77
|
+
let n = await _.resolveConversationWorkingDir(t), r = p(t), i = (i) => _.createConversation({
|
|
78
|
+
initialUserMsg: e.task,
|
|
79
|
+
metadata: r ? {
|
|
80
|
+
selected_repository: r.selected_repository,
|
|
81
|
+
selected_branch: r.selected_branch,
|
|
82
|
+
git_provider: r.git_provider
|
|
83
|
+
} : null,
|
|
84
|
+
workingDirOverride: n,
|
|
85
|
+
workspaceMode: i === "shared" ? "local_repo" : "new_worktree",
|
|
86
|
+
parentConversationId: t
|
|
87
|
+
}), a = e.isolation, o = null;
|
|
82
88
|
a === "worktree" && !O(r) && (a = "shared", o = `This conversation's workspace is a scratch directory with no commits, which git cannot cut a worktree from. ${k}`);
|
|
83
89
|
let s;
|
|
84
90
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"child-conversation-launch.js","names":[],"sources":["../../src/services/child-conversation-launch.ts"],"sourcesContent":["import i18n from \"#/i18n\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport {\n compareAgentServerVersions,\n getCachedAgentServerVersion,\n} from \"#/api/agent-server-compatibility\";\nimport {\n createCloudAppConversation,\n getCloudAppConversationStartTask,\n pickCloudBackendForLaunch,\n} from \"#/api/cloud/conversation-service.api\";\nimport type { Backend } from \"#/api/backend-registry/types\";\nimport {\n getStoredConversationMetadata,\n type ConversationMetadata,\n} from \"#/api/conversation-metadata-store\";\nimport AgentServerConversationService from \"#/api/conversation-service/agent-server-conversation-service.api\";\nimport type { AppConversationStartTask } from \"#/api/conversation-service/agent-server-conversation-service.types\";\nimport {\n CHILD_CONVERSATION_ISOLATIONS,\n CHILD_CONVERSATION_RESULT_PREFIX,\n CHILD_CONVERSATION_TARGETS,\n LAUNCH_CHILD_CONVERSATION_TOOL_NAME,\n MIN_AGENT_SERVER_VERSION_FOR_PARENT_LINK,\n type ChildConversationIsolation,\n type ChildConversationTarget,\n} from \"#/constants/child-conversation\";\nimport { useGoalStore } from \"#/stores/goal-store\";\nimport type { LaunchChildConversationAction } from \"#/types/agent-server/core\";\nimport { buildAgentCanvasPath } from \"#/utils/base-path\";\nimport {\n displayErrorToast,\n displaySuccessToastWithLink,\n} from \"#/utils/custom-toast-handlers\";\n\n/** Cadence and ceiling for waiting on a Cloud sandbox to expose its id. */\nconst CLOUD_START_POLL_INTERVAL_MS = 3_000;\nconst CLOUD_START_POLL_TIMEOUT_MS = 180_000;\n\nconst LEDGER_STORAGE_KEY_PREFIX = \"openhands-child-conversation-launches:\";\n\ninterface LaunchSuccess {\n status: \"launched\";\n target: ChildConversationTarget;\n conversation_id: string | null;\n url: string | null;\n initial_status: string;\n title: string | null;\n /** Local only: the directory the child inherited from this conversation. */\n workspace?: string;\n /** Local only: which isolation mode was actually applied. */\n isolation?: ChildConversationIsolation;\n /**\n * Present when the applied isolation is not the one that was asked for,\n * explaining why and what it means for the child.\n */\n isolation_note?: string;\n /** Cloud only: poll this if `conversation_id` is still null. */\n start_task_id?: string;\n /** Cloud only: which connected Cloud backend the child was launched on. */\n backend?: string;\n /** Whether the parent/child link was persisted server-side. */\n parent_link: boolean;\n /** Present when `parent_link` is false, explaining why. */\n parent_link_note?: string;\n}\n\ninterface LaunchFailure {\n status: \"error\";\n error: string;\n guidance: string;\n}\n\nexport type LaunchChildConversationResult = LaunchSuccess | LaunchFailure;\n\ninterface ValidatedParams {\n target: ChildConversationTarget;\n task: string;\n title: string | null;\n repository: string | null;\n branch: string | null;\n isolation: ChildConversationIsolation;\n}\n\nconst failure = (error: string, guidance: string): LaunchFailure => ({\n status: \"error\",\n error,\n guidance,\n});\n\nconst quoted = (values: readonly string[]) =>\n values.map((value) => `\"${value}\"`).join(\" or \");\n\nconst blankToNull = (value: string | null | undefined) => {\n const trimmed = value?.trim();\n return trimmed ? trimmed : null;\n};\n\n/**\n * Validate what the agent-server cannot.\n *\n * The tool's JSON Schema is turned into a pydantic model with `extra=\"forbid\"`,\n * so unknown/misspelled parameter names, missing required parameters and wrong\n * types already fail server-side with a corrective message. `enum` is the gap:\n * the SDK advertises it to the LLM but drops it when building the model, so a\n * misspelled `target` reaches us intact and must be rejected here. The\n * cross-target rules (cloud-only / local-only parameters) are ours to enforce\n * too, since a schema cannot express them.\n */\nfunction validateLaunchParams(\n action: LaunchChildConversationAction,\n):\n | { ok: true; params: ValidatedParams }\n | { ok: false; failure: LaunchFailure } {\n const target = action.target as ChildConversationTarget;\n if (!CHILD_CONVERSATION_TARGETS.includes(target)) {\n return {\n ok: false,\n failure: failure(\n `Unknown target ${JSON.stringify(action.target)}.`,\n `\\`target\\` must be exactly ${quoted(CHILD_CONVERSATION_TARGETS)}. Nothing was launched — call ${LAUNCH_CHILD_CONVERSATION_TOOL_NAME} again with a valid target.`,\n ),\n };\n }\n\n const task = blankToNull(action.task);\n if (!task) {\n return {\n ok: false,\n failure: failure(\n \"`task` is empty.\",\n \"`task` must be a self-contained brief: the child conversation cannot see this one, so state the goal, constraints and expected output.\",\n ),\n };\n }\n\n const repository = blankToNull(action.repository);\n const branch = blankToNull(action.branch);\n const isolation = blankToNull(\n action.isolation,\n ) as ChildConversationIsolation | null;\n\n if (target === \"local\" && (repository || branch)) {\n return {\n ok: false,\n failure: failure(\n '`repository`/`branch` were passed with target=\"local\".',\n 'A local child always runs in this conversation\\'s workspace. Drop `repository` and `branch`, or use target=\"cloud\" to run against a repository in a Cloud sandbox.',\n ),\n };\n }\n\n if (target === \"cloud\" && isolation) {\n return {\n ok: false,\n failure: failure(\n '`isolation` was passed with target=\"cloud\".',\n 'Cloud children always run in their own isolated sandbox. Drop `isolation`, or use target=\"local\" to choose between \"worktree\" and \"shared\".',\n ),\n };\n }\n\n if (branch && !repository) {\n return {\n ok: false,\n failure: failure(\n \"`branch` was passed without `repository`.\",\n 'Pass `repository` as \"owner/repo\" alongside `branch`, or drop `branch` to use the repository\\'s default branch.',\n ),\n };\n }\n\n if (isolation && !CHILD_CONVERSATION_ISOLATIONS.includes(isolation)) {\n return {\n ok: false,\n failure: failure(\n `Unknown isolation ${JSON.stringify(action.isolation)}.`,\n `\\`isolation\\` must be exactly ${quoted(CHILD_CONVERSATION_ISOLATIONS)}. Nothing was launched — call ${LAUNCH_CHILD_CONVERSATION_TOOL_NAME} again with a valid isolation.`,\n ),\n };\n }\n\n return {\n ok: true,\n params: {\n target,\n task,\n title: blankToNull(action.title),\n repository,\n branch,\n isolation: isolation ?? \"worktree\",\n },\n };\n}\n\n/**\n * Remember which tool calls have already been acted on.\n *\n * Unlike the Canvas UI tool, a launch is not idempotent: replaying its\n * ActionEvent (a socket reconnect that falls back to `resend_mode: \"all\"`, or a\n * REST/WebSocket race after a reload) would start a second — on Cloud, billable\n * — conversation. Claim the tool call before any network work so a replay that\n * arrives mid-flight is dropped too.\n */\nfunction claimToolCall(parentConversationId: string, toolCallId: string) {\n const key = `${LEDGER_STORAGE_KEY_PREFIX}${parentConversationId}`;\n let handled: string[] = [];\n try {\n const raw = window.localStorage.getItem(key);\n const parsed: unknown = raw ? JSON.parse(raw) : null;\n if (Array.isArray(parsed)) {\n handled = parsed.filter((id): id is string => typeof id === \"string\");\n }\n } catch {\n // A corrupt ledger must not block the launch; start a fresh one.\n }\n\n if (handled.includes(toolCallId)) return false;\n\n try {\n window.localStorage.setItem(key, JSON.stringify([...handled, toolCallId]));\n } catch {\n // Storage full or unavailable — proceed, accepting replay risk over never\n // launching at all.\n }\n return true;\n}\n\nfunction absoluteCanvasUrl(path: string) {\n const canvasPath = buildAgentCanvasPath(path);\n if (typeof window === \"undefined\") return canvasPath;\n return new URL(canvasPath, window.location.origin).toString();\n}\n\n/**\n * `parent_conversation_id` on the local start request landed in agent-server\n * 1.37.1. Older servers ignore unknown fields, so the child is created without\n * the link — report that rather than letting the agent assume a relationship\n * that does not exist.\n */\nfunction localParentLinkNote(): string | null {\n const version = getCachedAgentServerVersion();\n if (!version) return null;\n const comparison = compareAgentServerVersions(\n version,\n MIN_AGENT_SERVER_VERSION_FOR_PARENT_LINK,\n );\n if (comparison === null || comparison >= 0) return null;\n return `Agent server ${version} does not persist parent/child conversation links (needs ${MIN_AGENT_SERVER_VERSION_FOR_PARENT_LINK}); the child was created but is not linked to this conversation.`;\n}\n\n/**\n * Whether the parent's workspace can host a git worktree.\n *\n * A conversation started without a repository or an attached workspace runs in\n * a scratch directory that is `git init`-ed but never committed to. `git\n * worktree add` cannot branch from an unborn HEAD, and the agent-server raises\n * the resulting error straight out of its start-conversation handler as a 500,\n * so asking for a worktree there fails the whole launch. Conversation metadata\n * is only persisted when a repository or an explicit workspace was chosen (see\n * `createConversation`), so its absence pinpoints exactly those scratch\n * workspaces. Anything else is attempted and falls back on failure, because the\n * frontend cannot inspect the workspace's git state directly.\n */\nconst parentSupportsWorktree = (\n metadata: ConversationMetadata | null,\n): boolean => !!(metadata?.selected_repository || metadata?.selected_workspace);\n\nconst SHARED_FALLBACK_CONSEQUENCE =\n \"The child was launched in this conversation's directory instead, so it can see work in progress here and the two agents may conflict over the same files.\";\n\nasync function launchLocalChild(\n params: ValidatedParams,\n parentConversationId: string,\n): Promise<LaunchChildConversationResult> {\n // The agent-server rejects a parent whose workspace differs from the child's,\n // so the child requests the parent's own directory. `worktree` then carves an\n // isolated worktree out of it, which is what keeps siblings from colliding.\n const workspace =\n await AgentServerConversationService.resolveConversationWorkingDir(\n parentConversationId,\n );\n const parentMetadata = getStoredConversationMetadata(parentConversationId);\n\n const createChild = (isolation: ChildConversationIsolation) =>\n AgentServerConversationService.createConversation(\n params.task,\n undefined,\n undefined,\n parentMetadata\n ? {\n selected_repository: parentMetadata.selected_repository,\n selected_branch: parentMetadata.selected_branch,\n git_provider: parentMetadata.git_provider,\n }\n : null,\n workspace,\n isolation === \"shared\" ? \"local_repo\" : \"new_worktree\",\n parentConversationId,\n );\n\n let isolation = params.isolation;\n let isolationNote: string | null = null;\n\n if (isolation === \"worktree\" && !parentSupportsWorktree(parentMetadata)) {\n isolation = \"shared\";\n isolationNote = `This conversation's workspace is a scratch directory with no commits, which git cannot cut a worktree from. ${SHARED_FALLBACK_CONSEQUENCE}`;\n }\n\n let startTask;\n try {\n startTask = await createChild(isolation);\n } catch (worktreeError) {\n if (isolation !== \"worktree\") throw worktreeError;\n // Creating the worktree is the one part of a local launch that can fail on\n // an otherwise healthy workspace, so retry without it rather than losing\n // the launch. Anything else fails both attempts and is reported as-is.\n try {\n startTask = await createChild(\"shared\");\n } catch {\n throw worktreeError;\n }\n isolation = \"shared\";\n isolationNote = `Creating a git worktree in this conversation's workspace failed (${worktreeError instanceof Error ? worktreeError.message : String(worktreeError)}). ${SHARED_FALLBACK_CONSEQUENCE}`;\n }\n\n const conversationId = startTask.app_conversation_id ?? startTask.id;\n\n if (params.title) {\n // Local start requests carry no title — only `autotitle`. Best effort: a\n // failed rename must not fail the launch.\n await AgentServerConversationService.updateConversationTitle(\n conversationId,\n params.title,\n ).catch(() => undefined);\n }\n\n const parentLinkNote = localParentLinkNote();\n return {\n status: \"launched\",\n target: \"local\",\n conversation_id: conversationId,\n url: absoluteCanvasUrl(`/conversations/${conversationId}`),\n initial_status: startTask.status,\n title: params.title,\n workspace,\n isolation,\n ...(isolationNote ? { isolation_note: isolationNote } : {}),\n parent_link: !parentLinkNote,\n ...(parentLinkNote ? { parent_link_note: parentLinkNote } : {}),\n };\n}\n\nconst delay = (ms: number) =>\n new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n\n/**\n * Wait for the Cloud start task to expose its conversation id.\n *\n * The Cloud API provisions a sandbox asynchronously and only fills in\n * `app_conversation_id` once the task reaches READY, so without this the agent\n * would get a result with no conversation to open. Bounded: on timeout the\n * caller reports the still-provisioning task instead of hanging.\n */\nasync function waitForCloudConversationId(\n task: AppConversationStartTask,\n backend: Backend,\n): Promise<AppConversationStartTask> {\n const deadline = Date.now() + CLOUD_START_POLL_TIMEOUT_MS;\n let latest = task;\n while (!latest.app_conversation_id && latest.status !== \"ERROR\") {\n if (Date.now() >= deadline) break;\n\n await delay(CLOUD_START_POLL_INTERVAL_MS);\n\n const next = await getCloudAppConversationStartTask(\n latest.id,\n backend,\n ).catch(() => null);\n if (!next) break;\n latest = next;\n }\n return latest;\n}\n\nasync function launchCloudChild(\n params: ValidatedParams,\n parentConversationId: string,\n): Promise<LaunchChildConversationResult> {\n const backend = pickCloudBackendForLaunch();\n if (!backend) {\n return failure(\n \"No OpenHands Cloud backend is connected in Agent Canvas.\",\n 'Ask the user to connect OpenHands Cloud from the backend picker, then call this tool again — or relaunch now with target=\"local\".',\n );\n }\n\n const parentMetadata = getStoredConversationMetadata(parentConversationId);\n const startTask = await createCloudAppConversation(\n {\n initial_message: {\n role: \"user\",\n content: [{ type: \"text\", text: params.task }],\n },\n title: params.title,\n // Fall back to this conversation's repository so a bare `target: \"cloud\"`\n // call still lands the child on the code the user is working on. The\n // provider only travels with the inherited repository — it may not apply\n // to one the agent named itself.\n selected_repository:\n params.repository ?? parentMetadata?.selected_repository ?? null,\n selected_branch: params.branch ?? null,\n git_provider: params.repository\n ? null\n : (parentMetadata?.git_provider ?? null),\n // The parent runs on the local agent-server, so its id means nothing to\n // Cloud. Sending it would only hide the child from the Cloud\n // conversation list, which filters out anything with a parent.\n parent_conversation_id: null,\n },\n backend,\n );\n\n const settled = await waitForCloudConversationId(startTask, backend);\n if (settled.status === \"ERROR\") {\n return failure(\n settled.detail || \"The Cloud conversation failed to start.\",\n 'The Cloud sandbox could not be provisioned. Report this to the user; you can retry, or fall back to target=\"local\".',\n );\n }\n\n const conversationId = settled.app_conversation_id;\n return {\n status: \"launched\",\n target: \"cloud\",\n conversation_id: conversationId,\n url: conversationId\n ? `${backend.host.replace(/\\/$/, \"\")}/conversations/${conversationId}`\n : null,\n initial_status: settled.status,\n title: params.title,\n start_task_id: settled.id,\n backend: backend.name,\n // Cloud children of a local parent carry no server-side link; see above.\n parent_link: false,\n parent_link_note:\n \"This conversation runs on the local agent server, so OpenHands Cloud has no parent to link the child to.\",\n };\n}\n\n/**\n * Hand the outcome back to the agent and the user.\n *\n * Client tools are acknowledged by the agent-server before the browser does any\n * work, so a message is the only way to give the agent the child's id or tell\n * it how to fix a malformed call. `sendMessage` runs the agent, which is what\n * makes it relay the result to the user in its next turn.\n */\nasync function reportLaunchResult(\n parentConversationId: string,\n result: LaunchChildConversationResult,\n) {\n if (result.status === \"error\") {\n displayErrorToast(\n i18n.t(I18nKey.CHILD_CONVERSATION$LAUNCH_FAILED, {\n error: result.error,\n }),\n );\n } else if (result.url) {\n displaySuccessToastWithLink(\n i18n.t(\n result.target === \"cloud\"\n ? I18nKey.CHILD_CONVERSATION$LAUNCHED_CLOUD\n : I18nKey.CHILD_CONVERSATION$LAUNCHED_LOCAL,\n ),\n i18n.t(I18nKey.CHILD_CONVERSATION$OPEN),\n result.url,\n );\n }\n\n // The agent-server cancels an active `/goal` loop on any inbound message, so\n // a launch must not silently end one. The toast above still tells the user\n // what happened.\n const goalStatus =\n useGoalStore.getState().statusByConversation[parentConversationId];\n if (goalStatus?.active) return;\n\n await AgentServerConversationService.sendMessage(parentConversationId, {\n role: \"user\",\n content: [\n {\n type: \"text\",\n text: `${CHILD_CONVERSATION_RESULT_PREFIX}${JSON.stringify(result)}`,\n },\n ],\n });\n}\n\n/**\n * Execute a `launch_child_conversation` tool call.\n *\n * Never rejects: every failure is turned into corrective guidance for the\n * agent, because the agent-server has already told it the call succeeded.\n */\nexport async function handleLaunchChildConversationAction(\n action: LaunchChildConversationAction,\n parentConversationId: string,\n toolCallId: string,\n): Promise<void> {\n if (!claimToolCall(parentConversationId, toolCallId)) return;\n\n const validation = validateLaunchParams(action);\n let result: LaunchChildConversationResult;\n if (!validation.ok) {\n result = validation.failure;\n } else {\n try {\n result =\n validation.params.target === \"cloud\"\n ? await launchCloudChild(validation.params, parentConversationId)\n : await launchLocalChild(validation.params, parentConversationId);\n } catch (error) {\n result = failure(\n error instanceof Error ? error.message : String(error),\n \"The launch request failed. Report the error to the user; retry only if the cause looks transient.\",\n );\n }\n }\n\n await reportLaunchResult(parentConversationId, result).catch((error) => {\n console.warn(\n `[${LAUNCH_CHILD_CONVERSATION_TOOL_NAME}] Failed to report the launch result:`,\n error,\n );\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"child-conversation-launch.js","names":[],"sources":["../../src/services/child-conversation-launch.ts"],"sourcesContent":["import i18n from \"#/i18n\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport {\n compareAgentServerVersions,\n getCachedAgentServerVersion,\n} from \"#/api/agent-server-compatibility\";\nimport {\n createCloudAppConversation,\n getCloudAppConversationStartTask,\n pickCloudBackendForLaunch,\n} from \"#/api/cloud/conversation-service.api\";\nimport type { Backend } from \"#/api/backend-registry/types\";\nimport {\n getStoredConversationMetadata,\n type ConversationMetadata,\n} from \"#/api/conversation-metadata-store\";\nimport AgentServerConversationService from \"#/api/conversation-service/agent-server-conversation-service.api\";\nimport type { AppConversationStartTask } from \"#/api/conversation-service/agent-server-conversation-service.types\";\nimport {\n CHILD_CONVERSATION_ISOLATIONS,\n CHILD_CONVERSATION_RESULT_PREFIX,\n CHILD_CONVERSATION_TARGETS,\n LAUNCH_CHILD_CONVERSATION_TOOL_NAME,\n MIN_AGENT_SERVER_VERSION_FOR_PARENT_LINK,\n type ChildConversationIsolation,\n type ChildConversationTarget,\n} from \"#/constants/child-conversation\";\nimport { useGoalStore } from \"#/stores/goal-store\";\nimport type { LaunchChildConversationAction } from \"#/types/agent-server/core\";\nimport { buildAgentCanvasPath } from \"#/utils/base-path\";\nimport {\n displayErrorToast,\n displaySuccessToastWithLink,\n} from \"#/utils/custom-toast-handlers\";\n\n/** Cadence and ceiling for waiting on a Cloud sandbox to expose its id. */\nconst CLOUD_START_POLL_INTERVAL_MS = 3_000;\nconst CLOUD_START_POLL_TIMEOUT_MS = 180_000;\n\nconst LEDGER_STORAGE_KEY_PREFIX = \"openhands-child-conversation-launches:\";\n\ninterface LaunchSuccess {\n status: \"launched\";\n target: ChildConversationTarget;\n conversation_id: string | null;\n url: string | null;\n initial_status: string;\n title: string | null;\n /** Local only: the directory the child inherited from this conversation. */\n workspace?: string;\n /** Local only: which isolation mode was actually applied. */\n isolation?: ChildConversationIsolation;\n /**\n * Present when the applied isolation is not the one that was asked for,\n * explaining why and what it means for the child.\n */\n isolation_note?: string;\n /** Cloud only: poll this if `conversation_id` is still null. */\n start_task_id?: string;\n /** Cloud only: which connected Cloud backend the child was launched on. */\n backend?: string;\n /** Whether the parent/child link was persisted server-side. */\n parent_link: boolean;\n /** Present when `parent_link` is false, explaining why. */\n parent_link_note?: string;\n}\n\ninterface LaunchFailure {\n status: \"error\";\n error: string;\n guidance: string;\n}\n\nexport type LaunchChildConversationResult = LaunchSuccess | LaunchFailure;\n\ninterface ValidatedParams {\n target: ChildConversationTarget;\n task: string;\n title: string | null;\n repository: string | null;\n branch: string | null;\n isolation: ChildConversationIsolation;\n}\n\nconst failure = (error: string, guidance: string): LaunchFailure => ({\n status: \"error\",\n error,\n guidance,\n});\n\nconst quoted = (values: readonly string[]) =>\n values.map((value) => `\"${value}\"`).join(\" or \");\n\nconst blankToNull = (value: string | null | undefined) => {\n const trimmed = value?.trim();\n return trimmed ? trimmed : null;\n};\n\n/**\n * Validate what the agent-server cannot.\n *\n * The tool's JSON Schema is turned into a pydantic model with `extra=\"forbid\"`,\n * so unknown/misspelled parameter names, missing required parameters and wrong\n * types already fail server-side with a corrective message. `enum` is the gap:\n * the SDK advertises it to the LLM but drops it when building the model, so a\n * misspelled `target` reaches us intact and must be rejected here. The\n * cross-target rules (cloud-only / local-only parameters) are ours to enforce\n * too, since a schema cannot express them.\n */\nfunction validateLaunchParams(\n action: LaunchChildConversationAction,\n):\n | { ok: true; params: ValidatedParams }\n | { ok: false; failure: LaunchFailure } {\n const target = action.target as ChildConversationTarget;\n if (!CHILD_CONVERSATION_TARGETS.includes(target)) {\n return {\n ok: false,\n failure: failure(\n `Unknown target ${JSON.stringify(action.target)}.`,\n `\\`target\\` must be exactly ${quoted(CHILD_CONVERSATION_TARGETS)}. Nothing was launched — call ${LAUNCH_CHILD_CONVERSATION_TOOL_NAME} again with a valid target.`,\n ),\n };\n }\n\n const task = blankToNull(action.task);\n if (!task) {\n return {\n ok: false,\n failure: failure(\n \"`task` is empty.\",\n \"`task` must be a self-contained brief: the child conversation cannot see this one, so state the goal, constraints and expected output.\",\n ),\n };\n }\n\n const repository = blankToNull(action.repository);\n const branch = blankToNull(action.branch);\n const isolation = blankToNull(\n action.isolation,\n ) as ChildConversationIsolation | null;\n\n if (target === \"local\" && (repository || branch)) {\n return {\n ok: false,\n failure: failure(\n '`repository`/`branch` were passed with target=\"local\".',\n 'A local child always runs in this conversation\\'s workspace. Drop `repository` and `branch`, or use target=\"cloud\" to run against a repository in a Cloud sandbox.',\n ),\n };\n }\n\n if (target === \"cloud\" && isolation) {\n return {\n ok: false,\n failure: failure(\n '`isolation` was passed with target=\"cloud\".',\n 'Cloud children always run in their own isolated sandbox. Drop `isolation`, or use target=\"local\" to choose between \"worktree\" and \"shared\".',\n ),\n };\n }\n\n if (branch && !repository) {\n return {\n ok: false,\n failure: failure(\n \"`branch` was passed without `repository`.\",\n 'Pass `repository` as \"owner/repo\" alongside `branch`, or drop `branch` to use the repository\\'s default branch.',\n ),\n };\n }\n\n if (isolation && !CHILD_CONVERSATION_ISOLATIONS.includes(isolation)) {\n return {\n ok: false,\n failure: failure(\n `Unknown isolation ${JSON.stringify(action.isolation)}.`,\n `\\`isolation\\` must be exactly ${quoted(CHILD_CONVERSATION_ISOLATIONS)}. Nothing was launched — call ${LAUNCH_CHILD_CONVERSATION_TOOL_NAME} again with a valid isolation.`,\n ),\n };\n }\n\n return {\n ok: true,\n params: {\n target,\n task,\n title: blankToNull(action.title),\n repository,\n branch,\n isolation: isolation ?? \"worktree\",\n },\n };\n}\n\n/**\n * Remember which tool calls have already been acted on.\n *\n * Unlike the Canvas UI tool, a launch is not idempotent: replaying its\n * ActionEvent (a socket reconnect that falls back to `resend_mode: \"all\"`, or a\n * REST/WebSocket race after a reload) would start a second — on Cloud, billable\n * — conversation. Claim the tool call before any network work so a replay that\n * arrives mid-flight is dropped too.\n */\nfunction claimToolCall(parentConversationId: string, toolCallId: string) {\n const key = `${LEDGER_STORAGE_KEY_PREFIX}${parentConversationId}`;\n let handled: string[] = [];\n try {\n const raw = window.localStorage.getItem(key);\n const parsed: unknown = raw ? JSON.parse(raw) : null;\n if (Array.isArray(parsed)) {\n handled = parsed.filter((id): id is string => typeof id === \"string\");\n }\n } catch {\n // A corrupt ledger must not block the launch; start a fresh one.\n }\n\n if (handled.includes(toolCallId)) return false;\n\n try {\n window.localStorage.setItem(key, JSON.stringify([...handled, toolCallId]));\n } catch {\n // Storage full or unavailable — proceed, accepting replay risk over never\n // launching at all.\n }\n return true;\n}\n\nfunction absoluteCanvasUrl(path: string) {\n const canvasPath = buildAgentCanvasPath(path);\n if (typeof window === \"undefined\") return canvasPath;\n return new URL(canvasPath, window.location.origin).toString();\n}\n\n/**\n * `parent_conversation_id` on the local start request landed in agent-server\n * 1.37.1. Older servers ignore unknown fields, so the child is created without\n * the link — report that rather than letting the agent assume a relationship\n * that does not exist.\n */\nfunction localParentLinkNote(): string | null {\n const version = getCachedAgentServerVersion();\n if (!version) return null;\n const comparison = compareAgentServerVersions(\n version,\n MIN_AGENT_SERVER_VERSION_FOR_PARENT_LINK,\n );\n if (comparison === null || comparison >= 0) return null;\n return `Agent server ${version} does not persist parent/child conversation links (needs ${MIN_AGENT_SERVER_VERSION_FOR_PARENT_LINK}); the child was created but is not linked to this conversation.`;\n}\n\n/**\n * Whether the parent's workspace can host a git worktree.\n *\n * A conversation started without a repository or an attached workspace runs in\n * a scratch directory that is `git init`-ed but never committed to. `git\n * worktree add` cannot branch from an unborn HEAD, and the agent-server raises\n * the resulting error straight out of its start-conversation handler as a 500,\n * so asking for a worktree there fails the whole launch. Conversation metadata\n * is only persisted when a repository or an explicit workspace was chosen (see\n * `createConversation`), so its absence pinpoints exactly those scratch\n * workspaces. Anything else is attempted and falls back on failure, because the\n * frontend cannot inspect the workspace's git state directly.\n */\nconst parentSupportsWorktree = (\n metadata: ConversationMetadata | null,\n): boolean => !!(metadata?.selected_repository || metadata?.selected_workspace);\n\nconst SHARED_FALLBACK_CONSEQUENCE =\n \"The child was launched in this conversation's directory instead, so it can see work in progress here and the two agents may conflict over the same files.\";\n\nasync function launchLocalChild(\n params: ValidatedParams,\n parentConversationId: string,\n): Promise<LaunchChildConversationResult> {\n // The agent-server rejects a parent whose workspace differs from the child's,\n // so the child requests the parent's own directory. `worktree` then carves an\n // isolated worktree out of it, which is what keeps siblings from colliding.\n const workspace =\n await AgentServerConversationService.resolveConversationWorkingDir(\n parentConversationId,\n );\n const parentMetadata = getStoredConversationMetadata(parentConversationId);\n\n const createChild = (isolation: ChildConversationIsolation) =>\n AgentServerConversationService.createConversation({\n initialUserMsg: params.task,\n metadata: parentMetadata\n ? {\n selected_repository: parentMetadata.selected_repository,\n selected_branch: parentMetadata.selected_branch,\n git_provider: parentMetadata.git_provider,\n }\n : null,\n workingDirOverride: workspace,\n workspaceMode: isolation === \"shared\" ? \"local_repo\" : \"new_worktree\",\n parentConversationId,\n });\n\n let isolation = params.isolation;\n let isolationNote: string | null = null;\n\n if (isolation === \"worktree\" && !parentSupportsWorktree(parentMetadata)) {\n isolation = \"shared\";\n isolationNote = `This conversation's workspace is a scratch directory with no commits, which git cannot cut a worktree from. ${SHARED_FALLBACK_CONSEQUENCE}`;\n }\n\n let startTask;\n try {\n startTask = await createChild(isolation);\n } catch (worktreeError) {\n if (isolation !== \"worktree\") throw worktreeError;\n // Creating the worktree is the one part of a local launch that can fail on\n // an otherwise healthy workspace, so retry without it rather than losing\n // the launch. Anything else fails both attempts and is reported as-is.\n try {\n startTask = await createChild(\"shared\");\n } catch {\n throw worktreeError;\n }\n isolation = \"shared\";\n isolationNote = `Creating a git worktree in this conversation's workspace failed (${worktreeError instanceof Error ? worktreeError.message : String(worktreeError)}). ${SHARED_FALLBACK_CONSEQUENCE}`;\n }\n\n const conversationId = startTask.app_conversation_id ?? startTask.id;\n\n if (params.title) {\n // Local start requests carry no title — only `autotitle`. Best effort: a\n // failed rename must not fail the launch.\n await AgentServerConversationService.updateConversationTitle(\n conversationId,\n params.title,\n ).catch(() => undefined);\n }\n\n const parentLinkNote = localParentLinkNote();\n return {\n status: \"launched\",\n target: \"local\",\n conversation_id: conversationId,\n url: absoluteCanvasUrl(`/conversations/${conversationId}`),\n initial_status: startTask.status,\n title: params.title,\n workspace,\n isolation,\n ...(isolationNote ? { isolation_note: isolationNote } : {}),\n parent_link: !parentLinkNote,\n ...(parentLinkNote ? { parent_link_note: parentLinkNote } : {}),\n };\n}\n\nconst delay = (ms: number) =>\n new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n\n/**\n * Wait for the Cloud start task to expose its conversation id.\n *\n * The Cloud API provisions a sandbox asynchronously and only fills in\n * `app_conversation_id` once the task reaches READY, so without this the agent\n * would get a result with no conversation to open. Bounded: on timeout the\n * caller reports the still-provisioning task instead of hanging.\n */\nasync function waitForCloudConversationId(\n task: AppConversationStartTask,\n backend: Backend,\n): Promise<AppConversationStartTask> {\n const deadline = Date.now() + CLOUD_START_POLL_TIMEOUT_MS;\n let latest = task;\n while (!latest.app_conversation_id && latest.status !== \"ERROR\") {\n if (Date.now() >= deadline) break;\n\n await delay(CLOUD_START_POLL_INTERVAL_MS);\n\n const next = await getCloudAppConversationStartTask(\n latest.id,\n backend,\n ).catch(() => null);\n if (!next) break;\n latest = next;\n }\n return latest;\n}\n\nasync function launchCloudChild(\n params: ValidatedParams,\n parentConversationId: string,\n): Promise<LaunchChildConversationResult> {\n const backend = pickCloudBackendForLaunch();\n if (!backend) {\n return failure(\n \"No OpenHands Cloud backend is connected in Agent Canvas.\",\n 'Ask the user to connect OpenHands Cloud from the backend picker, then call this tool again — or relaunch now with target=\"local\".',\n );\n }\n\n const parentMetadata = getStoredConversationMetadata(parentConversationId);\n const startTask = await createCloudAppConversation(\n {\n initial_message: {\n role: \"user\",\n content: [{ type: \"text\", text: params.task }],\n },\n title: params.title,\n // Fall back to this conversation's repository so a bare `target: \"cloud\"`\n // call still lands the child on the code the user is working on. The\n // provider only travels with the inherited repository — it may not apply\n // to one the agent named itself.\n selected_repository:\n params.repository ?? parentMetadata?.selected_repository ?? null,\n selected_branch: params.branch ?? null,\n git_provider: params.repository\n ? null\n : (parentMetadata?.git_provider ?? null),\n // The parent runs on the local agent-server, so its id means nothing to\n // Cloud. Sending it would only hide the child from the Cloud\n // conversation list, which filters out anything with a parent.\n parent_conversation_id: null,\n },\n backend,\n );\n\n const settled = await waitForCloudConversationId(startTask, backend);\n if (settled.status === \"ERROR\") {\n return failure(\n settled.detail || \"The Cloud conversation failed to start.\",\n 'The Cloud sandbox could not be provisioned. Report this to the user; you can retry, or fall back to target=\"local\".',\n );\n }\n\n const conversationId = settled.app_conversation_id;\n return {\n status: \"launched\",\n target: \"cloud\",\n conversation_id: conversationId,\n url: conversationId\n ? `${backend.host.replace(/\\/$/, \"\")}/conversations/${conversationId}`\n : null,\n initial_status: settled.status,\n title: params.title,\n start_task_id: settled.id,\n backend: backend.name,\n // Cloud children of a local parent carry no server-side link; see above.\n parent_link: false,\n parent_link_note:\n \"This conversation runs on the local agent server, so OpenHands Cloud has no parent to link the child to.\",\n };\n}\n\n/**\n * Hand the outcome back to the agent and the user.\n *\n * Client tools are acknowledged by the agent-server before the browser does any\n * work, so a message is the only way to give the agent the child's id or tell\n * it how to fix a malformed call. `sendMessage` runs the agent, which is what\n * makes it relay the result to the user in its next turn.\n */\nasync function reportLaunchResult(\n parentConversationId: string,\n result: LaunchChildConversationResult,\n) {\n if (result.status === \"error\") {\n displayErrorToast(\n i18n.t(I18nKey.CHILD_CONVERSATION$LAUNCH_FAILED, {\n error: result.error,\n }),\n );\n } else if (result.url) {\n displaySuccessToastWithLink(\n i18n.t(\n result.target === \"cloud\"\n ? I18nKey.CHILD_CONVERSATION$LAUNCHED_CLOUD\n : I18nKey.CHILD_CONVERSATION$LAUNCHED_LOCAL,\n ),\n i18n.t(I18nKey.CHILD_CONVERSATION$OPEN),\n result.url,\n );\n }\n\n // The agent-server cancels an active `/goal` loop on any inbound message, so\n // a launch must not silently end one. The toast above still tells the user\n // what happened.\n const goalStatus =\n useGoalStore.getState().statusByConversation[parentConversationId];\n if (goalStatus?.active) return;\n\n await AgentServerConversationService.sendMessage(parentConversationId, {\n role: \"user\",\n content: [\n {\n type: \"text\",\n text: `${CHILD_CONVERSATION_RESULT_PREFIX}${JSON.stringify(result)}`,\n },\n ],\n });\n}\n\n/**\n * Execute a `launch_child_conversation` tool call.\n *\n * Never rejects: every failure is turned into corrective guidance for the\n * agent, because the agent-server has already told it the call succeeded.\n */\nexport async function handleLaunchChildConversationAction(\n action: LaunchChildConversationAction,\n parentConversationId: string,\n toolCallId: string,\n): Promise<void> {\n if (!claimToolCall(parentConversationId, toolCallId)) return;\n\n const validation = validateLaunchParams(action);\n let result: LaunchChildConversationResult;\n if (!validation.ok) {\n result = validation.failure;\n } else {\n try {\n result =\n validation.params.target === \"cloud\"\n ? await launchCloudChild(validation.params, parentConversationId)\n : await launchLocalChild(validation.params, parentConversationId);\n } catch (error) {\n result = failure(\n error instanceof Error ? error.message : String(error),\n \"The launch request failed. Report the error to the user; retry only if the cause looks transient.\",\n );\n }\n }\n\n await reportLaunchResult(parentConversationId, result).catch((error) => {\n console.warn(\n `[${LAUNCH_CHILD_CONVERSATION_TOOL_NAME}] Failed to report the launch result:`,\n error,\n );\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
require("../_virtual/_rolldown/runtime.cjs");var e={llm_model:`openhands/
|
|
1
|
+
require("../_virtual/_rolldown/runtime.cjs");var e={llm_model:`openhands/kimi-k3`,llm_base_url:``,agent:`CodeActAgent`,language:`en`,llm_api_key:null,llm_api_key_set:!1,search_api_key_set:!1,confirmation_mode:!1,security_analyzer:`llm`,max_iterations:null,remote_runtime_resource_factor:1,provider_tokens_set:{},enable_default_condenser:!0,condenser_max_size:240,enable_sound_notifications:!1,user_consents_to_analytics:null,enable_proactive_conversation_starters:!1,enable_solvability_analysis:!1,search_api_key:``,is_new_user:!0,disabled_skills:[],mcp_config:{},max_budget_per_task:null,email:``,email_verified:!0,git_user_name:`openhands`,git_user_email:`openhands@all-hands.dev`,title_llm_profile:null,agent_settings_schema:null,agent_settings:{schema_version:6,agent_kind:`openhands`,agent:`CodeActAgent`,llm:{model:`openhands/kimi-k3`},condenser:{enabled:!0,max_size:240},verification:{critic_enabled:!1,enable_iterative_refinement:!1},enable_sub_agents:!1,mcp_config:{}},conversation_settings_schema:null,conversation_settings:{schema_version:1,confirmation_mode:!1,security_analyzer:`llm`}};exports.DEFAULT_SETTINGS=e;
|
|
2
2
|
//# sourceMappingURL=settings.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings.cjs","names":[],"sources":["../../src/services/settings.ts"],"sourcesContent":["import { Settings } from \"#/types/settings\";\n\nexport const LATEST_SETTINGS_VERSION = 5;\n\nexport const DEFAULT_SETTINGS: Settings = {\n llm_model: \"openhands/
|
|
1
|
+
{"version":3,"file":"settings.cjs","names":[],"sources":["../../src/services/settings.ts"],"sourcesContent":["import { Settings } from \"#/types/settings\";\n\nexport const LATEST_SETTINGS_VERSION = 5;\n\nexport const DEFAULT_SETTINGS: Settings = {\n llm_model: \"openhands/kimi-k3\",\n llm_base_url: \"\",\n agent: \"CodeActAgent\",\n language: \"en\",\n llm_api_key: null,\n llm_api_key_set: false,\n search_api_key_set: false,\n confirmation_mode: false,\n security_analyzer: \"llm\",\n max_iterations: null,\n remote_runtime_resource_factor: 1,\n provider_tokens_set: {},\n enable_default_condenser: true,\n condenser_max_size: 240,\n enable_sound_notifications: false,\n user_consents_to_analytics: null,\n enable_proactive_conversation_starters: false,\n enable_solvability_analysis: false,\n search_api_key: \"\",\n is_new_user: true,\n disabled_skills: [],\n mcp_config: {},\n max_budget_per_task: null,\n email: \"\",\n email_verified: true,\n git_user_name: \"openhands\",\n git_user_email: \"openhands@all-hands.dev\",\n title_llm_profile: null,\n agent_settings_schema: null,\n agent_settings: {\n schema_version: 6,\n agent_kind: \"openhands\",\n agent: \"CodeActAgent\",\n llm: {\n model: \"openhands/kimi-k3\",\n },\n condenser: {\n enabled: true,\n max_size: 240,\n },\n verification: {\n critic_enabled: false,\n enable_iterative_refinement: false,\n },\n enable_sub_agents: false,\n mcp_config: {},\n },\n conversation_settings_schema: null,\n conversation_settings: {\n schema_version: 1,\n confirmation_mode: false,\n security_analyzer: \"llm\",\n },\n};\n\n/**\n * Get the default settings\n */\nexport const getDefaultSettings = (): Settings => DEFAULT_SETTINGS;\n"],"mappings":"6CAIA,IAAa,EAA6B,CACxC,UAAW,oBACX,aAAc,GACd,MAAO,eACP,SAAU,KACV,YAAa,KACb,gBAAiB,GACjB,mBAAoB,GACpB,kBAAmB,GACnB,kBAAmB,MACnB,eAAgB,KAChB,+BAAgC,EAChC,oBAAqB,CAAC,EACtB,yBAA0B,GAC1B,mBAAoB,IACpB,2BAA4B,GAC5B,2BAA4B,KAC5B,uCAAwC,GACxC,4BAA6B,GAC7B,eAAgB,GAChB,YAAa,GACb,gBAAiB,CAAC,EAClB,WAAY,CAAC,EACb,oBAAqB,KACrB,MAAO,GACP,eAAgB,GAChB,cAAe,YACf,eAAgB,0BAChB,kBAAmB,KACnB,sBAAuB,KACvB,eAAgB,CACd,eAAgB,EAChB,WAAY,YACZ,MAAO,eACP,IAAK,CACH,MAAO,mBACT,EACA,UAAW,CACT,QAAS,GACT,SAAU,GACZ,EACA,aAAc,CACZ,eAAgB,GAChB,4BAA6B,EAC/B,EACA,kBAAmB,GACnB,WAAY,CAAC,CACf,EACA,6BAA8B,KAC9B,sBAAuB,CACrB,eAAgB,EAChB,kBAAmB,GACnB,kBAAmB,KACrB,CACF"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//#region src/services/settings.ts
|
|
2
2
|
var e = {
|
|
3
|
-
llm_model: "openhands/
|
|
3
|
+
llm_model: "openhands/kimi-k3",
|
|
4
4
|
llm_base_url: "",
|
|
5
5
|
agent: "CodeActAgent",
|
|
6
6
|
language: "en",
|
|
@@ -33,7 +33,7 @@ var e = {
|
|
|
33
33
|
schema_version: 6,
|
|
34
34
|
agent_kind: "openhands",
|
|
35
35
|
agent: "CodeActAgent",
|
|
36
|
-
llm: { model: "openhands/
|
|
36
|
+
llm: { model: "openhands/kimi-k3" },
|
|
37
37
|
condenser: {
|
|
38
38
|
enabled: !0,
|
|
39
39
|
max_size: 240
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings.js","names":[],"sources":["../../src/services/settings.ts"],"sourcesContent":["import { Settings } from \"#/types/settings\";\n\nexport const LATEST_SETTINGS_VERSION = 5;\n\nexport const DEFAULT_SETTINGS: Settings = {\n llm_model: \"openhands/
|
|
1
|
+
{"version":3,"file":"settings.js","names":[],"sources":["../../src/services/settings.ts"],"sourcesContent":["import { Settings } from \"#/types/settings\";\n\nexport const LATEST_SETTINGS_VERSION = 5;\n\nexport const DEFAULT_SETTINGS: Settings = {\n llm_model: \"openhands/kimi-k3\",\n llm_base_url: \"\",\n agent: \"CodeActAgent\",\n language: \"en\",\n llm_api_key: null,\n llm_api_key_set: false,\n search_api_key_set: false,\n confirmation_mode: false,\n security_analyzer: \"llm\",\n max_iterations: null,\n remote_runtime_resource_factor: 1,\n provider_tokens_set: {},\n enable_default_condenser: true,\n condenser_max_size: 240,\n enable_sound_notifications: false,\n user_consents_to_analytics: null,\n enable_proactive_conversation_starters: false,\n enable_solvability_analysis: false,\n search_api_key: \"\",\n is_new_user: true,\n disabled_skills: [],\n mcp_config: {},\n max_budget_per_task: null,\n email: \"\",\n email_verified: true,\n git_user_name: \"openhands\",\n git_user_email: \"openhands@all-hands.dev\",\n title_llm_profile: null,\n agent_settings_schema: null,\n agent_settings: {\n schema_version: 6,\n agent_kind: \"openhands\",\n agent: \"CodeActAgent\",\n llm: {\n model: \"openhands/kimi-k3\",\n },\n condenser: {\n enabled: true,\n max_size: 240,\n },\n verification: {\n critic_enabled: false,\n enable_iterative_refinement: false,\n },\n enable_sub_agents: false,\n mcp_config: {},\n },\n conversation_settings_schema: null,\n conversation_settings: {\n schema_version: 1,\n confirmation_mode: false,\n security_analyzer: \"llm\",\n },\n};\n\n/**\n * Get the default settings\n */\nexport const getDefaultSettings = (): Settings => DEFAULT_SETTINGS;\n"],"mappings":";AAIA,IAAa,IAA6B;CACxC,WAAW;CACX,cAAc;CACd,OAAO;CACP,UAAU;CACV,aAAa;CACb,iBAAiB;CACjB,oBAAoB;CACpB,mBAAmB;CACnB,mBAAmB;CACnB,gBAAgB;CAChB,gCAAgC;CAChC,qBAAqB,CAAC;CACtB,0BAA0B;CAC1B,oBAAoB;CACpB,4BAA4B;CAC5B,4BAA4B;CAC5B,wCAAwC;CACxC,6BAA6B;CAC7B,gBAAgB;CAChB,aAAa;CACb,iBAAiB,CAAC;CAClB,YAAY,CAAC;CACb,qBAAqB;CACrB,OAAO;CACP,gBAAgB;CAChB,eAAe;CACf,gBAAgB;CAChB,mBAAmB;CACnB,uBAAuB;CACvB,gBAAgB;EACd,gBAAgB;EAChB,YAAY;EACZ,OAAO;EACP,KAAK,EACH,OAAO,oBACT;EACA,WAAW;GACT,SAAS;GACT,UAAU;EACZ;EACA,cAAc;GACZ,gBAAgB;GAChB,6BAA6B;EAC/B;EACA,mBAAmB;EACnB,YAAY,CAAC;CACf;CACA,8BAA8B;CAC9B,uBAAuB;EACrB,gBAAgB;EAChB,mBAAmB;EACnB,mBAAmB;CACrB;AACF"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
require("../_virtual/_rolldown/runtime.cjs");const e=require("../api/agent-server-config.cjs"),t=require("../package.cjs"),n=require("../api/client-source.cjs"),r=require("./telemetry-context.cjs");var i=`openhands-telemetry-consent`,a=`openhands-telemetry-consent-pending-cloud-sync`,o=`openhands-telemetry-consent-pending-local-revocation`,s=`openhands-telemetry-consent-change`,c=`openhands-telemetry-first-use`,l=`openhands-telemetry-session`,u=`agent-canvas`,d=`history_change`,f=`phc_BgzfxKdgsYMLFTmJqt424ZoyVHvKFfrwttLimzdYTKFK`,p=`https://z.openhands.dev`,m=`https://us.posthog.com`,h=null,g=null,_,v={},y=!1,b,x=0,S=-1,C=Object.freeze({client_source:n.AGENT_CANVAS_CLIENT_SOURCE,client_version:n.AGENT_CANVAS_CLIENT_VERSION,package_name:t.default.name,package_version:t.default.version}),w=r.getBackendTelemetryProperties({}),T=r.getCloudTelemetryProperties();function E(e){w=r.getBackendTelemetryProperties(e)}function D(e){T=r.getCloudTelemetryProperties(e)}function O(e){return e?{...e,properties:{...w,...T,...e.properties,...C}}:null}function k(e){y||z()!==`granted`?e.opt_out_capturing():e.opt_in_capturing()}function A(e,t=!1){e.reset(t),S=-1,k(e)}function j(e){if(b===void 0||!Y())return;let t=b?.distinctId,n=e.get_property(`$user_id`);if(n!=null&&n!==t&&A(e),b===null){S=x;return}(e.get_property(`$user_id`)!==b.distinctId||S!==x)&&(e.identify(b.distinctId,b.properties),S=x)}function M(e,t){let n=Object.keys(e);return n.length===Object.keys(t).length&&n.every(n=>e[n]===t[n])}function ee(e){if(e===!1){if(y)return;y=!0,h?.opt_out_capturing(),H();return}let t=y;if(y=!1,!h&&!g){let t=Object.fromEntries(Object.entries(e).filter(([,e])=>e!==void 0));v={...v,...t}}t&&(h&&(k(h),j(h)),H())}function N(){return y?null:{apiKey:v.apiKey||f,apiHost:v.apiHost||p,uiHost:v.uiHost||m}}function P(){return typeof window<`u`&&typeof localStorage<`u`}async function F(){if(!P())return null;if(h)return h;try{let{default:e}=await Promise.resolve().then(()=>require("../node_modules/posthog-js/dist/module.cjs"));return e}catch{return null}}function I(){return!!(y||typeof process<`u`&&process.env?.DO_NOT_TRACK===`1`||typeof navigator<`u`&&(navigator.doNotTrack===`1`||typeof window<`u`&&window.doNotTrack===`1`))}function L(e){h||(_=e)}async function R(e=!1){if(h)return h;if(g)return g;g=(async()=>{let t=N();if(!t)return null;let n=await F();if(!n)return null;let r=n.init(t.apiKey,{api_host:t.apiHost,ui_host:t.uiHost,opt_out_capturing_by_default:!e,persistence:`localStorage`,persistence_name:u,consent_persistence_name:`${u}-consent`,person_profiles:`always`,capture_pageview:d,autocapture:!0,disable_session_recording:!0,bootstrap:_,before_send:O},u);return r?(h=r,_=void 0,y?h.opt_out_capturing():z()===`granted`?(h.opt_in_capturing(),j(h)):e||h.opt_out_capturing(),h):null})();try{return await g}finally{h||(g=null)}}function z(){if(!P())return`pending`;if(I())return`denied`;if(e.getLockedCloudAuthMode()===`cookie`)return`granted`;try{let e=localStorage.getItem(i);if(e===`granted`||e===`denied`)return e}catch{}return`pending`}function B(){if(!P())return null;try{return localStorage.getItem(o)}catch{return null}}function V(e){if(!P())return()=>{};let t=t=>{(t.key===i||t.key===a)&&e()};return window.addEventListener(s,e),window.addEventListener(`storage`,t),()=>{window.removeEventListener(s,e),window.removeEventListener(`storage`,t)}}function H(){P()&&window.dispatchEvent(new Event(s))}function U(e){if(P())try{localStorage.setItem(a,e)}catch{}}function W(e){if(!(!P()||!e))try{localStorage.setItem(o,e)}catch{}}function G(e){if(P())try{if(localStorage.getItem(o)!==e)return;localStorage.removeItem(o)}catch{}}function K(e){if(P())try{if(e!==void 0&&localStorage.getItem(a)!==e)return;localStorage.removeItem(a),H()}catch{}}async function q(e,{syncToCloud:t=!0}={}){if(P())try{let t=z()===e;if(localStorage.setItem(i,e),y||t)return;let n=h??await R();if(!n)return;e===`granted`?(n.opt_in_capturing(),j(n)):(W(n.get_distinct_id?.()??null),n.get_property?.(`$user_id`)==null?n.opt_out_capturing():A(n))}catch{}finally{t&&U(e),H()}}async function J(e,t={}){let n=e===null?null:{distinctId:e,properties:t};if(b===n||b!=null&&n!==null&&b.distinctId===n.distinctId&&M(b.properties,t)||(b=n,x+=1,S=-1,!Y()))return;let r=h??await R();r&&Y()&&j(r)}function Y(){return z()===`granted`}function X(){if(!P())return!1;try{return localStorage.getItem(c)===`true`}catch{return!1}}function Z(){if(P())try{localStorage.setItem(c,`true`)}catch{}}async function Q(){if(I()||X())return;let e=await R(!0);!e||I()||((e.has_opted_out_capturing?.()??!1)&&e.opt_in_capturing(),e.capture(`canvas_install`,{platform:typeof navigator<`u`?navigator.platform:`unknown`,user_agent:typeof navigator<`u`?navigator.userAgent:`unknown`,referrer:typeof document<`u`?document.referrer:``,url_origin:typeof window<`u`?window.location.origin:``,embedded:typeof window<`u`&&window.self!==window.top}),Z(),z()!==`granted`&&e.opt_out_capturing())}function te(){if(!P())return!1;try{return sessionStorage.getItem(l)===`true`}catch{return!1}}function ne(){if(P())try{sessionStorage.setItem(l,`true`)}catch{}}async function $(){if(!Y()||z()!==`granted`)return null;let e=await R();return!e||!Y()?null:(e.has_opted_out_capturing?.()&&e.opt_in_capturing(),j(e),e)}async function re(){if(te())return;let e=await $();e&&(e.capture(`canvas_new_session`,{is_first_use:!X()}),ne())}async function ie(){return(await $())?.get_distinct_id?.()??null}async function ae(){if(!P())return null;if(z()!==`granted`){let e=B();if(e)return e}return y||I()?null:(await R())?.get_distinct_id?.()??null}async function oe(e,t={}){let n=await $();n&&n.capture(e,t)}async function se(
|
|
1
|
+
require("../_virtual/_rolldown/runtime.cjs");const e=require("../api/agent-server-config.cjs"),t=require("../package.cjs"),n=require("../api/client-source.cjs"),r=require("./telemetry-context.cjs");var i=`openhands-telemetry-consent`,a=`openhands-telemetry-consent-pending-cloud-sync`,o=`openhands-telemetry-consent-pending-local-revocation`,s=`openhands-telemetry-consent-change`,c=`openhands-telemetry-first-use`,l=`openhands-telemetry-session`,u=`agent-canvas`,d=`history_change`,f=`phc_BgzfxKdgsYMLFTmJqt424ZoyVHvKFfrwttLimzdYTKFK`,p=`https://z.openhands.dev`,m=`https://us.posthog.com`,h=null,g=null,_,v={},y=!1,b,x=0,S=-1,C=Object.freeze({client_source:n.AGENT_CANVAS_CLIENT_SOURCE,client_version:n.AGENT_CANVAS_CLIENT_VERSION,package_name:t.default.name,package_version:t.default.version}),w=r.getBackendTelemetryProperties({}),T=r.getCloudTelemetryProperties();function E(e){w=r.getBackendTelemetryProperties(e)}function D(e){T=r.getCloudTelemetryProperties(e)}function O(e){return e?{...e,properties:{...w,...T,...e.properties,...C}}:null}function k(e){y||z()!==`granted`?e.opt_out_capturing():e.opt_in_capturing()}function A(e,t=!1){e.reset(t),S=-1,k(e)}function j(e){if(b===void 0||!Y())return;let t=b?.distinctId,n=e.get_property(`$user_id`);if(n!=null&&n!==t&&A(e),b===null){S=x;return}(e.get_property(`$user_id`)!==b.distinctId||S!==x)&&(e.identify(b.distinctId,b.properties),S=x)}function M(e,t){let n=Object.keys(e);return n.length===Object.keys(t).length&&n.every(n=>e[n]===t[n])}function ee(e){if(e===!1){if(y)return;y=!0,h?.opt_out_capturing(),H();return}let t=y;if(y=!1,!h&&!g){let t=Object.fromEntries(Object.entries(e).filter(([,e])=>e!==void 0));v={...v,...t}}t&&(h&&(k(h),j(h)),H())}function N(){return y?null:{apiKey:v.apiKey||f,apiHost:v.apiHost||p,uiHost:v.uiHost||m}}function P(){return typeof window<`u`&&typeof localStorage<`u`}async function F(){if(!P())return null;if(h)return h;try{let{default:e}=await Promise.resolve().then(()=>require("../node_modules/posthog-js/dist/module.cjs"));return e}catch{return null}}function I(){return!!(y||typeof process<`u`&&process.env?.DO_NOT_TRACK===`1`||typeof navigator<`u`&&(navigator.doNotTrack===`1`||typeof window<`u`&&window.doNotTrack===`1`))}function L(e){h||(_=e)}async function R(e=!1){if(h)return h;if(g)return g;g=(async()=>{let t=N();if(!t)return null;let n=await F();if(!n)return null;let r=n.init(t.apiKey,{api_host:t.apiHost,ui_host:t.uiHost,opt_out_capturing_by_default:!e,persistence:`localStorage`,persistence_name:u,consent_persistence_name:`${u}-consent`,person_profiles:`always`,capture_pageview:d,autocapture:!0,disable_session_recording:!0,bootstrap:_,before_send:O},u);return r?(h=r,_=void 0,y?h.opt_out_capturing():z()===`granted`?(h.opt_in_capturing(),j(h)):e||h.opt_out_capturing(),h):null})();try{return await g}finally{h||(g=null)}}function z(){if(!P())return`pending`;if(I())return`denied`;if(e.getLockedCloudAuthMode()===`cookie`)return`granted`;try{let e=localStorage.getItem(i);if(e===`granted`||e===`denied`)return e}catch{}return`pending`}function B(){if(!P())return null;try{return localStorage.getItem(o)}catch{return null}}function V(e){if(!P())return()=>{};let t=t=>{(t.key===i||t.key===a)&&e()};return window.addEventListener(s,e),window.addEventListener(`storage`,t),()=>{window.removeEventListener(s,e),window.removeEventListener(`storage`,t)}}function H(){P()&&window.dispatchEvent(new Event(s))}function U(e){if(P())try{localStorage.setItem(a,e)}catch{}}function W(e){if(!(!P()||!e))try{localStorage.setItem(o,e)}catch{}}function G(e){if(P())try{if(localStorage.getItem(o)!==e)return;localStorage.removeItem(o)}catch{}}function K(e){if(P())try{if(e!==void 0&&localStorage.getItem(a)!==e)return;localStorage.removeItem(a),H()}catch{}}async function q(e,{syncToCloud:t=!0}={}){if(P())try{let t=z()===e;if(localStorage.setItem(i,e),y||t)return;let n=h??await R();if(!n)return;e===`granted`?(n.opt_in_capturing(),j(n)):(W(n.get_distinct_id?.()??null),n.get_property?.(`$user_id`)==null?n.opt_out_capturing():A(n))}catch{}finally{t&&U(e),H()}}async function J(e,t={}){let n=e===null?null:{distinctId:e,properties:t};if(b===n||b!=null&&n!==null&&b.distinctId===n.distinctId&&M(b.properties,t)||(b=n,x+=1,S=-1,!Y()))return;let r=h??await R();r&&Y()&&j(r)}function Y(){return z()===`granted`}function X(){if(!P())return!1;try{return localStorage.getItem(c)===`true`}catch{return!1}}function Z(){if(P())try{localStorage.setItem(c,`true`)}catch{}}async function Q(){if(I()||X())return;let e=await R(!0);!e||I()||((e.has_opted_out_capturing?.()??!1)&&e.opt_in_capturing(),e.capture(`canvas_install`,{platform:typeof navigator<`u`?navigator.platform:`unknown`,user_agent:typeof navigator<`u`?navigator.userAgent:`unknown`,referrer:typeof document<`u`?document.referrer:``,url_origin:typeof window<`u`?window.location.origin:``,embedded:typeof window<`u`&&window.self!==window.top}),Z(),z()!==`granted`&&e.opt_out_capturing())}function te(){if(!P())return!1;try{return sessionStorage.getItem(l)===`true`}catch{return!1}}function ne(){if(P())try{sessionStorage.setItem(l,`true`)}catch{}}async function $(){if(!Y()||z()!==`granted`)return null;let e=await R();return!e||!Y()?null:(e.has_opted_out_capturing?.()&&e.opt_in_capturing(),j(e),e)}async function re(){if(te())return;let e=await $();e&&(e.capture(`canvas_new_session`,{is_first_use:!X()}),ne())}async function ie(){return(await $())?.get_distinct_id?.()??null}async function ae(){if(!P())return null;if(z()!==`granted`){let e=B();if(e)return e}return y||I()?null:(await R())?.get_distinct_id?.()??null}async function oe(e,t={}){let n=await $();n&&n.capture(e,t)}async function se(){if(P()){try{W(h?.get_distinct_id?.()??null),localStorage.removeItem(i),localStorage.removeItem(c)}catch{}K();try{sessionStorage.removeItem(l)}catch{}w=r.getBackendTelemetryProperties({}),T=r.getCloudTelemetryProperties(),b=null,x+=1,S=-1;try{h&&A(h,!0)}catch{try{h?.opt_out_capturing()}catch{}}finally{H()}}}exports.clearPendingLocalTelemetryRevocation=G,exports.clearTelemetryData=se,exports.configurePostHogBootstrap=L,exports.configureTelemetry=ee,exports.getTelemetryConsent=z,exports.getTelemetryDistinctId=ie,exports.getTelemetryDistinctIdForConsentSync=ae,exports.initializePostHogClient=R,exports.isTelemetryEnabled=Y,exports.setTelemetryBackendContext=E,exports.setTelemetryCloudContext=D,exports.setTelemetryConsent=q,exports.setTelemetryIdentity=J,exports.subscribeTelemetryConsent=V,exports.trackEvent=oe,exports.trackInstall=Q,exports.trackSessionStart=re;
|
|
2
2
|
//# sourceMappingURL=telemetry.cjs.map
|