@openhands/agent-canvas 1.0.0-rc.8 → 1.0.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 +46 -31
- package/README.windows.md +2 -2
- package/bin/agent-canvas.mjs +3 -1
- package/build/assets/Trans-CBypf0vt.js +1 -0
- package/build/assets/{acp-providers-BqUvf67Q.js → acp-providers-BMyF5WII.js} +1 -1
- package/build/assets/active-backend-context-Cy_Ui5d7.js +1 -0
- package/build/assets/add-backend-modal-CUw7x0zm.js +1 -0
- package/build/assets/agent-server-client-options-FoO1qgAQ.js +1 -0
- package/build/assets/agent-server-conversation-service.api-D6Cmbnhd.js +5 -0
- package/build/assets/{agent-settings-DoHXHcoA.js → agent-settings-DW4vwOaz.js} +2 -2
- package/build/assets/{alert-banner-Bsvys-hT.js → alert-banner-BHmoArV2.js} +1 -1
- package/build/assets/{analytics-consent-form-modal-CVhsAREx.js → analytics-consent-form-modal-BNK0yu4L.js} +1 -1
- package/build/assets/api-key-entry-screen-BjVajIjf.js +1 -0
- package/build/assets/app-settings-C-5X6RzZ.js +1 -0
- package/build/assets/automation-detail-uDMoYmAc.js +1 -0
- package/build/assets/automations-list-DBCKCbId.js +1 -0
- package/build/assets/{back-nav-button-D20Avel_.js → back-nav-button-Bckz5Wh6.js} +1 -1
- package/build/assets/backend-form-modal-D2-XqJA4.js +1 -0
- package/build/assets/{backend-synced-settings-badge-Dcd4712m.js → backend-synced-settings-badge-Dx16CR_k.js} +1 -1
- package/build/assets/{base-modal-DvuGYyu1.js → base-modal-7QRNzf6r.js} +1 -1
- package/build/assets/{brand-button-9SOzmqPP.js → brand-button-CKLvirxz.js} +1 -1
- package/build/assets/browser-D1ZybR7v.js +5 -0
- package/build/assets/browser-store-hzasvz9c.js +1 -0
- package/build/assets/{browser-tab-bveyJhG9.js → browser-tab-iOQjXzmI.js} +1 -1
- package/build/assets/chat-send-button-_Uc9iFpG.js +1 -0
- package/build/assets/check-DfvhVBub.js +1 -0
- package/build/assets/{checkmark--JWAesua.js → checkmark-BHPhb50L.js} +1 -1
- package/build/assets/{chevron-down-B9j6lcFg.js → chevron-down-CMkqyPEY.js} +1 -1
- package/build/assets/{circle-plus-check-toggle-AO9DWyDX.js → circle-plus-check-toggle-ChmnRlpR.js} +1 -1
- package/build/assets/{close--W-tHn1h.js → close-DBs90sI6.js} +1 -1
- package/build/assets/{code-tag-chmctf4w.js → code-tag-BtHOqHwB.js} +1 -1
- package/build/assets/{color-themes-0biOprdo.js → color-themes-CBikRn3w.js} +1 -1
- package/build/assets/{combobox-caret-C9BNHfSu.js → combobox-caret-evUAh6YW.js} +1 -1
- package/build/assets/{command-store-UzKGSUC2.js → command-store-DZfR8QtE.js} +1 -1
- package/build/assets/condenser-settings-0tw3yXX8.js +1 -0
- package/build/assets/{confirmation-modal-Cq3eqvqH.js → confirmation-modal-DWuxe1zG.js} +1 -1
- package/build/assets/{context-menu-list-item-BQU0jZPq.js → context-menu-list-item-BbHFxHaq.js} +1 -1
- package/build/assets/conversation-B1v96pQf.js +19 -0
- package/build/assets/conversation-DgfcjCPm.js +1 -0
- package/build/assets/{conversation-local-storage-an3MiIiJ.js → conversation-local-storage-Btum2xBJ.js} +1 -1
- package/build/assets/conversation-panel-TJ7swm6a.js +1 -0
- package/build/assets/conversation-service.api-DXawvmNN.js +1 -0
- package/build/assets/conversation-state-store-DmuPn875.js +1 -0
- package/build/assets/{conversation-store-FQmakEd-.js → conversation-store-Bu89Yxg1.js} +1 -1
- package/build/assets/{conversation-tab-empty-state-C8tztloo.js → conversation-tab-empty-state-7js7FjYM.js} +1 -1
- package/build/assets/{copy-CdKN5rtJ.js → copy-B0SkXenR.js} +1 -1
- package/build/assets/copy-to-clipboard-button-CfH2EQz9.js +1 -0
- package/build/assets/{createLucideIcon-CkGTf9Qj.js → createLucideIcon-Bazr-V-B.js} +1 -1
- package/build/assets/declaration-Cn-NXHEy.js +1 -0
- package/build/assets/{device-verify-YuGXnpRk.js → device-verify-CWKyQ680.js} +1 -1
- package/build/assets/{dist-5dObF4p4.js → dist-Cbu6eGx8.js} +1 -1
- package/build/assets/dist-Dg2JWLGc.js +1 -0
- package/build/assets/{dropdown-classes-CVp0kVdt.js → dropdown-classes-BI1bI1ho.js} +1 -1
- package/build/assets/edit-automation-modal-DdAG6kFZ.js +1 -0
- package/build/assets/{ellipsis-button-k7HLwYth.js → ellipsis-button-DdCsOBHV.js} +1 -1
- package/build/assets/entry.client-DXyvKj5G.js +2 -0
- package/build/assets/{enum-filter-dropdown-COqUq3mB.js → enum-filter-dropdown-WROAIeys.js} +1 -1
- package/build/assets/{environment-switch-overlay-wB5LxfYZ.js → environment-switch-overlay-Dv0imPE6.js} +1 -1
- package/build/assets/{extensions-hub-CoWO3SzQ.js → extensions-hub-CkyDPXvn.js} +1 -1
- package/build/assets/{extensions-navigation-D5w2sFQe.js → extensions-navigation-gMR-la1J.js} +1 -1
- package/build/assets/{external-link-BATfjnkz.js → external-link-FsutnU75.js} +1 -1
- package/build/assets/files-tab-DNUoveJZ.js +1 -0
- package/build/assets/files-tab-store-SyvkH3ic.js +1 -0
- package/build/assets/{folder-DPTBlxWb.js → folder-DusyBXDE.js} +1 -1
- package/build/assets/{globe-Dpgjreyy.js → globe-BUcin4kT.js} +1 -1
- package/build/assets/home-D809jWVS.js +1 -0
- package/build/assets/{iconBase-BVhFI-0E.js → iconBase-B6CXDDaE.js} +1 -1
- package/build/assets/index-redirect-nMYgOTBX.js +1 -0
- package/build/assets/install-server-modal-D92Qy57I.js +1 -0
- package/build/assets/{launch-fU77utLO.js → launch-BnCG2g2a.js} +1 -1
- package/build/assets/lesson-plan-j-ZaE8vK.js +3 -0
- package/build/assets/{lightbulb-S616sGEL.js → lightbulb-BJ5tWmAh.js} +1 -1
- package/build/assets/{link-external-ooNztGLp.js → link-external-DUtmHAHi.js} +1 -1
- package/build/assets/{list-todo-nCa9zxVE.js → list-todo-C-gekh-4.js} +1 -1
- package/build/assets/{llm-client-P9f2gKeW.js → llm-client-BZUkZYlc.js} +1 -1
- package/build/assets/llm-not-configured-banner-PlvJ99rE.js +27 -0
- package/build/assets/llm-settings-Dgk32xRW.js +1 -0
- package/build/assets/llm-settings-Dxo7owKm.js +1 -0
- package/build/assets/llm-subscription-Bvu8BLXc.js +1 -0
- package/build/assets/llm-subscription-service-Bq6z3Wkv.js +1 -0
- package/build/assets/loader-circle-Cw7_q9hg.js +1 -0
- package/build/assets/{loading-spinner-D7bOU6I7.js → loading-spinner-RF3IlMF5.js} +1 -1
- package/build/assets/manage-backends-modal-BT66a6e0.js +1 -0
- package/build/assets/manifest-b8402d59.js +1 -0
- package/build/assets/markdown-renderer-Tw6FR2ad.js +2 -0
- package/build/assets/mcp-B_pA7vZg.js +9 -0
- package/build/assets/mcp-client-ppbYplKX.js +1 -0
- package/build/assets/messages-Cg9aNVi6.js +41 -0
- package/build/assets/{modal-backdrop-_VbcKk5K.js → modal-backdrop-DRpBVVW5.js} +1 -1
- package/build/assets/{modal-body-Cd-PtMHr.js → modal-body-CEV2O67p.js} +1 -1
- package/build/assets/{modal-classes-CNm4ovfm.js → modal-classes-B2DuQ9qD.js} +1 -1
- package/build/assets/{modal-close-button-Dbo0NAMt.js → modal-close-button-gtb7RHFB.js} +1 -1
- package/build/assets/model-selector-CAv3RrJ3.js +1 -0
- package/build/assets/{mouse-pointer-click-D0QNGSIo.js → mouse-pointer-click-B3i6HcaF.js} +1 -1
- package/build/assets/{navigation-context-BpAOh_t5.js → navigation-context-CM9JmTvm.js} +1 -1
- package/build/assets/{navigation-link-Dci7Nuyf.js → navigation-link-FmXzqR1J.js} +1 -1
- package/build/assets/onboarding-Q9CzuVWy.js +1 -0
- package/build/assets/{openhands-logo-Dzm-d_V_.js → openhands-logo-B4aEO2sf.js} +1 -1
- package/build/assets/option-service.api-C-s2BYZp.js +1 -0
- package/build/assets/organization-service.api-CXTKpFnV.js +1 -0
- package/build/assets/{path-utils-YlkpoImJ.js → path-utils-CE98fIFP.js} +1 -1
- package/build/assets/{pencil-DPEtl5QD.js → pencil-bWrxRWlr.js} +1 -1
- package/build/assets/{plan-components-CutRBi0G.js → plan-components-BF-X7vnQ.js} +1 -1
- package/build/assets/{planner-tab-DjIFIQDk.js → planner-tab-jkyaGiRc.js} +1 -1
- package/build/assets/plus-BTCK8WtR.js +1 -0
- package/build/assets/{profiles-client-BNvHck-I.js → profiles-client-CQ9L1yHR.js} +1 -1
- package/build/assets/providers-B3hkV58J.js +1 -0
- package/build/assets/proxy-BOcEWkCD.js +1 -0
- package/build/assets/{react-dom-hVBnwgwZ.js → react-dom-BBXlXOZX.js} +1 -1
- package/build/assets/{react-CM_dJw1Z.js → react-uQK8du1l.js} +1 -1
- package/build/assets/{react-Dy05vyj5.js → react-x84lbX6s.js} +1 -1
- package/build/assets/{recommended-automations-launcher-DCi0RXIj.js → recommended-automations-launcher-DMk35aFI.js} +11 -11
- package/build/assets/root-CV0kyxfP.js +2 -0
- package/build/assets/root-PB2Jnj61.css +1 -0
- package/build/assets/root-layout-Bl4Qzg5J.js +2 -0
- package/build/assets/{runtime-waiting-state-8i0Z3A_i.js → runtime-waiting-state-C1hJpXxl.js} +1 -1
- package/build/assets/sdk-section-page-DHbC2_j3.js +1 -0
- package/build/assets/sdk-settings-schema-z51bBmMl.js +1 -0
- package/build/assets/{search-C_l_XW4e.js → search-Dxm1MUMi.js} +1 -1
- package/build/assets/{secrets-service-D6Gcymcs.js → secrets-service-DlScPUwy.js} +1 -1
- package/build/assets/secrets-settings-B97-JKBe.js +1 -0
- package/build/assets/settings-BpmooyBV.js +1 -0
- package/build/assets/{settings-dropdown-input-BP-arqjU.js → settings-dropdown-input-hIIAlmHb.js} +1 -1
- package/build/assets/{settings-gear-f-zWpxfI.js → settings-gear-DQLTCnFx.js} +1 -1
- package/build/assets/{settings-index-B035V2pu.js → settings-index-kKASonWk.js} +1 -1
- package/build/assets/{settings-input-BM8ANxDb.js → settings-input-BlOzCtP3.js} +1 -1
- package/build/assets/{settings-list-classes-B9uo5WES.js → settings-list-classes-BFRbCy4U.js} +1 -1
- package/build/assets/settings-modal-C4pZwj-l.js +1 -0
- package/build/assets/{settings-section-header-context-Cid25HM2.js → settings-section-header-context-iz4Go0dL.js} +1 -1
- package/build/assets/settings-service.api-DVLwi82B.js +1 -0
- package/build/assets/{settings-switch-xa6q4M6j.js → settings-switch-6cXIH-UE.js} +1 -1
- package/build/assets/{settings-utils--H_EvFjx.js → settings-utils-CfScEaPn.js} +1 -1
- package/build/assets/shared-conversation-CLkayApe.js +1 -0
- package/build/assets/sidebar-mobile-menu-toggle-C8uT4Mhd.js +1 -0
- package/build/assets/{sidebar-nav-link-CPWuQ_c6.js → sidebar-nav-link-BKZiAQxQ.js} +1 -1
- package/build/assets/{skill-card-pill-row-DeodrwPG.js → skill-card-pill-row-D13WRKIE.js} +1 -1
- package/build/assets/{skills-BE5HJuGM.js → skills-NpRk6v79.js} +1 -1
- package/build/assets/{skills-client-Ui_9FvXp.js → skills-client-DsqwQEwj.js} +1 -1
- package/build/assets/{skills-plugins-Dc4ec3CW.js → skills-plugins-bkwxItAw.js} +1 -1
- package/build/assets/{skills-settings-B6HwvA0S.js → skills-settings-DMbrlB2b.js} +2 -2
- package/build/assets/{square-chevron-right-BWAB7NPp.js → square-chevron-right-DxZKcVq4.js} +1 -1
- package/build/assets/{styled-tooltip-X61SEwqk.js → styled-tooltip-DG1ofAcS.js} +1 -1
- package/build/assets/suspense-sOGeme-f.js +1 -0
- package/build/assets/{switch-skeleton-BbIWemkK.js → switch-skeleton-CZ6XCVZk.js} +1 -1
- package/build/assets/{task-list-tab-BFnyHGsn.js → task-list-tab-CddMPNCD.js} +1 -1
- package/build/assets/telemetry-CX4mTZUw.js +2 -0
- package/build/assets/{terminal-CltMeLv4.js → terminal-BOAVxAej.js} +1 -1
- package/build/assets/{terminal-B92mACR5.js → terminal-DbtwHqt4.js} +1 -1
- package/build/assets/{toggle-switch-CL_wRiGs.js → toggle-switch-C0t6ge2m.js} +1 -1
- package/build/assets/{trash-2-C-RvV8WA.js → trash-2-Dmprz0A0.js} +1 -1
- package/build/assets/{typography-BLSEGjph.js → typography-CNHbO1eE.js} +1 -1
- package/build/assets/{u-check-circle-dG_VJqx5.js → u-check-circle-CX66WzfT.js} +1 -1
- package/build/assets/{u-check-circle-half-D-5ZPRnd.js → u-check-circle-half-Bj853Ub0.js} +1 -1
- package/build/assets/{u-circuit-BXoisXOA.js → u-circuit-B9bLCP7N.js} +1 -1
- package/build/assets/{u-edit-DIgADxLH.js → u-edit-D7JyvoWm.js} +1 -1
- package/build/assets/use-acp-credential-form-Cj_oUYd5.js +1 -0
- package/build/assets/{use-active-conversation-B0_rXnqa.js → use-active-conversation-B64-yy2X.js} +1 -1
- package/build/assets/use-agent-settings-schema-BzbQYEzb.js +1 -0
- package/build/assets/{use-agent-state-BuOzLeFN.js → use-agent-state-DxFk391r.js} +1 -1
- package/build/assets/{use-breakpoint-DpxHDmuH.js → use-breakpoint-Cent5lpI.js} +1 -1
- package/build/assets/{use-click-outside-element-DhxCUyWl.js → use-click-outside-element-DOYR26nw.js} +1 -1
- package/build/assets/{use-cloud-current-user-id-DVZXa_WH.js → use-cloud-current-user-id-BVf7pb8n.js} +1 -1
- package/build/assets/use-config-CvdJUq4E.js +1 -0
- package/build/assets/use-create-conversation-Cnouynop.js +1 -0
- package/build/assets/{use-create-secret-ClPpLBgD.js → use-create-secret-Cgu4uxyr.js} +1 -1
- package/build/assets/{use-event-store-DNSmyzUh.js → use-event-store-Nv92IYMU.js} +1 -1
- package/build/assets/use-handle-plan-click-C7824bbe.js +1 -0
- package/build/assets/use-is-authed-mnJtd2bw.js +1 -0
- package/build/assets/{use-launch-skill-in-chat-BTgXIu3N.js → use-launch-skill-in-chat-NDUo_UCA.js} +1 -1
- package/build/assets/use-llm-profiles-9eH3Y3Ef.js +1 -0
- package/build/assets/use-runtime-is-ready-DEnxJH7W.js +1 -0
- package/build/assets/use-save-settings-DrClHnX7.js +1 -0
- package/build/assets/use-settings-BNAoCX93.js +1 -0
- package/build/assets/{use-settings-nav-items-DVrMNk0I.js → use-settings-nav-items-CLIW2p2n.js} +2 -2
- package/build/assets/{use-skills-Bv8LXrys.js → use-skills-B9gOHrOj.js} +1 -1
- package/build/assets/{use-task-list-E5t-jtgs.js → use-task-list-DLKPnq3I.js} +1 -1
- package/build/assets/{use-tracking-BhyV5A9i.js → use-tracking-Dph_dRlL.js} +1 -1
- package/build/assets/{use-user-conversation-6yFVEXiG.js → use-user-conversation-leIsQH1B.js} +1 -1
- package/build/assets/useMutation-cXADjWAv.js +1 -0
- package/build/assets/useQuery-BQr6A6ry.js +1 -0
- package/build/assets/useTranslation-Bp1btAjp.js +1 -0
- package/build/assets/{utils-eXk6yerZ.js → utils-o-OXNtEy.js} +1 -1
- package/build/assets/v4-DOSjXdIn.js +1 -0
- package/build/assets/{vendor~browser-tab-BGJDGHyS.js → vendor~browser-tab-642bOcE1.js} +1 -1
- package/build/assets/{vendor~conversation-panel~conversation-D98u43rl.js → vendor~conversation-panel~conversation-DqmbnXRn.js} +1 -1
- package/build/assets/{vendor~conversation-panel~conversation~alert-banner-CtjHOMO_.js → vendor~conversation-panel~conversation~alert-banner-CSDVP1nw.js} +1 -1
- package/build/assets/{vendor~conversation-panel~conversation~index-BXt2-3Cc.js → vendor~conversation-panel~conversation~index-DITarr3F.js} +1 -1
- package/build/assets/{vendor~entry.client-DrAdOKqA.js → vendor~entry.client-CQ77DucR.js} +1 -1
- package/build/assets/{vendor~entry.client-EcEhmoJW.js → vendor~entry.client-ePAFmSwg.js} +1 -1
- package/build/assets/vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~f0pn7nss-DUk-MwlC.js +177 -0
- package/build/assets/vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~lb3qbbk3-BvmOva8I.js +1 -0
- package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~lpdshwee-Cl4h-NSi.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~lpdshwee-BkQQxq_q.js} +1 -1
- package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~oli4dvxu-BmOMM-6e.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~oli4dvxu-8xF3WeB9.js} +1 -1
- package/build/assets/{vendor~entry.client~root~root-layout~index-redirect~home~conversation-panel~conversation~la~cnj3raoq-BjMt2JeR.js → vendor~entry.client~root~root-layout~index-redirect~home~conversation-panel~conversation~la~nyk4vv4g-UzR6fe3Y.js} +1 -1
- package/build/assets/{vendor~files-tab--640YzQO.js → vendor~files-tab-Cko7Kr5k.js} +1 -1
- package/build/assets/{vendor~home~conversation-panel~conversation-dhKA2JVJ.js → vendor~home~conversation-panel~conversation-D3otw5Jn.js} +1 -1
- package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DMOoHVBy.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-CMdKUYP2.js} +1 -1
- package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-BoE6JRJj.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DSR6Mugx.js} +1 -1
- package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-Dqpi2xyZ.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DdOzMvB1.js} +1 -1
- package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DX2CmDJ0.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-Dj2eezvL.js} +1 -1
- package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-BNExlCqT.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DyN8jeZz.js} +1 -1
- package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DCn1M97v.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-lpEWrbMA.js} +1 -1
- package/build/assets/{vendor~launch-C0VvUe2W.js → vendor~launch-DoYO54df.js} +1 -1
- package/build/assets/{vendor~root-layout~conversation-panel~conversation~shared-conversation-COLUW-6M.js → vendor~root-layout~conversation-panel~conversation~shared-conversation-BGwU2SbU.js} +1 -1
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation-eG1kjEbj.js → vendor~root-layout~home~conversation-panel~conversation-Iqs0j4Wo.js} +1 -1
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~bok0tgtf-7eqKdLSQ.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~bok0tgtf-BdS6bbw9.js} +1 -1
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~bok0tgtf-BP3MGAAY.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~bok0tgtf-Fd3F3jth.js} +1 -1
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~ceijy54y-Dkd2wxJA.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~ceijy54y-Cg0AqwMN.js} +2 -2
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~bxn4ldi1-_LydBB1e.js → vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~bxn4ldi1-BlsbqRyZ.js} +1 -1
- package/build/assets/vendor~root-layout~home~conversation-panel~conversation~launch~settings~settings-index~agen~ec6pk3ix-CBICqfKC.js +48 -0
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~launch~skills-settings~mcp~automati~dou5smdo-DavKsAvB.js → vendor~root-layout~home~conversation-panel~conversation~launch~skills-settings~automations-~nv6afr11-BYNoKMU0.js} +97 -69
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~shared-conversation~alert-banner~pl~rqjteh0a-CsO1gYxF.js → vendor~root-layout~home~conversation-panel~conversation~shared-conversation~alert-banner~pl~rqjteh0a-BspUuSsP.js} +1 -1
- package/build/assets/{vendor~root-layout~home~mcp~automations-list-D40jgugf.js → vendor~root-layout~home~mcp~automations-list-C9U_eOqU.js} +1 -1
- package/build/assets/{vendor~root-layout~home~mcp~automations-list-cNHi83v_.js → vendor~root-layout~home~mcp~automations-list-DhQ3LPVw.js} +1 -1
- package/build/assets/{vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-xCM3k6Rd.js → vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-BEbhHQYg.js} +1 -1
- package/build/assets/{vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-BIm99UaF.js → vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-DdgDNzMc.js} +2 -2
- package/build/assets/{verification-settings-Be6NxjuT.js → verification-settings-D7R-Ne6L.js} +1 -1
- package/build/assets/x-DCZg87p7.js +1 -0
- package/build/assets/{x-mark-C42svtnu.js → x-mark-jrBTJbnP.js} +1 -1
- package/build/index.html +4 -4
- package/build/locales/ar/openhands.json +22 -0
- package/build/locales/ca/openhands.json +22 -0
- package/build/locales/de/openhands.json +22 -0
- package/build/locales/en/openhands.json +22 -0
- package/build/locales/es/openhands.json +22 -0
- package/build/locales/fr/openhands.json +22 -0
- package/build/locales/it/openhands.json +22 -0
- package/build/locales/ja/openhands.json +22 -0
- package/build/locales/ko-KR/openhands.json +22 -0
- package/build/locales/no/openhands.json +22 -0
- package/build/locales/pt/openhands.json +22 -0
- package/build/locales/tr/openhands.json +22 -0
- package/build/locales/uk/openhands.json +22 -0
- package/build/locales/zh-CN/openhands.json +22 -0
- package/build/locales/zh-TW/openhands.json +22 -0
- package/config/defaults.json +4 -7
- package/dist/api/agent-server-adapter.cjs +3 -3
- package/dist/api/agent-server-adapter.cjs.map +1 -1
- package/dist/api/agent-server-adapter.d.ts +8 -0
- package/dist/api/agent-server-adapter.js +82 -80
- package/dist/api/agent-server-adapter.js.map +1 -1
- package/dist/api/agent-server-compatibility.cjs +1 -1
- package/dist/api/agent-server-compatibility.cjs.map +1 -1
- package/dist/api/agent-server-compatibility.d.ts +10 -0
- package/dist/api/agent-server-compatibility.js +69 -25
- package/dist/api/agent-server-compatibility.js.map +1 -1
- package/dist/api/backend-registry/default-backend.cjs +1 -1
- package/dist/api/backend-registry/default-backend.cjs.map +1 -1
- package/dist/api/backend-registry/default-backend.d.ts +6 -5
- package/dist/api/backend-registry/default-backend.js +1 -1
- package/dist/api/backend-registry/default-backend.js.map +1 -1
- package/dist/api/backend-registry/storage.cjs +1 -1
- package/dist/api/backend-registry/storage.cjs.map +1 -1
- package/dist/api/backend-registry/storage.js +38 -68
- package/dist/api/backend-registry/storage.js.map +1 -1
- package/dist/api/cloud/proxy.cjs +1 -1
- package/dist/api/cloud/proxy.cjs.map +1 -1
- package/dist/api/cloud/proxy.d.ts +3 -16
- package/dist/api/cloud/proxy.js +1 -1
- package/dist/api/cloud/proxy.js.map +1 -1
- package/dist/api/conversation-service/agent-server-conversation-service.api.cjs +1 -1
- package/dist/api/conversation-service/agent-server-conversation-service.api.cjs.map +1 -1
- package/dist/api/conversation-service/agent-server-conversation-service.api.js +75 -75
- package/dist/api/conversation-service/agent-server-conversation-service.api.js.map +1 -1
- package/dist/api/llm-subscription-service.cjs +2 -0
- package/dist/api/llm-subscription-service.cjs.map +1 -0
- package/dist/api/llm-subscription-service.d.ts +23 -0
- package/dist/api/llm-subscription-service.js +109 -0
- package/dist/api/llm-subscription-service.js.map +1 -0
- package/dist/api/mcp-service/mcp-service.api.cjs +1 -1
- package/dist/api/mcp-service/mcp-service.api.cjs.map +1 -1
- package/dist/api/mcp-service/mcp-service.api.d.ts +2 -3
- package/dist/api/mcp-service/mcp-service.api.js +38 -13
- package/dist/api/mcp-service/mcp-service.api.js.map +1 -1
- package/dist/api/settings-service/settings-service.api.cjs +1 -1
- package/dist/api/settings-service/settings-service.api.cjs.map +1 -1
- package/dist/api/settings-service/settings-service.api.js +41 -42
- package/dist/api/settings-service/settings-service.api.js.map +1 -1
- package/dist/components/conversation-events/chat/messages.cjs +1 -1
- package/dist/components/conversation-events/chat/messages.cjs.map +1 -1
- package/dist/components/conversation-events/chat/messages.js +4 -4
- package/dist/components/conversation-events/chat/messages.js.map +1 -1
- package/dist/components/features/backends/backend-form-modal.cjs +1 -1
- package/dist/components/features/backends/backend-form-modal.cjs.map +1 -1
- package/dist/components/features/backends/backend-form-modal.js +136 -135
- package/dist/components/features/backends/backend-form-modal.js.map +1 -1
- package/dist/components/features/backends/backend-selector.cjs +1 -1
- package/dist/components/features/backends/backend-selector.cjs.map +1 -1
- package/dist/components/features/backends/backend-selector.js +103 -91
- package/dist/components/features/backends/backend-selector.js.map +1 -1
- package/dist/components/features/backends/manage-backends-modal.cjs +1 -1
- package/dist/components/features/backends/manage-backends-modal.cjs.map +1 -1
- package/dist/components/features/backends/manage-backends-modal.js +14 -8
- package/dist/components/features/backends/manage-backends-modal.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 +1 -1
- package/dist/components/features/chat/path-component.js.map +1 -1
- package/dist/components/features/home/workspace-dropdown/folder-browser-modal.cjs +1 -1
- package/dist/components/features/home/workspace-dropdown/folder-browser-modal.cjs.map +1 -1
- package/dist/components/features/home/workspace-dropdown/folder-browser-modal.js +77 -66
- package/dist/components/features/home/workspace-dropdown/folder-browser-modal.js.map +1 -1
- package/dist/components/features/mcp-page/custom-server-editor.cjs +1 -1
- package/dist/components/features/mcp-page/custom-server-editor.cjs.map +1 -1
- package/dist/components/features/mcp-page/custom-server-editor.js +1 -0
- package/dist/components/features/mcp-page/custom-server-editor.js.map +1 -1
- package/dist/components/features/mcp-page/install-server-modal.cjs +1 -1
- package/dist/components/features/mcp-page/install-server-modal.cjs.map +1 -1
- package/dist/components/features/mcp-page/install-server-modal.js +73 -46
- package/dist/components/features/mcp-page/install-server-modal.js.map +1 -1
- package/dist/components/features/mcp-page/marketplace-card.cjs +1 -1
- package/dist/components/features/mcp-page/marketplace-card.cjs.map +1 -1
- package/dist/components/features/mcp-page/marketplace-card.js +6 -2
- package/dist/components/features/mcp-page/marketplace-card.js.map +1 -1
- package/dist/components/features/settings/brand-button.cjs +1 -1
- package/dist/components/features/settings/brand-button.cjs.map +1 -1
- package/dist/components/features/settings/brand-button.js +1 -1
- package/dist/components/features/settings/brand-button.js.map +1 -1
- package/dist/components/features/settings/llm-settings/openai-subscription-auth-card.cjs +2 -0
- package/dist/components/features/settings/llm-settings/openai-subscription-auth-card.cjs.map +1 -0
- package/dist/components/features/settings/llm-settings/openai-subscription-auth-card.d.ts +5 -0
- package/dist/components/features/settings/llm-settings/openai-subscription-auth-card.js +167 -0
- package/dist/components/features/settings/llm-settings/openai-subscription-auth-card.js.map +1 -0
- package/dist/components/shared/modals/settings/model-selector.cjs +1 -1
- package/dist/components/shared/modals/settings/model-selector.cjs.map +1 -1
- package/dist/components/shared/modals/settings/model-selector.d.ts +1 -2
- package/dist/components/shared/modals/settings/model-selector.js +59 -65
- package/dist/components/shared/modals/settings/model-selector.js.map +1 -1
- package/dist/components/shared/modals/settings/settings-form.cjs +1 -1
- package/dist/components/shared/modals/settings/settings-form.cjs.map +1 -1
- package/dist/components/shared/modals/settings/settings-form.js +1 -2
- package/dist/components/shared/modals/settings/settings-form.js.map +1 -1
- package/dist/config/defaults.cjs +2 -0
- package/dist/config/defaults.cjs.map +1 -0
- package/dist/config/defaults.js +35 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/constants/llm-subscription.cjs +2 -0
- package/dist/constants/llm-subscription.cjs.map +1 -0
- package/dist/constants/llm-subscription.d.ts +16 -0
- package/dist/constants/llm-subscription.js +47 -0
- package/dist/constants/llm-subscription.js.map +1 -0
- package/dist/contexts/conversation-websocket-context.cjs +1 -1
- package/dist/contexts/conversation-websocket-context.cjs.map +1 -1
- package/dist/contexts/conversation-websocket-context.js +1 -1
- package/dist/contexts/conversation-websocket-context.js.map +1 -1
- package/dist/hooks/mutation/use-llm-subscription-auth.cjs +2 -0
- package/dist/hooks/mutation/use-llm-subscription-auth.cjs.map +1 -0
- package/dist/hooks/mutation/use-llm-subscription-auth.d.ts +3 -0
- package/dist/hooks/mutation/use-llm-subscription-auth.js +30 -0
- package/dist/hooks/mutation/use-llm-subscription-auth.js.map +1 -0
- package/dist/hooks/mutation/use-save-fields-as-secrets.cjs +1 -1
- package/dist/hooks/mutation/use-save-fields-as-secrets.cjs.map +1 -1
- package/dist/hooks/mutation/use-save-fields-as-secrets.d.ts +8 -6
- package/dist/hooks/mutation/use-save-fields-as-secrets.js +1 -1
- package/dist/hooks/mutation/use-save-fields-as-secrets.js.map +1 -1
- package/dist/hooks/mutation/use-test-mcp-server.d.ts +1 -1
- package/dist/hooks/query/query-keys.cjs +1 -1
- package/dist/hooks/query/query-keys.cjs.map +1 -1
- package/dist/hooks/query/query-keys.d.ts +5 -0
- package/dist/hooks/query/query-keys.js +14 -2
- package/dist/hooks/query/query-keys.js.map +1 -1
- package/dist/hooks/query/use-agent-settings-schema.cjs +1 -1
- package/dist/hooks/query/use-agent-settings-schema.cjs.map +1 -1
- package/dist/hooks/query/use-agent-settings-schema.d.ts +2 -2
- package/dist/hooks/query/use-agent-settings-schema.js +21 -19
- package/dist/hooks/query/use-agent-settings-schema.js.map +1 -1
- package/dist/hooks/query/use-backends-health.cjs +1 -1
- package/dist/hooks/query/use-backends-health.cjs.map +1 -1
- package/dist/hooks/query/use-backends-health.js +38 -36
- package/dist/hooks/query/use-backends-health.js.map +1 -1
- package/dist/hooks/query/use-llm-subscription-models.cjs +2 -0
- package/dist/hooks/query/use-llm-subscription-models.cjs.map +1 -0
- package/dist/hooks/query/use-llm-subscription-models.d.ts +3 -0
- package/dist/hooks/query/use-llm-subscription-models.js +19 -0
- package/dist/hooks/query/use-llm-subscription-models.js.map +1 -0
- package/dist/hooks/query/use-llm-subscription-status.cjs +2 -0
- package/dist/hooks/query/use-llm-subscription-status.cjs.map +1 -0
- package/dist/hooks/query/use-llm-subscription-status.d.ts +3 -0
- package/dist/hooks/query/use-llm-subscription-status.js +19 -0
- package/dist/hooks/query/use-llm-subscription-status.js.map +1 -0
- package/dist/hooks/use-websocket.cjs +1 -1
- package/dist/hooks/use-websocket.cjs.map +1 -1
- package/dist/hooks/use-websocket.d.ts +0 -1
- package/dist/hooks/use-websocket.js +37 -38
- package/dist/hooks/use-websocket.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 +22 -0
- package/dist/i18n/declaration.js +1 -1
- package/dist/i18n/declaration.js.map +1 -1
- package/dist/i18n/translation.cjs +2 -2
- package/dist/i18n/translation.cjs.map +1 -1
- package/dist/i18n/translation.js +374 -0
- package/dist/i18n/translation.js.map +1 -1
- package/dist/locales/ar/openhands.json +22 -0
- package/dist/locales/ca/openhands.json +22 -0
- package/dist/locales/de/openhands.json +22 -0
- package/dist/locales/en/openhands.json +22 -0
- package/dist/locales/es/openhands.json +22 -0
- package/dist/locales/fr/openhands.json +22 -0
- package/dist/locales/it/openhands.json +22 -0
- package/dist/locales/ja/openhands.json +22 -0
- package/dist/locales/ko-KR/openhands.json +22 -0
- package/dist/locales/no/openhands.json +22 -0
- package/dist/locales/pt/openhands.json +22 -0
- package/dist/locales/tr/openhands.json +22 -0
- package/dist/locales/uk/openhands.json +22 -0
- package/dist/locales/zh-CN/openhands.json +22 -0
- package/dist/locales/zh-TW/openhands.json +22 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/github.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/github.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/github.js +10 -22
- package/dist/node_modules/@openhands/extensions/integrations/catalog/github.js.map +1 -1
- package/dist/node_modules/@openhands/extensions/skills/index.cjs +97 -69
- package/dist/node_modules/@openhands/extensions/skills/index.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/skills/index.js +3 -3
- package/dist/node_modules/@openhands/extensions/skills/index.js.map +1 -1
- package/dist/package.cjs +1 -1
- package/dist/package.cjs.map +1 -1
- package/dist/package.js +3 -5
- package/dist/package.js.map +1 -1
- package/dist/routes/files-tab.cjs +1 -1
- package/dist/routes/files-tab.cjs.map +1 -1
- package/dist/routes/files-tab.js +28 -17
- package/dist/routes/files-tab.js.map +1 -1
- package/dist/routes/llm-settings.cjs +1 -1
- package/dist/routes/llm-settings.cjs.map +1 -1
- package/dist/routes/llm-settings.js +142 -85
- package/dist/routes/llm-settings.js.map +1 -1
- package/dist/services/canvas-ui.cjs +1 -1
- package/dist/services/canvas-ui.cjs.map +1 -1
- package/dist/services/canvas-ui.d.ts +1 -1
- package/dist/services/canvas-ui.js +2 -2
- package/dist/services/canvas-ui.js.map +1 -1
- package/dist/stores/files-tab-store.cjs +1 -1
- package/dist/stores/files-tab-store.cjs.map +1 -1
- package/dist/stores/files-tab-store.d.ts +2 -1
- package/dist/stores/files-tab-store.js +5 -1
- package/dist/stores/files-tab-store.js.map +1 -1
- package/dist/stores/use-event-store.cjs +1 -1
- package/dist/stores/use-event-store.cjs.map +1 -1
- package/dist/stores/use-event-store.js +39 -34
- package/dist/stores/use-event-store.js.map +1 -1
- package/dist/types/mcp-server.d.ts +21 -0
- package/dist/ui/dropdown/dropdown.cjs +1 -1
- package/dist/ui/dropdown/dropdown.cjs.map +1 -1
- package/dist/ui/dropdown/dropdown.js +6 -2
- package/dist/ui/dropdown/dropdown.js.map +1 -1
- package/dist/utils/handle-event-for-ui.cjs +1 -1
- package/dist/utils/handle-event-for-ui.cjs.map +1 -1
- package/dist/utils/handle-event-for-ui.d.ts +2 -0
- package/dist/utils/handle-event-for-ui.js +1 -1
- package/dist/utils/handle-event-for-ui.js.map +1 -1
- package/dist/utils/llm-subscription-schema.cjs +2 -0
- package/dist/utils/llm-subscription-schema.cjs.map +1 -0
- package/dist/utils/llm-subscription-schema.d.ts +2 -0
- package/dist/utils/llm-subscription-schema.js +22 -0
- package/dist/utils/llm-subscription-schema.js.map +1 -0
- package/dist/utils/mcp-config.cjs +1 -1
- package/dist/utils/mcp-config.cjs.map +1 -1
- package/dist/utils/mcp-config.js +32 -17
- package/dist/utils/mcp-config.js.map +1 -1
- package/dist/utils/mcp-credential-validation.cjs +2 -0
- package/dist/utils/mcp-credential-validation.cjs.map +1 -0
- package/dist/utils/mcp-credential-validation.d.ts +22 -0
- package/dist/utils/mcp-credential-validation.js +31 -0
- package/dist/utils/mcp-credential-validation.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 -2
- package/dist/utils/mcp-marketplace-utils.js +33 -48
- package/dist/utils/mcp-marketplace-utils.js.map +1 -1
- package/dist/utils/sdk-settings-schema.cjs +1 -1
- package/dist/utils/sdk-settings-schema.cjs.map +1 -1
- package/dist/utils/sdk-settings-schema.js +64 -61
- package/dist/utils/sdk-settings-schema.js.map +1 -1
- package/dist/utils/websocket-url.cjs +1 -1
- package/dist/utils/websocket-url.cjs.map +1 -1
- package/dist/utils/websocket-url.js +2 -2
- package/dist/utils/websocket-url.js.map +1 -1
- package/package.json +3 -5
- package/scripts/check-sdk-version-sync.mjs +9 -27
- package/scripts/dev-with-automation.mjs +1 -3
- package/scripts/docker-build.mjs +0 -4
- package/scripts/run-staged-typecheck.mjs +44 -0
- package/build/assets/QueryClientProvider-XcSjsfpb.js +0 -1
- package/build/assets/Trans-sy4l4TyQ.js +0 -1
- package/build/assets/active-backend-context-CNF2lPkA.js +0 -1
- package/build/assets/add-backend-modal-BywVr6uq.js +0 -1
- package/build/assets/agent-server-adapter-k8veH-1O.js +0 -5
- package/build/assets/agent-server-client-options-B-C8JaTb.js +0 -1
- package/build/assets/agent-server-conversation-service.api-CGbkhsLj.js +0 -1
- package/build/assets/api-key-entry-screen-Dnr5TcV0.js +0 -1
- package/build/assets/app-settings-Bgm2-yOM.js +0 -1
- package/build/assets/automation-detail-86M_yMqz.js +0 -1
- package/build/assets/automations-list-BWUILrqY.js +0 -1
- package/build/assets/backend-form-modal-Dl29wkF5.js +0 -1
- package/build/assets/browser-store-JRrcGdlk.js +0 -1
- package/build/assets/browser-wz8UzRmF.js +0 -5
- package/build/assets/chat-send-button-BhoO7T0s.js +0 -1
- package/build/assets/check-BhnsMsWy.js +0 -1
- package/build/assets/condenser-settings-DgQ0rsAf.js +0 -1
- package/build/assets/context-CI9FqkUp.js +0 -1
- package/build/assets/conversation-CayU5Lrr.js +0 -19
- package/build/assets/conversation-erinyBqT.js +0 -1
- package/build/assets/conversation-panel-DiI4q-8-.js +0 -1
- package/build/assets/conversation-service.api-shHWtFwu.js +0 -1
- package/build/assets/conversation-state-store-NEktJKfL.js +0 -1
- package/build/assets/declaration-D9ucT0fq.js +0 -1
- package/build/assets/dist-BCpEDEJq.js +0 -1
- package/build/assets/edit-automation-modal-8y9Uctxo.js +0 -1
- package/build/assets/entry.client-D_wtryHT.js +0 -2
- package/build/assets/files-tab-CxdtgkIe.js +0 -1
- package/build/assets/files-tab-store-DSKUhziI.js +0 -1
- package/build/assets/home-3joHMYSR.js +0 -1
- package/build/assets/index-redirect-BQ_55qN6.js +0 -1
- package/build/assets/install-server-modal-_7l1gcjd.js +0 -1
- package/build/assets/lesson-plan-CHGc-B8Y.js +0 -3
- package/build/assets/llm-not-configured-banner-BMGzpBPV.js +0 -27
- package/build/assets/llm-settings-BRotm_g6.js +0 -1
- package/build/assets/llm-settings-yDgbXP6Q.js +0 -1
- package/build/assets/loader-circle-1XB9nbwF.js +0 -1
- package/build/assets/manage-backends-modal-tfdzTXWU.js +0 -1
- package/build/assets/manifest-bbc1374e.js +0 -1
- package/build/assets/markdown-renderer-z446oW0Z.js +0 -2
- package/build/assets/mcp-Dopstf0t.js +0 -9
- package/build/assets/mcp-settings-redirect-l3Zbmc0F.js +0 -1
- package/build/assets/messages-CsFUrAen.js +0 -41
- package/build/assets/model-selector-sioC8xP4.js +0 -1
- package/build/assets/onboarding-CQh50i2z.js +0 -1
- package/build/assets/option-service.api-DjPvPAtd.js +0 -1
- package/build/assets/organization-service.api-BNc9Kn6n.js +0 -1
- package/build/assets/plus-DKUID4kd.js +0 -1
- package/build/assets/providers-BiWSYwRT.js +0 -1
- package/build/assets/proxy--Uy1iGsW.js +0 -1
- package/build/assets/query-client-config-Ca3tW1AH.js +0 -1
- package/build/assets/root-CRkz_h2T.css +0 -1
- package/build/assets/root-DrHpnAqU.js +0 -2
- package/build/assets/root-layout-Cf7FC9DC.js +0 -2
- package/build/assets/sdk-section-page-COlGKv4E.js +0 -1
- package/build/assets/sdk-settings-schema-Big50zDH.js +0 -1
- package/build/assets/secrets-settings-DYfTc5c8.js +0 -1
- package/build/assets/settings-DRmVFdOc.js +0 -1
- package/build/assets/settings-modal-CeRvS5Bc.js +0 -1
- package/build/assets/settings-service.api-CFt5HmXD.js +0 -1
- package/build/assets/shared-conversation-CBbpyPaD.js +0 -1
- package/build/assets/sidebar-mobile-menu-toggle-SKcwsEtD.js +0 -1
- package/build/assets/suspense-Bqb0V0q1.js +0 -1
- package/build/assets/telemetry-DCFAqpIA.js +0 -2
- package/build/assets/use-acp-credential-form-LjCIhMSK.js +0 -1
- package/build/assets/use-agent-settings-schema-D8x5LJVS.js +0 -1
- package/build/assets/use-config-5zEjywCL.js +0 -1
- package/build/assets/use-create-conversation-pV2eA-e9.js +0 -1
- package/build/assets/use-handle-plan-click-CwN_nNib.js +0 -1
- package/build/assets/use-is-authed-B8eLO-Xq.js +0 -1
- package/build/assets/use-llm-profiles-CWLfWjav.js +0 -1
- package/build/assets/use-runtime-is-ready-Bbory9-s.js +0 -1
- package/build/assets/use-save-settings-Xp8DD-jf.js +0 -1
- package/build/assets/use-settings-0SeqaDeW.js +0 -1
- package/build/assets/useMutation-Dm84WAKR.js +0 -1
- package/build/assets/useQuery-DGRSm7IT.js +0 -1
- package/build/assets/useTranslation-CL6FTf1b.js +0 -1
- package/build/assets/vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~dqseey1n-D_BSEDk4.js +0 -1
- package/build/assets/vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~jfbjdnyv-C5ZIbuq8.js +0 -177
- package/build/assets/vendor~root-layout~home~conversation-panel~conversation~launch~mcp~settings~settings-index~~m3acswdn-CGm-Jxp5.js +0 -48
- package/build/assets/x-CCfDppg5.js +0 -1
- package/dist/api/settings-service/legacy-app-preferences-migration.cjs +0 -2
- package/dist/api/settings-service/legacy-app-preferences-migration.cjs.map +0 -1
- package/dist/api/settings-service/legacy-app-preferences-migration.d.ts +0 -34
- package/dist/api/settings-service/legacy-app-preferences-migration.js +0 -52
- package/dist/api/settings-service/legacy-app-preferences-migration.js.map +0 -1
- package/dist/hooks/query/use-openhands-verified-models.cjs +0 -2
- package/dist/hooks/query/use-openhands-verified-models.cjs.map +0 -1
- package/dist/hooks/query/use-openhands-verified-models.d.ts +0 -1
- package/dist/hooks/query/use-openhands-verified-models.js +0 -14
- package/dist/hooks/query/use-openhands-verified-models.js.map +0 -1
- package/dist/utils/normalize-display-model.cjs +0 -2
- package/dist/utils/normalize-display-model.cjs.map +0 -1
- package/dist/utils/normalize-display-model.d.ts +0 -9
- package/dist/utils/normalize-display-model.js +0 -13
- package/dist/utils/normalize-display-model.js.map +0 -1
- package/dist/utils/openhands-llm.cjs +0 -2
- package/dist/utils/openhands-llm.cjs.map +0 -1
- package/dist/utils/openhands-llm.d.ts +0 -15
- package/dist/utils/openhands-llm.js +0 -15
- package/dist/utils/openhands-llm.js.map +0 -1
- /package/build/assets/{agent-server-ui-style-scope-BwIZYdC1.js → agent-server-ui-style-scope-1MuaCC1k.js} +0 -0
- /package/build/assets/{common-Dh7OqABE.js → common-DqjLSBOt.js} +0 -0
- /package/build/assets/{environment-switch-store-CiurvTtK.js → environment-switch-store-CBXkf5bS.js} +0 -0
- /package/build/assets/{extension-module-card-classes-DP5J6ngE.js → extension-module-card-classes-CVGfXtoL.js} +0 -0
- /package/build/assets/{git-status-mapper-BI8FyUVp.js → git-status-mapper-DVFXF1_X.js} +0 -0
- /package/build/assets/{handle-capture-consent-CPMXU29K.js → handle-capture-consent-BTvatyfE.js} +0 -0
- /package/build/assets/{map-provider-BM2SJarp.js → map-provider-COgsZR9p.js} +0 -0
- /package/build/assets/{objectWithoutPropertiesLoose-DSQKyRhw.js → objectWithoutPropertiesLoose-B80nTzVc.js} +0 -0
- /package/build/assets/{preload-helper-CT1Z6Pdu.js → preload-helper-D_sPnjeL.js} +0 -0
- /package/build/assets/{rolldown-runtime-BFRubm34.js → rolldown-runtime-wFmyQBCi.js} +0 -0
- /package/build/assets/{sdk-settings-field-metadata-p2GVlft7.js → sdk-settings-field-metadata-Cc4D-ut7.js} +0 -0
- /package/build/assets/{settings-wh2sLLJM.js → settings-1287uR2J.js} +0 -0
- /package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~nh19ovoo-DJTFnsA1.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~cg1m3bv7-aUIHudsf.js} +0 -0
- /package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~ntycl9e1-BmZcy_kH.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~ntycl9e1-DPPGSgT1.js} +0 -0
|
@@ -2,7 +2,11 @@ import { create as e } from "../node_modules/zustand/esm/react.js";
|
|
|
2
2
|
//#region src/stores/files-tab-store.ts
|
|
3
3
|
var t = e((e) => ({
|
|
4
4
|
selectedPath: null,
|
|
5
|
-
|
|
5
|
+
selectedConversationId: null,
|
|
6
|
+
setSelectedPath: (t, n = null) => e({
|
|
7
|
+
selectedPath: t,
|
|
8
|
+
selectedConversationId: n
|
|
9
|
+
})
|
|
6
10
|
}));
|
|
7
11
|
//#endregion
|
|
8
12
|
export { t as useFilesTabStore };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files-tab-store.js","names":[],"sources":["../../src/stores/files-tab-store.ts"],"sourcesContent":["import { create } from \"zustand\";\n\ninterface FilesTabState {\n selectedPath: string | null;\n setSelectedPath: (path: string | null) => void;\n}\n\n// Hoisted out of files-tab.tsx local state so non-React callers (e.g. the\n// canvas_ui tool dispatcher in the WebSocket context) can drive selection.\nexport const useFilesTabStore = create<FilesTabState>((set) => ({\n selectedPath: null,\n setSelectedPath: (selectedPath)
|
|
1
|
+
{"version":3,"file":"files-tab-store.js","names":[],"sources":["../../src/stores/files-tab-store.ts"],"sourcesContent":["import { create } from \"zustand\";\n\ninterface FilesTabState {\n selectedPath: string | null;\n // The conversation a selection belongs to. A file picked in one\n // conversation must not leak into another (it usually doesn't exist in the\n // other conversation's workspace, see issue #1350), so every selection is\n // tagged with its conversation and the files tab ignores a path owned by a\n // different conversation.\n selectedConversationId: string | null;\n setSelectedPath: (\n path: string | null,\n conversationId?: string | null,\n ) => void;\n}\n\n// Hoisted out of files-tab.tsx local state so non-React callers (e.g. the\n// canvas_ui tool dispatcher in the WebSocket context) can drive selection.\nexport const useFilesTabStore = create<FilesTabState>((set) => ({\n selectedPath: null,\n selectedConversationId: null,\n setSelectedPath: (selectedPath, conversationId = null) =>\n set({ selectedPath, selectedConversationId: conversationId }),\n}));\n"],"mappings":";;AAkBA,IAAa,IAAmB,GAAuB,OAAS;CAC9D,cAAc;CACd,wBAAwB;CACxB,kBAAkB,GAAc,IAAiB,SAC/C,EAAI;EAAE;EAAc,wBAAwB;EAAgB,CAAC;CAChE,EAAE"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
require(`../_virtual/_rolldown/runtime.cjs`);const e=require(`../node_modules/zustand/esm/react.cjs`),t=require(`../utils/handle-event-for-ui.cjs`);var
|
|
1
|
+
require(`../_virtual/_rolldown/runtime.cjs`);const e=require(`../node_modules/zustand/esm/react.cjs`),t=require(`../types/agent-server/type-guards.cjs`),n=require(`../utils/handle-event-for-ui.cjs`);var r=e=>`id`in e?e.id:void 0,i=e=>`timestamp`in e?e.timestamp:void 0,a=(e,t)=>{let n=i(e),r=i(t);return!n&&!r?0:n?r?n.localeCompare(r):-1:1},o=(e,t)=>{if(e.length===0)return!1;let n=e[e.length-1],r=i(n),a=i(t);return!r||!a?!1:a<r},s=(e,i)=>{let a=r(i);if(a!==void 0&&e.eventIds.has(a))return e;let o=a===void 0?e.eventIds:new Set(e.eventIds).add(a),s=e.events.length-1,c=e.events[s],l=c&&t.isStreamingDeltaEvent(i)&&t.isStreamingDeltaEvent(c),u=[...e.events];return l?u[s]=n.mergeStreamingDeltaEvent(i,c):u.push(i),{...e,events:u,eventIds:o,uiEvents:n.handleEventForUI(i,e.uiEvents)}},c=e=>({...e,events:[...e.events].sort(a),uiEvents:[...e.uiEvents].sort(a)}),l=(e,t)=>{let n=s(e,t);return n===e?e:!o(e.events,t)&&!o(e.uiEvents,t)?n:c(n)},u=e.create()(e=>({events:[],eventIds:new Set,uiEvents:[],loadedConversationId:null,addEvent:t=>e(e=>l(e,t)),addEvents:i=>e(e=>{if(i.length===0)return e;let a=new Set(e.eventIds),o=[...e.events],s=[...e.uiEvents],l=!1;for(let e of i){let i=r(e);if(!(i!==void 0&&a.has(i))){l=!0,i!==void 0&&a.add(i);let r=o.length-1,c=o[r];c&&t.isStreamingDeltaEvent(e)&&t.isStreamingDeltaEvent(c)?o[r]=n.mergeStreamingDeltaEvent(e,c):o.push(e),s=n.handleEventForUI(e,s)}}return l?c({...e,events:o,eventIds:a,uiEvents:s}):e}),clearEvents:()=>e(()=>({events:[],eventIds:new Set,uiEvents:[],loadedConversationId:null})),clearEventsForConversation:t=>e(()=>({events:[],eventIds:new Set,uiEvents:[],loadedConversationId:t}))}));exports.useEventStore=u;
|
|
2
2
|
//# sourceMappingURL=use-event-store.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-event-store.cjs","names":[],"sources":["../../src/stores/use-event-store.ts"],"sourcesContent":["import { create } from \"zustand\";\nimport { OpenHandsEvent } from \"#/types/agent-server/core\";\nimport {
|
|
1
|
+
{"version":3,"file":"use-event-store.cjs","names":[],"sources":["../../src/stores/use-event-store.ts"],"sourcesContent":["import { create } from \"zustand\";\nimport { OpenHandsEvent } from \"#/types/agent-server/core\";\nimport {\n handleEventForUI,\n mergeStreamingDeltaEvent,\n} from \"#/utils/handle-event-for-ui\";\nimport { isStreamingDeltaEvent } from \"#/types/agent-server/type-guards\";\n\nexport type OHEvent = OpenHandsEvent & {\n isFromPlanningAgent?: boolean;\n};\n\nconst getEventId = (event: OHEvent): string | number | undefined =>\n \"id\" in event ? event.id : undefined;\n\nconst getEventTimestamp = (event: OHEvent): string | undefined =>\n \"timestamp\" in event ? event.timestamp : undefined;\n\n/**\n * Compare two events by timestamp for sorting.\n * Events without timestamps are placed at the end.\n */\nconst compareEventsByTimestamp = (a: OHEvent, b: OHEvent): number => {\n const timestampA = getEventTimestamp(a);\n const timestampB = getEventTimestamp(b);\n\n // Events without timestamps go to the end\n if (!timestampA && !timestampB) return 0;\n if (!timestampA) return 1;\n if (!timestampB) return -1;\n\n // Compare ISO timestamp strings (lexicographic comparison works for ISO format)\n return timestampA.localeCompare(timestampB);\n};\n\n/**\n * Check if the new event needs sorting (i.e., it's out of order).\n * Returns true if the new event's timestamp is earlier than the last event's timestamp.\n */\nconst needsSorting = (events: OHEvent[], newEvent: OHEvent): boolean => {\n if (events.length === 0) return false;\n\n const lastEvent = events[events.length - 1];\n const lastTimestamp = getEventTimestamp(lastEvent);\n const newTimestamp = getEventTimestamp(newEvent);\n\n // If either event doesn't have a timestamp, don't sort\n if (!lastTimestamp || !newTimestamp) return false;\n\n // Sort needed if new event's timestamp is earlier than last event's timestamp\n return newTimestamp < lastTimestamp;\n};\n\nexport interface EventState {\n events: OHEvent[];\n eventIds: Set<string | number>;\n uiEvents: OHEvent[];\n /**\n * The conversation whose events currently populate the store. The store is\n * global (not keyed by conversation), so the conversation route uses this to\n * tell a genuine conversation switch apart from a remount of the *same*\n * conversation (e.g. navigating to Settings and back) — only the former\n * should clear the accumulated events.\n */\n loadedConversationId: string | null;\n addEvent: (event: OHEvent) => void;\n /**\n * Bulk-insert events. Used for the initial REST history load and for\n * \"scroll up to load older\" pagination. Newly-added events are de-duped\n * against the existing store and the combined list is re-sorted by\n * timestamp so older pages drop into the correct position.\n */\n addEvents: (events: OHEvent[]) => void;\n /**\n * Clear all events. Also resets `loadedConversationId` to `null` so the\n * store never claims to hold a conversation whose events have been wiped —\n * the invariant (`loadedConversationId` reflects the conversation whose\n * events are in the arrays) holds even for a standalone clear.\n */\n clearEvents: () => void;\n /**\n * Atomically clear all events and record which conversation is now loaded.\n * Collapsing the reset and the bookkeeping into a single `set` keeps the\n * store invariant enforced at the boundary, rather than relying on every\n * call-site to invoke a clear and a `loadedConversationId` setter in the\n * right order.\n */\n clearEventsForConversation: (conversationId: string | null) => void;\n}\n\nconst appendEvent = (state: EventState, event: OHEvent): EventState => {\n // Deduplicate: skip if event with same id already exists (O(1) lookup)\n const eventId = getEventId(event);\n if (eventId !== undefined && state.eventIds.has(eventId)) {\n return state;\n }\n\n const newEventIds =\n eventId !== undefined\n ? new Set(state.eventIds).add(eventId)\n : state.eventIds;\n\n const lastEventIndex = state.events.length - 1;\n const lastEvent = state.events[lastEventIndex];\n const shouldMergeStreamingDelta =\n lastEvent &&\n isStreamingDeltaEvent(event) &&\n isStreamingDeltaEvent(lastEvent);\n const events = [...state.events];\n if (shouldMergeStreamingDelta) {\n events[lastEventIndex] = mergeStreamingDeltaEvent(event, lastEvent);\n } else {\n events.push(event);\n }\n\n return {\n ...state,\n events,\n eventIds: newEventIds,\n uiEvents: handleEventForUI(event, state.uiEvents),\n };\n};\n\nconst sortEventState = (state: EventState): EventState => ({\n ...state,\n events: [...state.events].sort(compareEventsByTimestamp),\n uiEvents: [...state.uiEvents].sort(compareEventsByTimestamp),\n});\n\nconst applyAddEvent = (state: EventState, event: OHEvent): EventState => {\n const next = appendEvent(state, event);\n if (next === state) {\n return state;\n }\n\n if (\n !needsSorting(state.events, event) &&\n !needsSorting(state.uiEvents, event)\n ) {\n return next;\n }\n\n return sortEventState(next);\n};\n\nexport const useEventStore = create<EventState>()((set) => ({\n events: [],\n eventIds: new Set(),\n uiEvents: [],\n loadedConversationId: null,\n addEvent: (event: OHEvent) => set((state) => applyAddEvent(state, event)),\n addEvents: (incoming: OHEvent[]) =>\n set((state) => {\n if (incoming.length === 0) return state;\n\n const eventIds = new Set(state.eventIds);\n const events = [...state.events];\n let uiEvents = [...state.uiEvents];\n let added = false;\n\n for (const event of incoming) {\n const eventId = getEventId(event);\n const isDuplicate = eventId !== undefined && eventIds.has(eventId);\n\n if (!isDuplicate) {\n added = true;\n if (eventId !== undefined) {\n eventIds.add(eventId);\n }\n\n const lastEventIndex = events.length - 1;\n const lastEvent = events[lastEventIndex];\n if (\n lastEvent &&\n isStreamingDeltaEvent(event) &&\n isStreamingDeltaEvent(lastEvent)\n ) {\n events[lastEventIndex] = mergeStreamingDeltaEvent(event, lastEvent);\n } else {\n events.push(event);\n }\n\n uiEvents = handleEventForUI(event, uiEvents);\n }\n }\n\n if (!added) {\n return state;\n }\n\n return sortEventState({\n ...state,\n events,\n eventIds,\n uiEvents,\n });\n }),\n clearEvents: () =>\n set(() => ({\n events: [],\n eventIds: new Set(),\n uiEvents: [],\n loadedConversationId: null,\n })),\n clearEventsForConversation: (conversationId: string | null) =>\n set(() => ({\n events: [],\n eventIds: new Set(),\n uiEvents: [],\n loadedConversationId: conversationId,\n })),\n}));\n\n// In dev builds, expose the store on `window` so that fixture/preview\n// scripts (e.g. .pr/issue-132 demo capture) can inject synthetic events\n// without round-tripping through the agent-server. Tree-shaken in\n// production builds via `import.meta.env.DEV`.\nif (\n typeof window !== \"undefined\" &&\n typeof import.meta !== \"undefined\" &&\n (import.meta as { env?: { DEV?: boolean } }).env?.DEV\n) {\n (\n window as unknown as { __OH_EVENT_STORE__?: typeof useEventStore }\n ).__OH_EVENT_STORE__ = useEventStore;\n}\n"],"mappings":"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"}
|
|
@@ -1,48 +1,53 @@
|
|
|
1
1
|
import { create as e } from "../node_modules/zustand/esm/react.js";
|
|
2
|
-
import {
|
|
2
|
+
import { isStreamingDeltaEvent as t } from "../types/agent-server/type-guards.js";
|
|
3
|
+
import { handleEventForUI as n, mergeStreamingDeltaEvent as r } from "../utils/handle-event-for-ui.js";
|
|
3
4
|
//#region src/stores/use-event-store.ts
|
|
4
|
-
var
|
|
5
|
-
let n =
|
|
6
|
-
return !n && !
|
|
7
|
-
},
|
|
5
|
+
var i = (e) => "id" in e ? e.id : void 0, a = (e) => "timestamp" in e ? e.timestamp : void 0, o = (e, t) => {
|
|
6
|
+
let n = a(e), r = a(t);
|
|
7
|
+
return !n && !r ? 0 : n ? r ? n.localeCompare(r) : -1 : 1;
|
|
8
|
+
}, s = (e, t) => {
|
|
8
9
|
if (e.length === 0) return !1;
|
|
9
|
-
let n = e[e.length - 1],
|
|
10
|
-
return !
|
|
11
|
-
},
|
|
12
|
-
let
|
|
13
|
-
if (
|
|
14
|
-
let
|
|
15
|
-
return {
|
|
10
|
+
let n = e[e.length - 1], r = a(n), i = a(t);
|
|
11
|
+
return !r || !i ? !1 : i < r;
|
|
12
|
+
}, c = (e, a) => {
|
|
13
|
+
let o = i(a);
|
|
14
|
+
if (o !== void 0 && e.eventIds.has(o)) return e;
|
|
15
|
+
let s = o === void 0 ? e.eventIds : new Set(e.eventIds).add(o), c = e.events.length - 1, l = e.events[c], u = l && t(a) && t(l), d = [...e.events];
|
|
16
|
+
return u ? d[c] = r(a, l) : d.push(a), {
|
|
16
17
|
...e,
|
|
17
|
-
events:
|
|
18
|
-
eventIds:
|
|
19
|
-
uiEvents:
|
|
18
|
+
events: d,
|
|
19
|
+
eventIds: s,
|
|
20
|
+
uiEvents: n(a, e.uiEvents)
|
|
20
21
|
};
|
|
21
|
-
},
|
|
22
|
+
}, l = (e) => ({
|
|
22
23
|
...e,
|
|
23
|
-
events: [...e.events].sort(
|
|
24
|
-
uiEvents: [...e.uiEvents].sort(
|
|
25
|
-
}),
|
|
26
|
-
let n =
|
|
27
|
-
return n === e ? e : !
|
|
28
|
-
},
|
|
24
|
+
events: [...e.events].sort(o),
|
|
25
|
+
uiEvents: [...e.uiEvents].sort(o)
|
|
26
|
+
}), u = (e, t) => {
|
|
27
|
+
let n = c(e, t);
|
|
28
|
+
return n === e ? e : !s(e.events, t) && !s(e.uiEvents, t) ? n : l(n);
|
|
29
|
+
}, d = e()((e) => ({
|
|
29
30
|
events: [],
|
|
30
31
|
eventIds: /* @__PURE__ */ new Set(),
|
|
31
32
|
uiEvents: [],
|
|
32
33
|
loadedConversationId: null,
|
|
33
|
-
addEvent: (t) => e((e) =>
|
|
34
|
-
addEvents: (
|
|
35
|
-
if (
|
|
36
|
-
let
|
|
37
|
-
for (let e of
|
|
38
|
-
let
|
|
39
|
-
|
|
34
|
+
addEvent: (t) => e((e) => u(e, t)),
|
|
35
|
+
addEvents: (a) => e((e) => {
|
|
36
|
+
if (a.length === 0) return e;
|
|
37
|
+
let o = new Set(e.eventIds), s = [...e.events], c = [...e.uiEvents], u = !1;
|
|
38
|
+
for (let e of a) {
|
|
39
|
+
let a = i(e);
|
|
40
|
+
if (!(a !== void 0 && o.has(a))) {
|
|
41
|
+
u = !0, a !== void 0 && o.add(a);
|
|
42
|
+
let i = s.length - 1, l = s[i];
|
|
43
|
+
l && t(e) && t(l) ? s[i] = r(e, l) : s.push(e), c = n(e, c);
|
|
44
|
+
}
|
|
40
45
|
}
|
|
41
|
-
return
|
|
46
|
+
return u ? l({
|
|
42
47
|
...e,
|
|
43
|
-
events:
|
|
44
|
-
eventIds:
|
|
45
|
-
uiEvents:
|
|
48
|
+
events: s,
|
|
49
|
+
eventIds: o,
|
|
50
|
+
uiEvents: c
|
|
46
51
|
}) : e;
|
|
47
52
|
}),
|
|
48
53
|
clearEvents: () => e(() => ({
|
|
@@ -59,6 +64,6 @@ var n = (e) => "id" in e ? e.id : void 0, r = (e) => "timestamp" in e ? e.timest
|
|
|
59
64
|
}))
|
|
60
65
|
}));
|
|
61
66
|
//#endregion
|
|
62
|
-
export {
|
|
67
|
+
export { d as useEventStore };
|
|
63
68
|
|
|
64
69
|
//# sourceMappingURL=use-event-store.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-event-store.js","names":[],"sources":["../../src/stores/use-event-store.ts"],"sourcesContent":["import { create } from \"zustand\";\nimport { OpenHandsEvent } from \"#/types/agent-server/core\";\nimport {
|
|
1
|
+
{"version":3,"file":"use-event-store.js","names":[],"sources":["../../src/stores/use-event-store.ts"],"sourcesContent":["import { create } from \"zustand\";\nimport { OpenHandsEvent } from \"#/types/agent-server/core\";\nimport {\n handleEventForUI,\n mergeStreamingDeltaEvent,\n} from \"#/utils/handle-event-for-ui\";\nimport { isStreamingDeltaEvent } from \"#/types/agent-server/type-guards\";\n\nexport type OHEvent = OpenHandsEvent & {\n isFromPlanningAgent?: boolean;\n};\n\nconst getEventId = (event: OHEvent): string | number | undefined =>\n \"id\" in event ? event.id : undefined;\n\nconst getEventTimestamp = (event: OHEvent): string | undefined =>\n \"timestamp\" in event ? event.timestamp : undefined;\n\n/**\n * Compare two events by timestamp for sorting.\n * Events without timestamps are placed at the end.\n */\nconst compareEventsByTimestamp = (a: OHEvent, b: OHEvent): number => {\n const timestampA = getEventTimestamp(a);\n const timestampB = getEventTimestamp(b);\n\n // Events without timestamps go to the end\n if (!timestampA && !timestampB) return 0;\n if (!timestampA) return 1;\n if (!timestampB) return -1;\n\n // Compare ISO timestamp strings (lexicographic comparison works for ISO format)\n return timestampA.localeCompare(timestampB);\n};\n\n/**\n * Check if the new event needs sorting (i.e., it's out of order).\n * Returns true if the new event's timestamp is earlier than the last event's timestamp.\n */\nconst needsSorting = (events: OHEvent[], newEvent: OHEvent): boolean => {\n if (events.length === 0) return false;\n\n const lastEvent = events[events.length - 1];\n const lastTimestamp = getEventTimestamp(lastEvent);\n const newTimestamp = getEventTimestamp(newEvent);\n\n // If either event doesn't have a timestamp, don't sort\n if (!lastTimestamp || !newTimestamp) return false;\n\n // Sort needed if new event's timestamp is earlier than last event's timestamp\n return newTimestamp < lastTimestamp;\n};\n\nexport interface EventState {\n events: OHEvent[];\n eventIds: Set<string | number>;\n uiEvents: OHEvent[];\n /**\n * The conversation whose events currently populate the store. The store is\n * global (not keyed by conversation), so the conversation route uses this to\n * tell a genuine conversation switch apart from a remount of the *same*\n * conversation (e.g. navigating to Settings and back) — only the former\n * should clear the accumulated events.\n */\n loadedConversationId: string | null;\n addEvent: (event: OHEvent) => void;\n /**\n * Bulk-insert events. Used for the initial REST history load and for\n * \"scroll up to load older\" pagination. Newly-added events are de-duped\n * against the existing store and the combined list is re-sorted by\n * timestamp so older pages drop into the correct position.\n */\n addEvents: (events: OHEvent[]) => void;\n /**\n * Clear all events. Also resets `loadedConversationId` to `null` so the\n * store never claims to hold a conversation whose events have been wiped —\n * the invariant (`loadedConversationId` reflects the conversation whose\n * events are in the arrays) holds even for a standalone clear.\n */\n clearEvents: () => void;\n /**\n * Atomically clear all events and record which conversation is now loaded.\n * Collapsing the reset and the bookkeeping into a single `set` keeps the\n * store invariant enforced at the boundary, rather than relying on every\n * call-site to invoke a clear and a `loadedConversationId` setter in the\n * right order.\n */\n clearEventsForConversation: (conversationId: string | null) => void;\n}\n\nconst appendEvent = (state: EventState, event: OHEvent): EventState => {\n // Deduplicate: skip if event with same id already exists (O(1) lookup)\n const eventId = getEventId(event);\n if (eventId !== undefined && state.eventIds.has(eventId)) {\n return state;\n }\n\n const newEventIds =\n eventId !== undefined\n ? new Set(state.eventIds).add(eventId)\n : state.eventIds;\n\n const lastEventIndex = state.events.length - 1;\n const lastEvent = state.events[lastEventIndex];\n const shouldMergeStreamingDelta =\n lastEvent &&\n isStreamingDeltaEvent(event) &&\n isStreamingDeltaEvent(lastEvent);\n const events = [...state.events];\n if (shouldMergeStreamingDelta) {\n events[lastEventIndex] = mergeStreamingDeltaEvent(event, lastEvent);\n } else {\n events.push(event);\n }\n\n return {\n ...state,\n events,\n eventIds: newEventIds,\n uiEvents: handleEventForUI(event, state.uiEvents),\n };\n};\n\nconst sortEventState = (state: EventState): EventState => ({\n ...state,\n events: [...state.events].sort(compareEventsByTimestamp),\n uiEvents: [...state.uiEvents].sort(compareEventsByTimestamp),\n});\n\nconst applyAddEvent = (state: EventState, event: OHEvent): EventState => {\n const next = appendEvent(state, event);\n if (next === state) {\n return state;\n }\n\n if (\n !needsSorting(state.events, event) &&\n !needsSorting(state.uiEvents, event)\n ) {\n return next;\n }\n\n return sortEventState(next);\n};\n\nexport const useEventStore = create<EventState>()((set) => ({\n events: [],\n eventIds: new Set(),\n uiEvents: [],\n loadedConversationId: null,\n addEvent: (event: OHEvent) => set((state) => applyAddEvent(state, event)),\n addEvents: (incoming: OHEvent[]) =>\n set((state) => {\n if (incoming.length === 0) return state;\n\n const eventIds = new Set(state.eventIds);\n const events = [...state.events];\n let uiEvents = [...state.uiEvents];\n let added = false;\n\n for (const event of incoming) {\n const eventId = getEventId(event);\n const isDuplicate = eventId !== undefined && eventIds.has(eventId);\n\n if (!isDuplicate) {\n added = true;\n if (eventId !== undefined) {\n eventIds.add(eventId);\n }\n\n const lastEventIndex = events.length - 1;\n const lastEvent = events[lastEventIndex];\n if (\n lastEvent &&\n isStreamingDeltaEvent(event) &&\n isStreamingDeltaEvent(lastEvent)\n ) {\n events[lastEventIndex] = mergeStreamingDeltaEvent(event, lastEvent);\n } else {\n events.push(event);\n }\n\n uiEvents = handleEventForUI(event, uiEvents);\n }\n }\n\n if (!added) {\n return state;\n }\n\n return sortEventState({\n ...state,\n events,\n eventIds,\n uiEvents,\n });\n }),\n clearEvents: () =>\n set(() => ({\n events: [],\n eventIds: new Set(),\n uiEvents: [],\n loadedConversationId: null,\n })),\n clearEventsForConversation: (conversationId: string | null) =>\n set(() => ({\n events: [],\n eventIds: new Set(),\n uiEvents: [],\n loadedConversationId: conversationId,\n })),\n}));\n\n// In dev builds, expose the store on `window` so that fixture/preview\n// scripts (e.g. .pr/issue-132 demo capture) can inject synthetic events\n// without round-tripping through the agent-server. Tree-shaken in\n// production builds via `import.meta.env.DEV`.\nif (\n typeof window !== \"undefined\" &&\n typeof import.meta !== \"undefined\" &&\n (import.meta as { env?: { DEV?: boolean } }).env?.DEV\n) {\n (\n window as unknown as { __OH_EVENT_STORE__?: typeof useEventStore }\n ).__OH_EVENT_STORE__ = useEventStore;\n}\n"],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { MCPTestFailureKind } from "@openhands/typescript-client";
|
|
1
2
|
export type MCPServerType = "sse" | "stdio" | "shttp";
|
|
2
3
|
export interface MCPServerConfig {
|
|
3
4
|
id: string;
|
|
@@ -10,3 +11,23 @@ export interface MCPServerConfig {
|
|
|
10
11
|
args?: string[];
|
|
11
12
|
env?: Record<string, string>;
|
|
12
13
|
}
|
|
14
|
+
export interface MCPTestToolCall {
|
|
15
|
+
name: string;
|
|
16
|
+
arguments: Record<string, unknown>;
|
|
17
|
+
}
|
|
18
|
+
export interface MCPTestToolResult {
|
|
19
|
+
is_error: boolean;
|
|
20
|
+
text: string;
|
|
21
|
+
}
|
|
22
|
+
export type ExtendedMCPTestFailureKind = MCPTestFailureKind | "credentials";
|
|
23
|
+
export interface ExtendedMCPTestSuccess {
|
|
24
|
+
ok: true;
|
|
25
|
+
tools: string[];
|
|
26
|
+
tool_result?: MCPTestToolResult | null;
|
|
27
|
+
}
|
|
28
|
+
export interface ExtendedMCPTestFailure {
|
|
29
|
+
ok: false;
|
|
30
|
+
error: string;
|
|
31
|
+
error_kind: ExtendedMCPTestFailureKind;
|
|
32
|
+
}
|
|
33
|
+
export type ExtendedMCPTestResponse = ExtendedMCPTestSuccess | ExtendedMCPTestFailure;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require(`../../_virtual/_rolldown/runtime.cjs`),t=require(`../../utils/utils.cjs`),n=require(`../../utils/dropdown-classes.cjs`),r=require(`../../node_modules/downshift/dist/downshift.esm.cjs`),i=require(`./loading-spinner.cjs`),a=require(`./clear-button.cjs`),o=require(`./toggle-button.cjs`),s=require(`./dropdown-menu.cjs`),c=require(`./dropdown-input.cjs`);let l=require(`react`);l=e.__toESM(l,1);let u=require(`react/jsx-runtime`);var d={position:`absolute`,width:1,height:1,padding:0,margin:-1,overflow:`hidden`,clip:`rect(0, 0, 0, 0)`,whiteSpace:`nowrap`,border:0};function f({options:e,emptyMessage:f=`No options`,clearable:p=!1,loading:m=!1,disabled:h=!1,placeholder:g,defaultValue:_,onChange:v,testId:y,className:b,footer:x,openUpward:S=!1,hideTrigger:C=!1,defaultOpen:w=!1,openOnHover:T=!1,italicPlaceholder:E=!0,fitContent:D=!1}){let O=l.default.useRef(null),[k,A]=(0,l.useState)(_?.label??``),[j,M]=(0,l.useState)(``),N=e.filter(e=>e.label.toLowerCase().includes(j.toLowerCase())),{isOpen:P,selectedItem:F,selectItem:I,openMenu:L,closeMenu:R,getToggleButtonProps:z,getMenuProps:B,getItemProps:V,getInputProps:H}=r.useCombobox({items:N,itemToString:e=>e?.label??``,inputValue:k,stateReducer:(e,t)=>t.type===r.useCombobox.stateChangeTypes.InputClick&&e.isOpen?{...t.changes,isOpen:!0}:t.changes,initialIsOpen:w,onInputValueChange:({inputValue:e})=>{A(e??``),M(e??``)},defaultSelectedItem:_,onSelectedItemChange:({selectedItem:e})=>{v?.(e??null)},onIsOpenChange:({isOpen:e,selectedItem:t})=>{e?(A(``),M(``)):(A(t?.label??``),M(``))}}),U=m||h,W=F?e.find(e=>e.value===F.value)??F:null,G=e=>H({...e,onChange:e=>{A(e.target.value),M(e.target.value)}});return(0,u.jsxs)(`div`,{className:t.cn(`relative`,D?`inline-block w-auto`:`w-full`),"data-testid":y,onMouseEnter:T?()=>{O.current&&=(clearTimeout(O.current),null),L()}:void 0,onMouseLeave:T?()=>{O.current=setTimeout(()=>R(),150)}:void 0,children:[C?(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(`input`,{...G({"aria-label":g??`Filter options`,tabIndex:-1}),style:d}),(0,u.jsx)(`button`,{type:`button`,...z({tabIndex:-1}),style:d,"aria-hidden":!0})]}):(0,u.jsxs)(`div`,{className:t.cn(n.dropdownTriggerShellClassName,D?`w-auto`:`w-full`,U&&`cursor-not-allowed opacity-60`,b),children:[W?.prefix?(0,u.jsx)(`span`,{className:`flex items-center shrink-0`,children:W.prefix}):null,(0,u.jsx)(c.DropdownInput,{placeholder:g,isDisabled:U,getInputProps:G,italicPlaceholder:E,fitContent:D}),m&&(0,u.jsx)(i.LoadingSpinner,{}),p&&F&&(0,u.jsx)(a.ClearButton,{onClear:()=>I(null)}),(0,u.jsx)(o.ToggleButton,{isOpen:P,isDisabled:U,getToggleButtonProps:z})]}),(0,u.jsx)(s.DropdownMenu,{isOpen:P,filteredOptions:N,selectedItem:F,emptyMessage:f,getMenuProps:B,getItemProps:V,footer:x,openUpward:S,fitContent:D})]})}exports.Dropdown=f;
|
|
1
|
+
const e=require(`../../_virtual/_rolldown/runtime.cjs`),t=require(`../../utils/utils.cjs`),n=require(`../../utils/dropdown-classes.cjs`),r=require(`../../node_modules/downshift/dist/downshift.esm.cjs`),i=require(`./loading-spinner.cjs`),a=require(`./clear-button.cjs`),o=require(`./toggle-button.cjs`),s=require(`./dropdown-menu.cjs`),c=require(`./dropdown-input.cjs`);let l=require(`react`);l=e.__toESM(l,1);let u=require(`react/jsx-runtime`);var d={position:`absolute`,width:1,height:1,padding:0,margin:-1,overflow:`hidden`,clip:`rect(0, 0, 0, 0)`,whiteSpace:`nowrap`,border:0};function f({options:e,emptyMessage:f=`No options`,clearable:p=!1,loading:m=!1,disabled:h=!1,placeholder:g,defaultValue:_,onChange:v,testId:y,className:b,footer:x,openUpward:S=!1,hideTrigger:C=!1,defaultOpen:w=!1,openOnHover:T=!1,italicPlaceholder:E=!0,fitContent:D=!1}){let O=l.default.useRef(null),[k,A]=(0,l.useState)(_?.label??``),[j,M]=(0,l.useState)(``);l.default.useEffect(()=>()=>{O.current&&=(clearTimeout(O.current),null)},[]);let N=e.filter(e=>e.label.toLowerCase().includes(j.toLowerCase())),{isOpen:P,selectedItem:F,selectItem:I,openMenu:L,closeMenu:R,getToggleButtonProps:z,getMenuProps:B,getItemProps:V,getInputProps:H}=r.useCombobox({items:N,itemToString:e=>e?.label??``,inputValue:k,stateReducer:(e,t)=>t.type===r.useCombobox.stateChangeTypes.InputClick&&e.isOpen?{...t.changes,isOpen:!0}:t.changes,initialIsOpen:w,onInputValueChange:({inputValue:e})=>{A(e??``),M(e??``)},defaultSelectedItem:_,onSelectedItemChange:({selectedItem:e})=>{v?.(e??null)},onIsOpenChange:({isOpen:e,selectedItem:t})=>{e?(A(``),M(``)):(A(t?.label??``),M(``))}}),U=m||h,W=F?e.find(e=>e.value===F.value)??F:null,G=e=>H({...e,onChange:e=>{A(e.target.value),M(e.target.value)}});return(0,u.jsxs)(`div`,{className:t.cn(`relative`,D?`inline-block w-auto`:`w-full`),"data-testid":y,onMouseEnter:T?()=>{O.current&&=(clearTimeout(O.current),null),L()}:void 0,onMouseLeave:T?()=>{O.current&&clearTimeout(O.current),O.current=setTimeout(()=>R(),150)}:void 0,children:[C?(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(`input`,{...G({"aria-label":g??`Filter options`,tabIndex:-1}),style:d}),(0,u.jsx)(`button`,{type:`button`,...z({tabIndex:-1}),style:d,"aria-hidden":!0})]}):(0,u.jsxs)(`div`,{className:t.cn(n.dropdownTriggerShellClassName,D?`w-auto`:`w-full`,U&&`cursor-not-allowed opacity-60`,b),children:[W?.prefix?(0,u.jsx)(`span`,{className:`flex items-center shrink-0`,children:W.prefix}):null,(0,u.jsx)(c.DropdownInput,{placeholder:g,isDisabled:U,getInputProps:G,italicPlaceholder:E,fitContent:D}),m&&(0,u.jsx)(i.LoadingSpinner,{}),p&&F&&(0,u.jsx)(a.ClearButton,{onClear:()=>I(null)}),(0,u.jsx)(o.ToggleButton,{isOpen:P,isDisabled:U,getToggleButtonProps:z})]}),(0,u.jsx)(s.DropdownMenu,{isOpen:P,filteredOptions:N,selectedItem:F,emptyMessage:f,getMenuProps:B,getItemProps:V,footer:x,openUpward:S,fitContent:D})]})}exports.Dropdown=f;
|
|
2
2
|
//# sourceMappingURL=dropdown.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dropdown.cjs","names":[],"sources":["../../../src/ui/dropdown/dropdown.tsx"],"sourcesContent":["import React, { useState } from \"react\";\nimport { useCombobox } from \"downshift\";\nimport { cn } from \"#/utils/utils\";\nimport { DropdownOption } from \"./types\";\nimport { dropdownTriggerShellClassName } from \"#/utils/dropdown-classes\";\nimport { LoadingSpinner } from \"./loading-spinner\";\nimport { ClearButton } from \"./clear-button\";\nimport { ToggleButton } from \"./toggle-button\";\nimport { DropdownMenu } from \"./dropdown-menu\";\nimport { DropdownInput } from \"./dropdown-input\";\n\n// Equivalent to Tailwind's `sr-only`, inlined so we don't depend on the\n// utility class being preserved by the host project's CSS pipeline.\nconst visuallyHiddenStyle: React.CSSProperties = {\n position: \"absolute\",\n width: 1,\n height: 1,\n padding: 0,\n margin: -1,\n overflow: \"hidden\",\n clip: \"rect(0, 0, 0, 0)\",\n whiteSpace: \"nowrap\",\n border: 0,\n};\n\ninterface DropdownProps {\n options: DropdownOption[];\n emptyMessage?: string;\n clearable?: boolean;\n loading?: boolean;\n disabled?: boolean;\n placeholder?: string;\n defaultValue?: DropdownOption;\n onChange?: (item: DropdownOption | null) => void;\n testId?: string;\n className?: string;\n footer?: React.ReactNode;\n openUpward?: boolean;\n hideTrigger?: boolean;\n defaultOpen?: boolean;\n /** Open the dropdown menu on hover instead of requiring a click. */\n openOnHover?: boolean;\n /** When false, the combobox placeholder uses normal (non-italic) type. */\n italicPlaceholder?: boolean;\n /** Size the trigger to its label instead of stretching to the container width. */\n fitContent?: boolean;\n}\n\nexport function Dropdown({\n options,\n emptyMessage = \"No options\",\n clearable = false,\n loading = false,\n disabled = false,\n placeholder,\n defaultValue,\n onChange,\n testId,\n className,\n footer,\n openUpward = false,\n hideTrigger = false,\n defaultOpen = false,\n openOnHover = false,\n italicPlaceholder = true,\n fitContent = false,\n}: DropdownProps) {\n const closeTimerRef = React.useRef<ReturnType<typeof setTimeout> | null>(\n null,\n );\n const [inputValue, setInputValue] = useState(defaultValue?.label ?? \"\");\n const [searchTerm, setSearchTerm] = useState(\"\");\n\n const filteredOptions = options.filter((option) =>\n option.label.toLowerCase().includes(searchTerm.toLowerCase()),\n );\n\n const {\n isOpen,\n selectedItem,\n selectItem,\n openMenu,\n closeMenu,\n getToggleButtonProps,\n getMenuProps,\n getItemProps,\n getInputProps,\n } = useCombobox({\n items: filteredOptions,\n itemToString: (item) => item?.label ?? \"\",\n inputValue,\n stateReducer: (state, actionAndChanges) =>\n actionAndChanges.type === useCombobox.stateChangeTypes.InputClick &&\n state.isOpen\n ? { ...actionAndChanges.changes, isOpen: true }\n : actionAndChanges.changes,\n initialIsOpen: defaultOpen,\n onInputValueChange: ({ inputValue: newValue }) => {\n setInputValue(newValue ?? \"\");\n setSearchTerm(newValue ?? \"\");\n },\n defaultSelectedItem: defaultValue,\n onSelectedItemChange: ({ selectedItem: newSelectedItem }) => {\n onChange?.(newSelectedItem ?? null);\n },\n onIsOpenChange: ({\n isOpen: newIsOpen,\n selectedItem: currentSelectedItem,\n }) => {\n if (newIsOpen) {\n // Clear the input on open so the user sees an empty search box\n // (with the placeholder reminding them of the current value)\n // and the full options list. Otherwise the active label would\n // appear both in the trigger AND as the highlighted menu row.\n setInputValue(\"\");\n setSearchTerm(\"\");\n } else {\n setInputValue(currentSelectedItem?.label ?? \"\");\n setSearchTerm(\"\");\n }\n },\n });\n\n const isDisabled = loading || disabled;\n\n // `selectedItem` is downshift's internal state, frozen to whatever\n // initialized it. Resolve the currently selected option against the\n // live `options` array so per-option fields like `prefix` (e.g. a\n // status indicator that re-renders on a timer) update on the trigger\n // without remounting the dropdown.\n const liveSelectedOption = selectedItem\n ? (options.find((o) => o.value === selectedItem.value) ?? selectedItem)\n : null;\n\n // Wrap getInputProps to inject a direct onChange handler that preserves\n // cursor position. Downshift's default onInputValueChange resets cursor\n // to end of input on every keystroke; reading from e.target.value keeps\n // the browser's native cursor position intact.\n const getInputPropsWithCursorFix = (props?: object) =>\n getInputProps({\n ...props,\n onChange: (e: React.ChangeEvent<HTMLInputElement>) => {\n setInputValue(e.target.value);\n setSearchTerm(e.target.value);\n },\n });\n\n return (\n <div\n className={cn(\"relative\", fitContent ? \"inline-block w-auto\" : \"w-full\")}\n data-testid={testId}\n onMouseEnter={\n openOnHover\n ? () => {\n if (closeTimerRef.current) {\n clearTimeout(closeTimerRef.current);\n closeTimerRef.current = null;\n }\n openMenu();\n }\n : undefined\n }\n onMouseLeave={\n openOnHover\n ? () => {\n closeTimerRef.current = setTimeout(() => closeMenu(), 150);\n }\n : undefined\n }\n >\n {!hideTrigger ? (\n <div\n className={cn(\n dropdownTriggerShellClassName,\n fitContent ? \"w-auto\" : \"w-full\",\n isDisabled && \"cursor-not-allowed opacity-60\",\n className,\n )}\n >\n {liveSelectedOption?.prefix ? (\n <span className=\"flex items-center shrink-0\">\n {liveSelectedOption.prefix}\n </span>\n ) : null}\n <DropdownInput\n placeholder={placeholder}\n isDisabled={isDisabled}\n getInputProps={getInputPropsWithCursorFix}\n italicPlaceholder={italicPlaceholder}\n fitContent={fitContent}\n />\n {loading && <LoadingSpinner />}\n {clearable && selectedItem && (\n <ClearButton onClear={() => selectItem(null)} />\n )}\n <ToggleButton\n isOpen={isOpen}\n isDisabled={isDisabled}\n getToggleButtonProps={getToggleButtonProps}\n />\n </div>\n ) : (\n // downshift's useCombobox always expects getInputProps() (and the\n // toggle button) to be wired up. When the trigger is hidden (e.g.\n // collapsed-sidebar popover) we still need to mount a real input\n // so it stops warning every render. Keep it visually hidden but\n // present in the DOM for accessibility.\n <>\n <input\n {...getInputPropsWithCursorFix({\n \"aria-label\": placeholder ?? \"Filter options\",\n tabIndex: -1,\n })}\n style={visuallyHiddenStyle}\n />\n <button\n type=\"button\"\n {...getToggleButtonProps({ tabIndex: -1 })}\n style={visuallyHiddenStyle}\n aria-hidden\n />\n </>\n )}\n <DropdownMenu\n isOpen={isOpen}\n filteredOptions={filteredOptions}\n selectedItem={selectedItem}\n emptyMessage={emptyMessage}\n getMenuProps={getMenuProps}\n getItemProps={getItemProps}\n footer={footer}\n openUpward={openUpward}\n fitContent={fitContent}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dropdown.cjs","names":[],"sources":["../../../src/ui/dropdown/dropdown.tsx"],"sourcesContent":["import React, { useState } from \"react\";\nimport { useCombobox } from \"downshift\";\nimport { cn } from \"#/utils/utils\";\nimport { DropdownOption } from \"./types\";\nimport { dropdownTriggerShellClassName } from \"#/utils/dropdown-classes\";\nimport { LoadingSpinner } from \"./loading-spinner\";\nimport { ClearButton } from \"./clear-button\";\nimport { ToggleButton } from \"./toggle-button\";\nimport { DropdownMenu } from \"./dropdown-menu\";\nimport { DropdownInput } from \"./dropdown-input\";\n\n// Equivalent to Tailwind's `sr-only`, inlined so we don't depend on the\n// utility class being preserved by the host project's CSS pipeline.\nconst visuallyHiddenStyle: React.CSSProperties = {\n position: \"absolute\",\n width: 1,\n height: 1,\n padding: 0,\n margin: -1,\n overflow: \"hidden\",\n clip: \"rect(0, 0, 0, 0)\",\n whiteSpace: \"nowrap\",\n border: 0,\n};\n\ninterface DropdownProps {\n options: DropdownOption[];\n emptyMessage?: string;\n clearable?: boolean;\n loading?: boolean;\n disabled?: boolean;\n placeholder?: string;\n defaultValue?: DropdownOption;\n onChange?: (item: DropdownOption | null) => void;\n testId?: string;\n className?: string;\n footer?: React.ReactNode;\n openUpward?: boolean;\n hideTrigger?: boolean;\n defaultOpen?: boolean;\n /** Open the dropdown menu on hover instead of requiring a click. */\n openOnHover?: boolean;\n /** When false, the combobox placeholder uses normal (non-italic) type. */\n italicPlaceholder?: boolean;\n /** Size the trigger to its label instead of stretching to the container width. */\n fitContent?: boolean;\n}\n\nexport function Dropdown({\n options,\n emptyMessage = \"No options\",\n clearable = false,\n loading = false,\n disabled = false,\n placeholder,\n defaultValue,\n onChange,\n testId,\n className,\n footer,\n openUpward = false,\n hideTrigger = false,\n defaultOpen = false,\n openOnHover = false,\n italicPlaceholder = true,\n fitContent = false,\n}: DropdownProps) {\n const closeTimerRef = React.useRef<ReturnType<typeof setTimeout> | null>(\n null,\n );\n const [inputValue, setInputValue] = useState(defaultValue?.label ?? \"\");\n const [searchTerm, setSearchTerm] = useState(\"\");\n\n React.useEffect(\n () => () => {\n if (closeTimerRef.current) {\n clearTimeout(closeTimerRef.current);\n closeTimerRef.current = null;\n }\n },\n [],\n );\n\n const filteredOptions = options.filter((option) =>\n option.label.toLowerCase().includes(searchTerm.toLowerCase()),\n );\n\n const {\n isOpen,\n selectedItem,\n selectItem,\n openMenu,\n closeMenu,\n getToggleButtonProps,\n getMenuProps,\n getItemProps,\n getInputProps,\n } = useCombobox({\n items: filteredOptions,\n itemToString: (item) => item?.label ?? \"\",\n inputValue,\n stateReducer: (state, actionAndChanges) =>\n actionAndChanges.type === useCombobox.stateChangeTypes.InputClick &&\n state.isOpen\n ? { ...actionAndChanges.changes, isOpen: true }\n : actionAndChanges.changes,\n initialIsOpen: defaultOpen,\n onInputValueChange: ({ inputValue: newValue }) => {\n setInputValue(newValue ?? \"\");\n setSearchTerm(newValue ?? \"\");\n },\n defaultSelectedItem: defaultValue,\n onSelectedItemChange: ({ selectedItem: newSelectedItem }) => {\n onChange?.(newSelectedItem ?? null);\n },\n onIsOpenChange: ({\n isOpen: newIsOpen,\n selectedItem: currentSelectedItem,\n }) => {\n if (newIsOpen) {\n // Clear the input on open so the user sees an empty search box\n // (with the placeholder reminding them of the current value)\n // and the full options list. Otherwise the active label would\n // appear both in the trigger AND as the highlighted menu row.\n setInputValue(\"\");\n setSearchTerm(\"\");\n } else {\n setInputValue(currentSelectedItem?.label ?? \"\");\n setSearchTerm(\"\");\n }\n },\n });\n\n const isDisabled = loading || disabled;\n\n // `selectedItem` is downshift's internal state, frozen to whatever\n // initialized it. Resolve the currently selected option against the\n // live `options` array so per-option fields like `prefix` (e.g. a\n // status indicator that re-renders on a timer) update on the trigger\n // without remounting the dropdown.\n const liveSelectedOption = selectedItem\n ? (options.find((o) => o.value === selectedItem.value) ?? selectedItem)\n : null;\n\n // Wrap getInputProps to inject a direct onChange handler that preserves\n // cursor position. Downshift's default onInputValueChange resets cursor\n // to end of input on every keystroke; reading from e.target.value keeps\n // the browser's native cursor position intact.\n const getInputPropsWithCursorFix = (props?: object) =>\n getInputProps({\n ...props,\n onChange: (e: React.ChangeEvent<HTMLInputElement>) => {\n setInputValue(e.target.value);\n setSearchTerm(e.target.value);\n },\n });\n\n return (\n <div\n className={cn(\"relative\", fitContent ? \"inline-block w-auto\" : \"w-full\")}\n data-testid={testId}\n onMouseEnter={\n openOnHover\n ? () => {\n if (closeTimerRef.current) {\n clearTimeout(closeTimerRef.current);\n closeTimerRef.current = null;\n }\n openMenu();\n }\n : undefined\n }\n onMouseLeave={\n openOnHover\n ? () => {\n if (closeTimerRef.current) {\n clearTimeout(closeTimerRef.current);\n }\n closeTimerRef.current = setTimeout(() => closeMenu(), 150);\n }\n : undefined\n }\n >\n {!hideTrigger ? (\n <div\n className={cn(\n dropdownTriggerShellClassName,\n fitContent ? \"w-auto\" : \"w-full\",\n isDisabled && \"cursor-not-allowed opacity-60\",\n className,\n )}\n >\n {liveSelectedOption?.prefix ? (\n <span className=\"flex items-center shrink-0\">\n {liveSelectedOption.prefix}\n </span>\n ) : null}\n <DropdownInput\n placeholder={placeholder}\n isDisabled={isDisabled}\n getInputProps={getInputPropsWithCursorFix}\n italicPlaceholder={italicPlaceholder}\n fitContent={fitContent}\n />\n {loading && <LoadingSpinner />}\n {clearable && selectedItem && (\n <ClearButton onClear={() => selectItem(null)} />\n )}\n <ToggleButton\n isOpen={isOpen}\n isDisabled={isDisabled}\n getToggleButtonProps={getToggleButtonProps}\n />\n </div>\n ) : (\n // downshift's useCombobox always expects getInputProps() (and the\n // toggle button) to be wired up. When the trigger is hidden (e.g.\n // collapsed-sidebar popover) we still need to mount a real input\n // so it stops warning every render. Keep it visually hidden but\n // present in the DOM for accessibility.\n <>\n <input\n {...getInputPropsWithCursorFix({\n \"aria-label\": placeholder ?? \"Filter options\",\n tabIndex: -1,\n })}\n style={visuallyHiddenStyle}\n />\n <button\n type=\"button\"\n {...getToggleButtonProps({ tabIndex: -1 })}\n style={visuallyHiddenStyle}\n aria-hidden\n />\n </>\n )}\n <DropdownMenu\n isOpen={isOpen}\n filteredOptions={filteredOptions}\n selectedItem={selectedItem}\n emptyMessage={emptyMessage}\n getMenuProps={getMenuProps}\n getItemProps={getItemProps}\n footer={footer}\n openUpward={openUpward}\n fitContent={fitContent}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -21,7 +21,11 @@ var p = {
|
|
|
21
21
|
border: 0
|
|
22
22
|
};
|
|
23
23
|
function m({ options: m, emptyMessage: h = "No options", clearable: g = !1, loading: _ = !1, disabled: v = !1, placeholder: y, defaultValue: b, onChange: x, testId: S, className: C, footer: w, openUpward: T = !1, hideTrigger: E = !1, defaultOpen: D = !1, openOnHover: O = !1, italicPlaceholder: k = !0, fitContent: A = !1 }) {
|
|
24
|
-
let j = c.useRef(null), [M, N] = l(b?.label ?? ""), [P, F] = l("")
|
|
24
|
+
let j = c.useRef(null), [M, N] = l(b?.label ?? ""), [P, F] = l("");
|
|
25
|
+
c.useEffect(() => () => {
|
|
26
|
+
j.current &&= (clearTimeout(j.current), null);
|
|
27
|
+
}, []);
|
|
28
|
+
let I = m.filter((e) => e.label.toLowerCase().includes(P.toLowerCase())), { isOpen: L, selectedItem: R, selectItem: z, openMenu: B, closeMenu: V, getToggleButtonProps: H, getMenuProps: U, getItemProps: W, getInputProps: G } = n({
|
|
25
29
|
items: I,
|
|
26
30
|
itemToString: (e) => e?.label ?? "",
|
|
27
31
|
inputValue: M,
|
|
@@ -53,7 +57,7 @@ function m({ options: m, emptyMessage: h = "No options", clearable: g = !1, load
|
|
|
53
57
|
j.current &&= (clearTimeout(j.current), null), B();
|
|
54
58
|
} : void 0,
|
|
55
59
|
onMouseLeave: O ? () => {
|
|
56
|
-
j.current = setTimeout(() => V(), 150);
|
|
60
|
+
j.current && clearTimeout(j.current), j.current = setTimeout(() => V(), 150);
|
|
57
61
|
} : void 0,
|
|
58
62
|
children: [E ? /* @__PURE__ */ f(u, { children: [/* @__PURE__ */ d("input", {
|
|
59
63
|
...J({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dropdown.js","names":[],"sources":["../../../src/ui/dropdown/dropdown.tsx"],"sourcesContent":["import React, { useState } from \"react\";\nimport { useCombobox } from \"downshift\";\nimport { cn } from \"#/utils/utils\";\nimport { DropdownOption } from \"./types\";\nimport { dropdownTriggerShellClassName } from \"#/utils/dropdown-classes\";\nimport { LoadingSpinner } from \"./loading-spinner\";\nimport { ClearButton } from \"./clear-button\";\nimport { ToggleButton } from \"./toggle-button\";\nimport { DropdownMenu } from \"./dropdown-menu\";\nimport { DropdownInput } from \"./dropdown-input\";\n\n// Equivalent to Tailwind's `sr-only`, inlined so we don't depend on the\n// utility class being preserved by the host project's CSS pipeline.\nconst visuallyHiddenStyle: React.CSSProperties = {\n position: \"absolute\",\n width: 1,\n height: 1,\n padding: 0,\n margin: -1,\n overflow: \"hidden\",\n clip: \"rect(0, 0, 0, 0)\",\n whiteSpace: \"nowrap\",\n border: 0,\n};\n\ninterface DropdownProps {\n options: DropdownOption[];\n emptyMessage?: string;\n clearable?: boolean;\n loading?: boolean;\n disabled?: boolean;\n placeholder?: string;\n defaultValue?: DropdownOption;\n onChange?: (item: DropdownOption | null) => void;\n testId?: string;\n className?: string;\n footer?: React.ReactNode;\n openUpward?: boolean;\n hideTrigger?: boolean;\n defaultOpen?: boolean;\n /** Open the dropdown menu on hover instead of requiring a click. */\n openOnHover?: boolean;\n /** When false, the combobox placeholder uses normal (non-italic) type. */\n italicPlaceholder?: boolean;\n /** Size the trigger to its label instead of stretching to the container width. */\n fitContent?: boolean;\n}\n\nexport function Dropdown({\n options,\n emptyMessage = \"No options\",\n clearable = false,\n loading = false,\n disabled = false,\n placeholder,\n defaultValue,\n onChange,\n testId,\n className,\n footer,\n openUpward = false,\n hideTrigger = false,\n defaultOpen = false,\n openOnHover = false,\n italicPlaceholder = true,\n fitContent = false,\n}: DropdownProps) {\n const closeTimerRef = React.useRef<ReturnType<typeof setTimeout> | null>(\n null,\n );\n const [inputValue, setInputValue] = useState(defaultValue?.label ?? \"\");\n const [searchTerm, setSearchTerm] = useState(\"\");\n\n const filteredOptions = options.filter((option) =>\n option.label.toLowerCase().includes(searchTerm.toLowerCase()),\n );\n\n const {\n isOpen,\n selectedItem,\n selectItem,\n openMenu,\n closeMenu,\n getToggleButtonProps,\n getMenuProps,\n getItemProps,\n getInputProps,\n } = useCombobox({\n items: filteredOptions,\n itemToString: (item) => item?.label ?? \"\",\n inputValue,\n stateReducer: (state, actionAndChanges) =>\n actionAndChanges.type === useCombobox.stateChangeTypes.InputClick &&\n state.isOpen\n ? { ...actionAndChanges.changes, isOpen: true }\n : actionAndChanges.changes,\n initialIsOpen: defaultOpen,\n onInputValueChange: ({ inputValue: newValue }) => {\n setInputValue(newValue ?? \"\");\n setSearchTerm(newValue ?? \"\");\n },\n defaultSelectedItem: defaultValue,\n onSelectedItemChange: ({ selectedItem: newSelectedItem }) => {\n onChange?.(newSelectedItem ?? null);\n },\n onIsOpenChange: ({\n isOpen: newIsOpen,\n selectedItem: currentSelectedItem,\n }) => {\n if (newIsOpen) {\n // Clear the input on open so the user sees an empty search box\n // (with the placeholder reminding them of the current value)\n // and the full options list. Otherwise the active label would\n // appear both in the trigger AND as the highlighted menu row.\n setInputValue(\"\");\n setSearchTerm(\"\");\n } else {\n setInputValue(currentSelectedItem?.label ?? \"\");\n setSearchTerm(\"\");\n }\n },\n });\n\n const isDisabled = loading || disabled;\n\n // `selectedItem` is downshift's internal state, frozen to whatever\n // initialized it. Resolve the currently selected option against the\n // live `options` array so per-option fields like `prefix` (e.g. a\n // status indicator that re-renders on a timer) update on the trigger\n // without remounting the dropdown.\n const liveSelectedOption = selectedItem\n ? (options.find((o) => o.value === selectedItem.value) ?? selectedItem)\n : null;\n\n // Wrap getInputProps to inject a direct onChange handler that preserves\n // cursor position. Downshift's default onInputValueChange resets cursor\n // to end of input on every keystroke; reading from e.target.value keeps\n // the browser's native cursor position intact.\n const getInputPropsWithCursorFix = (props?: object) =>\n getInputProps({\n ...props,\n onChange: (e: React.ChangeEvent<HTMLInputElement>) => {\n setInputValue(e.target.value);\n setSearchTerm(e.target.value);\n },\n });\n\n return (\n <div\n className={cn(\"relative\", fitContent ? \"inline-block w-auto\" : \"w-full\")}\n data-testid={testId}\n onMouseEnter={\n openOnHover\n ? () => {\n if (closeTimerRef.current) {\n clearTimeout(closeTimerRef.current);\n closeTimerRef.current = null;\n }\n openMenu();\n }\n : undefined\n }\n onMouseLeave={\n openOnHover\n ? () => {\n closeTimerRef.current = setTimeout(() => closeMenu(), 150);\n }\n : undefined\n }\n >\n {!hideTrigger ? (\n <div\n className={cn(\n dropdownTriggerShellClassName,\n fitContent ? \"w-auto\" : \"w-full\",\n isDisabled && \"cursor-not-allowed opacity-60\",\n className,\n )}\n >\n {liveSelectedOption?.prefix ? (\n <span className=\"flex items-center shrink-0\">\n {liveSelectedOption.prefix}\n </span>\n ) : null}\n <DropdownInput\n placeholder={placeholder}\n isDisabled={isDisabled}\n getInputProps={getInputPropsWithCursorFix}\n italicPlaceholder={italicPlaceholder}\n fitContent={fitContent}\n />\n {loading && <LoadingSpinner />}\n {clearable && selectedItem && (\n <ClearButton onClear={() => selectItem(null)} />\n )}\n <ToggleButton\n isOpen={isOpen}\n isDisabled={isDisabled}\n getToggleButtonProps={getToggleButtonProps}\n />\n </div>\n ) : (\n // downshift's useCombobox always expects getInputProps() (and the\n // toggle button) to be wired up. When the trigger is hidden (e.g.\n // collapsed-sidebar popover) we still need to mount a real input\n // so it stops warning every render. Keep it visually hidden but\n // present in the DOM for accessibility.\n <>\n <input\n {...getInputPropsWithCursorFix({\n \"aria-label\": placeholder ?? \"Filter options\",\n tabIndex: -1,\n })}\n style={visuallyHiddenStyle}\n />\n <button\n type=\"button\"\n {...getToggleButtonProps({ tabIndex: -1 })}\n style={visuallyHiddenStyle}\n aria-hidden\n />\n </>\n )}\n <DropdownMenu\n isOpen={isOpen}\n filteredOptions={filteredOptions}\n selectedItem={selectedItem}\n emptyMessage={emptyMessage}\n getMenuProps={getMenuProps}\n getItemProps={getItemProps}\n footer={footer}\n openUpward={openUpward}\n fitContent={fitContent}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dropdown.js","names":[],"sources":["../../../src/ui/dropdown/dropdown.tsx"],"sourcesContent":["import React, { useState } from \"react\";\nimport { useCombobox } from \"downshift\";\nimport { cn } from \"#/utils/utils\";\nimport { DropdownOption } from \"./types\";\nimport { dropdownTriggerShellClassName } from \"#/utils/dropdown-classes\";\nimport { LoadingSpinner } from \"./loading-spinner\";\nimport { ClearButton } from \"./clear-button\";\nimport { ToggleButton } from \"./toggle-button\";\nimport { DropdownMenu } from \"./dropdown-menu\";\nimport { DropdownInput } from \"./dropdown-input\";\n\n// Equivalent to Tailwind's `sr-only`, inlined so we don't depend on the\n// utility class being preserved by the host project's CSS pipeline.\nconst visuallyHiddenStyle: React.CSSProperties = {\n position: \"absolute\",\n width: 1,\n height: 1,\n padding: 0,\n margin: -1,\n overflow: \"hidden\",\n clip: \"rect(0, 0, 0, 0)\",\n whiteSpace: \"nowrap\",\n border: 0,\n};\n\ninterface DropdownProps {\n options: DropdownOption[];\n emptyMessage?: string;\n clearable?: boolean;\n loading?: boolean;\n disabled?: boolean;\n placeholder?: string;\n defaultValue?: DropdownOption;\n onChange?: (item: DropdownOption | null) => void;\n testId?: string;\n className?: string;\n footer?: React.ReactNode;\n openUpward?: boolean;\n hideTrigger?: boolean;\n defaultOpen?: boolean;\n /** Open the dropdown menu on hover instead of requiring a click. */\n openOnHover?: boolean;\n /** When false, the combobox placeholder uses normal (non-italic) type. */\n italicPlaceholder?: boolean;\n /** Size the trigger to its label instead of stretching to the container width. */\n fitContent?: boolean;\n}\n\nexport function Dropdown({\n options,\n emptyMessage = \"No options\",\n clearable = false,\n loading = false,\n disabled = false,\n placeholder,\n defaultValue,\n onChange,\n testId,\n className,\n footer,\n openUpward = false,\n hideTrigger = false,\n defaultOpen = false,\n openOnHover = false,\n italicPlaceholder = true,\n fitContent = false,\n}: DropdownProps) {\n const closeTimerRef = React.useRef<ReturnType<typeof setTimeout> | null>(\n null,\n );\n const [inputValue, setInputValue] = useState(defaultValue?.label ?? \"\");\n const [searchTerm, setSearchTerm] = useState(\"\");\n\n React.useEffect(\n () => () => {\n if (closeTimerRef.current) {\n clearTimeout(closeTimerRef.current);\n closeTimerRef.current = null;\n }\n },\n [],\n );\n\n const filteredOptions = options.filter((option) =>\n option.label.toLowerCase().includes(searchTerm.toLowerCase()),\n );\n\n const {\n isOpen,\n selectedItem,\n selectItem,\n openMenu,\n closeMenu,\n getToggleButtonProps,\n getMenuProps,\n getItemProps,\n getInputProps,\n } = useCombobox({\n items: filteredOptions,\n itemToString: (item) => item?.label ?? \"\",\n inputValue,\n stateReducer: (state, actionAndChanges) =>\n actionAndChanges.type === useCombobox.stateChangeTypes.InputClick &&\n state.isOpen\n ? { ...actionAndChanges.changes, isOpen: true }\n : actionAndChanges.changes,\n initialIsOpen: defaultOpen,\n onInputValueChange: ({ inputValue: newValue }) => {\n setInputValue(newValue ?? \"\");\n setSearchTerm(newValue ?? \"\");\n },\n defaultSelectedItem: defaultValue,\n onSelectedItemChange: ({ selectedItem: newSelectedItem }) => {\n onChange?.(newSelectedItem ?? null);\n },\n onIsOpenChange: ({\n isOpen: newIsOpen,\n selectedItem: currentSelectedItem,\n }) => {\n if (newIsOpen) {\n // Clear the input on open so the user sees an empty search box\n // (with the placeholder reminding them of the current value)\n // and the full options list. Otherwise the active label would\n // appear both in the trigger AND as the highlighted menu row.\n setInputValue(\"\");\n setSearchTerm(\"\");\n } else {\n setInputValue(currentSelectedItem?.label ?? \"\");\n setSearchTerm(\"\");\n }\n },\n });\n\n const isDisabled = loading || disabled;\n\n // `selectedItem` is downshift's internal state, frozen to whatever\n // initialized it. Resolve the currently selected option against the\n // live `options` array so per-option fields like `prefix` (e.g. a\n // status indicator that re-renders on a timer) update on the trigger\n // without remounting the dropdown.\n const liveSelectedOption = selectedItem\n ? (options.find((o) => o.value === selectedItem.value) ?? selectedItem)\n : null;\n\n // Wrap getInputProps to inject a direct onChange handler that preserves\n // cursor position. Downshift's default onInputValueChange resets cursor\n // to end of input on every keystroke; reading from e.target.value keeps\n // the browser's native cursor position intact.\n const getInputPropsWithCursorFix = (props?: object) =>\n getInputProps({\n ...props,\n onChange: (e: React.ChangeEvent<HTMLInputElement>) => {\n setInputValue(e.target.value);\n setSearchTerm(e.target.value);\n },\n });\n\n return (\n <div\n className={cn(\"relative\", fitContent ? \"inline-block w-auto\" : \"w-full\")}\n data-testid={testId}\n onMouseEnter={\n openOnHover\n ? () => {\n if (closeTimerRef.current) {\n clearTimeout(closeTimerRef.current);\n closeTimerRef.current = null;\n }\n openMenu();\n }\n : undefined\n }\n onMouseLeave={\n openOnHover\n ? () => {\n if (closeTimerRef.current) {\n clearTimeout(closeTimerRef.current);\n }\n closeTimerRef.current = setTimeout(() => closeMenu(), 150);\n }\n : undefined\n }\n >\n {!hideTrigger ? (\n <div\n className={cn(\n dropdownTriggerShellClassName,\n fitContent ? \"w-auto\" : \"w-full\",\n isDisabled && \"cursor-not-allowed opacity-60\",\n className,\n )}\n >\n {liveSelectedOption?.prefix ? (\n <span className=\"flex items-center shrink-0\">\n {liveSelectedOption.prefix}\n </span>\n ) : null}\n <DropdownInput\n placeholder={placeholder}\n isDisabled={isDisabled}\n getInputProps={getInputPropsWithCursorFix}\n italicPlaceholder={italicPlaceholder}\n fitContent={fitContent}\n />\n {loading && <LoadingSpinner />}\n {clearable && selectedItem && (\n <ClearButton onClear={() => selectItem(null)} />\n )}\n <ToggleButton\n isOpen={isOpen}\n isDisabled={isDisabled}\n getToggleButtonProps={getToggleButtonProps}\n />\n </div>\n ) : (\n // downshift's useCombobox always expects getInputProps() (and the\n // toggle button) to be wired up. When the trigger is hidden (e.g.\n // collapsed-sidebar popover) we still need to mount a real input\n // so it stops warning every render. Keep it visually hidden but\n // present in the DOM for accessibility.\n <>\n <input\n {...getInputPropsWithCursorFix({\n \"aria-label\": placeholder ?? \"Filter options\",\n tabIndex: -1,\n })}\n style={visuallyHiddenStyle}\n />\n <button\n type=\"button\"\n {...getToggleButtonProps({ tabIndex: -1 })}\n style={visuallyHiddenStyle}\n aria-hidden\n />\n </>\n )}\n <DropdownMenu\n isOpen={isOpen}\n filteredOptions={filteredOptions}\n selectedItem={selectedItem}\n emptyMessage={emptyMessage}\n getMenuProps={getMenuProps}\n getItemProps={getItemProps}\n footer={footer}\n openUpward={openUpward}\n fitContent={fitContent}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
require(`../_virtual/_rolldown/runtime.cjs`);const e=require(`../types/agent-server/type-guards.cjs`);var t=(e,t)=>({...t,content:`${t.content??``}${e.content??``}`||null,reasoning_content:`${t.reasoning_content??``}${e.reasoning_content??``}`||null}),n=(e,t)=>({...e,content:`${e.content??``}${t}`||null}),r=t=>{for(let n=t.length-1;n>=0;--n){let r=t[n];if(e.isMessageEvent(r)&&r.source===`user`)return n}return-1},i=e=>e.llm_message.content.filter(e=>e.type===`text`).map(e=>e.text).join(``),a=t=>e.isActionEvent(t)&&t.action.kind===`FinishAction`?t.action.message:e.isMessageEvent(t)&&t.source===`agent`?i(t):null,o=(e,t)=>{let n=0,r=0;for(let i of t){let t=e.indexOf(i,n);if(t===-1)return{matched:!1,lastMatchEnd:r};r=t+i.length,n=r}return{matched:!0,lastMatchEnd:r}},s=(t,i)=>{let s=r(i),c=i.map((e,t)=>({uiEvent:e,index:t})).filter(({uiEvent:t,index:n})=>n>s&&e.isStreamingDeltaEvent(t)).map(({index:e})=>e);if(c.length===0)return null;let l=a(t),u=c.map(e=>({event:i[e],index:e})).filter(t=>e.isStreamingDeltaEvent(t.event)&&(t.event.content?.length??0)>0),d=u.map(({event:e})=>e.content??``);if(!l||d.length===0)return null;let f=[...i],p=d.join(``),m=``;if(l.startsWith(p))m=l.slice(p.length);else{let e=o(l,d);if(!e.matched)return null;m=l.slice(e.lastMatchEnd)}let h=u.at(-1)?.index,g=h===void 0?void 0:f[h];return m&&h!==void 0&&g&&e.isStreamingDeltaEvent(g)&&(f[h]=n(g,m)),f},c=(n,r)=>{let i=[...r];if(e.isStreamingDeltaEvent(n)){if(n.content===null&&n.reasoning_content===null)return i;let r=i.length-1,a=i[r];return a&&e.isStreamingDeltaEvent(a)?(i[r]=t(n,a),i):(i.push(n),i)}if(e.isActionEvent(n)&&n.action.kind===`FinishAction`||e.isMessageEvent(n)&&n.source===`agent`){let e=s(n,i);if(e)return e}if(e.isACPToolCallEvent(n)){let t=i.findIndex(t=>e.isACPToolCallEvent(t)&&t.tool_call_id===n.tool_call_id);return t===-1?i.push(n):i[t]=n,i}if(e.isObservationEvent(n)){if(n.observation.kind===`ThinkObservation`||n.observation.kind===`FinishObservation`)return i;let e=i.findIndex(e=>e.id===n.action_id);e===-1?i.push(n):i[e]=n}else i.push(n);return i};exports.handleEventForUI=c;
|
|
1
|
+
require(`../_virtual/_rolldown/runtime.cjs`);const e=require(`../types/agent-server/type-guards.cjs`);var t=(e,t)=>({...t,content:`${t.content??``}${e.content??``}`||null,reasoning_content:`${t.reasoning_content??``}${e.reasoning_content??``}`||null}),n=(e,t)=>({...e,content:`${e.content??``}${t}`||null}),r=t=>{for(let n=t.length-1;n>=0;--n){let r=t[n];if(e.isMessageEvent(r)&&r.source===`user`)return n}return-1},i=e=>e.llm_message.content.filter(e=>e.type===`text`).map(e=>e.text).join(``),a=t=>e.isActionEvent(t)&&t.action.kind===`FinishAction`?t.action.message:e.isMessageEvent(t)&&t.source===`agent`?i(t):null,o=(e,t)=>{let n=0,r=0;for(let i of t){let t=e.indexOf(i,n);if(t===-1)return{matched:!1,lastMatchEnd:r};r=t+i.length,n=r}return{matched:!0,lastMatchEnd:r}},s=(t,i)=>{let s=r(i),c=i.map((e,t)=>({uiEvent:e,index:t})).filter(({uiEvent:t,index:n})=>n>s&&e.isStreamingDeltaEvent(t)).map(({index:e})=>e);if(c.length===0)return null;let l=a(t),u=c.map(e=>({event:i[e],index:e})).filter(t=>e.isStreamingDeltaEvent(t.event)&&(t.event.content?.length??0)>0),d=u.map(({event:e})=>e.content??``);if(!l||d.length===0)return null;let f=[...i],p=d.join(``),m=``;if(l.startsWith(p))m=l.slice(p.length);else{let e=o(l,d);if(!e.matched)return null;m=l.slice(e.lastMatchEnd)}let h=u.at(-1)?.index,g=h===void 0?void 0:f[h];return m&&h!==void 0&&g&&e.isStreamingDeltaEvent(g)&&(f[h]=n(g,m)),f},c=(n,r)=>{let i=[...r];if(e.isStreamingDeltaEvent(n)){if(n.content===null&&n.reasoning_content===null)return i;let r=i.length-1,a=i[r];return a&&e.isStreamingDeltaEvent(a)?(i[r]=t(n,a),i):(i.push(n),i)}if(e.isActionEvent(n)&&n.action.kind===`FinishAction`||e.isMessageEvent(n)&&n.source===`agent`){let e=s(n,i);if(e)return e}if(e.isACPToolCallEvent(n)){let t=i.findIndex(t=>e.isACPToolCallEvent(t)&&t.tool_call_id===n.tool_call_id);return t===-1?i.push(n):i[t]=n,i}if(e.isObservationEvent(n)){if(n.observation.kind===`ThinkObservation`||n.observation.kind===`FinishObservation`)return i;let e=i.findIndex(e=>e.id===n.action_id);e===-1?i.push(n):i[e]=n}else i.push(n);return i};exports.handleEventForUI=c,exports.mergeStreamingDeltaEvent=t;
|
|
2
2
|
//# sourceMappingURL=handle-event-for-ui.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handle-event-for-ui.cjs","names":[],"sources":["../../src/utils/handle-event-for-ui.ts"],"sourcesContent":["import { MessageEvent, OpenHandsEvent } from \"#/types/agent-server/core\";\nimport {\n isACPToolCallEvent,\n isActionEvent,\n isMessageEvent,\n isObservationEvent,\n isStreamingDeltaEvent,\n} from \"#/types/agent-server/type-guards\";\nimport { StreamingDeltaEvent } from \"#/types/agent-server/core/events/streaming-delta-event\";\n\nconst mergeStreamingDeltaEvent = (\n incoming: StreamingDeltaEvent,\n existing: StreamingDeltaEvent,\n): StreamingDeltaEvent => ({\n ...existing,\n content: `${existing.content ?? \"\"}${incoming.content ?? \"\"}` || null,\n reasoning_content:\n `${existing.reasoning_content ?? \"\"}${incoming.reasoning_content ?? \"\"}` ||\n null,\n});\n\nconst appendContentToStreamingDeltaEvent = (\n existing: StreamingDeltaEvent,\n content: string,\n): StreamingDeltaEvent => ({\n ...existing,\n content: `${existing.content ?? \"\"}${content}` || null,\n});\n\nconst findLastUserMessageIndex = (events: OpenHandsEvent[]): number => {\n for (let index = events.length - 1; index >= 0; index -= 1) {\n const event = events[index];\n if (isMessageEvent(event) && event.source === \"user\") {\n return index;\n }\n }\n return -1;\n};\n\n// Join text blocks WITHOUT a separator: streaming deltas concatenate content\n// tokens directly with no separator between LLM content blocks, so using \"\\n\"\n// here would cause startsWith/findTextSegmentsInOrder to miss when reconciling\n// a multi-block MessageEvent against the already-rendered streaming delta.\nconst getAgentMessageText = (event: MessageEvent): string =>\n event.llm_message.content\n .filter((content) => content.type === \"text\")\n .map((content) => content.text)\n .join(\"\");\n\nconst getFinalAgentText = (event: OpenHandsEvent): string | null => {\n if (isActionEvent(event) && event.action.kind === \"FinishAction\") {\n return event.action.message;\n }\n\n if (isMessageEvent(event) && event.source === \"agent\") {\n return getAgentMessageText(event);\n }\n\n return null;\n};\n\nconst findTextSegmentsInOrder = (\n text: string,\n segments: string[],\n): { matched: boolean; lastMatchEnd: number } => {\n let searchStart = 0;\n let lastMatchEnd = 0;\n\n for (const segment of segments) {\n const index = text.indexOf(segment, searchStart);\n if (index === -1) {\n return { matched: false, lastMatchEnd };\n }\n lastMatchEnd = index + segment.length;\n searchStart = lastMatchEnd;\n }\n\n return { matched: true, lastMatchEnd };\n};\n\nconst finalizeStreamingDeltasInPlace = (\n finalEvent: OpenHandsEvent,\n uiEvents: OpenHandsEvent[],\n): OpenHandsEvent[] | null => {\n const lastUserMessageIndex = findLastUserMessageIndex(uiEvents);\n const currentTurnStreamingDeltaIndexes = uiEvents\n .map((uiEvent, index) => ({ uiEvent, index }))\n .filter(\n ({ uiEvent, index }) =>\n index > lastUserMessageIndex && isStreamingDeltaEvent(uiEvent),\n )\n .map(({ index }) => index);\n\n if (currentTurnStreamingDeltaIndexes.length === 0) {\n return null;\n }\n\n const finalText = getFinalAgentText(finalEvent);\n // Only the regular `content` field participates in reconciliation.\n // Reasoning-only deltas (those that carry only `reasoning_content`) produce\n // an empty streamingSegments list, causing the function to return null so\n // the finalEvent is appended normally. This is intentional: reasoning\n // content renders in its own collapsed bubble and never overlaps with the\n // assistant's regular message text in `FinishAction.message`.\n const contentStreamingDeltas = currentTurnStreamingDeltaIndexes\n .map((index) => ({ event: uiEvents[index], index }))\n .filter(\n (item): item is { event: StreamingDeltaEvent; index: number } =>\n isStreamingDeltaEvent(item.event) &&\n (item.event.content?.length ?? 0) > 0,\n );\n const streamingSegments = contentStreamingDeltas.map(\n ({ event }) => event.content ?? \"\",\n );\n\n if (!finalText || streamingSegments.length === 0) {\n return null;\n }\n\n const nextUiEvents = [...uiEvents];\n const streamedText = streamingSegments.join(\"\");\n let unstreamedSuffix = \"\";\n\n if (finalText.startsWith(streamedText)) {\n unstreamedSuffix = finalText.slice(streamedText.length);\n } else {\n const match = findTextSegmentsInOrder(finalText, streamingSegments);\n if (!match.matched) {\n return null;\n }\n unstreamedSuffix = finalText.slice(match.lastMatchEnd);\n }\n\n const lastDeltaIndex = contentStreamingDeltas.at(-1)?.index;\n const lastDelta =\n lastDeltaIndex === undefined ? undefined : nextUiEvents[lastDeltaIndex];\n if (\n unstreamedSuffix &&\n lastDeltaIndex !== undefined &&\n lastDelta &&\n isStreamingDeltaEvent(lastDelta)\n ) {\n nextUiEvents[lastDeltaIndex] = appendContentToStreamingDeltaEvent(\n lastDelta,\n unstreamedSuffix,\n );\n }\n\n // Intentionally return nextUiEvents WITHOUT appending finalEvent.\n // The last content-bearing streaming delta (possibly extended with\n // unstreamedSuffix above) becomes the canonical final rendered bubble for\n // this turn. Appending finalEvent here would display the assistant message\n // twice.\n return nextUiEvents;\n};\n\n/**\n * Handles adding an event to the UI events array\n * Replaces actions with observations when they arrive (so UI shows observation instead of action)\n * Exception: ThinkAction is NOT replaced because the thought content is in the action, not in the observation\n *\n * ACPToolCallEvent merge: the SDK emits two events per ``tool_call_id`` — an\n * early ``started`` event (``pending`` / ``in_progress``) and one terminal\n * (completed / failed) event, the action->observation pair for a tool call.\n * Replace the started entry in place with the terminal one so a single card\n * updates from running to its result, exactly like an observation superseding\n * its action below.\n */\nexport const handleEventForUI = (\n event: OpenHandsEvent,\n uiEvents: OpenHandsEvent[],\n): OpenHandsEvent[] => {\n const newUiEvents = [...uiEvents];\n\n if (isStreamingDeltaEvent(event)) {\n if (event.content === null && event.reasoning_content === null) {\n return newUiEvents;\n }\n\n const lastIndex = newUiEvents.length - 1;\n const lastEvent = newUiEvents[lastIndex];\n if (lastEvent && isStreamingDeltaEvent(lastEvent)) {\n newUiEvents[lastIndex] = mergeStreamingDeltaEvent(event, lastEvent);\n return newUiEvents;\n }\n\n newUiEvents.push(event);\n return newUiEvents;\n }\n\n if (\n (isActionEvent(event) && event.action.kind === \"FinishAction\") ||\n (isMessageEvent(event) && event.source === \"agent\")\n ) {\n const finalizedUiEvents = finalizeStreamingDeltasInPlace(\n event,\n newUiEvents,\n );\n if (finalizedUiEvents) {\n // The reconciled streaming delta intentionally replaces this final event\n // for rendering. Today streamed agent responses only render text and\n // reasoning content; if final-event metadata such as activated\n // microagents becomes meaningful for streamed responses, add a rendered\n // wrapper that carries both the stable delta identity and that metadata.\n return finalizedUiEvents;\n }\n }\n\n if (isACPToolCallEvent(event)) {\n const existingIndex = newUiEvents.findIndex(\n (uiEvent) =>\n isACPToolCallEvent(uiEvent) &&\n uiEvent.tool_call_id === event.tool_call_id,\n );\n if (existingIndex !== -1) {\n newUiEvents[existingIndex] = event;\n } else {\n newUiEvents.push(event);\n }\n return newUiEvents;\n }\n\n if (isObservationEvent(event)) {\n // Don't add ThinkObservation at all - we keep the ThinkAction instead\n // The thought content is in the action, not the observation\n if (event.observation.kind === \"ThinkObservation\") {\n return newUiEvents;\n }\n\n // Don't add FinishObservation at all - we keep the FinishAction instead\n // Both contain the same message content, so we only need to display one\n // This also prevents duplicate messages when events arrive out of order due to React batching\n if (event.observation.kind === \"FinishObservation\") {\n return newUiEvents;\n }\n\n // Find and replace the corresponding action from uiEvents\n const actionIndex = newUiEvents.findIndex(\n (uiEvent) => uiEvent.id === event.action_id,\n );\n if (actionIndex !== -1) {\n newUiEvents[actionIndex] = event;\n } else {\n // Action not found in uiEvents, just add the observation\n newUiEvents.push(event);\n }\n } else {\n // For non-observation events, just add them to uiEvents\n newUiEvents.push(event);\n }\n\n return newUiEvents;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"handle-event-for-ui.cjs","names":[],"sources":["../../src/utils/handle-event-for-ui.ts"],"sourcesContent":["import { MessageEvent, OpenHandsEvent } from \"#/types/agent-server/core\";\nimport {\n isACPToolCallEvent,\n isActionEvent,\n isMessageEvent,\n isObservationEvent,\n isStreamingDeltaEvent,\n} from \"#/types/agent-server/type-guards\";\nimport { StreamingDeltaEvent } from \"#/types/agent-server/core/events/streaming-delta-event\";\n\nexport const mergeStreamingDeltaEvent = (\n incoming: StreamingDeltaEvent,\n existing: StreamingDeltaEvent,\n): StreamingDeltaEvent => ({\n ...existing,\n content: `${existing.content ?? \"\"}${incoming.content ?? \"\"}` || null,\n reasoning_content:\n `${existing.reasoning_content ?? \"\"}${incoming.reasoning_content ?? \"\"}` ||\n null,\n});\n\nconst appendContentToStreamingDeltaEvent = (\n existing: StreamingDeltaEvent,\n content: string,\n): StreamingDeltaEvent => ({\n ...existing,\n content: `${existing.content ?? \"\"}${content}` || null,\n});\n\nconst findLastUserMessageIndex = (events: OpenHandsEvent[]): number => {\n for (let index = events.length - 1; index >= 0; index -= 1) {\n const event = events[index];\n if (isMessageEvent(event) && event.source === \"user\") {\n return index;\n }\n }\n return -1;\n};\n\n// Join text blocks WITHOUT a separator: streaming deltas concatenate content\n// tokens directly with no separator between LLM content blocks, so using \"\\n\"\n// here would cause startsWith/findTextSegmentsInOrder to miss when reconciling\n// a multi-block MessageEvent against the already-rendered streaming delta.\nconst getAgentMessageText = (event: MessageEvent): string =>\n event.llm_message.content\n .filter((content) => content.type === \"text\")\n .map((content) => content.text)\n .join(\"\");\n\nconst getFinalAgentText = (event: OpenHandsEvent): string | null => {\n if (isActionEvent(event) && event.action.kind === \"FinishAction\") {\n return event.action.message;\n }\n\n if (isMessageEvent(event) && event.source === \"agent\") {\n return getAgentMessageText(event);\n }\n\n return null;\n};\n\nconst findTextSegmentsInOrder = (\n text: string,\n segments: string[],\n): { matched: boolean; lastMatchEnd: number } => {\n let searchStart = 0;\n let lastMatchEnd = 0;\n\n for (const segment of segments) {\n const index = text.indexOf(segment, searchStart);\n if (index === -1) {\n return { matched: false, lastMatchEnd };\n }\n lastMatchEnd = index + segment.length;\n searchStart = lastMatchEnd;\n }\n\n return { matched: true, lastMatchEnd };\n};\n\nconst finalizeStreamingDeltasInPlace = (\n finalEvent: OpenHandsEvent,\n uiEvents: OpenHandsEvent[],\n): OpenHandsEvent[] | null => {\n const lastUserMessageIndex = findLastUserMessageIndex(uiEvents);\n const currentTurnStreamingDeltaIndexes = uiEvents\n .map((uiEvent, index) => ({ uiEvent, index }))\n .filter(\n ({ uiEvent, index }) =>\n index > lastUserMessageIndex && isStreamingDeltaEvent(uiEvent),\n )\n .map(({ index }) => index);\n\n if (currentTurnStreamingDeltaIndexes.length === 0) {\n return null;\n }\n\n const finalText = getFinalAgentText(finalEvent);\n // Only the regular `content` field participates in reconciliation.\n // Reasoning-only deltas (those that carry only `reasoning_content`) produce\n // an empty streamingSegments list, causing the function to return null so\n // the finalEvent is appended normally. This is intentional: reasoning\n // content renders in its own collapsed bubble and never overlaps with the\n // assistant's regular message text in `FinishAction.message`.\n const contentStreamingDeltas = currentTurnStreamingDeltaIndexes\n .map((index) => ({ event: uiEvents[index], index }))\n .filter(\n (item): item is { event: StreamingDeltaEvent; index: number } =>\n isStreamingDeltaEvent(item.event) &&\n (item.event.content?.length ?? 0) > 0,\n );\n const streamingSegments = contentStreamingDeltas.map(\n ({ event }) => event.content ?? \"\",\n );\n\n if (!finalText || streamingSegments.length === 0) {\n return null;\n }\n\n const nextUiEvents = [...uiEvents];\n const streamedText = streamingSegments.join(\"\");\n let unstreamedSuffix = \"\";\n\n if (finalText.startsWith(streamedText)) {\n unstreamedSuffix = finalText.slice(streamedText.length);\n } else {\n const match = findTextSegmentsInOrder(finalText, streamingSegments);\n if (!match.matched) {\n return null;\n }\n unstreamedSuffix = finalText.slice(match.lastMatchEnd);\n }\n\n const lastDeltaIndex = contentStreamingDeltas.at(-1)?.index;\n const lastDelta =\n lastDeltaIndex === undefined ? undefined : nextUiEvents[lastDeltaIndex];\n if (\n unstreamedSuffix &&\n lastDeltaIndex !== undefined &&\n lastDelta &&\n isStreamingDeltaEvent(lastDelta)\n ) {\n nextUiEvents[lastDeltaIndex] = appendContentToStreamingDeltaEvent(\n lastDelta,\n unstreamedSuffix,\n );\n }\n\n // Intentionally return nextUiEvents WITHOUT appending finalEvent.\n // The last content-bearing streaming delta (possibly extended with\n // unstreamedSuffix above) becomes the canonical final rendered bubble for\n // this turn. Appending finalEvent here would display the assistant message\n // twice.\n return nextUiEvents;\n};\n\n/**\n * Handles adding an event to the UI events array\n * Replaces actions with observations when they arrive (so UI shows observation instead of action)\n * Exception: ThinkAction is NOT replaced because the thought content is in the action, not in the observation\n *\n * ACPToolCallEvent merge: the SDK emits two events per ``tool_call_id`` — an\n * early ``started`` event (``pending`` / ``in_progress``) and one terminal\n * (completed / failed) event, the action->observation pair for a tool call.\n * Replace the started entry in place with the terminal one so a single card\n * updates from running to its result, exactly like an observation superseding\n * its action below.\n */\nexport const handleEventForUI = (\n event: OpenHandsEvent,\n uiEvents: OpenHandsEvent[],\n): OpenHandsEvent[] => {\n const newUiEvents = [...uiEvents];\n\n if (isStreamingDeltaEvent(event)) {\n if (event.content === null && event.reasoning_content === null) {\n return newUiEvents;\n }\n\n const lastIndex = newUiEvents.length - 1;\n const lastEvent = newUiEvents[lastIndex];\n if (lastEvent && isStreamingDeltaEvent(lastEvent)) {\n newUiEvents[lastIndex] = mergeStreamingDeltaEvent(event, lastEvent);\n return newUiEvents;\n }\n\n newUiEvents.push(event);\n return newUiEvents;\n }\n\n if (\n (isActionEvent(event) && event.action.kind === \"FinishAction\") ||\n (isMessageEvent(event) && event.source === \"agent\")\n ) {\n const finalizedUiEvents = finalizeStreamingDeltasInPlace(\n event,\n newUiEvents,\n );\n if (finalizedUiEvents) {\n // The reconciled streaming delta intentionally replaces this final event\n // for rendering. Today streamed agent responses only render text and\n // reasoning content; if final-event metadata such as activated\n // microagents becomes meaningful for streamed responses, add a rendered\n // wrapper that carries both the stable delta identity and that metadata.\n return finalizedUiEvents;\n }\n }\n\n if (isACPToolCallEvent(event)) {\n const existingIndex = newUiEvents.findIndex(\n (uiEvent) =>\n isACPToolCallEvent(uiEvent) &&\n uiEvent.tool_call_id === event.tool_call_id,\n );\n if (existingIndex !== -1) {\n newUiEvents[existingIndex] = event;\n } else {\n newUiEvents.push(event);\n }\n return newUiEvents;\n }\n\n if (isObservationEvent(event)) {\n // Don't add ThinkObservation at all - we keep the ThinkAction instead\n // The thought content is in the action, not the observation\n if (event.observation.kind === \"ThinkObservation\") {\n return newUiEvents;\n }\n\n // Don't add FinishObservation at all - we keep the FinishAction instead\n // Both contain the same message content, so we only need to display one\n // This also prevents duplicate messages when events arrive out of order due to React batching\n if (event.observation.kind === \"FinishObservation\") {\n return newUiEvents;\n }\n\n // Find and replace the corresponding action from uiEvents\n const actionIndex = newUiEvents.findIndex(\n (uiEvent) => uiEvent.id === event.action_id,\n );\n if (actionIndex !== -1) {\n newUiEvents[actionIndex] = event;\n } else {\n // Action not found in uiEvents, just add the observation\n newUiEvents.push(event);\n }\n } else {\n // For non-observation events, just add them to uiEvents\n newUiEvents.push(event);\n }\n\n return newUiEvents;\n};\n"],"mappings":"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"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { OpenHandsEvent } from "#/types/agent-server/core";
|
|
2
|
+
import { StreamingDeltaEvent } from "#/types/agent-server/core/events/streaming-delta-event";
|
|
3
|
+
export declare const mergeStreamingDeltaEvent: (incoming: StreamingDeltaEvent, existing: StreamingDeltaEvent) => StreamingDeltaEvent;
|
|
2
4
|
/**
|
|
3
5
|
* Handles adding an event to the UI events array
|
|
4
6
|
* Replaces actions with observations when they arrive (so UI shows observation instead of action)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handle-event-for-ui.js","names":[],"sources":["../../src/utils/handle-event-for-ui.ts"],"sourcesContent":["import { MessageEvent, OpenHandsEvent } from \"#/types/agent-server/core\";\nimport {\n isACPToolCallEvent,\n isActionEvent,\n isMessageEvent,\n isObservationEvent,\n isStreamingDeltaEvent,\n} from \"#/types/agent-server/type-guards\";\nimport { StreamingDeltaEvent } from \"#/types/agent-server/core/events/streaming-delta-event\";\n\nconst mergeStreamingDeltaEvent = (\n incoming: StreamingDeltaEvent,\n existing: StreamingDeltaEvent,\n): StreamingDeltaEvent => ({\n ...existing,\n content: `${existing.content ?? \"\"}${incoming.content ?? \"\"}` || null,\n reasoning_content:\n `${existing.reasoning_content ?? \"\"}${incoming.reasoning_content ?? \"\"}` ||\n null,\n});\n\nconst appendContentToStreamingDeltaEvent = (\n existing: StreamingDeltaEvent,\n content: string,\n): StreamingDeltaEvent => ({\n ...existing,\n content: `${existing.content ?? \"\"}${content}` || null,\n});\n\nconst findLastUserMessageIndex = (events: OpenHandsEvent[]): number => {\n for (let index = events.length - 1; index >= 0; index -= 1) {\n const event = events[index];\n if (isMessageEvent(event) && event.source === \"user\") {\n return index;\n }\n }\n return -1;\n};\n\n// Join text blocks WITHOUT a separator: streaming deltas concatenate content\n// tokens directly with no separator between LLM content blocks, so using \"\\n\"\n// here would cause startsWith/findTextSegmentsInOrder to miss when reconciling\n// a multi-block MessageEvent against the already-rendered streaming delta.\nconst getAgentMessageText = (event: MessageEvent): string =>\n event.llm_message.content\n .filter((content) => content.type === \"text\")\n .map((content) => content.text)\n .join(\"\");\n\nconst getFinalAgentText = (event: OpenHandsEvent): string | null => {\n if (isActionEvent(event) && event.action.kind === \"FinishAction\") {\n return event.action.message;\n }\n\n if (isMessageEvent(event) && event.source === \"agent\") {\n return getAgentMessageText(event);\n }\n\n return null;\n};\n\nconst findTextSegmentsInOrder = (\n text: string,\n segments: string[],\n): { matched: boolean; lastMatchEnd: number } => {\n let searchStart = 0;\n let lastMatchEnd = 0;\n\n for (const segment of segments) {\n const index = text.indexOf(segment, searchStart);\n if (index === -1) {\n return { matched: false, lastMatchEnd };\n }\n lastMatchEnd = index + segment.length;\n searchStart = lastMatchEnd;\n }\n\n return { matched: true, lastMatchEnd };\n};\n\nconst finalizeStreamingDeltasInPlace = (\n finalEvent: OpenHandsEvent,\n uiEvents: OpenHandsEvent[],\n): OpenHandsEvent[] | null => {\n const lastUserMessageIndex = findLastUserMessageIndex(uiEvents);\n const currentTurnStreamingDeltaIndexes = uiEvents\n .map((uiEvent, index) => ({ uiEvent, index }))\n .filter(\n ({ uiEvent, index }) =>\n index > lastUserMessageIndex && isStreamingDeltaEvent(uiEvent),\n )\n .map(({ index }) => index);\n\n if (currentTurnStreamingDeltaIndexes.length === 0) {\n return null;\n }\n\n const finalText = getFinalAgentText(finalEvent);\n // Only the regular `content` field participates in reconciliation.\n // Reasoning-only deltas (those that carry only `reasoning_content`) produce\n // an empty streamingSegments list, causing the function to return null so\n // the finalEvent is appended normally. This is intentional: reasoning\n // content renders in its own collapsed bubble and never overlaps with the\n // assistant's regular message text in `FinishAction.message`.\n const contentStreamingDeltas = currentTurnStreamingDeltaIndexes\n .map((index) => ({ event: uiEvents[index], index }))\n .filter(\n (item): item is { event: StreamingDeltaEvent; index: number } =>\n isStreamingDeltaEvent(item.event) &&\n (item.event.content?.length ?? 0) > 0,\n );\n const streamingSegments = contentStreamingDeltas.map(\n ({ event }) => event.content ?? \"\",\n );\n\n if (!finalText || streamingSegments.length === 0) {\n return null;\n }\n\n const nextUiEvents = [...uiEvents];\n const streamedText = streamingSegments.join(\"\");\n let unstreamedSuffix = \"\";\n\n if (finalText.startsWith(streamedText)) {\n unstreamedSuffix = finalText.slice(streamedText.length);\n } else {\n const match = findTextSegmentsInOrder(finalText, streamingSegments);\n if (!match.matched) {\n return null;\n }\n unstreamedSuffix = finalText.slice(match.lastMatchEnd);\n }\n\n const lastDeltaIndex = contentStreamingDeltas.at(-1)?.index;\n const lastDelta =\n lastDeltaIndex === undefined ? undefined : nextUiEvents[lastDeltaIndex];\n if (\n unstreamedSuffix &&\n lastDeltaIndex !== undefined &&\n lastDelta &&\n isStreamingDeltaEvent(lastDelta)\n ) {\n nextUiEvents[lastDeltaIndex] = appendContentToStreamingDeltaEvent(\n lastDelta,\n unstreamedSuffix,\n );\n }\n\n // Intentionally return nextUiEvents WITHOUT appending finalEvent.\n // The last content-bearing streaming delta (possibly extended with\n // unstreamedSuffix above) becomes the canonical final rendered bubble for\n // this turn. Appending finalEvent here would display the assistant message\n // twice.\n return nextUiEvents;\n};\n\n/**\n * Handles adding an event to the UI events array\n * Replaces actions with observations when they arrive (so UI shows observation instead of action)\n * Exception: ThinkAction is NOT replaced because the thought content is in the action, not in the observation\n *\n * ACPToolCallEvent merge: the SDK emits two events per ``tool_call_id`` — an\n * early ``started`` event (``pending`` / ``in_progress``) and one terminal\n * (completed / failed) event, the action->observation pair for a tool call.\n * Replace the started entry in place with the terminal one so a single card\n * updates from running to its result, exactly like an observation superseding\n * its action below.\n */\nexport const handleEventForUI = (\n event: OpenHandsEvent,\n uiEvents: OpenHandsEvent[],\n): OpenHandsEvent[] => {\n const newUiEvents = [...uiEvents];\n\n if (isStreamingDeltaEvent(event)) {\n if (event.content === null && event.reasoning_content === null) {\n return newUiEvents;\n }\n\n const lastIndex = newUiEvents.length - 1;\n const lastEvent = newUiEvents[lastIndex];\n if (lastEvent && isStreamingDeltaEvent(lastEvent)) {\n newUiEvents[lastIndex] = mergeStreamingDeltaEvent(event, lastEvent);\n return newUiEvents;\n }\n\n newUiEvents.push(event);\n return newUiEvents;\n }\n\n if (\n (isActionEvent(event) && event.action.kind === \"FinishAction\") ||\n (isMessageEvent(event) && event.source === \"agent\")\n ) {\n const finalizedUiEvents = finalizeStreamingDeltasInPlace(\n event,\n newUiEvents,\n );\n if (finalizedUiEvents) {\n // The reconciled streaming delta intentionally replaces this final event\n // for rendering. Today streamed agent responses only render text and\n // reasoning content; if final-event metadata such as activated\n // microagents becomes meaningful for streamed responses, add a rendered\n // wrapper that carries both the stable delta identity and that metadata.\n return finalizedUiEvents;\n }\n }\n\n if (isACPToolCallEvent(event)) {\n const existingIndex = newUiEvents.findIndex(\n (uiEvent) =>\n isACPToolCallEvent(uiEvent) &&\n uiEvent.tool_call_id === event.tool_call_id,\n );\n if (existingIndex !== -1) {\n newUiEvents[existingIndex] = event;\n } else {\n newUiEvents.push(event);\n }\n return newUiEvents;\n }\n\n if (isObservationEvent(event)) {\n // Don't add ThinkObservation at all - we keep the ThinkAction instead\n // The thought content is in the action, not the observation\n if (event.observation.kind === \"ThinkObservation\") {\n return newUiEvents;\n }\n\n // Don't add FinishObservation at all - we keep the FinishAction instead\n // Both contain the same message content, so we only need to display one\n // This also prevents duplicate messages when events arrive out of order due to React batching\n if (event.observation.kind === \"FinishObservation\") {\n return newUiEvents;\n }\n\n // Find and replace the corresponding action from uiEvents\n const actionIndex = newUiEvents.findIndex(\n (uiEvent) => uiEvent.id === event.action_id,\n );\n if (actionIndex !== -1) {\n newUiEvents[actionIndex] = event;\n } else {\n // Action not found in uiEvents, just add the observation\n newUiEvents.push(event);\n }\n } else {\n // For non-observation events, just add them to uiEvents\n newUiEvents.push(event);\n }\n\n return newUiEvents;\n};\n"],"mappings":";;AAUA,IAAM,KACJ,GACA,OACyB;CACzB,GAAG;CACH,SAAS,GAAG,EAAS,WAAW,KAAK,EAAS,WAAW,QAAQ;CACjE,mBACE,GAAG,EAAS,qBAAqB,KAAK,EAAS,qBAAqB,QACpE;CACH,GAEK,KACJ,GACA,OACyB;CACzB,GAAG;CACH,SAAS,GAAG,EAAS,WAAW,KAAK,OAAa;CACnD,GAEK,KAA4B,MAAqC;AACrE,MAAK,IAAI,IAAQ,EAAO,SAAS,GAAG,KAAS,GAAG,KAAY;EAC1D,IAAM,IAAQ,EAAO;AACrB,MAAI,EAAe,EAAM,IAAI,EAAM,WAAW,OAC5C,QAAO;;AAGX,QAAO;GAOH,KAAuB,MAC3B,EAAM,YAAY,QACf,QAAQ,MAAY,EAAQ,SAAS,OAAO,CAC5C,KAAK,MAAY,EAAQ,KAAK,CAC9B,KAAK,GAAG,EAEP,KAAqB,MACrB,EAAc,EAAM,IAAI,EAAM,OAAO,SAAS,iBACzC,EAAM,OAAO,UAGlB,EAAe,EAAM,IAAI,EAAM,WAAW,UACrC,EAAoB,EAAM,GAG5B,MAGH,KACJ,GACA,MAC+C;CAC/C,IAAI,IAAc,GACd,IAAe;AAEnB,MAAK,IAAM,KAAW,GAAU;EAC9B,IAAM,IAAQ,EAAK,QAAQ,GAAS,EAAY;AAChD,MAAI,MAAU,GACZ,QAAO;GAAE,SAAS;GAAO;GAAc;AAGzC,EADA,IAAe,IAAQ,EAAQ,QAC/B,IAAc;;AAGhB,QAAO;EAAE,SAAS;EAAM;EAAc;GAGlC,KACJ,GACA,MAC4B;CAC5B,IAAM,IAAuB,EAAyB,EAAS,EACzD,IAAmC,EACtC,KAAK,GAAS,OAAW;EAAE;EAAS;EAAO,EAAE,CAC7C,QACE,EAAE,YAAS,eACV,IAAQ,KAAwB,EAAsB,EAAQ,CACjE,CACA,KAAK,EAAE,eAAY,EAAM;AAE5B,KAAI,EAAiC,WAAW,EAC9C,QAAO;CAGT,IAAM,IAAY,EAAkB,EAAW,EAOzC,IAAyB,EAC5B,KAAK,OAAW;EAAE,OAAO,EAAS;EAAQ;EAAO,EAAE,CACnD,QACE,MACC,EAAsB,EAAK,MAAM,KAChC,EAAK,MAAM,SAAS,UAAU,KAAK,EACvC,EACG,IAAoB,EAAuB,KAC9C,EAAE,eAAY,EAAM,WAAW,GACjC;AAED,KAAI,CAAC,KAAa,EAAkB,WAAW,EAC7C,QAAO;CAGT,IAAM,IAAe,CAAC,GAAG,EAAS,EAC5B,IAAe,EAAkB,KAAK,GAAG,EAC3C,IAAmB;AAEvB,KAAI,EAAU,WAAW,EAAa,CACpC,KAAmB,EAAU,MAAM,EAAa,OAAO;MAClD;EACL,IAAM,IAAQ,EAAwB,GAAW,EAAkB;AACnE,MAAI,CAAC,EAAM,QACT,QAAO;AAET,MAAmB,EAAU,MAAM,EAAM,aAAa;;CAGxD,IAAM,IAAiB,EAAuB,GAAG,GAAG,EAAE,OAChD,IACJ,MAAmB,KAAA,IAAY,KAAA,IAAY,EAAa;AAkB1D,QAhBE,KACA,MAAmB,KAAA,KACnB,KACA,EAAsB,EAAU,KAEhC,EAAa,KAAkB,EAC7B,GACA,EACD,GAQI;GAeI,KACX,GACA,MACqB;CACrB,IAAM,IAAc,CAAC,GAAG,EAAS;AAEjC,KAAI,EAAsB,EAAM,EAAE;AAChC,MAAI,EAAM,YAAY,QAAQ,EAAM,sBAAsB,KACxD,QAAO;EAGT,IAAM,IAAY,EAAY,SAAS,GACjC,IAAY,EAAY;AAO9B,SANI,KAAa,EAAsB,EAAU,IAC/C,EAAY,KAAa,EAAyB,GAAO,EAAU,EAC5D,MAGT,EAAY,KAAK,EAAM,EAChB;;AAGT,KACG,EAAc,EAAM,IAAI,EAAM,OAAO,SAAS,kBAC9C,EAAe,EAAM,IAAI,EAAM,WAAW,SAC3C;EACA,IAAM,IAAoB,EACxB,GACA,EACD;AACD,MAAI,EAMF,QAAO;;AAIX,KAAI,EAAmB,EAAM,EAAE;EAC7B,IAAM,IAAgB,EAAY,WAC/B,MACC,EAAmB,EAAQ,IAC3B,EAAQ,iBAAiB,EAAM,aAClC;AAMD,SALI,MAAkB,KAGpB,EAAY,KAAK,EAAM,GAFvB,EAAY,KAAiB,GAIxB;;AAGT,KAAI,EAAmB,EAAM,EAAE;AAU7B,MAPI,EAAM,YAAY,SAAS,sBAO3B,EAAM,YAAY,SAAS,oBAC7B,QAAO;EAIT,IAAM,IAAc,EAAY,WAC7B,MAAY,EAAQ,OAAO,EAAM,UACnC;AACD,EAAI,MAAgB,KAIlB,EAAY,KAAK,EAAM,GAHvB,EAAY,KAAe;OAO7B,GAAY,KAAK,EAAM;AAGzB,QAAO"}
|
|
1
|
+
{"version":3,"file":"handle-event-for-ui.js","names":[],"sources":["../../src/utils/handle-event-for-ui.ts"],"sourcesContent":["import { MessageEvent, OpenHandsEvent } from \"#/types/agent-server/core\";\nimport {\n isACPToolCallEvent,\n isActionEvent,\n isMessageEvent,\n isObservationEvent,\n isStreamingDeltaEvent,\n} from \"#/types/agent-server/type-guards\";\nimport { StreamingDeltaEvent } from \"#/types/agent-server/core/events/streaming-delta-event\";\n\nexport const mergeStreamingDeltaEvent = (\n incoming: StreamingDeltaEvent,\n existing: StreamingDeltaEvent,\n): StreamingDeltaEvent => ({\n ...existing,\n content: `${existing.content ?? \"\"}${incoming.content ?? \"\"}` || null,\n reasoning_content:\n `${existing.reasoning_content ?? \"\"}${incoming.reasoning_content ?? \"\"}` ||\n null,\n});\n\nconst appendContentToStreamingDeltaEvent = (\n existing: StreamingDeltaEvent,\n content: string,\n): StreamingDeltaEvent => ({\n ...existing,\n content: `${existing.content ?? \"\"}${content}` || null,\n});\n\nconst findLastUserMessageIndex = (events: OpenHandsEvent[]): number => {\n for (let index = events.length - 1; index >= 0; index -= 1) {\n const event = events[index];\n if (isMessageEvent(event) && event.source === \"user\") {\n return index;\n }\n }\n return -1;\n};\n\n// Join text blocks WITHOUT a separator: streaming deltas concatenate content\n// tokens directly with no separator between LLM content blocks, so using \"\\n\"\n// here would cause startsWith/findTextSegmentsInOrder to miss when reconciling\n// a multi-block MessageEvent against the already-rendered streaming delta.\nconst getAgentMessageText = (event: MessageEvent): string =>\n event.llm_message.content\n .filter((content) => content.type === \"text\")\n .map((content) => content.text)\n .join(\"\");\n\nconst getFinalAgentText = (event: OpenHandsEvent): string | null => {\n if (isActionEvent(event) && event.action.kind === \"FinishAction\") {\n return event.action.message;\n }\n\n if (isMessageEvent(event) && event.source === \"agent\") {\n return getAgentMessageText(event);\n }\n\n return null;\n};\n\nconst findTextSegmentsInOrder = (\n text: string,\n segments: string[],\n): { matched: boolean; lastMatchEnd: number } => {\n let searchStart = 0;\n let lastMatchEnd = 0;\n\n for (const segment of segments) {\n const index = text.indexOf(segment, searchStart);\n if (index === -1) {\n return { matched: false, lastMatchEnd };\n }\n lastMatchEnd = index + segment.length;\n searchStart = lastMatchEnd;\n }\n\n return { matched: true, lastMatchEnd };\n};\n\nconst finalizeStreamingDeltasInPlace = (\n finalEvent: OpenHandsEvent,\n uiEvents: OpenHandsEvent[],\n): OpenHandsEvent[] | null => {\n const lastUserMessageIndex = findLastUserMessageIndex(uiEvents);\n const currentTurnStreamingDeltaIndexes = uiEvents\n .map((uiEvent, index) => ({ uiEvent, index }))\n .filter(\n ({ uiEvent, index }) =>\n index > lastUserMessageIndex && isStreamingDeltaEvent(uiEvent),\n )\n .map(({ index }) => index);\n\n if (currentTurnStreamingDeltaIndexes.length === 0) {\n return null;\n }\n\n const finalText = getFinalAgentText(finalEvent);\n // Only the regular `content` field participates in reconciliation.\n // Reasoning-only deltas (those that carry only `reasoning_content`) produce\n // an empty streamingSegments list, causing the function to return null so\n // the finalEvent is appended normally. This is intentional: reasoning\n // content renders in its own collapsed bubble and never overlaps with the\n // assistant's regular message text in `FinishAction.message`.\n const contentStreamingDeltas = currentTurnStreamingDeltaIndexes\n .map((index) => ({ event: uiEvents[index], index }))\n .filter(\n (item): item is { event: StreamingDeltaEvent; index: number } =>\n isStreamingDeltaEvent(item.event) &&\n (item.event.content?.length ?? 0) > 0,\n );\n const streamingSegments = contentStreamingDeltas.map(\n ({ event }) => event.content ?? \"\",\n );\n\n if (!finalText || streamingSegments.length === 0) {\n return null;\n }\n\n const nextUiEvents = [...uiEvents];\n const streamedText = streamingSegments.join(\"\");\n let unstreamedSuffix = \"\";\n\n if (finalText.startsWith(streamedText)) {\n unstreamedSuffix = finalText.slice(streamedText.length);\n } else {\n const match = findTextSegmentsInOrder(finalText, streamingSegments);\n if (!match.matched) {\n return null;\n }\n unstreamedSuffix = finalText.slice(match.lastMatchEnd);\n }\n\n const lastDeltaIndex = contentStreamingDeltas.at(-1)?.index;\n const lastDelta =\n lastDeltaIndex === undefined ? undefined : nextUiEvents[lastDeltaIndex];\n if (\n unstreamedSuffix &&\n lastDeltaIndex !== undefined &&\n lastDelta &&\n isStreamingDeltaEvent(lastDelta)\n ) {\n nextUiEvents[lastDeltaIndex] = appendContentToStreamingDeltaEvent(\n lastDelta,\n unstreamedSuffix,\n );\n }\n\n // Intentionally return nextUiEvents WITHOUT appending finalEvent.\n // The last content-bearing streaming delta (possibly extended with\n // unstreamedSuffix above) becomes the canonical final rendered bubble for\n // this turn. Appending finalEvent here would display the assistant message\n // twice.\n return nextUiEvents;\n};\n\n/**\n * Handles adding an event to the UI events array\n * Replaces actions with observations when they arrive (so UI shows observation instead of action)\n * Exception: ThinkAction is NOT replaced because the thought content is in the action, not in the observation\n *\n * ACPToolCallEvent merge: the SDK emits two events per ``tool_call_id`` — an\n * early ``started`` event (``pending`` / ``in_progress``) and one terminal\n * (completed / failed) event, the action->observation pair for a tool call.\n * Replace the started entry in place with the terminal one so a single card\n * updates from running to its result, exactly like an observation superseding\n * its action below.\n */\nexport const handleEventForUI = (\n event: OpenHandsEvent,\n uiEvents: OpenHandsEvent[],\n): OpenHandsEvent[] => {\n const newUiEvents = [...uiEvents];\n\n if (isStreamingDeltaEvent(event)) {\n if (event.content === null && event.reasoning_content === null) {\n return newUiEvents;\n }\n\n const lastIndex = newUiEvents.length - 1;\n const lastEvent = newUiEvents[lastIndex];\n if (lastEvent && isStreamingDeltaEvent(lastEvent)) {\n newUiEvents[lastIndex] = mergeStreamingDeltaEvent(event, lastEvent);\n return newUiEvents;\n }\n\n newUiEvents.push(event);\n return newUiEvents;\n }\n\n if (\n (isActionEvent(event) && event.action.kind === \"FinishAction\") ||\n (isMessageEvent(event) && event.source === \"agent\")\n ) {\n const finalizedUiEvents = finalizeStreamingDeltasInPlace(\n event,\n newUiEvents,\n );\n if (finalizedUiEvents) {\n // The reconciled streaming delta intentionally replaces this final event\n // for rendering. Today streamed agent responses only render text and\n // reasoning content; if final-event metadata such as activated\n // microagents becomes meaningful for streamed responses, add a rendered\n // wrapper that carries both the stable delta identity and that metadata.\n return finalizedUiEvents;\n }\n }\n\n if (isACPToolCallEvent(event)) {\n const existingIndex = newUiEvents.findIndex(\n (uiEvent) =>\n isACPToolCallEvent(uiEvent) &&\n uiEvent.tool_call_id === event.tool_call_id,\n );\n if (existingIndex !== -1) {\n newUiEvents[existingIndex] = event;\n } else {\n newUiEvents.push(event);\n }\n return newUiEvents;\n }\n\n if (isObservationEvent(event)) {\n // Don't add ThinkObservation at all - we keep the ThinkAction instead\n // The thought content is in the action, not the observation\n if (event.observation.kind === \"ThinkObservation\") {\n return newUiEvents;\n }\n\n // Don't add FinishObservation at all - we keep the FinishAction instead\n // Both contain the same message content, so we only need to display one\n // This also prevents duplicate messages when events arrive out of order due to React batching\n if (event.observation.kind === \"FinishObservation\") {\n return newUiEvents;\n }\n\n // Find and replace the corresponding action from uiEvents\n const actionIndex = newUiEvents.findIndex(\n (uiEvent) => uiEvent.id === event.action_id,\n );\n if (actionIndex !== -1) {\n newUiEvents[actionIndex] = event;\n } else {\n // Action not found in uiEvents, just add the observation\n newUiEvents.push(event);\n }\n } else {\n // For non-observation events, just add them to uiEvents\n newUiEvents.push(event);\n }\n\n return newUiEvents;\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
require(`../_virtual/_rolldown/runtime.cjs`);const e=require(`../constants/llm-subscription.cjs`);var t=`llm`;function n(n){if(!n?.sections)return n;let r=!1,i=n.sections.map(n=>{if(n.key!==t)return n;let i=new Set(n.fields.map(e=>e.key)),a=e.LLM_SUBSCRIPTION_SCHEMA_FIELDS.filter(e=>!i.has(e.key));return a.length===0?n:(r=!0,{...n,fields:[...n.fields,...a]})});return r?{...n,sections:i}:n}exports.withLlmSubscriptionSchemaFields=n;
|
|
2
|
+
//# sourceMappingURL=llm-subscription-schema.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-subscription-schema.cjs","names":[],"sources":["../../src/utils/llm-subscription-schema.ts"],"sourcesContent":["import type { SettingsSchema } from \"#/types/settings\";\nimport { LLM_SUBSCRIPTION_SCHEMA_FIELDS } from \"#/constants/llm-subscription\";\n\nconst LLM_SECTION_KEY = \"llm\";\n\nexport function withLlmSubscriptionSchemaFields(\n schema: SettingsSchema | null | undefined,\n): SettingsSchema | null | undefined {\n if (!schema?.sections) return schema;\n\n let changed = false;\n const sections = schema.sections.map((section) => {\n if (section.key !== LLM_SECTION_KEY) return section;\n\n const existingKeys = new Set(section.fields.map((field) => field.key));\n const missingFields = LLM_SUBSCRIPTION_SCHEMA_FIELDS.filter(\n (field) => !existingKeys.has(field.key),\n );\n\n if (missingFields.length === 0) return section;\n changed = true;\n return {\n ...section,\n fields: [...section.fields, ...missingFields],\n };\n });\n\n if (!changed) return schema;\n return { ...schema, sections };\n}\n"],"mappings":"kGAGA,IAAM,EAAkB,MAExB,SAAgB,EACd,EACmC,CACnC,GAAI,CAAC,GAAQ,SAAU,OAAO,EAE9B,IAAI,EAAU,GACR,EAAW,EAAO,SAAS,IAAK,GAAY,CAChD,GAAI,EAAQ,MAAQ,EAAiB,OAAO,EAE5C,IAAM,EAAe,IAAI,IAAI,EAAQ,OAAO,IAAK,GAAU,EAAM,IAAI,CAAC,CAChE,EAAgB,EAAA,+BAA+B,OAClD,GAAU,CAAC,EAAa,IAAI,EAAM,IAAI,CACxC,CAID,OAFI,EAAc,SAAW,EAAU,GACvC,EAAU,GACH,CACL,GAAG,EACH,OAAQ,CAAC,GAAG,EAAQ,OAAQ,GAAG,EAAc,CAC9C,GACD,CAGF,OADK,EACE,CAAE,GAAG,EAAQ,WAAU,CADT"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { LLM_SUBSCRIPTION_SCHEMA_FIELDS as e } from "../constants/llm-subscription.js";
|
|
2
|
+
//#region src/utils/llm-subscription-schema.ts
|
|
3
|
+
var t = "llm";
|
|
4
|
+
function n(n) {
|
|
5
|
+
if (!n?.sections) return n;
|
|
6
|
+
let r = !1, i = n.sections.map((n) => {
|
|
7
|
+
if (n.key !== t) return n;
|
|
8
|
+
let i = new Set(n.fields.map((e) => e.key)), a = e.filter((e) => !i.has(e.key));
|
|
9
|
+
return a.length === 0 ? n : (r = !0, {
|
|
10
|
+
...n,
|
|
11
|
+
fields: [...n.fields, ...a]
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
return r ? {
|
|
15
|
+
...n,
|
|
16
|
+
sections: i
|
|
17
|
+
} : n;
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { n as withLlmSubscriptionSchemaFields };
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=llm-subscription-schema.js.map
|