@openhands/agent-canvas 1.0.0-alpha.7 → 1.0.0-alpha.9

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.
Files changed (745) hide show
  1. package/README.md +25 -23
  2. package/bin/agent-canvas.mjs +27 -1
  3. package/build/assets/{QueryClientProvider-DITRCGAK.js → QueryClientProvider-B7kl84Kj.js} +1 -1
  4. package/build/assets/{Trans-D43bd3yR.js → Trans-1j65oy9O.js} +1 -1
  5. package/build/assets/{acp-providers-SCPK1BIU.js → acp-providers-DauuOsW9.js} +1 -1
  6. package/build/assets/{acp-route-guard-IWlFmS6x.js → acp-route-guard-CQTmeJwM.js} +1 -1
  7. package/build/assets/{active-backend-context-CkP3ZEJs.js → active-backend-context-TVbjnvmP.js} +1 -1
  8. package/build/assets/add-backend-modal-FsnpTTgO.js +1 -0
  9. package/build/assets/{agent-server-client-options-8OJSXbm8.js → agent-server-client-options-DT2GP6VJ.js} +1 -1
  10. package/build/assets/{agent-server-compatibility-DvKtnXHw.js → agent-server-compatibility-2aOx5iWd.js} +1 -1
  11. package/build/assets/agent-server-conversation-service.api-BZmUqtiO.js +5 -0
  12. package/build/assets/{agent-settings-DdisD2Xx.js → agent-settings-B247S9G3.js} +2 -2
  13. package/build/assets/{alert-banner-CvTYN73l.js → alert-banner-BWoqueRw.js} +1 -1
  14. package/build/assets/{analytics-consent-form-modal-BKgT9i2w.js → analytics-consent-form-modal-C7sXfxRh.js} +1 -1
  15. package/build/assets/{app-settings-DcYXtxGP.js → app-settings-BVeSaty9.js} +1 -1
  16. package/build/assets/{automation-detail-D7GEU0vR.js → automation-detail-R-99FUce.js} +1 -1
  17. package/build/assets/{automations-list-CkVNsgzm.js → automations-list-Dfu2c-_D.js} +1 -1
  18. package/build/assets/backend-form-modal-DxYjqqAK.js +1 -0
  19. package/build/assets/{backend-synced-settings-badge-BFy2HylT.js → backend-synced-settings-badge-nAfiUWvM.js} +1 -1
  20. package/build/assets/{base-modal-B4HvlFHE.js → base-modal-CQRvRHu1.js} +1 -1
  21. package/build/assets/{brand-button-8fVVei4i.js → brand-button-C2nEKopC.js} +1 -1
  22. package/build/assets/browser-HrYc5Gce.js +5 -0
  23. package/build/assets/{browser-tab-DTM6RyoV.js → browser-tab-B_BuTvrO.js} +1 -1
  24. package/build/assets/{checkmark-BcvXE9bf.js → checkmark-BJJrZUF8.js} +1 -1
  25. package/build/assets/{chevron-left-small-BqSkXTeq.js → chevron-left-small-CSh-sE9L.js} +1 -1
  26. package/build/assets/{circle-plus-check-toggle-DRvuu-RD.js → circle-plus-check-toggle-qs8Va1cC.js} +1 -1
  27. package/build/assets/{clock-DfoVUZVq.js → clock-ZR4Kn-_Y.js} +1 -1
  28. package/build/assets/{close-SnIy2eLD.js → close-BdmyeRqS.js} +1 -1
  29. package/build/assets/{combobox-caret-BMsz5mQX.js → combobox-caret-B53O9Hsq.js} +1 -1
  30. package/build/assets/{condenser-settings-DduLQcpV.js → condenser-settings-A35V3yng.js} +1 -1
  31. package/build/assets/{confirmation-modal-B-DOYMUH.js → confirmation-modal-C9-La0h3.js} +1 -1
  32. package/build/assets/{context-menu-list-item-DzjPB8aC.js → context-menu-list-item-Buu9nc0q.js} +1 -1
  33. package/build/assets/conversation--ldUK72N.js +19 -0
  34. package/build/assets/conversation-eNrhH94O.js +1 -0
  35. package/build/assets/conversation-panel-B49Jpqpb.js +1 -0
  36. package/build/assets/{conversation-service.api-YTGTw0pz.js → conversation-service.api--f8WglOC.js} +1 -1
  37. package/build/assets/{conversation-tab-empty-state-BtFDbyTe.js → conversation-tab-empty-state-D8dNvo-V.js} +1 -1
  38. package/build/assets/conversation-websocket-context-BW68-J8o.js +3 -0
  39. package/build/assets/{copy-BxgbrjDT.js → copy-C7Ti2d8C.js} +1 -1
  40. package/build/assets/{custom-toast-handlers-BYxhSr3t.js → custom-toast-handlers-BOc3qeQ7.js} +1 -1
  41. package/build/assets/declaration-D378OjpZ.js +1 -0
  42. package/build/assets/{device-verify-CTbXX9CQ.js → device-verify-CMusn8nX.js} +1 -1
  43. package/build/assets/edit-automation-modal-Dnjxbjn7.js +1 -0
  44. package/build/assets/{ellipsis-button-BoU2-xlG.js → ellipsis-button-ugUATsNo.js} +1 -1
  45. package/build/assets/{entry.client-DU7-q4ZU.js → entry.client-CqqXOSvd.js} +2 -2
  46. package/build/assets/{enum-filter-dropdown-BJt-NplD.js → enum-filter-dropdown-1vpOGySB.js} +1 -1
  47. package/build/assets/{environment-switch-overlay-DQ1n6Iu6.js → environment-switch-overlay-CTCTQikP.js} +1 -1
  48. package/build/assets/{extensions-hub-BW1FAKFJ.js → extensions-hub-BSUseHVF.js} +1 -1
  49. package/build/assets/{extensions-navigation-CbPMhSML.js → extensions-navigation-CT1kc1u_.js} +1 -1
  50. package/build/assets/files-tab-CQHdWpQt.js +1 -0
  51. package/build/assets/{folder-CerIk8uG.js → folder-0WSMImNX.js} +1 -1
  52. package/build/assets/git-control-bar-branch-button-C8u5rzjc.js +27 -0
  53. package/build/assets/{git-provider-icon-D8RE4unY.js → git-provider-icon-D-a-rcLm.js} +1 -1
  54. package/build/assets/{home-DR11ejqB.js → home-DD0GroCu.js} +1 -1
  55. package/build/assets/{i18n-DkYgs32x.js → i18n-DjAGhTis.js} +1 -1
  56. package/build/assets/install-server-modal-z5VaHeXd.js +1 -0
  57. package/build/assets/{launch-DKCU9uJH.js → launch-B2mbfOSm.js} +1 -1
  58. package/build/assets/{lesson-plan-CmkRbe6Z.js → lesson-plan-DRYG5SLI.js} +1 -1
  59. package/build/assets/{link-external-CvxB0BmI.js → link-external-C9d6Fo3x.js} +1 -1
  60. package/build/assets/{llm-client-BpIfxETv.js → llm-client-ChQzg4wX.js} +1 -1
  61. package/build/assets/llm-settings-BEyqixPI.js +1 -0
  62. package/build/assets/{llm-settings-BOJC4vD-.js → llm-settings-BdiaGFbg.js} +1 -1
  63. package/build/assets/{loading-spinner-91b5FiMQ.js → loading-spinner-C04FGh14.js} +1 -1
  64. package/build/assets/{manage-backends-modal-DqpzcxdI.js → manage-backends-modal-s22zCdEW.js} +1 -1
  65. package/build/assets/{manage-workspaces-modal-eG6XgAvw.js → manage-workspaces-modal-C5EuW8m1.js} +1 -1
  66. package/build/assets/manifest-9d1c34fb.js +1 -0
  67. package/build/assets/{markdown-renderer-wZnLDbA1.js → markdown-renderer-CEX4Becj.js} +1 -1
  68. package/build/assets/mcp-C06YssEI.js +9 -0
  69. package/build/assets/messages-6aOyUu3r.js +36 -0
  70. package/build/assets/{modal-backdrop-B04pVYAD.js → modal-backdrop-DTYGVmOR.js} +1 -1
  71. package/build/assets/{modal-body-CgUoFQA1.js → modal-body-YElmM1dV.js} +1 -1
  72. package/build/assets/{modal-close-button-SM_WXzDY.js → modal-close-button-C_GpQt9F.js} +1 -1
  73. package/build/assets/{model-selector-7id-Uirf.js → model-selector-DeMmw-Xa.js} +1 -1
  74. package/build/assets/{navigation-context-BFjstyH6.js → navigation-context-DeIPtGPp.js} +1 -1
  75. package/build/assets/{navigation-link-DFQ7YcWq.js → navigation-link-C9JD4PYD.js} +1 -1
  76. package/build/assets/{openhands-logo-DkDp75rC.js → openhands-logo-CI5Fhn1W.js} +1 -1
  77. package/build/assets/{option-service.api-DN0ZcGjw.js → option-service.api-DsI1UW7N.js} +1 -1
  78. package/build/assets/{organization-service.api-Ct2dZF8M.js → organization-service.api-COwMPFg5.js} +1 -1
  79. package/build/assets/{path-utils-D1ZtqFC7.js → path-utils-BVbe598W.js} +1 -1
  80. package/build/assets/{plan-components-gOm-daR3.js → plan-components-DEjMuDDG.js} +1 -1
  81. package/build/assets/{planner-tab-yubfN-6U.js → planner-tab-bN6r1G-1.js} +1 -1
  82. package/build/assets/{profiles-client-D4twHRVf.js → profiles-client-BGkKEV9j.js} +1 -1
  83. package/build/assets/{providers-C2T07PM3.js → providers-DXvCAN_u.js} +1 -1
  84. package/build/assets/{proxy-BMZyC45G.js → proxy-CurRmrqf.js} +1 -1
  85. package/build/assets/{query-client-config-CiK0GJJO.js → query-client-config-Ba7qAAoO.js} +1 -1
  86. package/build/assets/recommended-automations-launcher-mJhK6Atl.js +52 -0
  87. package/build/assets/root-3t9rxEpE.js +2 -0
  88. package/build/assets/root-DHeCXo9N.css +1 -0
  89. package/build/assets/{root-layout-B4QioBS6.js → root-layout-BjVwHmta.js} +2 -2
  90. package/build/assets/{sdk-section-page-03k88tIR.js → sdk-section-page-CJW0G04-.js} +1 -1
  91. package/build/assets/{sdk-settings-schema-BY8dOy3a.js → sdk-settings-schema-QBYH-ONX.js} +1 -1
  92. package/build/assets/{search-BCAF9EDS.js → search-Cq_cFrDt.js} +1 -1
  93. package/build/assets/{secrets-service-Z3qtRb_G.js → secrets-service-Bwd5DeUs.js} +1 -1
  94. package/build/assets/{secrets-settings-BnlByuMZ.js → secrets-settings-MLXqOtX2.js} +1 -1
  95. package/build/assets/{server-client-CG1zHqph.js → server-client-C3mC8Hl3.js} +1 -1
  96. package/build/assets/{settings-DyzGLF_d.js → settings-D7E2U5tK.js} +1 -1
  97. package/build/assets/{settings-client-CkXDJwIY.js → settings-client-CwjfwoiB.js} +1 -1
  98. package/build/assets/{settings-dropdown-input-CAQWQgx-.js → settings-dropdown-input-VwAXNrOb.js} +1 -1
  99. package/build/assets/{settings-gear-D4ZkEDGb.js → settings-gear-BJwWR1ej.js} +1 -1
  100. package/build/assets/{settings-index-KtTw49xL.js → settings-index-J-3BNR0W.js} +1 -1
  101. package/build/assets/{settings-input-BWCZt9g2.js → settings-input-DBywAnA7.js} +1 -1
  102. package/build/assets/{settings-list-classes-xMleGkTC.js → settings-list-classes-BOS092DR.js} +1 -1
  103. package/build/assets/{settings-modal-Cv2YWSUY.js → settings-modal-B8vgWDTe.js} +1 -1
  104. package/build/assets/{settings-section-header-context-1wfkgjZZ.js → settings-section-header-context-32x6WTyL.js} +1 -1
  105. package/build/assets/settings-service.api-FvJGK45W.js +1 -0
  106. package/build/assets/{settings-switch-CGap2LtG.js → settings-switch-DTKmHC8F.js} +1 -1
  107. package/build/assets/{settings-utils-BBozxqqi.js → settings-utils-BsvSU3OM.js} +1 -1
  108. package/build/assets/{shared-conversation-DQlzwdpo.js → shared-conversation-EZV0FRIf.js} +1 -1
  109. package/build/assets/{sidebar-mobile-menu-toggle-DXplko7u.js → sidebar-mobile-menu-toggle-BnbzzpQl.js} +1 -1
  110. package/build/assets/{sidebar-nav-link-B4h8naZ7.js → sidebar-nav-link-CnWoZcwc.js} +1 -1
  111. package/build/assets/{skill-card-pill-row-D0oTWx-a.js → skill-card-pill-row-tZ599jli.js} +1 -1
  112. package/build/assets/{skills-BN8atjgW.js → skills-ZyAO5dyK.js} +1 -1
  113. package/build/assets/{skills-plugins-BTnp7QcQ.js → skills-plugins-BSRz041I.js} +1 -1
  114. package/build/assets/{skills-settings-CbOQvzkR.js → skills-settings-CG2hu34D.js} +2 -2
  115. package/build/assets/{status-DDL-ipIP.js → status-CsatcFbK.js} +1 -1
  116. package/build/assets/{styled-tooltip-Awq4HMw3.js → styled-tooltip-CS3mB_1X.js} +1 -1
  117. package/build/assets/{switch-skeleton-Bv21RGWd.js → switch-skeleton-C-CfhYYV.js} +1 -1
  118. package/build/assets/{task-list-tab-B45ktzHM.js → task-list-tab-465DDju0.js} +1 -1
  119. package/build/assets/{terminal-D5pzR9Ru.js → terminal-CcgBEVnC.js} +1 -1
  120. package/build/assets/{terminal-DGuR4559.js → terminal-LNa-iU5c.js} +1 -1
  121. package/build/assets/{toggle-switch-gj6T-wsU.js → toggle-switch-k-IZCDbt.js} +1 -1
  122. package/build/assets/{typography-BbaUAC4V.js → typography-vVUMoNUg.js} +1 -1
  123. package/build/assets/{u-check-circle-DHGiAi-w.js → u-check-circle-DplbarS5.js} +1 -1
  124. package/build/assets/{u-check-circle-half-BPcWtWwv.js → u-check-circle-half-yDuiSZHC.js} +1 -1
  125. package/build/assets/{u-circuit-B_nK9hOu.js → u-circuit-C9tYkpeK.js} +1 -1
  126. package/build/assets/{u-edit-BPFJBd34.js → u-edit-KAUlufD8.js} +1 -1
  127. package/build/assets/{use-active-conversation-Bu5J9iLy.js → use-active-conversation-DS5j9R4q.js} +1 -1
  128. package/build/assets/{use-agent-settings-schema-BbtOsR7P.js → use-agent-settings-schema-Bvp5UzV8.js} +1 -1
  129. package/build/assets/{use-agent-state-DN9Nc5pP.js → use-agent-state-D2C9SeGw.js} +1 -1
  130. package/build/assets/{use-cloud-current-user-id-B_rMUiu8.js → use-cloud-current-user-id-DWVar4st.js} +1 -1
  131. package/build/assets/{use-config-Bcz2JL2t.js → use-config-BSu_53GL.js} +1 -1
  132. package/build/assets/{use-conversation-id-BOaaZahn.js → use-conversation-id-DajhCn2A.js} +1 -1
  133. package/build/assets/{use-create-conversation-BWFA_FId.js → use-create-conversation-BEZg__Vv.js} +1 -1
  134. package/build/assets/{use-event-store-CQZCcVz-.js → use-event-store-BT_gV3ut.js} +1 -1
  135. package/build/assets/{use-handle-plan-click-CgrCGmT1.js → use-handle-plan-click-uOpew2LO.js} +1 -1
  136. package/build/assets/use-is-authed-hXC8vxgT.js +1 -0
  137. package/build/assets/{use-is-creating-conversation-DhoM7UAB.js → use-is-creating-conversation-DhDeeWfA.js} +1 -1
  138. package/build/assets/{use-launch-skill-in-chat-DOyQsXFO.js → use-launch-skill-in-chat-DVGPFrbI.js} +1 -1
  139. package/build/assets/{use-llm-profiles-CAIzHJDX.js → use-llm-profiles-O4a9V6RC.js} +1 -1
  140. package/build/assets/use-runtime-is-ready-pGSbPddC.js +1 -0
  141. package/build/assets/{use-save-settings-5m3w89Ph.js → use-save-settings-CEEKSTWG.js} +1 -1
  142. package/build/assets/{use-settings-DzG0C3vO.js → use-settings-DQ7Oo1Hj.js} +1 -1
  143. package/build/assets/{use-settings-nav-items-BIsKeX52.js → use-settings-nav-items-YmrXrjn9.js} +2 -2
  144. package/build/assets/use-skills-BIvlWblA.js +1 -0
  145. package/build/assets/{use-task-list-Bs90uF2N.js → use-task-list-DDeNHprj.js} +1 -1
  146. package/build/assets/{use-unified-vscode-url-C5iI-Z5A.js → use-unified-vscode-url-wAMzv8Sn.js} +1 -1
  147. package/build/assets/use-user-conversation-B_zDoSeh.js +1 -0
  148. package/build/assets/{useMutation-CRJwk4cR.js → useMutation-B4OUESdw.js} +1 -1
  149. package/build/assets/{useTranslation-01pF7z10.js → useTranslation-CpIcQBq6.js} +1 -1
  150. package/build/assets/{utils-Czcl6buL.js → utils-D-HX7JCe.js} +1 -1
  151. package/build/assets/{vendor~conversation-panel~conversation-CbjvWBSu.js → vendor~conversation-panel~conversation-BlCIz9XQ.js} +1 -1
  152. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-CofhIDpd.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-Ds9quNZ9.js} +1 -1
  153. package/build/assets/vendor~home~mcp~automations-list-C5PoHCy6.js +1 -0
  154. package/build/assets/{vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-BQPOygpY.js → vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-CGlZoBKa.js} +1 -1
  155. package/build/assets/{vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-CyYIBiBk.js → vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-DE11mPxp.js} +1 -1
  156. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-CuGq_cxH.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-8b8V5bfO.js} +1 -1
  157. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-CFpDeb9o.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-Dy7L6fMG.js} +1 -1
  158. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~k776hupu-C1p8-pMr.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~k776hupu-D40EXhZx.js} +1 -1
  159. package/build/assets/vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~dp08i1qy-CHrEOFl6.js +48 -0
  160. package/build/assets/{vendor~root~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-s~kyz9p27j-DlKA6SoO.js → vendor~root~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-s~kyz9p27j-CyUbhpbm.js} +1 -1
  161. package/build/assets/{verification-settings-DbziMp4K.js → verification-settings-BtlTiHP8.js} +1 -1
  162. package/build/assets/{vscode-tab-BVhQR2rt.js → vscode-tab-B0vdh9gU.js} +1 -1
  163. package/build/assets/{waiting-for-runtime-message-JotSOBdC.js → waiting-for-runtime-message-DWPl_Yby.js} +1 -1
  164. package/build/assets/{x-mark-CZ57VvRX.js → x-mark-CWI0f9yI.js} +1 -1
  165. package/build/favicon.svg +1 -0
  166. package/build/index.html +4 -4
  167. package/build/locales/ar/openhands.json +8 -0
  168. package/build/locales/ca/openhands.json +8 -0
  169. package/build/locales/de/openhands.json +8 -0
  170. package/build/locales/en/openhands.json +8 -0
  171. package/build/locales/es/openhands.json +8 -0
  172. package/build/locales/fr/openhands.json +8 -0
  173. package/build/locales/it/openhands.json +8 -0
  174. package/build/locales/ja/openhands.json +8 -0
  175. package/build/locales/ko-KR/openhands.json +8 -0
  176. package/build/locales/no/openhands.json +8 -0
  177. package/build/locales/pt/openhands.json +8 -0
  178. package/build/locales/tr/openhands.json +8 -0
  179. package/build/locales/uk/openhands.json +8 -0
  180. package/build/locales/zh-CN/openhands.json +8 -0
  181. package/build/locales/zh-TW/openhands.json +8 -0
  182. package/config/defaults.json +1 -1
  183. package/dist/api/agent-server-adapter.cjs +1 -1
  184. package/dist/api/agent-server-adapter.cjs.map +1 -1
  185. package/dist/api/agent-server-adapter.js +1 -0
  186. package/dist/api/agent-server-adapter.js.map +1 -1
  187. package/dist/api/agent-server-config.cjs +1 -1
  188. package/dist/api/agent-server-config.cjs.map +1 -1
  189. package/dist/api/agent-server-config.d.ts +1 -1
  190. package/dist/api/agent-server-config.js +1 -1
  191. package/dist/api/agent-server-config.js.map +1 -1
  192. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs +1 -1
  193. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs.map +1 -1
  194. package/dist/api/conversation-service/agent-server-conversation-service.api.d.ts +12 -0
  195. package/dist/api/conversation-service/agent-server-conversation-service.api.js +4 -0
  196. package/dist/api/conversation-service/agent-server-conversation-service.api.js.map +1 -1
  197. package/dist/api/mcp-service/mcp-service.api.cjs +2 -0
  198. package/dist/api/mcp-service/mcp-service.api.cjs.map +1 -0
  199. package/dist/api/mcp-service/mcp-service.api.d.ts +6 -0
  200. package/dist/api/mcp-service/mcp-service.api.js +36 -0
  201. package/dist/api/mcp-service/mcp-service.api.js.map +1 -0
  202. package/dist/api/settings-service/settings-service.api.cjs +1 -1
  203. package/dist/api/settings-service/settings-service.api.cjs.map +1 -1
  204. package/dist/api/settings-service/settings-service.api.d.ts +1 -0
  205. package/dist/api/settings-service/settings-service.api.js +59 -41
  206. package/dist/api/settings-service/settings-service.api.js.map +1 -1
  207. package/dist/api/skills-service.cjs +1 -1
  208. package/dist/api/skills-service.cjs.map +1 -1
  209. package/dist/api/skills-service.d.ts +1 -1
  210. package/dist/api/skills-service.js +2 -2
  211. package/dist/api/skills-service.js.map +1 -1
  212. package/dist/components/features/automations/detail/activity-log-item.d.ts +1 -1
  213. package/dist/components/features/automations/recommended-automations-launcher.d.ts +1 -1
  214. package/dist/components/features/backends/backend-form-modal.cjs +1 -1
  215. package/dist/components/features/backends/backend-form-modal.cjs.map +1 -1
  216. package/dist/components/features/backends/backend-form-modal.js +149 -142
  217. package/dist/components/features/backends/backend-form-modal.js.map +1 -1
  218. package/dist/components/features/chat/change-agent-button.cjs +1 -1
  219. package/dist/components/features/chat/change-agent-button.cjs.map +1 -1
  220. package/dist/components/features/chat/change-agent-button.js +65 -59
  221. package/dist/components/features/chat/change-agent-button.js.map +1 -1
  222. package/dist/components/features/chat/chat-interface.cjs +2 -2
  223. package/dist/components/features/chat/chat-interface.cjs.map +1 -1
  224. package/dist/components/features/chat/chat-interface.js +15 -14
  225. package/dist/components/features/chat/chat-interface.js.map +1 -1
  226. package/dist/components/features/chat/components/chat-input-actions.cjs +1 -1
  227. package/dist/components/features/chat/components/chat-input-actions.cjs.map +1 -1
  228. package/dist/components/features/chat/components/chat-input-actions.js +127 -149
  229. package/dist/components/features/chat/components/chat-input-actions.js.map +1 -1
  230. package/dist/components/features/chat/components/chat-input-model.cjs +1 -1
  231. package/dist/components/features/chat/components/chat-input-model.cjs.map +1 -1
  232. package/dist/components/features/chat/components/chat-input-model.d.ts +10 -0
  233. package/dist/components/features/chat/components/chat-input-model.js +95 -60
  234. package/dist/components/features/chat/components/chat-input-model.js.map +1 -1
  235. package/dist/components/features/chat/git-control-bar.cjs +1 -1
  236. package/dist/components/features/chat/git-control-bar.cjs.map +1 -1
  237. package/dist/components/features/chat/git-control-bar.js +60 -59
  238. package/dist/components/features/chat/git-control-bar.js.map +1 -1
  239. package/dist/components/features/conversation/conversation-name-with-status.cjs +1 -1
  240. package/dist/components/features/conversation/conversation-name-with-status.cjs.map +1 -1
  241. package/dist/components/features/conversation/conversation-name-with-status.js +2 -2
  242. package/dist/components/features/conversation/conversation-name-with-status.js.map +1 -1
  243. package/dist/components/features/conversation/conversation-name.cjs +1 -1
  244. package/dist/components/features/conversation/conversation-name.cjs.map +1 -1
  245. package/dist/components/features/conversation/conversation-name.js +3 -3
  246. package/dist/components/features/conversation/conversation-name.js.map +1 -1
  247. package/dist/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.cjs +1 -1
  248. package/dist/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.cjs.map +1 -1
  249. package/dist/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.js +1 -1
  250. package/dist/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.js.map +1 -1
  251. package/dist/components/features/conversation/conversation-tabs/conversation-tabs.cjs +1 -1
  252. package/dist/components/features/conversation/conversation-tabs/conversation-tabs.cjs.map +1 -1
  253. package/dist/components/features/conversation/conversation-tabs/conversation-tabs.js +16 -16
  254. package/dist/components/features/conversation/conversation-tabs/conversation-tabs.js.map +1 -1
  255. package/dist/components/features/conversation-panel/skills-modal.cjs +1 -1
  256. package/dist/components/features/conversation-panel/skills-modal.cjs.map +1 -1
  257. package/dist/components/features/conversation-panel/skills-modal.js +1 -1
  258. package/dist/components/features/conversation-panel/skills-modal.js.map +1 -1
  259. package/dist/components/features/mcp-logo-badge.cjs +1 -1
  260. package/dist/components/features/mcp-logo-badge.cjs.map +1 -1
  261. package/dist/components/features/mcp-logo-badge.d.ts +2 -2
  262. package/dist/components/features/mcp-logo-badge.js +1 -1
  263. package/dist/components/features/mcp-logo-badge.js.map +1 -1
  264. package/dist/components/features/mcp-page/custom-server-editor.cjs +1 -1
  265. package/dist/components/features/mcp-page/custom-server-editor.cjs.map +1 -1
  266. package/dist/components/features/mcp-page/custom-server-editor.js +64 -41
  267. package/dist/components/features/mcp-page/custom-server-editor.js.map +1 -1
  268. package/dist/components/features/mcp-page/install-server-modal.cjs +1 -1
  269. package/dist/components/features/mcp-page/install-server-modal.cjs.map +1 -1
  270. package/dist/components/features/mcp-page/install-server-modal.d.ts +1 -1
  271. package/dist/components/features/mcp-page/install-server-modal.js +126 -102
  272. package/dist/components/features/mcp-page/install-server-modal.js.map +1 -1
  273. package/dist/components/features/mcp-page/installed-server-card.cjs +1 -1
  274. package/dist/components/features/mcp-page/installed-server-card.cjs.map +1 -1
  275. package/dist/components/features/mcp-page/installed-server-card.js +1 -1
  276. package/dist/components/features/mcp-page/installed-server-card.js.map +1 -1
  277. package/dist/components/features/mcp-page/marketplace-card.cjs +1 -1
  278. package/dist/components/features/mcp-page/marketplace-card.cjs.map +1 -1
  279. package/dist/components/features/mcp-page/marketplace-card.d.ts +1 -1
  280. package/dist/components/features/mcp-page/marketplace-card.js +27 -25
  281. package/dist/components/features/mcp-page/marketplace-card.js.map +1 -1
  282. package/dist/components/features/mcp-page/marketplace-section.cjs +1 -1
  283. package/dist/components/features/mcp-page/marketplace-section.cjs.map +1 -1
  284. package/dist/components/features/mcp-page/marketplace-section.d.ts +1 -1
  285. package/dist/components/features/mcp-page/marketplace-section.js +1 -1
  286. package/dist/components/features/mcp-page/marketplace-section.js.map +1 -1
  287. package/dist/components/features/mcp-page/mcp-logo-stack-badge.d.ts +2 -2
  288. package/dist/components/features/settings/mcp-settings/mcp-server-form.cjs +7 -7
  289. package/dist/components/features/settings/mcp-settings/mcp-server-form.cjs.map +1 -1
  290. package/dist/components/features/settings/mcp-settings/mcp-server-form.d.ts +8 -12
  291. package/dist/components/features/settings/mcp-settings/mcp-server-form.js +114 -87
  292. package/dist/components/features/settings/mcp-settings/mcp-server-form.js.map +1 -1
  293. package/dist/context/scroll-context.cjs +1 -1
  294. package/dist/context/scroll-context.cjs.map +1 -1
  295. package/dist/context/scroll-context.d.ts +1 -0
  296. package/dist/context/scroll-context.js +4 -1
  297. package/dist/context/scroll-context.js.map +1 -1
  298. package/dist/contexts/conversation-websocket-context.cjs +3 -3
  299. package/dist/contexts/conversation-websocket-context.cjs.map +1 -1
  300. package/dist/contexts/conversation-websocket-context.js +97 -89
  301. package/dist/contexts/conversation-websocket-context.js.map +1 -1
  302. package/dist/favicon.svg +1 -0
  303. package/dist/hooks/chat/use-slash-command.cjs +1 -1
  304. package/dist/hooks/chat/use-slash-command.cjs.map +1 -1
  305. package/dist/hooks/chat/use-slash-command.js +1 -1
  306. package/dist/hooks/chat/use-slash-command.js.map +1 -1
  307. package/dist/hooks/mutation/use-switch-acp-model.cjs +2 -0
  308. package/dist/hooks/mutation/use-switch-acp-model.cjs.map +1 -0
  309. package/dist/hooks/mutation/use-switch-acp-model.d.ts +23 -0
  310. package/dist/hooks/mutation/use-switch-acp-model.js +26 -0
  311. package/dist/hooks/mutation/use-switch-acp-model.js.map +1 -0
  312. package/dist/hooks/mutation/use-test-mcp-server.cjs +2 -0
  313. package/dist/hooks/mutation/use-test-mcp-server.cjs.map +1 -0
  314. package/dist/hooks/mutation/use-test-mcp-server.d.ts +2 -0
  315. package/dist/hooks/mutation/use-test-mcp-server.js +10 -0
  316. package/dist/hooks/mutation/use-test-mcp-server.js.map +1 -0
  317. package/dist/hooks/query/use-automation-detail.d.ts +3 -2
  318. package/dist/hooks/query/use-conversation-skills.cjs +2 -0
  319. package/dist/hooks/query/use-conversation-skills.cjs.map +1 -0
  320. package/dist/hooks/query/use-conversation-skills.d.ts +7 -0
  321. package/dist/hooks/query/use-conversation-skills.js +8 -0
  322. package/dist/hooks/query/use-conversation-skills.js.map +1 -0
  323. package/dist/hooks/query/use-skills.cjs +1 -1
  324. package/dist/hooks/query/use-skills.cjs.map +1 -1
  325. package/dist/hooks/query/use-skills.d.ts +6 -1
  326. package/dist/hooks/query/use-skills.js +3 -3
  327. package/dist/hooks/query/use-skills.js.map +1 -1
  328. package/dist/hooks/use-acp-model-context.cjs.map +1 -1
  329. package/dist/hooks/use-acp-model-context.d.ts +3 -4
  330. package/dist/hooks/use-acp-model-context.js.map +1 -1
  331. package/dist/hooks/use-chat-input-model-state.cjs +2 -0
  332. package/dist/hooks/use-chat-input-model-state.cjs.map +1 -0
  333. package/dist/hooks/use-chat-input-model-state.d.ts +12 -0
  334. package/dist/hooks/use-chat-input-model-state.js +29 -0
  335. package/dist/hooks/use-chat-input-model-state.js.map +1 -0
  336. package/dist/i18n/declaration.cjs +1 -1
  337. package/dist/i18n/declaration.cjs.map +1 -1
  338. package/dist/i18n/declaration.d.ts +8 -0
  339. package/dist/i18n/declaration.js +1 -1
  340. package/dist/i18n/declaration.js.map +1 -1
  341. package/dist/i18n/translation.cjs +2 -2
  342. package/dist/i18n/translation.cjs.map +1 -1
  343. package/dist/i18n/translation.js +136 -0
  344. package/dist/i18n/translation.js.map +1 -1
  345. package/dist/locales/ar/openhands.json +8 -0
  346. package/dist/locales/ca/openhands.json +8 -0
  347. package/dist/locales/de/openhands.json +8 -0
  348. package/dist/locales/en/openhands.json +8 -0
  349. package/dist/locales/es/openhands.json +8 -0
  350. package/dist/locales/fr/openhands.json +8 -0
  351. package/dist/locales/it/openhands.json +8 -0
  352. package/dist/locales/ja/openhands.json +8 -0
  353. package/dist/locales/ko-KR/openhands.json +8 -0
  354. package/dist/locales/no/openhands.json +8 -0
  355. package/dist/locales/pt/openhands.json +8 -0
  356. package/dist/locales/tr/openhands.json +8 -0
  357. package/dist/locales/uk/openhands.json +8 -0
  358. package/dist/locales/zh-CN/openhands.json +8 -0
  359. package/dist/locales/zh-TW/openhands.json +8 -0
  360. package/dist/node_modules/@openhands/extensions/integrations/catalog/airtable.cjs +2 -0
  361. package/dist/node_modules/@openhands/extensions/integrations/catalog/airtable.cjs.map +1 -0
  362. package/dist/node_modules/@openhands/extensions/integrations/catalog/airtable.js +37 -0
  363. package/dist/node_modules/@openhands/extensions/integrations/catalog/airtable.js.map +1 -0
  364. package/dist/node_modules/@openhands/extensions/integrations/catalog/apify.cjs +2 -0
  365. package/dist/node_modules/@openhands/extensions/integrations/catalog/apify.cjs.map +1 -0
  366. package/dist/node_modules/@openhands/extensions/integrations/catalog/apify.js +36 -0
  367. package/dist/node_modules/@openhands/extensions/integrations/catalog/apify.js.map +1 -0
  368. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/atlassian.cjs +1 -1
  369. package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian.cjs.map +1 -0
  370. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/atlassian.js +15 -5
  371. package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian.js.map +1 -0
  372. package/dist/node_modules/@openhands/extensions/integrations/catalog/brave-search.cjs +2 -0
  373. package/dist/node_modules/@openhands/extensions/integrations/catalog/brave-search.cjs.map +1 -0
  374. package/dist/node_modules/@openhands/extensions/integrations/catalog/brave-search.js +36 -0
  375. package/dist/node_modules/@openhands/extensions/integrations/catalog/brave-search.js.map +1 -0
  376. package/dist/node_modules/@openhands/extensions/integrations/catalog/browser-mcp.cjs +2 -0
  377. package/dist/node_modules/@openhands/extensions/integrations/catalog/browser-mcp.cjs.map +1 -0
  378. package/dist/node_modules/@openhands/extensions/integrations/catalog/browser-mcp.js +31 -0
  379. package/dist/node_modules/@openhands/extensions/integrations/catalog/browser-mcp.js.map +1 -0
  380. package/dist/node_modules/@openhands/extensions/integrations/catalog/clickhouse.cjs +2 -0
  381. package/dist/node_modules/@openhands/extensions/integrations/catalog/clickhouse.cjs.map +1 -0
  382. package/dist/node_modules/@openhands/extensions/integrations/catalog/clickhouse.js +52 -0
  383. package/dist/node_modules/@openhands/extensions/integrations/catalog/clickhouse.js.map +1 -0
  384. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-bindings.cjs +1 -1
  385. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-bindings.cjs.map +1 -0
  386. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-bindings.js +15 -5
  387. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-bindings.js.map +1 -0
  388. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-browser-rendering.cjs +2 -0
  389. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-browser-rendering.cjs.map +1 -0
  390. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-browser-rendering.js +15 -5
  391. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-browser-rendering.js.map +1 -0
  392. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-builds.cjs +1 -1
  393. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-builds.cjs.map +1 -0
  394. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-builds.js +15 -5
  395. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-builds.js.map +1 -0
  396. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-docs.cjs +1 -1
  397. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-docs.cjs.map +1 -0
  398. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-docs.js +15 -5
  399. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-docs.js.map +1 -0
  400. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-observability.cjs +2 -0
  401. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-observability.cjs.map +1 -0
  402. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/cloudflare-observability.js +15 -5
  403. package/dist/node_modules/@openhands/extensions/integrations/catalog/cloudflare-observability.js.map +1 -0
  404. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/deepwiki.cjs +1 -1
  405. package/dist/node_modules/@openhands/extensions/integrations/catalog/deepwiki.cjs.map +1 -0
  406. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/deepwiki.js +15 -5
  407. package/dist/node_modules/@openhands/extensions/integrations/catalog/deepwiki.js.map +1 -0
  408. package/dist/node_modules/@openhands/extensions/integrations/catalog/elevenlabs.cjs +2 -0
  409. package/dist/node_modules/@openhands/extensions/integrations/catalog/elevenlabs.cjs.map +1 -0
  410. package/dist/node_modules/@openhands/extensions/integrations/catalog/elevenlabs.js +36 -0
  411. package/dist/node_modules/@openhands/extensions/integrations/catalog/elevenlabs.js.map +1 -0
  412. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/everything.cjs +1 -1
  413. package/dist/node_modules/@openhands/extensions/integrations/catalog/everything.cjs.map +1 -0
  414. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/everything.js +13 -6
  415. package/dist/node_modules/@openhands/extensions/integrations/catalog/everything.js.map +1 -0
  416. package/dist/node_modules/@openhands/extensions/integrations/catalog/exa.cjs +2 -0
  417. package/dist/node_modules/@openhands/extensions/integrations/catalog/exa.cjs.map +1 -0
  418. package/dist/node_modules/@openhands/extensions/integrations/catalog/exa.js +36 -0
  419. package/dist/node_modules/@openhands/extensions/integrations/catalog/exa.js.map +1 -0
  420. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/fetch.cjs +1 -1
  421. package/dist/node_modules/@openhands/extensions/integrations/catalog/fetch.cjs.map +1 -0
  422. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/fetch.js +13 -6
  423. package/dist/node_modules/@openhands/extensions/integrations/catalog/fetch.js.map +1 -0
  424. package/dist/node_modules/@openhands/extensions/integrations/catalog/figma.cjs +2 -0
  425. package/dist/node_modules/@openhands/extensions/integrations/catalog/figma.cjs.map +1 -0
  426. package/dist/node_modules/@openhands/extensions/integrations/catalog/figma.js +40 -0
  427. package/dist/node_modules/@openhands/extensions/integrations/catalog/figma.js.map +1 -0
  428. package/dist/node_modules/@openhands/extensions/integrations/catalog/filesystem.cjs +2 -0
  429. package/dist/node_modules/@openhands/extensions/integrations/catalog/filesystem.cjs.map +1 -0
  430. package/dist/node_modules/@openhands/extensions/integrations/catalog/filesystem.js +39 -0
  431. package/dist/node_modules/@openhands/extensions/integrations/catalog/filesystem.js.map +1 -0
  432. package/dist/node_modules/@openhands/extensions/integrations/catalog/firecrawl.cjs +2 -0
  433. package/dist/node_modules/@openhands/extensions/integrations/catalog/firecrawl.cjs.map +1 -0
  434. package/dist/node_modules/@openhands/extensions/integrations/catalog/firecrawl.js +36 -0
  435. package/dist/node_modules/@openhands/extensions/integrations/catalog/firecrawl.js.map +1 -0
  436. package/dist/node_modules/@openhands/extensions/integrations/catalog/git.cjs +2 -0
  437. package/dist/node_modules/@openhands/extensions/integrations/catalog/git.cjs.map +1 -0
  438. package/dist/node_modules/@openhands/extensions/integrations/catalog/git.js +40 -0
  439. package/dist/node_modules/@openhands/extensions/integrations/catalog/git.js.map +1 -0
  440. package/dist/node_modules/@openhands/extensions/integrations/catalog/github.cjs +2 -0
  441. package/dist/node_modules/@openhands/extensions/integrations/catalog/github.cjs.map +1 -0
  442. package/dist/node_modules/@openhands/extensions/integrations/catalog/github.js +47 -0
  443. package/dist/node_modules/@openhands/extensions/integrations/catalog/github.js.map +1 -0
  444. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/huggingface.cjs +1 -1
  445. package/dist/node_modules/@openhands/extensions/integrations/catalog/huggingface.cjs.map +1 -0
  446. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/huggingface.js +15 -5
  447. package/dist/node_modules/@openhands/extensions/integrations/catalog/huggingface.js.map +1 -0
  448. package/dist/node_modules/@openhands/extensions/integrations/catalog/kagi.cjs +2 -0
  449. package/dist/node_modules/@openhands/extensions/integrations/catalog/kagi.cjs.map +1 -0
  450. package/dist/node_modules/@openhands/extensions/integrations/catalog/kagi.js +36 -0
  451. package/dist/node_modules/@openhands/extensions/integrations/catalog/kagi.js.map +1 -0
  452. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/linear.cjs +1 -1
  453. package/dist/node_modules/@openhands/extensions/integrations/catalog/linear.cjs.map +1 -0
  454. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/linear.js +15 -5
  455. package/dist/node_modules/@openhands/extensions/integrations/catalog/linear.js.map +1 -0
  456. package/dist/node_modules/@openhands/extensions/integrations/catalog/memory.cjs +2 -0
  457. package/dist/node_modules/@openhands/extensions/integrations/catalog/memory.cjs.map +1 -0
  458. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/memory.js +13 -6
  459. package/dist/node_modules/@openhands/extensions/integrations/catalog/memory.js.map +1 -0
  460. package/dist/node_modules/@openhands/extensions/integrations/catalog/mongodb.cjs +2 -0
  461. package/dist/node_modules/@openhands/extensions/integrations/catalog/mongodb.cjs.map +1 -0
  462. package/dist/node_modules/@openhands/extensions/integrations/catalog/mongodb.js +36 -0
  463. package/dist/node_modules/@openhands/extensions/integrations/catalog/mongodb.js.map +1 -0
  464. package/dist/node_modules/@openhands/extensions/integrations/catalog/neon.cjs +2 -0
  465. package/dist/node_modules/@openhands/extensions/integrations/catalog/neon.cjs.map +1 -0
  466. package/dist/node_modules/@openhands/extensions/integrations/catalog/neon.js +40 -0
  467. package/dist/node_modules/@openhands/extensions/integrations/catalog/neon.js.map +1 -0
  468. package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.cjs +2 -0
  469. package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.cjs.map +1 -0
  470. package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.js +39 -0
  471. package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.js.map +1 -0
  472. package/dist/node_modules/@openhands/extensions/integrations/catalog/obsidian.cjs +2 -0
  473. package/dist/node_modules/@openhands/extensions/integrations/catalog/obsidian.cjs.map +1 -0
  474. package/dist/node_modules/@openhands/extensions/integrations/catalog/obsidian.js +38 -0
  475. package/dist/node_modules/@openhands/extensions/integrations/catalog/obsidian.js.map +1 -0
  476. package/dist/node_modules/@openhands/extensions/integrations/catalog/paypal.cjs +2 -0
  477. package/dist/node_modules/@openhands/extensions/integrations/catalog/paypal.cjs.map +1 -0
  478. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/paypal.js +15 -5
  479. package/dist/node_modules/@openhands/extensions/integrations/catalog/paypal.js.map +1 -0
  480. package/dist/node_modules/@openhands/extensions/integrations/catalog/playwright.cjs +2 -0
  481. package/dist/node_modules/@openhands/extensions/integrations/catalog/playwright.cjs.map +1 -0
  482. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/playwright.js +13 -6
  483. package/dist/node_modules/@openhands/extensions/integrations/catalog/playwright.js.map +1 -0
  484. package/dist/node_modules/@openhands/extensions/integrations/catalog/redis.cjs +2 -0
  485. package/dist/node_modules/@openhands/extensions/integrations/catalog/redis.cjs.map +1 -0
  486. package/dist/node_modules/@openhands/extensions/integrations/catalog/redis.js +43 -0
  487. package/dist/node_modules/@openhands/extensions/integrations/catalog/redis.js.map +1 -0
  488. package/dist/node_modules/@openhands/extensions/integrations/catalog/resend.cjs +2 -0
  489. package/dist/node_modules/@openhands/extensions/integrations/catalog/resend.cjs.map +1 -0
  490. package/dist/node_modules/@openhands/extensions/integrations/catalog/resend.js +41 -0
  491. package/dist/node_modules/@openhands/extensions/integrations/catalog/resend.js.map +1 -0
  492. package/dist/node_modules/@openhands/extensions/integrations/catalog/sentry.cjs +2 -0
  493. package/dist/node_modules/@openhands/extensions/integrations/catalog/sentry.cjs.map +1 -0
  494. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/sentry.js +15 -5
  495. package/dist/node_modules/@openhands/extensions/integrations/catalog/sentry.js.map +1 -0
  496. package/dist/node_modules/@openhands/extensions/integrations/catalog/sequential-thinking.cjs +2 -0
  497. package/dist/node_modules/@openhands/extensions/integrations/catalog/sequential-thinking.cjs.map +1 -0
  498. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/sequential-thinking.js +13 -6
  499. package/dist/node_modules/@openhands/extensions/integrations/catalog/sequential-thinking.js.map +1 -0
  500. package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.cjs +2 -0
  501. package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.cjs.map +1 -0
  502. package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.js +45 -0
  503. package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.js.map +1 -0
  504. package/dist/node_modules/@openhands/extensions/integrations/catalog/stripe.cjs +2 -0
  505. package/dist/node_modules/@openhands/extensions/integrations/catalog/stripe.cjs.map +1 -0
  506. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/stripe.js +15 -5
  507. package/dist/node_modules/@openhands/extensions/integrations/catalog/stripe.js.map +1 -0
  508. package/dist/node_modules/@openhands/extensions/integrations/catalog/supabase.cjs +2 -0
  509. package/dist/node_modules/@openhands/extensions/integrations/catalog/supabase.cjs.map +1 -0
  510. package/dist/node_modules/@openhands/extensions/integrations/catalog/supabase.js +37 -0
  511. package/dist/node_modules/@openhands/extensions/integrations/catalog/supabase.js.map +1 -0
  512. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/tavily.cjs +1 -1
  513. package/dist/node_modules/@openhands/extensions/integrations/catalog/tavily.cjs.map +1 -0
  514. package/dist/node_modules/@openhands/extensions/integrations/catalog/tavily.js +39 -0
  515. package/dist/node_modules/@openhands/extensions/integrations/catalog/tavily.js.map +1 -0
  516. package/dist/node_modules/@openhands/extensions/integrations/catalog/time.cjs +2 -0
  517. package/dist/node_modules/@openhands/extensions/integrations/catalog/time.cjs.map +1 -0
  518. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/catalog/time.js +13 -6
  519. package/dist/node_modules/@openhands/extensions/integrations/catalog/time.js.map +1 -0
  520. package/dist/node_modules/@openhands/extensions/integrations/index.cjs +2 -0
  521. package/dist/node_modules/@openhands/extensions/integrations/index.cjs.map +1 -0
  522. package/dist/node_modules/@openhands/extensions/integrations/index.js +175 -0
  523. package/dist/node_modules/@openhands/extensions/integrations/index.js.map +1 -0
  524. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/logos.cjs +1 -1
  525. package/dist/node_modules/@openhands/extensions/integrations/logos.cjs.map +1 -0
  526. package/dist/node_modules/@openhands/extensions/{mcps → integrations}/logos.js +2 -2
  527. package/dist/node_modules/@openhands/extensions/integrations/logos.js.map +1 -0
  528. package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-catalog.cjs +2 -0
  529. package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-catalog.cjs.map +1 -0
  530. package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-catalog.js +548 -0
  531. package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-catalog.js.map +1 -0
  532. package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-registration-defaults.cjs +2 -0
  533. package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-registration-defaults.cjs.map +1 -0
  534. package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-registration-defaults.js +482 -0
  535. package/dist/node_modules/@openhands/extensions/integrations/oauth-provider-registration-defaults.js.map +1 -0
  536. package/dist/node_modules/@openhands/typescript-client/dist/client/conversation-client.cjs +1 -1
  537. package/dist/node_modules/@openhands/typescript-client/dist/client/conversation-client.cjs.map +1 -1
  538. package/dist/node_modules/@openhands/typescript-client/dist/client/conversation-client.js +3 -0
  539. package/dist/node_modules/@openhands/typescript-client/dist/client/conversation-client.js.map +1 -1
  540. package/dist/node_modules/@openhands/typescript-client/dist/client/mcp-client.cjs +2 -0
  541. package/dist/node_modules/@openhands/typescript-client/dist/client/mcp-client.cjs.map +1 -0
  542. package/dist/node_modules/@openhands/typescript-client/dist/client/mcp-client.js +22 -0
  543. package/dist/node_modules/@openhands/typescript-client/dist/client/mcp-client.js.map +1 -0
  544. package/dist/node_modules/@openhands/typescript-client/dist/index.cjs +1 -1
  545. package/dist/node_modules/@openhands/typescript-client/dist/index.js +1 -0
  546. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.cjs +1 -1
  547. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.cjs.map +1 -1
  548. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.js +3 -0
  549. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.js.map +1 -1
  550. package/dist/package.cjs +1 -1
  551. package/dist/package.cjs.map +1 -1
  552. package/dist/package.js +6 -4
  553. package/dist/package.js.map +1 -1
  554. package/dist/routes/conversation.cjs +1 -1
  555. package/dist/routes/conversation.cjs.map +1 -1
  556. package/dist/routes/conversation.js +61 -63
  557. package/dist/routes/conversation.js.map +1 -1
  558. package/dist/routes/mcp.cjs +1 -1
  559. package/dist/routes/mcp.cjs.map +1 -1
  560. package/dist/routes/mcp.js +1 -1
  561. package/dist/routes/mcp.js.map +1 -1
  562. package/dist/stores/use-event-store.cjs +1 -1
  563. package/dist/stores/use-event-store.cjs.map +1 -1
  564. package/dist/stores/use-event-store.d.ts +22 -0
  565. package/dist/stores/use-event-store.js +9 -1
  566. package/dist/stores/use-event-store.js.map +1 -1
  567. package/dist/ui/context-menu.d.ts +1 -1
  568. package/dist/ui/help-link.d.ts +1 -1
  569. package/dist/utils/mcp-marketplace-utils.cjs +1 -1
  570. package/dist/utils/mcp-marketplace-utils.cjs.map +1 -1
  571. package/dist/utils/mcp-marketplace-utils.d.ts +21 -1
  572. package/dist/utils/mcp-marketplace-utils.js +23 -13
  573. package/dist/utils/mcp-marketplace-utils.js.map +1 -1
  574. package/dist/utils/settings-utils.cjs.map +1 -1
  575. package/dist/utils/settings-utils.js.map +1 -1
  576. package/package.json +6 -4
  577. package/scripts/check-sdk-version-sync.mjs +6 -6
  578. package/scripts/dev-safe.mjs +60 -24
  579. package/scripts/dev-with-automation.mjs +30 -50
  580. package/tools/canvas_ui_tool.py +129 -0
  581. package/build/assets/add-backend-modal-CqjNjGqY.js +0 -1
  582. package/build/assets/agent-server-conversation-service.api-BdEre_71.js +0 -5
  583. package/build/assets/backend-form-modal-KudhWUX8.js +0 -1
  584. package/build/assets/browser-vYpdU3CR.js +0 -5
  585. package/build/assets/conversation-COZAKz_K.js +0 -1
  586. package/build/assets/conversation-DWcvnmds.js +0 -19
  587. package/build/assets/conversation-panel-CZDStT0b.js +0 -1
  588. package/build/assets/conversation-websocket-context-DulnrIHh.js +0 -3
  589. package/build/assets/declaration-C9nuq2Dj.js +0 -1
  590. package/build/assets/edit-automation-modal-C3bFxS2f.js +0 -1
  591. package/build/assets/files-tab-CbJ4s7Ik.js +0 -1
  592. package/build/assets/git-control-bar-branch-button-Bm6rzSpo.js +0 -27
  593. package/build/assets/install-server-modal-VB5hOBpW.js +0 -1
  594. package/build/assets/llm-settings-CIdxmimN.js +0 -1
  595. package/build/assets/manifest-f041e61a.js +0 -1
  596. package/build/assets/mcp-BdfyCW1l.js +0 -9
  597. package/build/assets/messages-v-q35ObG.js +0 -36
  598. package/build/assets/recommended-automations-launcher-Cx7svuGE.js +0 -52
  599. package/build/assets/root-D2PVd51i.js +0 -2
  600. package/build/assets/root-DEotKI6b.css +0 -1
  601. package/build/assets/settings-service.api-Z6x0l0GU.js +0 -1
  602. package/build/assets/use-is-authed-BFoh8Ogh.js +0 -1
  603. package/build/assets/use-runtime-is-ready-BQWLEyqa.js +0 -1
  604. package/build/assets/use-skills-Cn-78xP1.js +0 -1
  605. package/build/assets/use-user-conversation-BCYpbPT1.js +0 -1
  606. package/build/assets/vendor~home~mcp~automations-list-DRfWZRnF.js +0 -1
  607. package/build/assets/vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~dp08i1qy-BJm2mGIp.js +0 -48
  608. package/dist/node_modules/@openhands/extensions/mcps/catalog/airtable.cjs +0 -2
  609. package/dist/node_modules/@openhands/extensions/mcps/catalog/airtable.cjs.map +0 -1
  610. package/dist/node_modules/@openhands/extensions/mcps/catalog/airtable.js +0 -30
  611. package/dist/node_modules/@openhands/extensions/mcps/catalog/airtable.js.map +0 -1
  612. package/dist/node_modules/@openhands/extensions/mcps/catalog/apify.cjs +0 -2
  613. package/dist/node_modules/@openhands/extensions/mcps/catalog/apify.cjs.map +0 -1
  614. package/dist/node_modules/@openhands/extensions/mcps/catalog/apify.js +0 -29
  615. package/dist/node_modules/@openhands/extensions/mcps/catalog/apify.js.map +0 -1
  616. package/dist/node_modules/@openhands/extensions/mcps/catalog/atlassian.cjs.map +0 -1
  617. package/dist/node_modules/@openhands/extensions/mcps/catalog/atlassian.js.map +0 -1
  618. package/dist/node_modules/@openhands/extensions/mcps/catalog/brave-search.cjs +0 -2
  619. package/dist/node_modules/@openhands/extensions/mcps/catalog/brave-search.cjs.map +0 -1
  620. package/dist/node_modules/@openhands/extensions/mcps/catalog/brave-search.js +0 -29
  621. package/dist/node_modules/@openhands/extensions/mcps/catalog/brave-search.js.map +0 -1
  622. package/dist/node_modules/@openhands/extensions/mcps/catalog/browser-mcp.cjs +0 -2
  623. package/dist/node_modules/@openhands/extensions/mcps/catalog/browser-mcp.cjs.map +0 -1
  624. package/dist/node_modules/@openhands/extensions/mcps/catalog/browser-mcp.js +0 -24
  625. package/dist/node_modules/@openhands/extensions/mcps/catalog/browser-mcp.js.map +0 -1
  626. package/dist/node_modules/@openhands/extensions/mcps/catalog/clickhouse.cjs +0 -2
  627. package/dist/node_modules/@openhands/extensions/mcps/catalog/clickhouse.cjs.map +0 -1
  628. package/dist/node_modules/@openhands/extensions/mcps/catalog/clickhouse.js +0 -45
  629. package/dist/node_modules/@openhands/extensions/mcps/catalog/clickhouse.js.map +0 -1
  630. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-bindings.cjs.map +0 -1
  631. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-bindings.js.map +0 -1
  632. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-browser-rendering.cjs +0 -2
  633. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-browser-rendering.cjs.map +0 -1
  634. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-browser-rendering.js.map +0 -1
  635. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-builds.cjs.map +0 -1
  636. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-builds.js.map +0 -1
  637. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-docs.cjs.map +0 -1
  638. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-docs.js.map +0 -1
  639. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-observability.cjs +0 -2
  640. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-observability.cjs.map +0 -1
  641. package/dist/node_modules/@openhands/extensions/mcps/catalog/cloudflare-observability.js.map +0 -1
  642. package/dist/node_modules/@openhands/extensions/mcps/catalog/deepwiki.cjs.map +0 -1
  643. package/dist/node_modules/@openhands/extensions/mcps/catalog/deepwiki.js.map +0 -1
  644. package/dist/node_modules/@openhands/extensions/mcps/catalog/elevenlabs.cjs +0 -2
  645. package/dist/node_modules/@openhands/extensions/mcps/catalog/elevenlabs.cjs.map +0 -1
  646. package/dist/node_modules/@openhands/extensions/mcps/catalog/elevenlabs.js +0 -29
  647. package/dist/node_modules/@openhands/extensions/mcps/catalog/elevenlabs.js.map +0 -1
  648. package/dist/node_modules/@openhands/extensions/mcps/catalog/everything.cjs.map +0 -1
  649. package/dist/node_modules/@openhands/extensions/mcps/catalog/everything.js.map +0 -1
  650. package/dist/node_modules/@openhands/extensions/mcps/catalog/exa.cjs +0 -2
  651. package/dist/node_modules/@openhands/extensions/mcps/catalog/exa.cjs.map +0 -1
  652. package/dist/node_modules/@openhands/extensions/mcps/catalog/exa.js +0 -29
  653. package/dist/node_modules/@openhands/extensions/mcps/catalog/exa.js.map +0 -1
  654. package/dist/node_modules/@openhands/extensions/mcps/catalog/fetch.cjs.map +0 -1
  655. package/dist/node_modules/@openhands/extensions/mcps/catalog/fetch.js.map +0 -1
  656. package/dist/node_modules/@openhands/extensions/mcps/catalog/figma.cjs +0 -2
  657. package/dist/node_modules/@openhands/extensions/mcps/catalog/figma.cjs.map +0 -1
  658. package/dist/node_modules/@openhands/extensions/mcps/catalog/figma.js +0 -33
  659. package/dist/node_modules/@openhands/extensions/mcps/catalog/figma.js.map +0 -1
  660. package/dist/node_modules/@openhands/extensions/mcps/catalog/filesystem.cjs +0 -2
  661. package/dist/node_modules/@openhands/extensions/mcps/catalog/filesystem.cjs.map +0 -1
  662. package/dist/node_modules/@openhands/extensions/mcps/catalog/filesystem.js +0 -32
  663. package/dist/node_modules/@openhands/extensions/mcps/catalog/filesystem.js.map +0 -1
  664. package/dist/node_modules/@openhands/extensions/mcps/catalog/firecrawl.cjs +0 -2
  665. package/dist/node_modules/@openhands/extensions/mcps/catalog/firecrawl.cjs.map +0 -1
  666. package/dist/node_modules/@openhands/extensions/mcps/catalog/firecrawl.js +0 -29
  667. package/dist/node_modules/@openhands/extensions/mcps/catalog/firecrawl.js.map +0 -1
  668. package/dist/node_modules/@openhands/extensions/mcps/catalog/git.cjs +0 -2
  669. package/dist/node_modules/@openhands/extensions/mcps/catalog/git.cjs.map +0 -1
  670. package/dist/node_modules/@openhands/extensions/mcps/catalog/git.js +0 -33
  671. package/dist/node_modules/@openhands/extensions/mcps/catalog/git.js.map +0 -1
  672. package/dist/node_modules/@openhands/extensions/mcps/catalog/github.cjs +0 -2
  673. package/dist/node_modules/@openhands/extensions/mcps/catalog/github.cjs.map +0 -1
  674. package/dist/node_modules/@openhands/extensions/mcps/catalog/github.js +0 -40
  675. package/dist/node_modules/@openhands/extensions/mcps/catalog/github.js.map +0 -1
  676. package/dist/node_modules/@openhands/extensions/mcps/catalog/huggingface.cjs.map +0 -1
  677. package/dist/node_modules/@openhands/extensions/mcps/catalog/huggingface.js.map +0 -1
  678. package/dist/node_modules/@openhands/extensions/mcps/catalog/kagi.cjs +0 -2
  679. package/dist/node_modules/@openhands/extensions/mcps/catalog/kagi.cjs.map +0 -1
  680. package/dist/node_modules/@openhands/extensions/mcps/catalog/kagi.js +0 -29
  681. package/dist/node_modules/@openhands/extensions/mcps/catalog/kagi.js.map +0 -1
  682. package/dist/node_modules/@openhands/extensions/mcps/catalog/linear.cjs.map +0 -1
  683. package/dist/node_modules/@openhands/extensions/mcps/catalog/linear.js.map +0 -1
  684. package/dist/node_modules/@openhands/extensions/mcps/catalog/memory.cjs +0 -2
  685. package/dist/node_modules/@openhands/extensions/mcps/catalog/memory.cjs.map +0 -1
  686. package/dist/node_modules/@openhands/extensions/mcps/catalog/memory.js.map +0 -1
  687. package/dist/node_modules/@openhands/extensions/mcps/catalog/mongodb.cjs +0 -2
  688. package/dist/node_modules/@openhands/extensions/mcps/catalog/mongodb.cjs.map +0 -1
  689. package/dist/node_modules/@openhands/extensions/mcps/catalog/mongodb.js +0 -29
  690. package/dist/node_modules/@openhands/extensions/mcps/catalog/mongodb.js.map +0 -1
  691. package/dist/node_modules/@openhands/extensions/mcps/catalog/neon.cjs +0 -2
  692. package/dist/node_modules/@openhands/extensions/mcps/catalog/neon.cjs.map +0 -1
  693. package/dist/node_modules/@openhands/extensions/mcps/catalog/neon.js +0 -33
  694. package/dist/node_modules/@openhands/extensions/mcps/catalog/neon.js.map +0 -1
  695. package/dist/node_modules/@openhands/extensions/mcps/catalog/notion.cjs +0 -2
  696. package/dist/node_modules/@openhands/extensions/mcps/catalog/notion.cjs.map +0 -1
  697. package/dist/node_modules/@openhands/extensions/mcps/catalog/notion.js +0 -32
  698. package/dist/node_modules/@openhands/extensions/mcps/catalog/notion.js.map +0 -1
  699. package/dist/node_modules/@openhands/extensions/mcps/catalog/obsidian.cjs +0 -2
  700. package/dist/node_modules/@openhands/extensions/mcps/catalog/obsidian.cjs.map +0 -1
  701. package/dist/node_modules/@openhands/extensions/mcps/catalog/obsidian.js +0 -31
  702. package/dist/node_modules/@openhands/extensions/mcps/catalog/obsidian.js.map +0 -1
  703. package/dist/node_modules/@openhands/extensions/mcps/catalog/paypal.cjs +0 -2
  704. package/dist/node_modules/@openhands/extensions/mcps/catalog/paypal.cjs.map +0 -1
  705. package/dist/node_modules/@openhands/extensions/mcps/catalog/paypal.js.map +0 -1
  706. package/dist/node_modules/@openhands/extensions/mcps/catalog/playwright.cjs +0 -2
  707. package/dist/node_modules/@openhands/extensions/mcps/catalog/playwright.cjs.map +0 -1
  708. package/dist/node_modules/@openhands/extensions/mcps/catalog/playwright.js.map +0 -1
  709. package/dist/node_modules/@openhands/extensions/mcps/catalog/redis.cjs +0 -2
  710. package/dist/node_modules/@openhands/extensions/mcps/catalog/redis.cjs.map +0 -1
  711. package/dist/node_modules/@openhands/extensions/mcps/catalog/redis.js +0 -36
  712. package/dist/node_modules/@openhands/extensions/mcps/catalog/redis.js.map +0 -1
  713. package/dist/node_modules/@openhands/extensions/mcps/catalog/resend.cjs +0 -2
  714. package/dist/node_modules/@openhands/extensions/mcps/catalog/resend.cjs.map +0 -1
  715. package/dist/node_modules/@openhands/extensions/mcps/catalog/resend.js +0 -34
  716. package/dist/node_modules/@openhands/extensions/mcps/catalog/resend.js.map +0 -1
  717. package/dist/node_modules/@openhands/extensions/mcps/catalog/sentry.cjs +0 -2
  718. package/dist/node_modules/@openhands/extensions/mcps/catalog/sentry.cjs.map +0 -1
  719. package/dist/node_modules/@openhands/extensions/mcps/catalog/sentry.js.map +0 -1
  720. package/dist/node_modules/@openhands/extensions/mcps/catalog/sequential-thinking.cjs +0 -2
  721. package/dist/node_modules/@openhands/extensions/mcps/catalog/sequential-thinking.cjs.map +0 -1
  722. package/dist/node_modules/@openhands/extensions/mcps/catalog/sequential-thinking.js.map +0 -1
  723. package/dist/node_modules/@openhands/extensions/mcps/catalog/slack.cjs +0 -2
  724. package/dist/node_modules/@openhands/extensions/mcps/catalog/slack.cjs.map +0 -1
  725. package/dist/node_modules/@openhands/extensions/mcps/catalog/slack.js +0 -38
  726. package/dist/node_modules/@openhands/extensions/mcps/catalog/slack.js.map +0 -1
  727. package/dist/node_modules/@openhands/extensions/mcps/catalog/stripe.cjs +0 -2
  728. package/dist/node_modules/@openhands/extensions/mcps/catalog/stripe.cjs.map +0 -1
  729. package/dist/node_modules/@openhands/extensions/mcps/catalog/stripe.js.map +0 -1
  730. package/dist/node_modules/@openhands/extensions/mcps/catalog/supabase.cjs +0 -2
  731. package/dist/node_modules/@openhands/extensions/mcps/catalog/supabase.cjs.map +0 -1
  732. package/dist/node_modules/@openhands/extensions/mcps/catalog/supabase.js +0 -30
  733. package/dist/node_modules/@openhands/extensions/mcps/catalog/supabase.js.map +0 -1
  734. package/dist/node_modules/@openhands/extensions/mcps/catalog/tavily.cjs.map +0 -1
  735. package/dist/node_modules/@openhands/extensions/mcps/catalog/tavily.js +0 -32
  736. package/dist/node_modules/@openhands/extensions/mcps/catalog/tavily.js.map +0 -1
  737. package/dist/node_modules/@openhands/extensions/mcps/catalog/time.cjs +0 -2
  738. package/dist/node_modules/@openhands/extensions/mcps/catalog/time.cjs.map +0 -1
  739. package/dist/node_modules/@openhands/extensions/mcps/catalog/time.js.map +0 -1
  740. package/dist/node_modules/@openhands/extensions/mcps/index.cjs +0 -2
  741. package/dist/node_modules/@openhands/extensions/mcps/index.cjs.map +0 -1
  742. package/dist/node_modules/@openhands/extensions/mcps/index.js +0 -87
  743. package/dist/node_modules/@openhands/extensions/mcps/index.js.map +0 -1
  744. package/dist/node_modules/@openhands/extensions/mcps/logos.cjs.map +0 -1
  745. package/dist/node_modules/@openhands/extensions/mcps/logos.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"backend-form-modal.js","names":[],"sources":["../../../../src/components/features/backends/backend-form-modal.tsx"],"sourcesContent":["import React from \"react\";\nimport { useQuery } from \"@tanstack/react-query\";\nimport { useTranslation } from \"react-i18next\";\nimport { ServerClient } from \"@openhands/typescript-client/clients\";\nimport OpenHandsLogoWhite from \"#/assets/branding/openhands-logo-white.svg?react\";\nimport { ModalBackdrop } from \"#/components/shared/modals/modal-backdrop\";\nimport {\n MODAL_MAX_WIDTH_VIEWPORT,\n modalWidthClassName,\n} from \"#/components/shared/modals/modal-body\";\nimport { ModalCloseButton } from \"#/components/shared/modals/modal-close-button\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { SettingsInput } from \"#/components/features/settings/settings-input\";\nimport { useActiveBackendContext } from \"#/contexts/active-backend-context\";\nimport { useBackendsHealth } from \"#/hooks/query/use-backends-health\";\nimport { getAgentServerClientOptions } from \"#/api/agent-server-client-options\";\nimport ChevronDownSmallIcon from \"#/icons/chevron-down-small.svg?react\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport type { Backend, BackendKind } from \"#/api/backend-registry/types\";\nimport { cn } from \"#/utils/utils\";\nimport { BackendStatusDot } from \"./backend-status-dot\";\nimport { DeviceFlowAuth } from \"./device-flow-auth\";\n\nexport type BackendFormMode = \"add\" | \"edit\";\n\ninterface BackendFormModalProps {\n mode: BackendFormMode;\n /** Required when `mode === \"edit\"`. */\n backend?: Backend;\n onClose: () => void;\n}\n\nfunction inferKindFromHost(host: string): BackendKind {\n const trimmed = host.trim().toLowerCase();\n if (trimmed.includes(\"all-hands.dev\") || trimmed.includes(\"openhands.dev\")) {\n return \"cloud\";\n }\n return \"local\";\n}\n\n/**\n * Returns true for hostnames that represent a local / private-network address.\n * Used by normalizeHost to choose http:// instead of https://.\n */\nfunction isLocalAddress(hostname: string): boolean {\n // Strip IPv6 bracket notation: [::1] → ::1\n const h = hostname.toLowerCase().replace(/^\\[|\\]$/g, \"\");\n // IPv6 loopback, any-address, and named loopback\n if (h === \"localhost\" || h === \"::1\" || h === \"::\" || h === \"0.0.0.0\")\n return true;\n // 127.x.x.x loopback range + IPv4-mapped loopback (::ffff:127.x.x.x)\n if (/^127\\./.test(h) || /^::ffff:127\\./i.test(h)) return true;\n // RFC 1918 private ranges\n if (/^10\\./.test(h)) return true;\n if (/^192\\.168\\./.test(h)) return true;\n if (/^172\\.(1[6-9]|2\\d|3[01])\\./.test(h)) return true;\n // IPv6 link-local (fe80::/10) and unique local (fc00::/7)\n if (/^fe[89ab][0-9a-f]:/i.test(h)) return true;\n if (/^f[cd][0-9a-f]{2}:/i.test(h)) return true;\n // mDNS / Bonjour (.local)\n if (h.endsWith(\".local\")) return true;\n // Single-label hostnames (no dots, no colons) are local network names.\n // Colons are excluded so bare IPv6 addresses don't accidentally match.\n if (!h.includes(\".\") && !h.includes(\":\")) return true;\n return false;\n}\n\nfunction normalizeHost(host: string): string {\n const trimmed = host.trim().replace(/\\/+$/, \"\");\n if (!trimmed) return \"\";\n // Already has an explicit scheme — respect it.\n if (/^https?:\\/\\//i.test(trimmed)) return trimmed;\n // Extract the pure hostname for scheme selection, handling three cases:\n // [::1]:8080 → bracket IPv6 notation → extract ::1\n // ::1 → bare IPv6 (multiple colons, no bracket) → whole string\n // host:port → regular host:port → part before the colon\n const bracketMatch = trimmed.match(/^\\[([^\\]]+)\\]/);\n const hostname = bracketMatch\n ? bracketMatch[1]\n : (trimmed.match(/:/g) ?? []).length > 1\n ? trimmed\n : trimmed.split(\":\")[0];\n const scheme = isLocalAddress(hostname) ? \"http\" : \"https\";\n return `${scheme}://${trimmed}`;\n}\n\n/**\n * Returns true when `host` represents a reachable backend URL.\n *\n * Rules (applied in order):\n * 1. Must be non-empty after trimming.\n * 2. Must contain no whitespace — spaces can never appear in a host/port.\n * 3. After normalisation (bare hosts get `https://` prepended), must parse\n * as a valid http or https URL with a non-empty hostname.\n */\nfunction isValidHostUrl(host: string): boolean {\n const trimmed = host.trim();\n if (!trimmed) return false;\n // Spaces anywhere in the input are an immediate rejection.\n if (/\\s/.test(trimmed)) return false;\n const normalized = normalizeHost(trimmed);\n if (!normalized) return false;\n try {\n const url = new URL(normalized);\n return (\n (url.protocol === \"http:\" || url.protocol === \"https:\") &&\n url.hostname.length > 0\n );\n } catch {\n return false;\n }\n}\n\nconst DEFAULT_OPENHANDS_CLOUD_HOST = \"https://app.all-hands.dev\";\n\n/**\n * Live status row for the edit form: shows a connection dot, a\n * \"Local\"/\"Cloud\" label, and the agent server's reported version when\n * available. Replaces the legacy local/cloud radio fieldset (kind is\n * now inferred from the host).\n */\nfunction BackendStatusBadge({\n backend,\n testIdRoot,\n}: {\n backend: Backend;\n testIdRoot: string;\n}) {\n const { t } = useTranslation(\"openhands\");\n const healthByBackendId = useBackendsHealth([backend]);\n const health = healthByBackendId[backend.id];\n const isConnected = health?.isConnected ?? null;\n const disabled = health?.disabled === true;\n const consecutiveFailures = health?.consecutiveFailures ?? 0;\n const lastError = health?.lastError ?? null;\n\n const { data: version } = useQuery({\n queryKey: [\"backend-version\", backend.host, backend.apiKey],\n queryFn: async () => {\n const info = await new ServerClient(\n getAgentServerClientOptions({\n host: backend.host,\n sessionApiKey: backend.apiKey || null,\n timeout: 5000,\n }),\n ).getServerInfo();\n return info.version ?? null;\n },\n retry: false,\n staleTime: 60_000,\n enabled: backend.kind === \"local\" && !disabled,\n });\n\n let statusLabel: string;\n if (isConnected === true) {\n statusLabel = t(I18nKey.ONBOARDING$BACKEND_STATUS_CONNECTED);\n } else if (isConnected === false) {\n statusLabel = t(I18nKey.ONBOARDING$BACKEND_STATUS_DISCONNECTED);\n } else {\n statusLabel = t(I18nKey.ONBOARDING$BACKEND_STATUS_CHECKING);\n }\n\n const kindLabel =\n backend.kind === \"cloud\"\n ? t(I18nKey.BACKEND$KIND_CLOUD)\n : t(I18nKey.BACKEND$KIND_LOCAL);\n\n return (\n <div className=\"flex flex-col gap-2\">\n <div\n data-testid={`${testIdRoot}-status`}\n className=\"flex items-center gap-3 text-sm\"\n >\n <BackendStatusDot isConnected={isConnected} />\n <span className=\"text-white\" data-testid={`${testIdRoot}-status-label`}>\n {statusLabel}\n </span>\n <span className=\"text-tertiary-alt\">·</span>\n <span className=\"text-[var(--oh-text-tertiary)]\">{kindLabel}</span>\n {version ? (\n <span\n className=\"text-xs text-[var(--oh-muted)]\"\n data-testid={`${testIdRoot}-version`}\n >\n {t(I18nKey.BACKEND$VERSION_LABEL, { version })}\n </span>\n ) : null}\n </div>\n\n {disabled ? (\n <div\n data-testid={`${testIdRoot}-status-error`}\n className=\"flex flex-col gap-1 rounded-md border border-red-500/40 bg-red-500/10 p-3 text-sm\"\n >\n <span className=\"font-semibold text-red-300\">\n {t(I18nKey.BACKEND$HEALTH_FAILED_TITLE)}\n </span>\n <span className=\"text-xs text-[var(--oh-text-tertiary)]\">\n {t(I18nKey.BACKEND$HEALTH_FAILED_DETAIL, {\n count: consecutiveFailures,\n })}\n </span>\n {lastError ? (\n <span\n data-testid={`${testIdRoot}-status-error-message`}\n className=\"text-xs text-red-300 whitespace-pre-wrap break-words\"\n >\n {lastError}\n </span>\n ) : null}\n </div>\n ) : null}\n </div>\n );\n}\n\nexport interface BackendFormProps {\n mode: BackendFormMode;\n /** Required when `mode === \"edit\"`. */\n backend?: Backend;\n /**\n * Called after the form is submitted and the backend has been\n * persisted. Use this to dismiss a containing modal, advance an\n * onboarding step, etc.\n */\n onSubmitted: () => void;\n /**\n * Optional render slot rendered in place of the default\n * Save / Cancel button row, so callers (e.g. the onboarding flow)\n * can re-skin the action area while still owning submission via the\n * standard `<form onSubmit>` flow. Receives the form's submit-ready\n * state.\n */\n renderActions?: (state: {\n canSubmit: boolean;\n testIdRoot: string;\n }) => React.ReactNode;\n /** Used to disambiguate test ids across the same screen. */\n testIdRoot?: string;\n}\n\n/**\n * Reusable form body for adding / editing a backend. Renders the\n * common name / host / API-key inputs plus the kind selector\n * (radio buttons in `add` mode, status badge in `edit` mode).\n *\n * Rendered as a `<form>`, so consumers should put any extra controls\n * either inside `renderActions` or as siblings inside a wrapping\n * element — but submission flows through the standard form submit so\n * Enter-to-submit still works.\n */\nexport function BackendForm({\n mode,\n backend,\n onSubmitted,\n renderActions,\n testIdRoot: explicitTestIdRoot,\n}: BackendFormProps) {\n const { t } = useTranslation(\"openhands\");\n const { addBackend, updateBackend } = useActiveBackendContext();\n\n const [name, setName] = React.useState(backend?.name ?? \"\");\n const [host, setHost] = React.useState(backend?.host ?? \"\");\n const [apiKey, setApiKey] = React.useState(backend?.apiKey ?? \"\");\n\n // Inline validation: only show errors after the user has left a field.\n const [nameTouched, setNameTouched] = React.useState(false);\n const [hostTouched, setHostTouched] = React.useState(false);\n\n // Kind is inferred from the host on every change.\n const kind: BackendKind = inferKindFromHost(host);\n\n const testIdRoot =\n explicitTestIdRoot ?? (mode === \"edit\" ? \"edit-backend\" : \"add-backend\");\n\n const canSubmit =\n name.trim().length > 0 &&\n isValidHostUrl(host) &&\n (kind === \"local\" || apiKey.trim().length > 0);\n\n // Error messages — only surfaced after the user has blurred the field.\n const nameError =\n nameTouched && !name.trim() ? t(I18nKey.BACKEND$NAME_REQUIRED) : undefined;\n const hostError = hostTouched\n ? !host.trim()\n ? t(I18nKey.BACKEND$HOST_REQUIRED)\n : !isValidHostUrl(host)\n ? t(I18nKey.BACKEND$HOST_INVALID)\n : undefined\n : undefined;\n\n const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n if (!canSubmit) {\n // Mark all validated fields as touched so inline errors become visible\n // (e.g. user pressed Enter before filling required fields).\n setNameTouched(true);\n setHostTouched(true);\n return;\n }\n\n const payload = {\n name: name.trim(),\n host: normalizeHost(host),\n apiKey: apiKey.trim(),\n kind,\n };\n\n if (mode === \"edit\" && backend) {\n updateBackend(backend.id, payload);\n } else {\n addBackend(payload);\n }\n\n onSubmitted();\n };\n\n return (\n <form\n data-testid={`${testIdRoot}-form`}\n onSubmit={handleSubmit}\n className=\"flex flex-col gap-4\"\n >\n <SettingsInput\n testId={`${testIdRoot}-name`}\n name={`${testIdRoot}-name`}\n type=\"text\"\n label={t(I18nKey.BACKEND$NAME_LABEL)}\n value={name}\n onChange={setName}\n onBlur={() => setNameTouched(true)}\n placeholder=\"Production\"\n className=\"w-full\"\n showRequiredTag\n error={nameError}\n />\n\n <SettingsInput\n testId={`${testIdRoot}-host`}\n name={`${testIdRoot}-host`}\n type=\"text\"\n label={t(I18nKey.BACKEND$HOST_LABEL)}\n value={host}\n onChange={setHost}\n onBlur={() => setHostTouched(true)}\n placeholder={DEFAULT_OPENHANDS_CLOUD_HOST}\n className=\"w-full\"\n showRequiredTag\n error={hostError}\n />\n\n <SettingsInput\n testId={`${testIdRoot}-api-key`}\n name={`${testIdRoot}-api-key`}\n type=\"password\"\n label={t(I18nKey.BACKEND$KEY_LABEL)}\n value={apiKey}\n onChange={setApiKey}\n placeholder=\"\"\n className=\"w-full\"\n />\n\n {mode === \"edit\" && backend && (\n <BackendStatusBadge backend={backend} testIdRoot={testIdRoot} />\n )}\n\n {renderActions ? (\n renderActions({ canSubmit, testIdRoot })\n ) : (\n <div className=\"flex justify-end gap-2 mt-2 w-full\">\n <BrandButton\n type=\"button\"\n variant=\"secondary\"\n onClick={onSubmitted}\n testId={`${testIdRoot}-cancel`}\n >\n {t(I18nKey.BUTTON$CANCEL)}\n </BrandButton>\n <BrandButton\n type=\"submit\"\n variant=\"primary\"\n isDisabled={!canSubmit}\n testId={`${testIdRoot}-submit`}\n >\n {t(I18nKey.BACKEND$SAVE)}\n </BrandButton>\n </div>\n )}\n </form>\n );\n}\n\n// ── Add-mode two-column layout ──────────────────────────────────────\n\n/**\n * Left column of the \"Add a Backend\" modal: manual connection via\n * Host + API Key. Designed for self-hosted agent servers and\n * self-hosted OpenHands Cloud with API key auth.\n */\nfunction ManualConnectionColumn({ onClose }: { onClose: () => void }) {\n const { t } = useTranslation(\"openhands\");\n const { addBackend } = useActiveBackendContext();\n\n const [name, setName] = React.useState(\"\");\n const [host, setHost] = React.useState(\"\");\n const [apiKey, setApiKey] = React.useState(\"\");\n\n const kind: BackendKind = inferKindFromHost(host);\n const canSubmit =\n name.trim().length > 0 &&\n isValidHostUrl(host) &&\n (kind === \"local\" || apiKey.trim().length > 0);\n\n const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {\n e.preventDefault();\n if (!canSubmit) return;\n addBackend({\n name: name.trim(),\n host: normalizeHost(host),\n apiKey: apiKey.trim(),\n kind,\n });\n onClose();\n };\n\n return (\n <form\n data-testid=\"add-backend-form\"\n onSubmit={handleSubmit}\n className=\"flex flex-col gap-4 flex-1 min-w-0\"\n >\n <div className=\"flex flex-col gap-1\">\n <SettingsInput\n testId=\"add-backend-name\"\n name=\"add-backend-name\"\n type=\"text\"\n label={t(I18nKey.BACKEND$NAME_LABEL)}\n value={name}\n onChange={setName}\n placeholder=\"e.g. My Server\"\n className=\"w-full\"\n />\n <p className=\"text-xs text-[var(--oh-muted)]\">\n {t(I18nKey.BACKEND$NAME_HELPER)}\n </p>\n </div>\n\n <div className=\"flex flex-col gap-1\">\n <SettingsInput\n testId=\"add-backend-host\"\n name=\"add-backend-host\"\n type=\"text\"\n label={t(I18nKey.BACKEND$HOST_LABEL)}\n value={host}\n onChange={setHost}\n placeholder=\"http://localhost:8000\"\n className=\"w-full\"\n />\n <p\n className=\"text-xs text-[var(--oh-muted)]\"\n data-testid=\"add-backend-host-helper\"\n >\n {t(I18nKey.BACKEND$HOST_HELPER)}\n </p>\n </div>\n\n <SettingsInput\n testId=\"add-backend-api-key\"\n name=\"add-backend-api-key\"\n type=\"password\"\n label={t(I18nKey.BACKEND$KEY_LABEL)}\n value={apiKey}\n onChange={setApiKey}\n placeholder=\"sk-••••••••••\"\n className=\"w-full\"\n />\n\n <BrandButton\n type=\"submit\"\n variant=\"secondary\"\n isDisabled={!canSubmit}\n testId=\"add-backend-submit\"\n className=\"w-full text-center\"\n >\n {t(I18nKey.BACKEND$CONNECT)}\n </BrandButton>\n </form>\n );\n}\n\n/**\n * Right column of the \"Add a Backend\" modal: one-click OAuth login\n * with OpenHands Cloud. Includes an \"Advanced\" disclosure for\n * users who self-host OpenHands Cloud and need to override the host.\n */\nfunction CloudLoginColumn({ onClose }: { onClose: () => void }) {\n const { t } = useTranslation(\"openhands\");\n const { addBackend } = useActiveBackendContext();\n\n const [advancedOpen, setAdvancedOpen] = React.useState(false);\n const [customHost, setCustomHost] = React.useState(\"\");\n\n const effectiveHost = customHost.trim() || DEFAULT_OPENHANDS_CLOUD_HOST;\n\n const handleLoginSuccess = (apiKey: string) => {\n addBackend({\n name: \"OpenHands Cloud\",\n host: normalizeHost(effectiveHost),\n apiKey,\n kind: \"cloud\",\n });\n onClose();\n };\n\n return (\n <div className=\"flex flex-1 min-w-0 flex-col items-center gap-3\">\n <div className=\"flex flex-col items-center gap-1\">\n <OpenHandsLogoWhite width={56} height={56} aria-hidden />\n\n <h4\n className=\"text-lg font-medium text-white\"\n data-testid=\"add-backend-cloud-title\"\n >\n {t(I18nKey.BACKEND$CLOUD_TITLE)}\n </h4>\n </div>\n\n <p className=\"text-center text-sm leading-relaxed text-[var(--oh-muted)]\">\n {t(I18nKey.BACKEND$CLOUD_DESCRIPTION)}\n </p>\n\n <DeviceFlowAuth\n host={effectiveHost}\n onSuccess={handleLoginSuccess}\n testIdRoot=\"add-backend\"\n />\n\n <div className=\"w-full\">\n <button\n type=\"button\"\n onClick={() => setAdvancedOpen((open) => !open)}\n aria-expanded={advancedOpen}\n data-testid=\"add-backend-advanced-toggle\"\n className=\"flex w-full cursor-pointer items-center justify-center gap-1 text-center text-xs text-[var(--oh-muted)] transition-colors hover:text-content-2\"\n >\n <span>{t(I18nKey.BACKEND$ADVANCED)}</span>\n <ChevronDownSmallIcon\n className={cn(\n \"h-4 w-4 shrink-0 text-muted transition-transform\",\n advancedOpen && \"rotate-180\",\n )}\n aria-hidden\n />\n </button>\n <div\n className={cn(\n \"pt-2\",\n !advancedOpen && \"pointer-events-none invisible\",\n )}\n aria-hidden={!advancedOpen}\n >\n <SettingsInput\n testId=\"add-backend-cloud-host\"\n name=\"add-backend-cloud-host\"\n type=\"text\"\n label={t(I18nKey.BACKEND$HOST_LABEL)}\n value={customHost}\n onChange={setCustomHost}\n placeholder={DEFAULT_OPENHANDS_CLOUD_HOST}\n className=\"w-full\"\n />\n <p className=\"mt-1 text-xs text-[var(--oh-muted)]\">\n {t(I18nKey.BACKEND$LOGIN_CLOUD_HINT)}\n </p>\n </div>\n </div>\n </div>\n );\n}\n\n// ── Modal wrappers ──────────────────────────────────────────────────\n\n/**\n * Modal wrapper. In **add** mode it renders a two-column layout\n * (manual connection | OR | Cloud login). In **edit** mode it wraps\n * the standard `BackendForm`.\n */\nexport function BackendFormModal({\n mode,\n backend,\n onClose,\n}: BackendFormModalProps) {\n const { t } = useTranslation(\"openhands\");\n\n if (mode === \"add\") {\n return (\n <ModalBackdrop\n onClose={onClose}\n closeOnEscape={false}\n aria-label={t(I18nKey.BACKEND$ADD_TITLE)}\n >\n <div\n data-testid=\"add-backend-modal\"\n className={cn(\n \"relative rounded-xl border border-[var(--oh-border)] bg-base-secondary\",\n modalWidthClassName(\"xl\"),\n MODAL_MAX_WIDTH_VIEWPORT,\n )}\n >\n <ModalCloseButton onClose={onClose} testId=\"add-backend-close\" />\n {/* Header */}\n <div className=\"px-6 pt-6 pb-2 pr-12\">\n <h2 className=\"text-lg font-semibold\">\n {t(I18nKey.BACKEND$ADD_TITLE)}\n </h2>\n </div>\n\n {/* Two-column body */}\n <div className=\"flex gap-6 px-6 pb-6 pt-2\">\n {/* Left: manual connection */}\n <div className=\"flex-1 min-w-0\">\n <ManualConnectionColumn onClose={onClose} />\n </div>\n\n {/* Vertical OR divider */}\n <div className=\"flex shrink-0 flex-col items-center\">\n <div className=\"flex-1 w-px bg-[var(--oh-border)]\" />\n <span className=\"py-3 text-xs uppercase text-[var(--oh-muted)]\">\n {t(I18nKey.BACKEND$LOGIN_OR)}\n </span>\n <div className=\"flex-1 w-px bg-[var(--oh-border)]\" />\n </div>\n\n {/* Right: cloud login */}\n <div className=\"flex-1 min-w-0\">\n <CloudLoginColumn onClose={onClose} />\n </div>\n </div>\n </div>\n </ModalBackdrop>\n );\n }\n\n // Edit mode — single-column form (unchanged)\n const testIdRoot = \"edit-backend\";\n return (\n <ModalBackdrop\n onClose={onClose}\n closeOnEscape={false}\n aria-label={t(I18nKey.BACKEND$EDIT_TITLE)}\n >\n <div\n data-testid={`${testIdRoot}-modal`}\n className={cn(\n \"relative bg-base-secondary p-6 rounded-xl flex flex-col gap-4 border border-[var(--oh-border)]\",\n modalWidthClassName(\"md\"),\n )}\n >\n <ModalCloseButton onClose={onClose} testId={`${testIdRoot}-close`} />\n <h2 className=\"pr-6 text-lg font-semibold\">\n {t(I18nKey.BACKEND$EDIT_TITLE)}\n </h2>\n <BackendForm\n mode=\"edit\"\n backend={backend}\n onSubmitted={onClose}\n testIdRoot={testIdRoot}\n />\n </div>\n </ModalBackdrop>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAgCA,SAAS,EAAkB,GAA2B;CACpD,IAAM,IAAU,EAAK,MAAM,CAAC,aAAa;AAIzC,QAHI,EAAQ,SAAS,gBAAgB,IAAI,EAAQ,SAAS,gBAAgB,GACjE,UAEF;;AAOT,SAAS,EAAe,GAA2B;CAEjD,IAAM,IAAI,EAAS,aAAa,CAAC,QAAQ,YAAY,GAAG;AAkBxD,QADA,GAfI,MAAM,eAAe,MAAM,SAAS,MAAM,QAAQ,MAAM,aAGxD,SAAS,KAAK,EAAE,IAAI,iBAAiB,KAAK,EAAE,IAE5C,QAAQ,KAAK,EAAE,IACf,cAAc,KAAK,EAAE,IACrB,6BAA6B,KAAK,EAAE,IAEpC,sBAAsB,KAAK,EAAE,IAC7B,sBAAsB,KAAK,EAAE,IAE7B,EAAE,SAAS,SAAS,IAGpB,CAAC,EAAE,SAAS,IAAI,IAAI,CAAC,EAAE,SAAS,IAAI;;AAI1C,SAAS,EAAc,GAAsB;CAC3C,IAAM,IAAU,EAAK,MAAM,CAAC,QAAQ,QAAQ,GAAG;AAC/C,KAAI,CAAC,EAAS,QAAO;AAErB,KAAI,gBAAgB,KAAK,EAAQ,CAAE,QAAO;CAK1C,IAAM,IAAe,EAAQ,MAAM,gBAAgB;AAOnD,QAAO,GADQ,EALE,IACb,EAAa,MACZ,EAAQ,MAAM,KAAK,IAAI,EAAE,EAAE,SAAS,IACnC,IACA,EAAQ,MAAM,IAAI,CAAC,GACc,GAAG,SAAS,QAClC,KAAK;;AAYxB,SAAS,EAAe,GAAuB;CAC7C,IAAM,IAAU,EAAK,MAAM;AAG3B,KAFI,CAAC,KAED,KAAK,KAAK,EAAQ,CAAE,QAAO;CAC/B,IAAM,IAAa,EAAc,EAAQ;AACzC,KAAI,CAAC,EAAY,QAAO;AACxB,KAAI;EACF,IAAM,IAAM,IAAI,IAAI,EAAW;AAC/B,UACG,EAAI,aAAa,WAAW,EAAI,aAAa,aAC9C,EAAI,SAAS,SAAS;SAElB;AACN,SAAO;;;AAIX,IAAM,IAA+B;AAQrC,SAAS,EAAmB,EAC1B,YACA,iBAIC;CACD,IAAM,EAAE,SAAM,EAAe,YAAY,EAEnC,IADoB,EAAkB,CAAC,EAAQ,CACtC,CAAkB,EAAQ,KACnC,IAAc,GAAQ,eAAe,MACrC,IAAW,GAAQ,aAAa,IAChC,IAAsB,GAAQ,uBAAuB,GACrD,IAAY,GAAQ,aAAa,MAEjC,EAAE,MAAM,MAAY,EAAS;EACjC,UAAU;GAAC;GAAmB,EAAQ;GAAM,EAAQ;GAAO;EAC3D,SAAS,aAQA,MAPY,IAAI,EACrB,EAA4B;GAC1B,MAAM,EAAQ;GACd,eAAe,EAAQ,UAAU;GACjC,SAAS;GACV,CAAC,CACH,CAAC,eAAe,EACL,WAAW;EAEzB,OAAO;EACP,WAAW;EACX,SAAS,EAAQ,SAAS,WAAW,CAAC;EACvC,CAAC,EAEE;AACJ,CAKE,IAJc,EADZ,MAAgB,KACF,EAAQ,sCACf,MAAgB,KACT,EAAQ,yCAER,EAAQ,mCAAmC;CAG7D,IAAM,IACJ,EAAQ,SAAS,UACb,EAAE,EAAQ,mBAAmB,GAC7B,EAAE,EAAQ,mBAAmB;AAEnC,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GACE,eAAa,GAAG,EAAW;GAC3B,WAAU;aAFZ;IAIE,kBAAC,GAAD,EAA+B,gBAAe,CAAA;IAC9C,kBAAC,QAAD;KAAM,WAAU;KAAa,eAAa,GAAG,EAAW;eACrD;KACI,CAAA;IACP,kBAAC,QAAD;KAAM,WAAU;eAAoB;KAAQ,CAAA;IAC5C,kBAAC,QAAD;KAAM,WAAU;eAAkC;KAAiB,CAAA;IAClE,IACC,kBAAC,QAAD;KACE,WAAU;KACV,eAAa,GAAG,EAAW;eAE1B,EAAE,EAAQ,uBAAuB,EAAE,YAAS,CAAC;KACzC,CAAA,GACL;IACA;MAEL,IACC,kBAAC,OAAD;GACE,eAAa,GAAG,EAAW;GAC3B,WAAU;aAFZ;IAIE,kBAAC,QAAD;KAAM,WAAU;eACb,EAAE,EAAQ,4BAA4B;KAClC,CAAA;IACP,kBAAC,QAAD;KAAM,WAAU;eACb,EAAE,EAAQ,8BAA8B,EACvC,OAAO,GACR,CAAC;KACG,CAAA;IACN,IACC,kBAAC,QAAD;KACE,eAAa,GAAG,EAAW;KAC3B,WAAU;eAET;KACI,CAAA,GACL;IACA;OACJ,KACA;;;AAuCV,SAAgB,EAAY,EAC1B,SACA,YACA,gBACA,kBACA,YAAY,KACO;CACnB,IAAM,EAAE,SAAM,EAAe,YAAY,EACnC,EAAE,eAAY,qBAAkB,GAAyB,EAEzD,CAAC,GAAM,KAAW,EAAM,SAAS,GAAS,QAAQ,GAAG,EACrD,CAAC,GAAM,KAAW,EAAM,SAAS,GAAS,QAAQ,GAAG,EACrD,CAAC,GAAQ,KAAa,EAAM,SAAS,GAAS,UAAU,GAAG,EAG3D,CAAC,GAAa,KAAkB,EAAM,SAAS,GAAM,EACrD,CAAC,GAAa,KAAkB,EAAM,SAAS,GAAM,EAGrD,IAAoB,EAAkB,EAAK,EAE3C,IACJ,MAAuB,MAAS,SAAS,iBAAiB,gBAEtD,IACJ,EAAK,MAAM,CAAC,SAAS,KACrB,EAAe,EAAK,KACnB,MAAS,WAAW,EAAO,MAAM,CAAC,SAAS,IAGxC,IACJ,KAAe,CAAC,EAAK,MAAM,GAAG,EAAE,EAAQ,sBAAsB,GAAG,KAAA,GAC7D,IAAY,IACb,EAAK,MAAM,GAET,EAAe,EAAK,GAEnB,KAAA,IADA,EAAE,EAAQ,qBAAqB,GAFjC,EAAE,EAAQ,sBAAsB,GAIlC,KAAA;AA4BJ,QACE,kBAAC,QAAD;EACE,eAAa,GAAG,EAAW;EAC3B,WA7BkB,MAA4C;AAEhE,OADA,EAAM,gBAAgB,EAClB,CAAC,GAAW;AAId,IADA,EAAe,GAAK,EACpB,EAAe,GAAK;AACpB;;GAGF,IAAM,IAAU;IACd,MAAM,EAAK,MAAM;IACjB,MAAM,EAAc,EAAK;IACzB,QAAQ,EAAO,MAAM;IACrB;IACD;AAQD,GANI,MAAS,UAAU,IACrB,EAAc,EAAQ,IAAI,EAAQ,GAElC,EAAW,EAAQ,EAGrB,GAAa;;EAOX,WAAU;YAHZ;GAKE,kBAAC,GAAD;IACE,QAAQ,GAAG,EAAW;IACtB,MAAM,GAAG,EAAW;IACpB,MAAK;IACL,OAAO,EAAE,EAAQ,mBAAmB;IACpC,OAAO;IACP,UAAU;IACV,cAAc,EAAe,GAAK;IAClC,aAAY;IACZ,WAAU;IACV,iBAAA;IACA,OAAO;IACP,CAAA;GAEF,kBAAC,GAAD;IACE,QAAQ,GAAG,EAAW;IACtB,MAAM,GAAG,EAAW;IACpB,MAAK;IACL,OAAO,EAAE,EAAQ,mBAAmB;IACpC,OAAO;IACP,UAAU;IACV,cAAc,EAAe,GAAK;IAClC,aAAa;IACb,WAAU;IACV,iBAAA;IACA,OAAO;IACP,CAAA;GAEF,kBAAC,GAAD;IACE,QAAQ,GAAG,EAAW;IACtB,MAAM,GAAG,EAAW;IACpB,MAAK;IACL,OAAO,EAAE,EAAQ,kBAAkB;IACnC,OAAO;IACP,UAAU;IACV,aAAY;IACZ,WAAU;IACV,CAAA;GAED,MAAS,UAAU,KAClB,kBAAC,GAAD;IAA6B;IAAqB;IAAc,CAAA;GAGjE,IACC,EAAc;IAAE;IAAW;IAAY,CAAC,GAExC,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KACE,MAAK;KACL,SAAQ;KACR,SAAS;KACT,QAAQ,GAAG,EAAW;eAErB,EAAE,EAAQ,cAAc;KACb,CAAA,EACd,kBAAC,GAAD;KACE,MAAK;KACL,SAAQ;KACR,YAAY,CAAC;KACb,QAAQ,GAAG,EAAW;eAErB,EAAE,EAAQ,aAAa;KACZ,CAAA,CACV;;GAEH;;;AAWX,SAAS,EAAuB,EAAE,cAAoC;CACpE,IAAM,EAAE,SAAM,EAAe,YAAY,EACnC,EAAE,kBAAe,GAAyB,EAE1C,CAAC,GAAM,KAAW,EAAM,SAAS,GAAG,EACpC,CAAC,GAAM,KAAW,EAAM,SAAS,GAAG,EACpC,CAAC,GAAQ,KAAa,EAAM,SAAS,GAAG,EAExC,IAAoB,EAAkB,EAAK,EAC3C,IACJ,EAAK,MAAM,CAAC,SAAS,KACrB,EAAe,EAAK,KACnB,MAAS,WAAW,EAAO,MAAM,CAAC,SAAS;AAc9C,QACE,kBAAC,QAAD;EACE,eAAY;EACZ,WAfkB,MAAwC;AAC5D,KAAE,gBAAgB,EACb,MACL,EAAW;IACT,MAAM,EAAK,MAAM;IACjB,MAAM,EAAc,EAAK;IACzB,QAAQ,EAAO,MAAM;IACrB;IACD,CAAC,EACF,GAAS;;EAOP,WAAU;YAHZ;GAKE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KACE,QAAO;KACP,MAAK;KACL,MAAK;KACL,OAAO,EAAE,EAAQ,mBAAmB;KACpC,OAAO;KACP,UAAU;KACV,aAAY;KACZ,WAAU;KACV,CAAA,EACF,kBAAC,KAAD;KAAG,WAAU;eACV,EAAE,EAAQ,oBAAoB;KAC7B,CAAA,CACA;;GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KACE,QAAO;KACP,MAAK;KACL,MAAK;KACL,OAAO,EAAE,EAAQ,mBAAmB;KACpC,OAAO;KACP,UAAU;KACV,aAAY;KACZ,WAAU;KACV,CAAA,EACF,kBAAC,KAAD;KACE,WAAU;KACV,eAAY;eAEX,EAAE,EAAQ,oBAAoB;KAC7B,CAAA,CACA;;GAEN,kBAAC,GAAD;IACE,QAAO;IACP,MAAK;IACL,MAAK;IACL,OAAO,EAAE,EAAQ,kBAAkB;IACnC,OAAO;IACP,UAAU;IACV,aAAY;IACZ,WAAU;IACV,CAAA;GAEF,kBAAC,GAAD;IACE,MAAK;IACL,SAAQ;IACR,YAAY,CAAC;IACb,QAAO;IACP,WAAU;cAET,EAAE,EAAQ,gBAAgB;IACf,CAAA;GACT;;;AASX,SAAS,EAAiB,EAAE,cAAoC;CAC9D,IAAM,EAAE,SAAM,EAAe,YAAY,EACnC,EAAE,kBAAe,GAAyB,EAE1C,CAAC,GAAc,KAAmB,EAAM,SAAS,GAAM,EACvD,CAAC,GAAY,KAAiB,EAAM,SAAS,GAAG,EAEhD,IAAgB,EAAW,MAAM,IAAI;AAY3C,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAoB,OAAO;KAAI,QAAQ;KAAI,eAAA;KAAc,CAAA,EAEzD,kBAAC,MAAD;KACE,WAAU;KACV,eAAY;eAEX,EAAE,EAAQ,oBAAoB;KAC5B,CAAA,CACD;;GAEN,kBAAC,KAAD;IAAG,WAAU;cACV,EAAE,EAAQ,0BAA0B;IACnC,CAAA;GAEJ,kBAAC,GAAD;IACE,MAAM;IACN,YA7BsB,MAAmB;AAO7C,KANA,EAAW;MACT,MAAM;MACN,MAAM,EAAc,EAAc;MAClC;MACA,MAAM;MACP,CAAC,EACF,GAAS;;IAuBL,YAAW;IACX,CAAA;GAEF,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,UAAD;KACE,MAAK;KACL,eAAe,GAAiB,MAAS,CAAC,EAAK;KAC/C,iBAAe;KACf,eAAY;KACZ,WAAU;eALZ,CAOE,kBAAC,QAAD,EAAA,UAAO,EAAE,EAAQ,iBAAiB,EAAQ,CAAA,EAC1C,kBAAC,GAAD;MACE,WAAW,EACT,oDACA,KAAgB,aACjB;MACD,eAAA;MACA,CAAA,CACK;QACT,kBAAC,OAAD;KACE,WAAW,EACT,QACA,CAAC,KAAgB,gCAClB;KACD,eAAa,CAAC;eALhB,CAOE,kBAAC,GAAD;MACE,QAAO;MACP,MAAK;MACL,MAAK;MACL,OAAO,EAAE,EAAQ,mBAAmB;MACpC,OAAO;MACP,UAAU;MACV,aAAa;MACb,WAAU;MACV,CAAA,EACF,kBAAC,KAAD;MAAG,WAAU;gBACV,EAAE,EAAQ,yBAAyB;MAClC,CAAA,CACA;OACF;;GACF;;;AAWV,SAAgB,EAAiB,EAC/B,SACA,YACA,cACwB;CACxB,IAAM,EAAE,SAAM,EAAe,YAAY;AAEzC,KAAI,MAAS,MACX,QACE,kBAAC,GAAD;EACW;EACT,eAAe;EACf,cAAY,EAAE,EAAQ,kBAAkB;YAExC,kBAAC,OAAD;GACE,eAAY;GACZ,WAAW,EACT,0EACA,EAAoB,KAAK,EACzB,EACD;aANH;IAQE,kBAAC,GAAD;KAA2B;KAAS,QAAO;KAAsB,CAAA;IAEjE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,MAAD;MAAI,WAAU;gBACX,EAAE,EAAQ,kBAAkB;MAC1B,CAAA;KACD,CAAA;IAGN,kBAAC,OAAD;KAAK,WAAU;eAAf;MAEE,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,GAAD,EAAiC,YAAW,CAAA;OACxC,CAAA;MAGN,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,OAAD,EAAK,WAAU,qCAAsC,CAAA;QACrD,kBAAC,QAAD;SAAM,WAAU;mBACb,EAAE,EAAQ,iBAAiB;SACvB,CAAA;QACP,kBAAC,OAAD,EAAK,WAAU,qCAAsC,CAAA;QACjD;;MAGN,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,GAAD,EAA2B,YAAW,CAAA;OAClC,CAAA;MACF;;IACF;;EACQ,CAAA;CAKpB,IAAM,IAAa;AACnB,QACE,kBAAC,GAAD;EACW;EACT,eAAe;EACf,cAAY,EAAE,EAAQ,mBAAmB;YAEzC,kBAAC,OAAD;GACE,eAAa,GAAG,EAAW;GAC3B,WAAW,EACT,kGACA,EAAoB,KAAK,CAC1B;aALH;IAOE,kBAAC,GAAD;KAA2B;KAAS,QAAQ,GAAG,EAAW;KAAW,CAAA;IACrE,kBAAC,MAAD;KAAI,WAAU;eACX,EAAE,EAAQ,mBAAmB;KAC3B,CAAA;IACL,kBAAC,GAAD;KACE,MAAK;KACI;KACT,aAAa;KACD;KACZ,CAAA;IACE;;EACQ,CAAA"}
1
+ {"version":3,"file":"backend-form-modal.js","names":[],"sources":["../../../../src/components/features/backends/backend-form-modal.tsx"],"sourcesContent":["import React from \"react\";\nimport { useQuery } from \"@tanstack/react-query\";\nimport { useTranslation } from \"react-i18next\";\nimport { ServerClient } from \"@openhands/typescript-client/clients\";\nimport OpenHandsLogoWhite from \"#/assets/branding/openhands-logo-white.svg?react\";\nimport { ModalBackdrop } from \"#/components/shared/modals/modal-backdrop\";\nimport {\n MODAL_MAX_WIDTH_VIEWPORT,\n modalWidthClassName,\n} from \"#/components/shared/modals/modal-body\";\nimport { ModalCloseButton } from \"#/components/shared/modals/modal-close-button\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { SettingsInput } from \"#/components/features/settings/settings-input\";\nimport { useActiveBackendContext } from \"#/contexts/active-backend-context\";\nimport { useNavigation } from \"#/context/navigation-context\";\nimport { useBackendsHealth } from \"#/hooks/query/use-backends-health\";\nimport { getAgentServerClientOptions } from \"#/api/agent-server-client-options\";\nimport ChevronDownSmallIcon from \"#/icons/chevron-down-small.svg?react\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport type { Backend, BackendKind } from \"#/api/backend-registry/types\";\nimport { cn } from \"#/utils/utils\";\nimport { BackendStatusDot } from \"./backend-status-dot\";\nimport { DeviceFlowAuth } from \"./device-flow-auth\";\n\nexport type BackendFormMode = \"add\" | \"edit\";\n\ninterface BackendFormModalProps {\n mode: BackendFormMode;\n /** Required when `mode === \"edit\"`. */\n backend?: Backend;\n onClose: () => void;\n}\n\nfunction inferKindFromHost(host: string): BackendKind {\n const trimmed = host.trim().toLowerCase();\n if (trimmed.includes(\"all-hands.dev\") || trimmed.includes(\"openhands.dev\")) {\n return \"cloud\";\n }\n return \"local\";\n}\n\n/**\n * Returns true for hostnames that represent a local / private-network address.\n * Used by normalizeHost to choose http:// instead of https://.\n */\nfunction isLocalAddress(hostname: string): boolean {\n // Strip IPv6 bracket notation: [::1] → ::1\n const h = hostname.toLowerCase().replace(/^\\[|\\]$/g, \"\");\n // IPv6 loopback, any-address, and named loopback\n if (h === \"localhost\" || h === \"::1\" || h === \"::\" || h === \"0.0.0.0\")\n return true;\n // 127.x.x.x loopback range + IPv4-mapped loopback (::ffff:127.x.x.x)\n if (/^127\\./.test(h) || /^::ffff:127\\./i.test(h)) return true;\n // RFC 1918 private ranges\n if (/^10\\./.test(h)) return true;\n if (/^192\\.168\\./.test(h)) return true;\n if (/^172\\.(1[6-9]|2\\d|3[01])\\./.test(h)) return true;\n // IPv6 link-local (fe80::/10) and unique local (fc00::/7)\n if (/^fe[89ab][0-9a-f]:/i.test(h)) return true;\n if (/^f[cd][0-9a-f]{2}:/i.test(h)) return true;\n // mDNS / Bonjour (.local)\n if (h.endsWith(\".local\")) return true;\n // Single-label hostnames (no dots, no colons) are local network names.\n // Colons are excluded so bare IPv6 addresses don't accidentally match.\n if (!h.includes(\".\") && !h.includes(\":\")) return true;\n return false;\n}\n\nfunction normalizeHost(host: string): string {\n const trimmed = host.trim().replace(/\\/+$/, \"\");\n if (!trimmed) return \"\";\n // Already has an explicit scheme — respect it.\n if (/^https?:\\/\\//i.test(trimmed)) return trimmed;\n // Extract the pure hostname for scheme selection, handling three cases:\n // [::1]:8080 → bracket IPv6 notation → extract ::1\n // ::1 → bare IPv6 (multiple colons, no bracket) → whole string\n // host:port → regular host:port → part before the colon\n const bracketMatch = trimmed.match(/^\\[([^\\]]+)\\]/);\n const hostname = bracketMatch\n ? bracketMatch[1]\n : (trimmed.match(/:/g) ?? []).length > 1\n ? trimmed\n : trimmed.split(\":\")[0];\n const scheme = isLocalAddress(hostname) ? \"http\" : \"https\";\n return `${scheme}://${trimmed}`;\n}\n\n/**\n * Returns true when `host` represents a reachable backend URL.\n *\n * Rules (applied in order):\n * 1. Must be non-empty after trimming.\n * 2. Must contain no whitespace — spaces can never appear in a host/port.\n * 3. After normalisation (bare hosts get `https://` prepended), must parse\n * as a valid http or https URL with a non-empty hostname.\n */\nfunction isValidHostUrl(host: string): boolean {\n const trimmed = host.trim();\n if (!trimmed) return false;\n // Spaces anywhere in the input are an immediate rejection.\n if (/\\s/.test(trimmed)) return false;\n const normalized = normalizeHost(trimmed);\n if (!normalized) return false;\n try {\n const url = new URL(normalized);\n return (\n (url.protocol === \"http:\" || url.protocol === \"https:\") &&\n url.hostname.length > 0\n );\n } catch {\n return false;\n }\n}\n\nconst DEFAULT_OPENHANDS_CLOUD_HOST = \"https://app.all-hands.dev\";\n\n/**\n * Live status row for the edit form: shows a connection dot, a\n * \"Local\"/\"Cloud\" label, and the agent server's reported version when\n * available. Replaces the legacy local/cloud radio fieldset (kind is\n * now inferred from the host).\n */\nfunction BackendStatusBadge({\n backend,\n testIdRoot,\n}: {\n backend: Backend;\n testIdRoot: string;\n}) {\n const { t } = useTranslation(\"openhands\");\n const healthByBackendId = useBackendsHealth([backend]);\n const health = healthByBackendId[backend.id];\n const isConnected = health?.isConnected ?? null;\n const disabled = health?.disabled === true;\n const consecutiveFailures = health?.consecutiveFailures ?? 0;\n const lastError = health?.lastError ?? null;\n\n const { data: version } = useQuery({\n queryKey: [\"backend-version\", backend.host, backend.apiKey],\n queryFn: async () => {\n const info = await new ServerClient(\n getAgentServerClientOptions({\n host: backend.host,\n sessionApiKey: backend.apiKey || null,\n timeout: 5000,\n }),\n ).getServerInfo();\n return info.version ?? null;\n },\n retry: false,\n staleTime: 60_000,\n enabled: backend.kind === \"local\" && !disabled,\n });\n\n let statusLabel: string;\n if (isConnected === true) {\n statusLabel = t(I18nKey.ONBOARDING$BACKEND_STATUS_CONNECTED);\n } else if (isConnected === false) {\n statusLabel = t(I18nKey.ONBOARDING$BACKEND_STATUS_DISCONNECTED);\n } else {\n statusLabel = t(I18nKey.ONBOARDING$BACKEND_STATUS_CHECKING);\n }\n\n const kindLabel =\n backend.kind === \"cloud\"\n ? t(I18nKey.BACKEND$KIND_CLOUD)\n : t(I18nKey.BACKEND$KIND_LOCAL);\n\n return (\n <div className=\"flex flex-col gap-2\">\n <div\n data-testid={`${testIdRoot}-status`}\n className=\"flex items-center gap-3 text-sm\"\n >\n <BackendStatusDot isConnected={isConnected} />\n <span className=\"text-white\" data-testid={`${testIdRoot}-status-label`}>\n {statusLabel}\n </span>\n <span className=\"text-tertiary-alt\">·</span>\n <span className=\"text-[var(--oh-text-tertiary)]\">{kindLabel}</span>\n {version ? (\n <span\n className=\"text-xs text-[var(--oh-muted)]\"\n data-testid={`${testIdRoot}-version`}\n >\n {t(I18nKey.BACKEND$VERSION_LABEL, { version })}\n </span>\n ) : null}\n </div>\n\n {disabled ? (\n <div\n data-testid={`${testIdRoot}-status-error`}\n className=\"flex flex-col gap-1 rounded-md border border-red-500/40 bg-red-500/10 p-3 text-sm\"\n >\n <span className=\"font-semibold text-red-300\">\n {t(I18nKey.BACKEND$HEALTH_FAILED_TITLE)}\n </span>\n <span className=\"text-xs text-[var(--oh-text-tertiary)]\">\n {t(I18nKey.BACKEND$HEALTH_FAILED_DETAIL, {\n count: consecutiveFailures,\n })}\n </span>\n {lastError ? (\n <span\n data-testid={`${testIdRoot}-status-error-message`}\n className=\"text-xs text-red-300 whitespace-pre-wrap break-words\"\n >\n {lastError}\n </span>\n ) : null}\n </div>\n ) : null}\n </div>\n );\n}\n\nexport interface BackendFormProps {\n mode: BackendFormMode;\n /** Required when `mode === \"edit\"`. */\n backend?: Backend;\n /**\n * Called after the form is submitted and the backend has been\n * persisted. Use this to dismiss a containing modal, advance an\n * onboarding step, etc.\n */\n onSubmitted: () => void;\n /**\n * Optional render slot rendered in place of the default\n * Save / Cancel button row, so callers (e.g. the onboarding flow)\n * can re-skin the action area while still owning submission via the\n * standard `<form onSubmit>` flow. Receives the form's submit-ready\n * state.\n */\n renderActions?: (state: {\n canSubmit: boolean;\n testIdRoot: string;\n }) => React.ReactNode;\n /** Used to disambiguate test ids across the same screen. */\n testIdRoot?: string;\n}\n\n/**\n * Reusable form body for adding / editing a backend. Renders the\n * common name / host / API-key inputs plus the kind selector\n * (radio buttons in `add` mode, status badge in `edit` mode).\n *\n * Rendered as a `<form>`, so consumers should put any extra controls\n * either inside `renderActions` or as siblings inside a wrapping\n * element — but submission flows through the standard form submit so\n * Enter-to-submit still works.\n */\nexport function BackendForm({\n mode,\n backend,\n onSubmitted,\n renderActions,\n testIdRoot: explicitTestIdRoot,\n}: BackendFormProps) {\n const { t } = useTranslation(\"openhands\");\n const { addBackend, updateBackend } = useActiveBackendContext();\n\n const [name, setName] = React.useState(backend?.name ?? \"\");\n const [host, setHost] = React.useState(backend?.host ?? \"\");\n const [apiKey, setApiKey] = React.useState(backend?.apiKey ?? \"\");\n\n // Inline validation: only show errors after the user has left a field.\n const [nameTouched, setNameTouched] = React.useState(false);\n const [hostTouched, setHostTouched] = React.useState(false);\n\n // Kind is inferred from the host on every change.\n const kind: BackendKind = inferKindFromHost(host);\n\n const testIdRoot =\n explicitTestIdRoot ?? (mode === \"edit\" ? \"edit-backend\" : \"add-backend\");\n\n const canSubmit =\n name.trim().length > 0 &&\n isValidHostUrl(host) &&\n (kind === \"local\" || apiKey.trim().length > 0);\n\n // Error messages — only surfaced after the user has blurred the field.\n const nameError =\n nameTouched && !name.trim() ? t(I18nKey.BACKEND$NAME_REQUIRED) : undefined;\n const hostError = hostTouched\n ? !host.trim()\n ? t(I18nKey.BACKEND$HOST_REQUIRED)\n : !isValidHostUrl(host)\n ? t(I18nKey.BACKEND$HOST_INVALID)\n : undefined\n : undefined;\n\n const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n if (!canSubmit) {\n // Mark all validated fields as touched so inline errors become visible\n // (e.g. user pressed Enter before filling required fields).\n setNameTouched(true);\n setHostTouched(true);\n return;\n }\n\n const payload = {\n name: name.trim(),\n host: normalizeHost(host),\n apiKey: apiKey.trim(),\n kind,\n };\n\n if (mode === \"edit\" && backend) {\n updateBackend(backend.id, payload);\n } else {\n addBackend(payload);\n }\n\n onSubmitted();\n };\n\n return (\n <form\n data-testid={`${testIdRoot}-form`}\n onSubmit={handleSubmit}\n className=\"flex flex-col gap-4\"\n >\n <SettingsInput\n testId={`${testIdRoot}-name`}\n name={`${testIdRoot}-name`}\n type=\"text\"\n label={t(I18nKey.BACKEND$NAME_LABEL)}\n value={name}\n onChange={setName}\n onBlur={() => setNameTouched(true)}\n placeholder=\"Production\"\n className=\"w-full\"\n showRequiredTag\n error={nameError}\n />\n\n <SettingsInput\n testId={`${testIdRoot}-host`}\n name={`${testIdRoot}-host`}\n type=\"text\"\n label={t(I18nKey.BACKEND$HOST_LABEL)}\n value={host}\n onChange={setHost}\n onBlur={() => setHostTouched(true)}\n placeholder={DEFAULT_OPENHANDS_CLOUD_HOST}\n className=\"w-full\"\n showRequiredTag\n error={hostError}\n />\n\n <SettingsInput\n testId={`${testIdRoot}-api-key`}\n name={`${testIdRoot}-api-key`}\n type=\"password\"\n label={t(I18nKey.BACKEND$KEY_LABEL)}\n value={apiKey}\n onChange={setApiKey}\n placeholder=\"\"\n className=\"w-full\"\n />\n\n {mode === \"edit\" && backend && (\n <BackendStatusBadge backend={backend} testIdRoot={testIdRoot} />\n )}\n\n {renderActions ? (\n renderActions({ canSubmit, testIdRoot })\n ) : (\n <div className=\"flex justify-end gap-2 mt-2 w-full\">\n <BrandButton\n type=\"button\"\n variant=\"secondary\"\n onClick={onSubmitted}\n testId={`${testIdRoot}-cancel`}\n >\n {t(I18nKey.BUTTON$CANCEL)}\n </BrandButton>\n <BrandButton\n type=\"submit\"\n variant=\"primary\"\n isDisabled={!canSubmit}\n testId={`${testIdRoot}-submit`}\n >\n {t(I18nKey.BACKEND$SAVE)}\n </BrandButton>\n </div>\n )}\n </form>\n );\n}\n\n// ── Add-mode two-column layout ──────────────────────────────────────\n\n/**\n * @spec BM-002 — Adding a backend auto-switches the active selection to it\n * (BM-001), so a backend-scoped detail page the user is viewing now belongs\n * to the previous backend. Redirect to that section's list so they never see\n * stale data, mirroring the switch-backend redirect in BackendSelector.\n */\nfunction useRedirectAfterAddBackend() {\n const { currentPath, navigate } = useNavigation();\n return React.useCallback(() => {\n if (/^\\/automations\\/[^/]+/.test(currentPath)) navigate(\"/automations\");\n else if (/^\\/conversations\\/[^/]+/.test(currentPath))\n navigate(\"/conversations\");\n }, [currentPath, navigate]);\n}\n\n/**\n * Left column of the \"Add a Backend\" modal: manual connection via\n * Host + API Key. Designed for self-hosted agent servers and\n * self-hosted OpenHands Cloud with API key auth.\n */\nfunction ManualConnectionColumn({ onClose }: { onClose: () => void }) {\n const { t } = useTranslation(\"openhands\");\n const { addBackend } = useActiveBackendContext();\n const redirectAfterAdd = useRedirectAfterAddBackend();\n\n const [name, setName] = React.useState(\"\");\n const [host, setHost] = React.useState(\"\");\n const [apiKey, setApiKey] = React.useState(\"\");\n\n const kind: BackendKind = inferKindFromHost(host);\n const canSubmit =\n name.trim().length > 0 &&\n isValidHostUrl(host) &&\n (kind === \"local\" || apiKey.trim().length > 0);\n\n const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {\n e.preventDefault();\n if (!canSubmit) return;\n addBackend({\n name: name.trim(),\n host: normalizeHost(host),\n apiKey: apiKey.trim(),\n kind,\n });\n redirectAfterAdd();\n onClose();\n };\n\n return (\n <form\n data-testid=\"add-backend-form\"\n onSubmit={handleSubmit}\n className=\"flex flex-col gap-4 flex-1 min-w-0\"\n >\n <div className=\"flex flex-col gap-1\">\n <SettingsInput\n testId=\"add-backend-name\"\n name=\"add-backend-name\"\n type=\"text\"\n label={t(I18nKey.BACKEND$NAME_LABEL)}\n value={name}\n onChange={setName}\n placeholder=\"e.g. My Server\"\n className=\"w-full\"\n />\n <p className=\"text-xs text-[var(--oh-muted)]\">\n {t(I18nKey.BACKEND$NAME_HELPER)}\n </p>\n </div>\n\n <div className=\"flex flex-col gap-1\">\n <SettingsInput\n testId=\"add-backend-host\"\n name=\"add-backend-host\"\n type=\"text\"\n label={t(I18nKey.BACKEND$HOST_LABEL)}\n value={host}\n onChange={setHost}\n placeholder=\"http://localhost:8000\"\n className=\"w-full\"\n />\n <p\n className=\"text-xs text-[var(--oh-muted)]\"\n data-testid=\"add-backend-host-helper\"\n >\n {t(I18nKey.BACKEND$HOST_HELPER)}\n </p>\n </div>\n\n <SettingsInput\n testId=\"add-backend-api-key\"\n name=\"add-backend-api-key\"\n type=\"password\"\n label={t(I18nKey.BACKEND$KEY_LABEL)}\n value={apiKey}\n onChange={setApiKey}\n placeholder=\"sk-••••••••••\"\n className=\"w-full\"\n />\n\n <BrandButton\n type=\"submit\"\n variant=\"secondary\"\n isDisabled={!canSubmit}\n testId=\"add-backend-submit\"\n className=\"w-full text-center\"\n >\n {t(I18nKey.BACKEND$CONNECT)}\n </BrandButton>\n </form>\n );\n}\n\n/**\n * Right column of the \"Add a Backend\" modal: one-click OAuth login\n * with OpenHands Cloud. Includes an \"Advanced\" disclosure for\n * users who self-host OpenHands Cloud and need to override the host.\n */\nfunction CloudLoginColumn({ onClose }: { onClose: () => void }) {\n const { t } = useTranslation(\"openhands\");\n const { addBackend } = useActiveBackendContext();\n const redirectAfterAdd = useRedirectAfterAddBackend();\n\n const [advancedOpen, setAdvancedOpen] = React.useState(false);\n const [customHost, setCustomHost] = React.useState(\"\");\n\n const effectiveHost = customHost.trim() || DEFAULT_OPENHANDS_CLOUD_HOST;\n\n const handleLoginSuccess = (apiKey: string) => {\n addBackend({\n name: \"OpenHands Cloud\",\n host: normalizeHost(effectiveHost),\n apiKey,\n kind: \"cloud\",\n });\n redirectAfterAdd();\n onClose();\n };\n\n return (\n <div className=\"flex flex-1 min-w-0 flex-col items-center gap-3\">\n <div className=\"flex flex-col items-center gap-1\">\n <OpenHandsLogoWhite width={56} height={56} aria-hidden />\n\n <h4\n className=\"text-lg font-medium text-white\"\n data-testid=\"add-backend-cloud-title\"\n >\n {t(I18nKey.BACKEND$CLOUD_TITLE)}\n </h4>\n </div>\n\n <p className=\"text-center text-sm leading-relaxed text-[var(--oh-muted)]\">\n {t(I18nKey.BACKEND$CLOUD_DESCRIPTION)}\n </p>\n\n <DeviceFlowAuth\n host={effectiveHost}\n onSuccess={handleLoginSuccess}\n testIdRoot=\"add-backend\"\n />\n\n <div className=\"w-full\">\n <button\n type=\"button\"\n onClick={() => setAdvancedOpen((open) => !open)}\n aria-expanded={advancedOpen}\n data-testid=\"add-backend-advanced-toggle\"\n className=\"flex w-full cursor-pointer items-center justify-center gap-1 text-center text-xs text-[var(--oh-muted)] transition-colors hover:text-content-2\"\n >\n <span>{t(I18nKey.BACKEND$ADVANCED)}</span>\n <ChevronDownSmallIcon\n className={cn(\n \"h-4 w-4 shrink-0 text-muted transition-transform\",\n advancedOpen && \"rotate-180\",\n )}\n aria-hidden\n />\n </button>\n <div\n className={cn(\n \"pt-2\",\n !advancedOpen && \"pointer-events-none invisible\",\n )}\n aria-hidden={!advancedOpen}\n >\n <SettingsInput\n testId=\"add-backend-cloud-host\"\n name=\"add-backend-cloud-host\"\n type=\"text\"\n label={t(I18nKey.BACKEND$HOST_LABEL)}\n value={customHost}\n onChange={setCustomHost}\n placeholder={DEFAULT_OPENHANDS_CLOUD_HOST}\n className=\"w-full\"\n />\n <p className=\"mt-1 text-xs text-[var(--oh-muted)]\">\n {t(I18nKey.BACKEND$LOGIN_CLOUD_HINT)}\n </p>\n </div>\n </div>\n </div>\n );\n}\n\n// ── Modal wrappers ──────────────────────────────────────────────────\n\n/**\n * Modal wrapper. In **add** mode it renders a two-column layout\n * (manual connection | OR | Cloud login). In **edit** mode it wraps\n * the standard `BackendForm`.\n */\nexport function BackendFormModal({\n mode,\n backend,\n onClose,\n}: BackendFormModalProps) {\n const { t } = useTranslation(\"openhands\");\n\n if (mode === \"add\") {\n return (\n <ModalBackdrop\n onClose={onClose}\n closeOnEscape={false}\n aria-label={t(I18nKey.BACKEND$ADD_TITLE)}\n >\n <div\n data-testid=\"add-backend-modal\"\n className={cn(\n \"relative rounded-xl border border-[var(--oh-border)] bg-base-secondary\",\n modalWidthClassName(\"xl\"),\n MODAL_MAX_WIDTH_VIEWPORT,\n )}\n >\n <ModalCloseButton onClose={onClose} testId=\"add-backend-close\" />\n {/* Header */}\n <div className=\"px-6 pt-6 pb-2 pr-12\">\n <h2 className=\"text-lg font-semibold\">\n {t(I18nKey.BACKEND$ADD_TITLE)}\n </h2>\n </div>\n\n {/* Two-column body */}\n <div className=\"flex gap-6 px-6 pb-6 pt-2\">\n {/* Left: manual connection */}\n <div className=\"flex-1 min-w-0\">\n <ManualConnectionColumn onClose={onClose} />\n </div>\n\n {/* Vertical OR divider */}\n <div className=\"flex shrink-0 flex-col items-center\">\n <div className=\"flex-1 w-px bg-[var(--oh-border)]\" />\n <span className=\"py-3 text-xs uppercase text-[var(--oh-muted)]\">\n {t(I18nKey.BACKEND$LOGIN_OR)}\n </span>\n <div className=\"flex-1 w-px bg-[var(--oh-border)]\" />\n </div>\n\n {/* Right: cloud login */}\n <div className=\"flex-1 min-w-0\">\n <CloudLoginColumn onClose={onClose} />\n </div>\n </div>\n </div>\n </ModalBackdrop>\n );\n }\n\n // Edit mode — single-column form (unchanged)\n const testIdRoot = \"edit-backend\";\n return (\n <ModalBackdrop\n onClose={onClose}\n closeOnEscape={false}\n aria-label={t(I18nKey.BACKEND$EDIT_TITLE)}\n >\n <div\n data-testid={`${testIdRoot}-modal`}\n className={cn(\n \"relative bg-base-secondary p-6 rounded-xl flex flex-col gap-4 border border-[var(--oh-border)]\",\n modalWidthClassName(\"md\"),\n )}\n >\n <ModalCloseButton onClose={onClose} testId={`${testIdRoot}-close`} />\n <h2 className=\"pr-6 text-lg font-semibold\">\n {t(I18nKey.BACKEND$EDIT_TITLE)}\n </h2>\n <BackendForm\n mode=\"edit\"\n backend={backend}\n onSubmitted={onClose}\n testIdRoot={testIdRoot}\n />\n </div>\n </ModalBackdrop>\n );\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const e=require(`../../../_virtual/_rolldown/runtime.cjs`),t=require(`../../../node_modules/react-i18next/dist/es/useTranslation.cjs`),n=require(`../../../i18n/declaration.cjs`),r=require(`../../../types/agent-state.cjs`),i=require(`../../../utils/utils.cjs`),a=require(`../../../stores/conversation-store.cjs`),o=require(`../../../node_modules/@tanstack/react-query/build/modern/QueryClientProvider.cjs`),s=require(`../../../hooks/query/use-active-conversation.cjs`),c=require(`../../../hooks/use-agent-state.cjs`),l=require(`../../../hooks/use-unified-websocket-status.cjs`),u=require(`../../../hooks/query/use-sub-conversation-task-polling.cjs`),d=require(`../../../ui/typography.cjs`),f=require(`../../../ui/combobox-caret.cjs`),p=require(`../../../icons/lesson-plan.cjs`),m=require(`../../../icons/code-pill.cjs`),h=require(`./change-agent-context-menu.cjs`),g=require(`../../../hooks/use-handle-plan-click.cjs`);let _=require(`react`);_=e.__toESM(_,1);let v=require(`react/jsx-runtime`);function y(){let[e,y]=(0,_.useState)(!1),{conversationMode:b,setConversationMode:x,subConversationTaskId:S}=a.useConversationStore(),C=l.useUnifiedWebSocketStatus()===`OPEN`,{curAgentState:w}=c.useAgentState(),{t:T}=t.useTranslation(`openhands`),E=w===r.AgentState.RUNNING,{data:D}=s.useActiveConversation(),O=o.useQueryClient(),k=(0,_.useRef)(null),{taskStatus:A,subConversationId:j}=u.useSubConversationTaskPolling(S,D?.id||null);(0,_.useEffect)(()=>{A===`READY`&&j&&D?.id&&S&&k.current!==S&&(k.current=S,O.invalidateQueries({queryKey:[`user`,`conversation`,D.id]}))},[A,j,D?.id,S,O]);let{handlePlanClick:M,isCreatingConversation:N}=g.useHandlePlanClick();(0,_.useEffect)(()=>{(E||!C)&&e&&y(!1)},[E,e,C]);let P=E||N||!C;(0,_.useEffect)(()=>{if(P)return;let e=e=>{if(e.shiftKey&&e.key===`Tab`){e.preventDefault(),e.stopPropagation();let t=b===`code`?`plan`:`code`;t===`plan`?M(e):x(t)}};return document.addEventListener(`keydown`,e),()=>{document.removeEventListener(`keydown`,e)}},[P,b,x,M]);let F=t=>{t.preventDefault(),t.stopPropagation(),y(!e)},I=e=>{e.preventDefault(),e.stopPropagation(),x(`code`)},L=b===`code`,R=(0,_.useMemo)(()=>T(L?n.I18nKey.COMMON$CODE:n.I18nKey.COMMON$PLAN),[L,T]),z=(0,_.useMemo)(()=>L?(0,v.jsx)(m.CodePillIcon,{className:`h-[11px] w-[11px] shrink-0`}):(0,v.jsx)(p.default,{width:18,height:18,color:`currentColor`}),[L]);return(0,v.jsxs)(`div`,{className:`relative`,children:[(0,v.jsxs)(`button`,{type:`button`,onClick:F,disabled:P,className:i.cn(`flex items-center rounded-[100px] transition-[border-color,color,opacity]`,L?`border border-transparent text-[var(--oh-muted)]`:`border border-[#597FF4] bg-[#4A67BD]`,!P&&L&&`cursor-pointer hover:text-white hover:bg-white/10`,!P&&!L&&`cursor-pointer text-white hover:bg-white/10`,P&&i.cn(`opacity-50 cursor-not-allowed`,L&&`border-transparent`)),children:[(0,v.jsxs)(`div`,{className:`flex items-center gap-1 pl-1.5`,children:[z,(0,v.jsx)(d.Typography.Text,{className:`text-2.75 not-italic font-normal leading-5`,children:R})]}),(0,v.jsx)(f.ComboboxCaretInline,{isOpen:e})]}),e&&(0,v.jsx)(h.ChangeAgentContextMenu,{onClose:()=>y(!1),onCodeClick:I,onPlanClick:M})]})}exports.ChangeAgentButton=y;
1
+ const e=require(`../../../_virtual/_rolldown/runtime.cjs`),t=require(`../../../node_modules/react-i18next/dist/es/useTranslation.cjs`),n=require(`../../../i18n/declaration.cjs`),r=require(`../../../types/agent-state.cjs`),i=require(`../../../utils/utils.cjs`),a=require(`../../../hooks/use-conversation-id.cjs`),o=require(`../../../stores/conversation-store.cjs`),s=require(`../../../node_modules/@tanstack/react-query/build/modern/QueryClientProvider.cjs`),c=require(`../../../hooks/query/use-active-conversation.cjs`),l=require(`../../../hooks/use-agent-state.cjs`),u=require(`../../shared/buttons/styled-tooltip.cjs`),d=require(`../../../hooks/use-unified-websocket-status.cjs`),f=require(`../../../hooks/query/use-sub-conversation-task-polling.cjs`),p=require(`../../../ui/typography.cjs`),m=require(`../../../ui/combobox-caret.cjs`),h=require(`../../../icons/lesson-plan.cjs`),g=require(`../../../icons/code-pill.cjs`),_=require(`./change-agent-context-menu.cjs`),v=require(`../../../hooks/use-handle-plan-click.cjs`);let y=require(`react`);y=e.__toESM(y,1);let b=require(`react/jsx-runtime`);function x(){let[e,x]=(0,y.useState)(!1),{conversationMode:S,setConversationMode:C,subConversationTaskId:w}=o.useConversationStore(),{conversationId:T}=a.useOptionalConversationId(),E=!T,D=d.useUnifiedWebSocketStatus()===`OPEN`,{curAgentState:O}=l.useAgentState(),{t:k}=t.useTranslation(`openhands`),A=O===r.AgentState.RUNNING,{data:j}=c.useActiveConversation(),M=s.useQueryClient(),N=(0,y.useRef)(null),{taskStatus:P,subConversationId:F}=f.useSubConversationTaskPolling(w,j?.id||null);(0,y.useEffect)(()=>{P===`READY`&&F&&j?.id&&w&&N.current!==w&&(N.current=w,M.invalidateQueries({queryKey:[`user`,`conversation`,j.id]}))},[P,F,j?.id,w,M]);let{handlePlanClick:I,isCreatingConversation:L}=v.useHandlePlanClick();(0,y.useEffect)(()=>{(A||!D)&&e&&x(!1)},[A,e,D]);let R=E||A||L||!D;(0,y.useEffect)(()=>{if(R)return;let e=e=>{if(e.shiftKey&&e.key===`Tab`){e.preventDefault(),e.stopPropagation();let t=S===`code`?`plan`:`code`;t===`plan`?I(e):C(t)}};return document.addEventListener(`keydown`,e),()=>{document.removeEventListener(`keydown`,e)}},[R,S,C,I]);let z=t=>{t.preventDefault(),t.stopPropagation(),x(!e)},B=e=>{e.preventDefault(),e.stopPropagation(),C(`code`)},V=S===`code`,H=(0,y.useMemo)(()=>k(V?n.I18nKey.COMMON$CODE:n.I18nKey.COMMON$PLAN),[V,k]),U=(0,y.useMemo)(()=>V?(0,b.jsx)(g.CodePillIcon,{className:`h-[11px] w-[11px] shrink-0`}):(0,b.jsx)(h.default,{width:18,height:18,color:`currentColor`}),[V]),W=(0,b.jsxs)(`div`,{className:`relative`,children:[(0,b.jsxs)(`button`,{type:`button`,onClick:z,disabled:R,className:i.cn(`flex items-center rounded-[100px] transition-[border-color,color,opacity]`,V?`border border-transparent text-[var(--oh-muted)]`:`border border-[#597FF4] bg-[#4A67BD]`,!R&&V&&`cursor-pointer hover:text-white hover:bg-white/10`,!R&&!V&&`cursor-pointer text-white hover:bg-white/10`,R&&i.cn(`opacity-50 cursor-not-allowed`,V&&`border-transparent`)),children:[(0,b.jsxs)(`div`,{className:`flex items-center gap-1 pl-1.5`,children:[U,(0,b.jsx)(p.Typography.Text,{className:`text-2.75 not-italic font-normal leading-5`,children:H})]}),(0,b.jsx)(m.ComboboxCaretInline,{isOpen:e})]}),e&&(0,b.jsx)(_.ChangeAgentContextMenu,{onClose:()=>x(!1),onCodeClick:B,onPlanClick:I})]});return E?(0,b.jsx)(u.StyledTooltip,{content:k(n.I18nKey.CHANGE_AGENT$SWITCH_AFTER_CONVERSATION),placement:`top`,children:W}):W}exports.ChangeAgentButton=x;
2
2
  //# sourceMappingURL=change-agent-button.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"change-agent-button.cjs","names":[],"sources":["../../../../src/components/features/chat/change-agent-button.tsx"],"sourcesContent":["import React, { useMemo, useEffect, useState, useRef } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { Typography } from \"#/ui/typography\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { ComboboxCaretInline } from \"#/ui/combobox-caret\";\nimport LessonPlanIcon from \"#/icons/lesson-plan.svg?react\";\nimport { CodePillIcon } from \"#/icons/code-pill\";\nimport { useConversationStore } from \"#/stores/conversation-store\";\nimport { ChangeAgentContextMenu } from \"./change-agent-context-menu\";\nimport { cn } from \"#/utils/utils\";\nimport { useAgentState } from \"#/hooks/use-agent-state\";\nimport { AgentState } from \"#/types/agent-state\";\nimport { useActiveConversation } from \"#/hooks/query/use-active-conversation\";\nimport { useUnifiedWebSocketStatus } from \"#/hooks/use-unified-websocket-status\";\nimport { useSubConversationTaskPolling } from \"#/hooks/query/use-sub-conversation-task-polling\";\nimport { useHandlePlanClick } from \"#/hooks/use-handle-plan-click\";\n\nexport function ChangeAgentButton() {\n const [contextMenuOpen, setContextMenuOpen] = useState<boolean>(false);\n\n const { conversationMode, setConversationMode, subConversationTaskId } =\n useConversationStore();\n\n const webSocketStatus = useUnifiedWebSocketStatus();\n\n const isWebSocketConnected = webSocketStatus === \"OPEN\";\n\n const { curAgentState } = useAgentState();\n\n const { t } = useTranslation(\"openhands\");\n\n const isAgentRunning = curAgentState === AgentState.RUNNING;\n\n const { data: conversation } = useActiveConversation();\n\n const queryClient = useQueryClient();\n\n // Track the last invalidated task ID to prevent duplicate invalidations\n const lastInvalidatedTaskIdRef = useRef<string | null>(null);\n\n // Poll sub-conversation task status\n const { taskStatus, subConversationId } = useSubConversationTaskPolling(\n subConversationTaskId,\n conversation?.id || null,\n );\n\n // Invalidate parent conversation cache when task is ready (only once per task)\n useEffect(() => {\n if (\n taskStatus === \"READY\" &&\n subConversationId &&\n conversation?.id &&\n subConversationTaskId &&\n lastInvalidatedTaskIdRef.current !== subConversationTaskId\n ) {\n // Mark this task as invalidated to prevent duplicate calls\n lastInvalidatedTaskIdRef.current = subConversationTaskId;\n // Invalidate the parent conversation to refetch with updated sub_conversation_ids\n queryClient.invalidateQueries({\n queryKey: [\"user\", \"conversation\", conversation.id],\n });\n }\n }, [\n taskStatus,\n subConversationId,\n conversation?.id,\n subConversationTaskId,\n queryClient,\n ]);\n\n // Get handlePlanClick and isCreatingConversation from custom hook\n const { handlePlanClick, isCreatingConversation } = useHandlePlanClick();\n\n // Close context menu when agent starts running\n useEffect(() => {\n if ((isAgentRunning || !isWebSocketConnected) && contextMenuOpen) {\n setContextMenuOpen(false);\n }\n }, [isAgentRunning, contextMenuOpen, isWebSocketConnected]);\n\n const isButtonDisabled =\n isAgentRunning || isCreatingConversation || !isWebSocketConnected;\n\n // Handle Shift + Tab keyboard shortcut to cycle through modes\n useEffect(() => {\n if (isButtonDisabled) {\n return undefined;\n }\n\n const handleKeyDown = (event: KeyboardEvent) => {\n // Check for Shift + Tab combination\n if (event.shiftKey && event.key === \"Tab\") {\n // Prevent default tab navigation behavior\n event.preventDefault();\n event.stopPropagation();\n\n // Cycle between modes: code -> plan -> code\n const nextMode = conversationMode === \"code\" ? \"plan\" : \"code\";\n if (nextMode === \"plan\") {\n handlePlanClick(event);\n } else {\n setConversationMode(nextMode);\n }\n }\n };\n\n document.addEventListener(\"keydown\", handleKeyDown);\n\n return () => {\n document.removeEventListener(\"keydown\", handleKeyDown);\n };\n }, [\n isButtonDisabled,\n conversationMode,\n setConversationMode,\n handlePlanClick,\n ]);\n\n const handleButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n event.stopPropagation();\n setContextMenuOpen(!contextMenuOpen);\n };\n\n const handleCodeClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n event.stopPropagation();\n setConversationMode(\"code\");\n };\n\n const isExecutionAgent = conversationMode === \"code\";\n\n const buttonLabel = useMemo(() => {\n if (isExecutionAgent) {\n return t(I18nKey.COMMON$CODE);\n }\n return t(I18nKey.COMMON$PLAN);\n }, [isExecutionAgent, t]);\n\n const buttonIcon = useMemo(() => {\n if (isExecutionAgent) {\n return <CodePillIcon className=\"h-[11px] w-[11px] shrink-0\" />;\n }\n return <LessonPlanIcon width={18} height={18} color=\"currentColor\" />;\n }, [isExecutionAgent]);\n\n return (\n <div className=\"relative\">\n <button\n type=\"button\"\n onClick={handleButtonClick}\n disabled={isButtonDisabled}\n className={cn(\n \"flex items-center rounded-[100px] transition-[border-color,color,opacity]\",\n isExecutionAgent\n ? \"border border-transparent text-[var(--oh-muted)]\"\n : \"border border-[#597FF4] bg-[#4A67BD]\",\n !isButtonDisabled &&\n isExecutionAgent &&\n \"cursor-pointer hover:text-white hover:bg-white/10\",\n !isButtonDisabled &&\n !isExecutionAgent &&\n \"cursor-pointer text-white hover:bg-white/10\",\n isButtonDisabled &&\n cn(\n \"opacity-50 cursor-not-allowed\",\n isExecutionAgent && \"border-transparent\",\n ),\n )}\n >\n <div className=\"flex items-center gap-1 pl-1.5\">\n {buttonIcon}\n <Typography.Text className=\"text-2.75 not-italic font-normal leading-5\">\n {buttonLabel}\n </Typography.Text>\n </div>\n <ComboboxCaretInline isOpen={contextMenuOpen} />\n </button>\n {contextMenuOpen && (\n <ChangeAgentContextMenu\n onClose={() => setContextMenuOpen(false)}\n onCodeClick={handleCodeClick}\n onPlanClick={handlePlanClick}\n />\n )}\n </div>\n );\n}\n"],"mappings":"i+BAkBA,SAAgB,GAAoB,CAClC,GAAM,CAAC,EAAiB,IAAA,EAAA,EAAA,UAAwC,GAAM,CAEhE,CAAE,mBAAkB,sBAAqB,yBAC7C,EAAA,sBAAsB,CAIlB,EAFkB,EAAA,2BAEK,GAAoB,OAE3C,CAAE,iBAAkB,EAAA,eAAe,CAEnC,CAAE,KAAM,EAAA,eAAe,YAAY,CAEnC,EAAiB,IAAkB,EAAA,WAAW,QAE9C,CAAE,KAAM,GAAiB,EAAA,uBAAuB,CAEhD,EAAc,EAAA,gBAAgB,CAG9B,GAAA,EAAA,EAAA,QAAiD,KAAK,CAGtD,CAAE,aAAY,qBAAsB,EAAA,8BACxC,EACA,GAAc,IAAM,KACrB,EAGD,EAAA,EAAA,eAAgB,CAEZ,IAAe,SACf,GACA,GAAc,IACd,GACA,EAAyB,UAAY,IAGrC,EAAyB,QAAU,EAEnC,EAAY,kBAAkB,CAC5B,SAAU,CAAC,OAAQ,eAAgB,EAAa,GAAG,CACpD,CAAC,GAEH,CACD,EACA,EACA,GAAc,GACd,EACA,EACD,CAAC,CAGF,GAAM,CAAE,kBAAiB,0BAA2B,EAAA,oBAAoB,EAGxE,EAAA,EAAA,eAAgB,EACT,GAAkB,CAAC,IAAyB,GAC/C,EAAmB,GAAM,EAE1B,CAAC,EAAgB,EAAiB,EAAqB,CAAC,CAE3D,IAAM,EACJ,GAAkB,GAA0B,CAAC,GAG/C,EAAA,EAAA,eAAgB,CACd,GAAI,EACF,OAGF,IAAM,EAAiB,GAAyB,CAE9C,GAAI,EAAM,UAAY,EAAM,MAAQ,MAAO,CAEzC,EAAM,gBAAgB,CACtB,EAAM,iBAAiB,CAGvB,IAAM,EAAW,IAAqB,OAAS,OAAS,OACpD,IAAa,OACf,EAAgB,EAAM,CAEtB,EAAoB,EAAS,GAOnC,OAFA,SAAS,iBAAiB,UAAW,EAAc,KAEtC,CACX,SAAS,oBAAoB,UAAW,EAAc,GAEvD,CACD,EACA,EACA,EACA,EACD,CAAC,CAEF,IAAM,EAAqB,GAA+C,CACxE,EAAM,gBAAgB,CACtB,EAAM,iBAAiB,CACvB,EAAmB,CAAC,EAAgB,EAGhC,EAAmB,GAA+C,CACtE,EAAM,gBAAgB,CACtB,EAAM,iBAAiB,CACvB,EAAoB,OAAO,EAGvB,EAAmB,IAAqB,OAExC,GAAA,EAAA,EAAA,aAEK,EADL,EACO,EAAA,QAAQ,YAEV,EAAA,QAAQ,YAFc,CAG9B,CAAC,EAAkB,EAAE,CAAC,CAEnB,GAAA,EAAA,EAAA,aACA,GACK,EAAA,EAAA,KAAC,EAAA,aAAD,CAAc,UAAU,6BAA+B,CAAA,EAEzD,EAAA,EAAA,KAAC,EAAA,QAAD,CAAgB,MAAO,GAAI,OAAQ,GAAI,MAAM,eAAiB,CAAA,CACpE,CAAC,EAAiB,CAAC,CAEtB,OACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,oBAAf,EACE,EAAA,EAAA,MAAC,SAAD,CACE,KAAK,SACL,QAAS,EACT,SAAU,EACV,UAAW,EAAA,GACT,4EACA,EACI,mDACA,uCACJ,CAAC,GACC,GACA,oDACF,CAAC,GACC,CAAC,GACD,8CACF,GACE,EAAA,GACE,gCACA,GAAoB,qBACrB,CACJ,UApBH,EAsBE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,0CAAf,CACG,GACD,EAAA,EAAA,KAAC,EAAA,WAAW,KAAZ,CAAiB,UAAU,sDACxB,EACe,CAAA,CACd,IACN,EAAA,EAAA,KAAC,EAAA,oBAAD,CAAqB,OAAQ,EAAmB,CAAA,CACzC,GACR,IACC,EAAA,EAAA,KAAC,EAAA,uBAAD,CACE,YAAe,EAAmB,GAAM,CACxC,YAAa,EACb,YAAa,EACb,CAAA,CAEA"}
1
+ {"version":3,"file":"change-agent-button.cjs","names":[],"sources":["../../../../src/components/features/chat/change-agent-button.tsx"],"sourcesContent":["import React, { useMemo, useEffect, useState, useRef } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { Typography } from \"#/ui/typography\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { ComboboxCaretInline } from \"#/ui/combobox-caret\";\nimport LessonPlanIcon from \"#/icons/lesson-plan.svg?react\";\nimport { CodePillIcon } from \"#/icons/code-pill\";\nimport { useConversationStore } from \"#/stores/conversation-store\";\nimport { ChangeAgentContextMenu } from \"./change-agent-context-menu\";\nimport { cn } from \"#/utils/utils\";\nimport { useAgentState } from \"#/hooks/use-agent-state\";\nimport { AgentState } from \"#/types/agent-state\";\nimport { useActiveConversation } from \"#/hooks/query/use-active-conversation\";\nimport { useUnifiedWebSocketStatus } from \"#/hooks/use-unified-websocket-status\";\nimport { useSubConversationTaskPolling } from \"#/hooks/query/use-sub-conversation-task-polling\";\nimport { useHandlePlanClick } from \"#/hooks/use-handle-plan-click\";\nimport { useOptionalConversationId } from \"#/hooks/use-conversation-id\";\nimport { StyledTooltip } from \"#/components/shared/buttons/styled-tooltip\";\n\nexport function ChangeAgentButton() {\n const [contextMenuOpen, setContextMenuOpen] = useState<boolean>(false);\n\n const { conversationMode, setConversationMode, subConversationTaskId } =\n useConversationStore();\n\n const { conversationId } = useOptionalConversationId();\n\n const isHomePage = !conversationId;\n\n const webSocketStatus = useUnifiedWebSocketStatus();\n\n const isWebSocketConnected = webSocketStatus === \"OPEN\";\n\n const { curAgentState } = useAgentState();\n\n const { t } = useTranslation(\"openhands\");\n\n const isAgentRunning = curAgentState === AgentState.RUNNING;\n\n const { data: conversation } = useActiveConversation();\n\n const queryClient = useQueryClient();\n\n // Track the last invalidated task ID to prevent duplicate invalidations\n const lastInvalidatedTaskIdRef = useRef<string | null>(null);\n\n // Poll sub-conversation task status\n const { taskStatus, subConversationId } = useSubConversationTaskPolling(\n subConversationTaskId,\n conversation?.id || null,\n );\n\n // Invalidate parent conversation cache when task is ready (only once per task)\n useEffect(() => {\n if (\n taskStatus === \"READY\" &&\n subConversationId &&\n conversation?.id &&\n subConversationTaskId &&\n lastInvalidatedTaskIdRef.current !== subConversationTaskId\n ) {\n // Mark this task as invalidated to prevent duplicate calls\n lastInvalidatedTaskIdRef.current = subConversationTaskId;\n // Invalidate the parent conversation to refetch with updated sub_conversation_ids\n queryClient.invalidateQueries({\n queryKey: [\"user\", \"conversation\", conversation.id],\n });\n }\n }, [\n taskStatus,\n subConversationId,\n conversation?.id,\n subConversationTaskId,\n queryClient,\n ]);\n\n // Get handlePlanClick and isCreatingConversation from custom hook\n const { handlePlanClick, isCreatingConversation } = useHandlePlanClick();\n\n // Close context menu when agent starts running\n useEffect(() => {\n if ((isAgentRunning || !isWebSocketConnected) && contextMenuOpen) {\n setContextMenuOpen(false);\n }\n }, [isAgentRunning, contextMenuOpen, isWebSocketConnected]);\n\n const isButtonDisabled =\n isHomePage ||\n isAgentRunning ||\n isCreatingConversation ||\n !isWebSocketConnected;\n\n // Handle Shift + Tab keyboard shortcut to cycle through modes\n useEffect(() => {\n if (isButtonDisabled) {\n return undefined;\n }\n\n const handleKeyDown = (event: KeyboardEvent) => {\n // Check for Shift + Tab combination\n if (event.shiftKey && event.key === \"Tab\") {\n // Prevent default tab navigation behavior\n event.preventDefault();\n event.stopPropagation();\n\n // Cycle between modes: code -> plan -> code\n const nextMode = conversationMode === \"code\" ? \"plan\" : \"code\";\n if (nextMode === \"plan\") {\n handlePlanClick(event);\n } else {\n setConversationMode(nextMode);\n }\n }\n };\n\n document.addEventListener(\"keydown\", handleKeyDown);\n\n return () => {\n document.removeEventListener(\"keydown\", handleKeyDown);\n };\n }, [\n isButtonDisabled,\n conversationMode,\n setConversationMode,\n handlePlanClick,\n ]);\n\n const handleButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n event.stopPropagation();\n setContextMenuOpen(!contextMenuOpen);\n };\n\n const handleCodeClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n event.stopPropagation();\n setConversationMode(\"code\");\n };\n\n const isExecutionAgent = conversationMode === \"code\";\n\n const buttonLabel = useMemo(() => {\n if (isExecutionAgent) {\n return t(I18nKey.COMMON$CODE);\n }\n return t(I18nKey.COMMON$PLAN);\n }, [isExecutionAgent, t]);\n\n const buttonIcon = useMemo(() => {\n if (isExecutionAgent) {\n return <CodePillIcon className=\"h-[11px] w-[11px] shrink-0\" />;\n }\n return <LessonPlanIcon width={18} height={18} color=\"currentColor\" />;\n }, [isExecutionAgent]);\n\n const button = (\n <div className=\"relative\">\n <button\n type=\"button\"\n onClick={handleButtonClick}\n disabled={isButtonDisabled}\n className={cn(\n \"flex items-center rounded-[100px] transition-[border-color,color,opacity]\",\n isExecutionAgent\n ? \"border border-transparent text-[var(--oh-muted)]\"\n : \"border border-[#597FF4] bg-[#4A67BD]\",\n !isButtonDisabled &&\n isExecutionAgent &&\n \"cursor-pointer hover:text-white hover:bg-white/10\",\n !isButtonDisabled &&\n !isExecutionAgent &&\n \"cursor-pointer text-white hover:bg-white/10\",\n isButtonDisabled &&\n cn(\n \"opacity-50 cursor-not-allowed\",\n isExecutionAgent && \"border-transparent\",\n ),\n )}\n >\n <div className=\"flex items-center gap-1 pl-1.5\">\n {buttonIcon}\n <Typography.Text className=\"text-2.75 not-italic font-normal leading-5\">\n {buttonLabel}\n </Typography.Text>\n </div>\n <ComboboxCaretInline isOpen={contextMenuOpen} />\n </button>\n {contextMenuOpen && (\n <ChangeAgentContextMenu\n onClose={() => setContextMenuOpen(false)}\n onCodeClick={handleCodeClick}\n onPlanClick={handlePlanClick}\n />\n )}\n </div>\n );\n\n if (isHomePage) {\n return (\n <StyledTooltip\n content={t(I18nKey.CHANGE_AGENT$SWITCH_AFTER_CONVERSATION)}\n placement=\"top\"\n >\n {button}\n </StyledTooltip>\n );\n }\n\n return button;\n}\n"],"mappings":"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"}
@@ -2,94 +2,100 @@ import { useTranslation as e } from "../../../node_modules/react-i18next/dist/es
2
2
  import { I18nKey as t } from "../../../i18n/declaration.js";
3
3
  import { AgentState as n } from "../../../types/agent-state.js";
4
4
  import { cn as r } from "../../../utils/utils.js";
5
- import { useConversationStore as i } from "../../../stores/conversation-store.js";
6
- import { useQueryClient as a } from "../../../node_modules/@tanstack/react-query/build/modern/QueryClientProvider.js";
7
- import { useActiveConversation as o } from "../../../hooks/query/use-active-conversation.js";
8
- import { useAgentState as s } from "../../../hooks/use-agent-state.js";
9
- import { useUnifiedWebSocketStatus as c } from "../../../hooks/use-unified-websocket-status.js";
10
- import { useSubConversationTaskPolling as l } from "../../../hooks/query/use-sub-conversation-task-polling.js";
11
- import { Typography as u } from "../../../ui/typography.js";
12
- import { ComboboxCaretInline as d } from "../../../ui/combobox-caret.js";
13
- import f from "../../../icons/lesson-plan.js";
14
- import { CodePillIcon as p } from "../../../icons/code-pill.js";
15
- import { ChangeAgentContextMenu as m } from "./change-agent-context-menu.js";
16
- import { useHandlePlanClick as h } from "../../../hooks/use-handle-plan-click.js";
17
- import { useEffect as g, useMemo as _, useRef as v, useState as y } from "react";
18
- import { jsx as b, jsxs as x } from "react/jsx-runtime";
5
+ import { useOptionalConversationId as i } from "../../../hooks/use-conversation-id.js";
6
+ import { useConversationStore as a } from "../../../stores/conversation-store.js";
7
+ import { useQueryClient as o } from "../../../node_modules/@tanstack/react-query/build/modern/QueryClientProvider.js";
8
+ import { useActiveConversation as s } from "../../../hooks/query/use-active-conversation.js";
9
+ import { useAgentState as c } from "../../../hooks/use-agent-state.js";
10
+ import { StyledTooltip as l } from "../../shared/buttons/styled-tooltip.js";
11
+ import { useUnifiedWebSocketStatus as u } from "../../../hooks/use-unified-websocket-status.js";
12
+ import { useSubConversationTaskPolling as d } from "../../../hooks/query/use-sub-conversation-task-polling.js";
13
+ import { Typography as f } from "../../../ui/typography.js";
14
+ import { ComboboxCaretInline as p } from "../../../ui/combobox-caret.js";
15
+ import m from "../../../icons/lesson-plan.js";
16
+ import { CodePillIcon as h } from "../../../icons/code-pill.js";
17
+ import { ChangeAgentContextMenu as g } from "./change-agent-context-menu.js";
18
+ import { useHandlePlanClick as _ } from "../../../hooks/use-handle-plan-click.js";
19
+ import { useEffect as v, useMemo as y, useRef as b, useState as x } from "react";
20
+ import { jsx as S, jsxs as C } from "react/jsx-runtime";
19
21
  //#region src/components/features/chat/change-agent-button.tsx
20
- function S() {
21
- let [S, C] = y(!1), { conversationMode: w, setConversationMode: T, subConversationTaskId: E } = i(), D = c() === "OPEN", { curAgentState: O } = s(), { t: k } = e("openhands"), A = O === n.RUNNING, { data: j } = o(), M = a(), N = v(null), { taskStatus: P, subConversationId: F } = l(E, j?.id || null);
22
- g(() => {
23
- P === "READY" && F && j?.id && E && N.current !== E && (N.current = E, M.invalidateQueries({ queryKey: [
22
+ function w() {
23
+ let [w, T] = x(!1), { conversationMode: E, setConversationMode: D, subConversationTaskId: O } = a(), { conversationId: k } = i(), A = !k, j = u() === "OPEN", { curAgentState: M } = c(), { t: N } = e("openhands"), P = M === n.RUNNING, { data: F } = s(), I = o(), L = b(null), { taskStatus: R, subConversationId: z } = d(O, F?.id || null);
24
+ v(() => {
25
+ R === "READY" && z && F?.id && O && L.current !== O && (L.current = O, I.invalidateQueries({ queryKey: [
24
26
  "user",
25
27
  "conversation",
26
- j.id
28
+ F.id
27
29
  ] }));
28
30
  }, [
29
- P,
30
- F,
31
- j?.id,
32
- E,
33
- M
31
+ R,
32
+ z,
33
+ F?.id,
34
+ O,
35
+ I
34
36
  ]);
35
- let { handlePlanClick: I, isCreatingConversation: L } = h();
36
- g(() => {
37
- (A || !D) && S && C(!1);
37
+ let { handlePlanClick: B, isCreatingConversation: V } = _();
38
+ v(() => {
39
+ (P || !j) && w && T(!1);
38
40
  }, [
39
- A,
40
- S,
41
- D
41
+ P,
42
+ w,
43
+ j
42
44
  ]);
43
- let R = A || L || !D;
44
- g(() => {
45
- if (R) return;
45
+ let H = A || P || V || !j;
46
+ v(() => {
47
+ if (H) return;
46
48
  let e = (e) => {
47
49
  if (e.shiftKey && e.key === "Tab") {
48
50
  e.preventDefault(), e.stopPropagation();
49
- let t = w === "code" ? "plan" : "code";
50
- t === "plan" ? I(e) : T(t);
51
+ let t = E === "code" ? "plan" : "code";
52
+ t === "plan" ? B(e) : D(t);
51
53
  }
52
54
  };
53
55
  return document.addEventListener("keydown", e), () => {
54
56
  document.removeEventListener("keydown", e);
55
57
  };
56
58
  }, [
57
- R,
58
- w,
59
- T,
60
- I
59
+ H,
60
+ E,
61
+ D,
62
+ B
61
63
  ]);
62
- let z = (e) => {
63
- e.preventDefault(), e.stopPropagation(), C(!S);
64
- }, B = (e) => {
65
- e.preventDefault(), e.stopPropagation(), T("code");
66
- }, V = w === "code", H = _(() => k(V ? t.COMMON$CODE : t.COMMON$PLAN), [V, k]), U = _(() => V ? /* @__PURE__ */ b(p, { className: "h-[11px] w-[11px] shrink-0" }) : /* @__PURE__ */ b(f, {
64
+ let U = (e) => {
65
+ e.preventDefault(), e.stopPropagation(), T(!w);
66
+ }, W = (e) => {
67
+ e.preventDefault(), e.stopPropagation(), D("code");
68
+ }, G = E === "code", K = y(() => N(G ? t.COMMON$CODE : t.COMMON$PLAN), [G, N]), q = y(() => G ? /* @__PURE__ */ S(h, { className: "h-[11px] w-[11px] shrink-0" }) : /* @__PURE__ */ S(m, {
67
69
  width: 18,
68
70
  height: 18,
69
71
  color: "currentColor"
70
- }), [V]);
71
- return /* @__PURE__ */ x("div", {
72
+ }), [G]), J = /* @__PURE__ */ C("div", {
72
73
  className: "relative",
73
- children: [/* @__PURE__ */ x("button", {
74
+ children: [/* @__PURE__ */ C("button", {
74
75
  type: "button",
75
- onClick: z,
76
- disabled: R,
77
- className: r("flex items-center rounded-[100px] transition-[border-color,color,opacity]", V ? "border border-transparent text-[var(--oh-muted)]" : "border border-[#597FF4] bg-[#4A67BD]", !R && V && "cursor-pointer hover:text-white hover:bg-white/10", !R && !V && "cursor-pointer text-white hover:bg-white/10", R && r("opacity-50 cursor-not-allowed", V && "border-transparent")),
78
- children: [/* @__PURE__ */ x("div", {
76
+ onClick: U,
77
+ disabled: H,
78
+ className: r("flex items-center rounded-[100px] transition-[border-color,color,opacity]", G ? "border border-transparent text-[var(--oh-muted)]" : "border border-[#597FF4] bg-[#4A67BD]", !H && G && "cursor-pointer hover:text-white hover:bg-white/10", !H && !G && "cursor-pointer text-white hover:bg-white/10", H && r("opacity-50 cursor-not-allowed", G && "border-transparent")),
79
+ children: [/* @__PURE__ */ C("div", {
79
80
  className: "flex items-center gap-1 pl-1.5",
80
- children: [U, /* @__PURE__ */ b(u.Text, {
81
+ children: [q, /* @__PURE__ */ S(f.Text, {
81
82
  className: "text-2.75 not-italic font-normal leading-5",
82
- children: H
83
+ children: K
83
84
  })]
84
- }), /* @__PURE__ */ b(d, { isOpen: S })]
85
- }), S && /* @__PURE__ */ b(m, {
86
- onClose: () => C(!1),
87
- onCodeClick: B,
88
- onPlanClick: I
85
+ }), /* @__PURE__ */ S(p, { isOpen: w })]
86
+ }), w && /* @__PURE__ */ S(g, {
87
+ onClose: () => T(!1),
88
+ onCodeClick: W,
89
+ onPlanClick: B
89
90
  })]
90
91
  });
92
+ return A ? /* @__PURE__ */ S(l, {
93
+ content: N(t.CHANGE_AGENT$SWITCH_AFTER_CONVERSATION),
94
+ placement: "top",
95
+ children: J
96
+ }) : J;
91
97
  }
92
98
  //#endregion
93
- export { S as ChangeAgentButton };
99
+ export { w as ChangeAgentButton };
94
100
 
95
101
  //# sourceMappingURL=change-agent-button.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"change-agent-button.js","names":[],"sources":["../../../../src/components/features/chat/change-agent-button.tsx"],"sourcesContent":["import React, { useMemo, useEffect, useState, useRef } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { Typography } from \"#/ui/typography\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { ComboboxCaretInline } from \"#/ui/combobox-caret\";\nimport LessonPlanIcon from \"#/icons/lesson-plan.svg?react\";\nimport { CodePillIcon } from \"#/icons/code-pill\";\nimport { useConversationStore } from \"#/stores/conversation-store\";\nimport { ChangeAgentContextMenu } from \"./change-agent-context-menu\";\nimport { cn } from \"#/utils/utils\";\nimport { useAgentState } from \"#/hooks/use-agent-state\";\nimport { AgentState } from \"#/types/agent-state\";\nimport { useActiveConversation } from \"#/hooks/query/use-active-conversation\";\nimport { useUnifiedWebSocketStatus } from \"#/hooks/use-unified-websocket-status\";\nimport { useSubConversationTaskPolling } from \"#/hooks/query/use-sub-conversation-task-polling\";\nimport { useHandlePlanClick } from \"#/hooks/use-handle-plan-click\";\n\nexport function ChangeAgentButton() {\n const [contextMenuOpen, setContextMenuOpen] = useState<boolean>(false);\n\n const { conversationMode, setConversationMode, subConversationTaskId } =\n useConversationStore();\n\n const webSocketStatus = useUnifiedWebSocketStatus();\n\n const isWebSocketConnected = webSocketStatus === \"OPEN\";\n\n const { curAgentState } = useAgentState();\n\n const { t } = useTranslation(\"openhands\");\n\n const isAgentRunning = curAgentState === AgentState.RUNNING;\n\n const { data: conversation } = useActiveConversation();\n\n const queryClient = useQueryClient();\n\n // Track the last invalidated task ID to prevent duplicate invalidations\n const lastInvalidatedTaskIdRef = useRef<string | null>(null);\n\n // Poll sub-conversation task status\n const { taskStatus, subConversationId } = useSubConversationTaskPolling(\n subConversationTaskId,\n conversation?.id || null,\n );\n\n // Invalidate parent conversation cache when task is ready (only once per task)\n useEffect(() => {\n if (\n taskStatus === \"READY\" &&\n subConversationId &&\n conversation?.id &&\n subConversationTaskId &&\n lastInvalidatedTaskIdRef.current !== subConversationTaskId\n ) {\n // Mark this task as invalidated to prevent duplicate calls\n lastInvalidatedTaskIdRef.current = subConversationTaskId;\n // Invalidate the parent conversation to refetch with updated sub_conversation_ids\n queryClient.invalidateQueries({\n queryKey: [\"user\", \"conversation\", conversation.id],\n });\n }\n }, [\n taskStatus,\n subConversationId,\n conversation?.id,\n subConversationTaskId,\n queryClient,\n ]);\n\n // Get handlePlanClick and isCreatingConversation from custom hook\n const { handlePlanClick, isCreatingConversation } = useHandlePlanClick();\n\n // Close context menu when agent starts running\n useEffect(() => {\n if ((isAgentRunning || !isWebSocketConnected) && contextMenuOpen) {\n setContextMenuOpen(false);\n }\n }, [isAgentRunning, contextMenuOpen, isWebSocketConnected]);\n\n const isButtonDisabled =\n isAgentRunning || isCreatingConversation || !isWebSocketConnected;\n\n // Handle Shift + Tab keyboard shortcut to cycle through modes\n useEffect(() => {\n if (isButtonDisabled) {\n return undefined;\n }\n\n const handleKeyDown = (event: KeyboardEvent) => {\n // Check for Shift + Tab combination\n if (event.shiftKey && event.key === \"Tab\") {\n // Prevent default tab navigation behavior\n event.preventDefault();\n event.stopPropagation();\n\n // Cycle between modes: code -> plan -> code\n const nextMode = conversationMode === \"code\" ? \"plan\" : \"code\";\n if (nextMode === \"plan\") {\n handlePlanClick(event);\n } else {\n setConversationMode(nextMode);\n }\n }\n };\n\n document.addEventListener(\"keydown\", handleKeyDown);\n\n return () => {\n document.removeEventListener(\"keydown\", handleKeyDown);\n };\n }, [\n isButtonDisabled,\n conversationMode,\n setConversationMode,\n handlePlanClick,\n ]);\n\n const handleButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n event.stopPropagation();\n setContextMenuOpen(!contextMenuOpen);\n };\n\n const handleCodeClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n event.stopPropagation();\n setConversationMode(\"code\");\n };\n\n const isExecutionAgent = conversationMode === \"code\";\n\n const buttonLabel = useMemo(() => {\n if (isExecutionAgent) {\n return t(I18nKey.COMMON$CODE);\n }\n return t(I18nKey.COMMON$PLAN);\n }, [isExecutionAgent, t]);\n\n const buttonIcon = useMemo(() => {\n if (isExecutionAgent) {\n return <CodePillIcon className=\"h-[11px] w-[11px] shrink-0\" />;\n }\n return <LessonPlanIcon width={18} height={18} color=\"currentColor\" />;\n }, [isExecutionAgent]);\n\n return (\n <div className=\"relative\">\n <button\n type=\"button\"\n onClick={handleButtonClick}\n disabled={isButtonDisabled}\n className={cn(\n \"flex items-center rounded-[100px] transition-[border-color,color,opacity]\",\n isExecutionAgent\n ? \"border border-transparent text-[var(--oh-muted)]\"\n : \"border border-[#597FF4] bg-[#4A67BD]\",\n !isButtonDisabled &&\n isExecutionAgent &&\n \"cursor-pointer hover:text-white hover:bg-white/10\",\n !isButtonDisabled &&\n !isExecutionAgent &&\n \"cursor-pointer text-white hover:bg-white/10\",\n isButtonDisabled &&\n cn(\n \"opacity-50 cursor-not-allowed\",\n isExecutionAgent && \"border-transparent\",\n ),\n )}\n >\n <div className=\"flex items-center gap-1 pl-1.5\">\n {buttonIcon}\n <Typography.Text className=\"text-2.75 not-italic font-normal leading-5\">\n {buttonLabel}\n </Typography.Text>\n </div>\n <ComboboxCaretInline isOpen={contextMenuOpen} />\n </button>\n {contextMenuOpen && (\n <ChangeAgentContextMenu\n onClose={() => setContextMenuOpen(false)}\n onCodeClick={handleCodeClick}\n onPlanClick={handlePlanClick}\n />\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAkBA,SAAgB,IAAoB;CAClC,IAAM,CAAC,GAAiB,KAAsB,EAAkB,GAAM,EAEhE,EAAE,qBAAkB,wBAAqB,6BAC7C,GAAsB,EAIlB,IAFkB,GAEK,KAAoB,QAE3C,EAAE,qBAAkB,GAAe,EAEnC,EAAE,SAAM,EAAe,YAAY,EAEnC,IAAiB,MAAkB,EAAW,SAE9C,EAAE,MAAM,MAAiB,GAAuB,EAEhD,IAAc,GAAgB,EAG9B,IAA2B,EAAsB,KAAK,EAGtD,EAAE,eAAY,yBAAsB,EACxC,GACA,GAAc,MAAM,KACrB;AAGD,SAAgB;AACd,EACE,MAAe,WACf,KACA,GAAc,MACd,KACA,EAAyB,YAAY,MAGrC,EAAyB,UAAU,GAEnC,EAAY,kBAAkB,EAC5B,UAAU;GAAC;GAAQ;GAAgB,EAAa;GAAG,EACpD,CAAC;IAEH;EACD;EACA;EACA,GAAc;EACd;EACA;EACD,CAAC;CAGF,IAAM,EAAE,oBAAiB,8BAA2B,GAAoB;AAGxE,SAAgB;AACd,GAAK,KAAkB,CAAC,MAAyB,KAC/C,EAAmB,GAAM;IAE1B;EAAC;EAAgB;EAAiB;EAAqB,CAAC;CAE3D,IAAM,IACJ,KAAkB,KAA0B,CAAC;AAG/C,SAAgB;AACd,MAAI,EACF;EAGF,IAAM,KAAiB,MAAyB;AAE9C,OAAI,EAAM,YAAY,EAAM,QAAQ,OAAO;AAGzC,IADA,EAAM,gBAAgB,EACtB,EAAM,iBAAiB;IAGvB,IAAM,IAAW,MAAqB,SAAS,SAAS;AACxD,IAAI,MAAa,SACf,EAAgB,EAAM,GAEtB,EAAoB,EAAS;;;AAOnC,SAFA,SAAS,iBAAiB,WAAW,EAAc,QAEtC;AACX,YAAS,oBAAoB,WAAW,EAAc;;IAEvD;EACD;EACA;EACA;EACA;EACD,CAAC;CAEF,IAAM,KAAqB,MAA+C;AAGxE,EAFA,EAAM,gBAAgB,EACtB,EAAM,iBAAiB,EACvB,EAAmB,CAAC,EAAgB;IAGhC,KAAmB,MAA+C;AAGtE,EAFA,EAAM,gBAAgB,EACtB,EAAM,iBAAiB,EACvB,EAAoB,OAAO;IAGvB,IAAmB,MAAqB,QAExC,IAAc,QAET,EADL,IACO,EAAQ,cAEV,EAAQ,YAFc,EAG9B,CAAC,GAAkB,EAAE,CAAC,EAEnB,IAAa,QACb,IACK,kBAAC,GAAD,EAAc,WAAU,8BAA+B,CAAA,GAEzD,kBAAC,GAAD;EAAgB,OAAO;EAAI,QAAQ;EAAI,OAAM;EAAiB,CAAA,EACpE,CAAC,EAAiB,CAAC;AAEtB,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,UAAD;GACE,MAAK;GACL,SAAS;GACT,UAAU;GACV,WAAW,EACT,6EACA,IACI,qDACA,wCACJ,CAAC,KACC,KACA,qDACF,CAAC,KACC,CAAC,KACD,+CACF,KACE,EACE,iCACA,KAAoB,qBACrB,CACJ;aApBH,CAsBE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACG,GACD,kBAAC,EAAW,MAAZ;KAAiB,WAAU;eACxB;KACe,CAAA,CACd;OACN,kBAAC,GAAD,EAAqB,QAAQ,GAAmB,CAAA,CACzC;MACR,KACC,kBAAC,GAAD;GACE,eAAe,EAAmB,GAAM;GACxC,aAAa;GACb,aAAa;GACb,CAAA,CAEA"}
1
+ {"version":3,"file":"change-agent-button.js","names":[],"sources":["../../../../src/components/features/chat/change-agent-button.tsx"],"sourcesContent":["import React, { useMemo, useEffect, useState, useRef } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { Typography } from \"#/ui/typography\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { ComboboxCaretInline } from \"#/ui/combobox-caret\";\nimport LessonPlanIcon from \"#/icons/lesson-plan.svg?react\";\nimport { CodePillIcon } from \"#/icons/code-pill\";\nimport { useConversationStore } from \"#/stores/conversation-store\";\nimport { ChangeAgentContextMenu } from \"./change-agent-context-menu\";\nimport { cn } from \"#/utils/utils\";\nimport { useAgentState } from \"#/hooks/use-agent-state\";\nimport { AgentState } from \"#/types/agent-state\";\nimport { useActiveConversation } from \"#/hooks/query/use-active-conversation\";\nimport { useUnifiedWebSocketStatus } from \"#/hooks/use-unified-websocket-status\";\nimport { useSubConversationTaskPolling } from \"#/hooks/query/use-sub-conversation-task-polling\";\nimport { useHandlePlanClick } from \"#/hooks/use-handle-plan-click\";\nimport { useOptionalConversationId } from \"#/hooks/use-conversation-id\";\nimport { StyledTooltip } from \"#/components/shared/buttons/styled-tooltip\";\n\nexport function ChangeAgentButton() {\n const [contextMenuOpen, setContextMenuOpen] = useState<boolean>(false);\n\n const { conversationMode, setConversationMode, subConversationTaskId } =\n useConversationStore();\n\n const { conversationId } = useOptionalConversationId();\n\n const isHomePage = !conversationId;\n\n const webSocketStatus = useUnifiedWebSocketStatus();\n\n const isWebSocketConnected = webSocketStatus === \"OPEN\";\n\n const { curAgentState } = useAgentState();\n\n const { t } = useTranslation(\"openhands\");\n\n const isAgentRunning = curAgentState === AgentState.RUNNING;\n\n const { data: conversation } = useActiveConversation();\n\n const queryClient = useQueryClient();\n\n // Track the last invalidated task ID to prevent duplicate invalidations\n const lastInvalidatedTaskIdRef = useRef<string | null>(null);\n\n // Poll sub-conversation task status\n const { taskStatus, subConversationId } = useSubConversationTaskPolling(\n subConversationTaskId,\n conversation?.id || null,\n );\n\n // Invalidate parent conversation cache when task is ready (only once per task)\n useEffect(() => {\n if (\n taskStatus === \"READY\" &&\n subConversationId &&\n conversation?.id &&\n subConversationTaskId &&\n lastInvalidatedTaskIdRef.current !== subConversationTaskId\n ) {\n // Mark this task as invalidated to prevent duplicate calls\n lastInvalidatedTaskIdRef.current = subConversationTaskId;\n // Invalidate the parent conversation to refetch with updated sub_conversation_ids\n queryClient.invalidateQueries({\n queryKey: [\"user\", \"conversation\", conversation.id],\n });\n }\n }, [\n taskStatus,\n subConversationId,\n conversation?.id,\n subConversationTaskId,\n queryClient,\n ]);\n\n // Get handlePlanClick and isCreatingConversation from custom hook\n const { handlePlanClick, isCreatingConversation } = useHandlePlanClick();\n\n // Close context menu when agent starts running\n useEffect(() => {\n if ((isAgentRunning || !isWebSocketConnected) && contextMenuOpen) {\n setContextMenuOpen(false);\n }\n }, [isAgentRunning, contextMenuOpen, isWebSocketConnected]);\n\n const isButtonDisabled =\n isHomePage ||\n isAgentRunning ||\n isCreatingConversation ||\n !isWebSocketConnected;\n\n // Handle Shift + Tab keyboard shortcut to cycle through modes\n useEffect(() => {\n if (isButtonDisabled) {\n return undefined;\n }\n\n const handleKeyDown = (event: KeyboardEvent) => {\n // Check for Shift + Tab combination\n if (event.shiftKey && event.key === \"Tab\") {\n // Prevent default tab navigation behavior\n event.preventDefault();\n event.stopPropagation();\n\n // Cycle between modes: code -> plan -> code\n const nextMode = conversationMode === \"code\" ? \"plan\" : \"code\";\n if (nextMode === \"plan\") {\n handlePlanClick(event);\n } else {\n setConversationMode(nextMode);\n }\n }\n };\n\n document.addEventListener(\"keydown\", handleKeyDown);\n\n return () => {\n document.removeEventListener(\"keydown\", handleKeyDown);\n };\n }, [\n isButtonDisabled,\n conversationMode,\n setConversationMode,\n handlePlanClick,\n ]);\n\n const handleButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n event.stopPropagation();\n setContextMenuOpen(!contextMenuOpen);\n };\n\n const handleCodeClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n event.stopPropagation();\n setConversationMode(\"code\");\n };\n\n const isExecutionAgent = conversationMode === \"code\";\n\n const buttonLabel = useMemo(() => {\n if (isExecutionAgent) {\n return t(I18nKey.COMMON$CODE);\n }\n return t(I18nKey.COMMON$PLAN);\n }, [isExecutionAgent, t]);\n\n const buttonIcon = useMemo(() => {\n if (isExecutionAgent) {\n return <CodePillIcon className=\"h-[11px] w-[11px] shrink-0\" />;\n }\n return <LessonPlanIcon width={18} height={18} color=\"currentColor\" />;\n }, [isExecutionAgent]);\n\n const button = (\n <div className=\"relative\">\n <button\n type=\"button\"\n onClick={handleButtonClick}\n disabled={isButtonDisabled}\n className={cn(\n \"flex items-center rounded-[100px] transition-[border-color,color,opacity]\",\n isExecutionAgent\n ? \"border border-transparent text-[var(--oh-muted)]\"\n : \"border border-[#597FF4] bg-[#4A67BD]\",\n !isButtonDisabled &&\n isExecutionAgent &&\n \"cursor-pointer hover:text-white hover:bg-white/10\",\n !isButtonDisabled &&\n !isExecutionAgent &&\n \"cursor-pointer text-white hover:bg-white/10\",\n isButtonDisabled &&\n cn(\n \"opacity-50 cursor-not-allowed\",\n isExecutionAgent && \"border-transparent\",\n ),\n )}\n >\n <div className=\"flex items-center gap-1 pl-1.5\">\n {buttonIcon}\n <Typography.Text className=\"text-2.75 not-italic font-normal leading-5\">\n {buttonLabel}\n </Typography.Text>\n </div>\n <ComboboxCaretInline isOpen={contextMenuOpen} />\n </button>\n {contextMenuOpen && (\n <ChangeAgentContextMenu\n onClose={() => setContextMenuOpen(false)}\n onCodeClick={handleCodeClick}\n onPlanClick={handlePlanClick}\n />\n )}\n </div>\n );\n\n if (isHomePage) {\n return (\n <StyledTooltip\n content={t(I18nKey.CHANGE_AGENT$SWITCH_AFTER_CONVERSATION)}\n placement=\"top\"\n >\n {button}\n </StyledTooltip>\n );\n }\n\n return button;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,IAAoB;CAClC,IAAM,CAAC,GAAiB,KAAsB,EAAkB,GAAM,EAEhE,EAAE,qBAAkB,wBAAqB,6BAC7C,GAAsB,EAElB,EAAE,sBAAmB,GAA2B,EAEhD,IAAa,CAAC,GAId,IAFkB,GAEK,KAAoB,QAE3C,EAAE,qBAAkB,GAAe,EAEnC,EAAE,SAAM,EAAe,YAAY,EAEnC,IAAiB,MAAkB,EAAW,SAE9C,EAAE,MAAM,MAAiB,GAAuB,EAEhD,IAAc,GAAgB,EAG9B,IAA2B,EAAsB,KAAK,EAGtD,EAAE,eAAY,yBAAsB,EACxC,GACA,GAAc,MAAM,KACrB;AAGD,SAAgB;AACd,EACE,MAAe,WACf,KACA,GAAc,MACd,KACA,EAAyB,YAAY,MAGrC,EAAyB,UAAU,GAEnC,EAAY,kBAAkB,EAC5B,UAAU;GAAC;GAAQ;GAAgB,EAAa;GAAG,EACpD,CAAC;IAEH;EACD;EACA;EACA,GAAc;EACd;EACA;EACD,CAAC;CAGF,IAAM,EAAE,oBAAiB,8BAA2B,GAAoB;AAGxE,SAAgB;AACd,GAAK,KAAkB,CAAC,MAAyB,KAC/C,EAAmB,GAAM;IAE1B;EAAC;EAAgB;EAAiB;EAAqB,CAAC;CAE3D,IAAM,IACJ,KACA,KACA,KACA,CAAC;AAGH,SAAgB;AACd,MAAI,EACF;EAGF,IAAM,KAAiB,MAAyB;AAE9C,OAAI,EAAM,YAAY,EAAM,QAAQ,OAAO;AAGzC,IADA,EAAM,gBAAgB,EACtB,EAAM,iBAAiB;IAGvB,IAAM,IAAW,MAAqB,SAAS,SAAS;AACxD,IAAI,MAAa,SACf,EAAgB,EAAM,GAEtB,EAAoB,EAAS;;;AAOnC,SAFA,SAAS,iBAAiB,WAAW,EAAc,QAEtC;AACX,YAAS,oBAAoB,WAAW,EAAc;;IAEvD;EACD;EACA;EACA;EACA;EACD,CAAC;CAEF,IAAM,KAAqB,MAA+C;AAGxE,EAFA,EAAM,gBAAgB,EACtB,EAAM,iBAAiB,EACvB,EAAmB,CAAC,EAAgB;IAGhC,KAAmB,MAA+C;AAGtE,EAFA,EAAM,gBAAgB,EACtB,EAAM,iBAAiB,EACvB,EAAoB,OAAO;IAGvB,IAAmB,MAAqB,QAExC,IAAc,QAET,EADL,IACO,EAAQ,cAEV,EAAQ,YAFc,EAG9B,CAAC,GAAkB,EAAE,CAAC,EAEnB,IAAa,QACb,IACK,kBAAC,GAAD,EAAc,WAAU,8BAA+B,CAAA,GAEzD,kBAAC,GAAD;EAAgB,OAAO;EAAI,QAAQ;EAAI,OAAM;EAAiB,CAAA,EACpE,CAAC,EAAiB,CAAC,EAEhB,IACJ,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,UAAD;GACE,MAAK;GACL,SAAS;GACT,UAAU;GACV,WAAW,EACT,6EACA,IACI,qDACA,wCACJ,CAAC,KACC,KACA,qDACF,CAAC,KACC,CAAC,KACD,+CACF,KACE,EACE,iCACA,KAAoB,qBACrB,CACJ;aApBH,CAsBE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACG,GACD,kBAAC,EAAW,MAAZ;KAAiB,WAAU;eACxB;KACe,CAAA,CACd;OACN,kBAAC,GAAD,EAAqB,QAAQ,GAAmB,CAAA,CACzC;MACR,KACC,kBAAC,GAAD;GACE,eAAe,EAAmB,GAAM;GACxC,aAAa;GACb,aAAa;GACb,CAAA,CAEA;;AAcR,QAXI,IAEA,kBAAC,GAAD;EACE,SAAS,EAAE,EAAQ,uCAAuC;EAC1D,WAAU;YAET;EACa,CAAA,GAIb"}
@@ -1,4 +1,4 @@
1
- const e=require(`../../../_virtual/_rolldown/runtime.cjs`),t=require(`../../../node_modules/react-i18next/dist/es/useTranslation.cjs`),n=require(`../../../i18n/declaration.cjs`),r=require(`../../../types/agent-state.cjs`),i=require(`../../../utils/utils.cjs`),a=require(`../../../hooks/use-conversation-id.cjs`),o=require(`../../../stores/conversation-store.cjs`),s=require(`../../../utils/custom-toast-handlers.cjs`),c=require(`../../../node_modules/posthog-js/react/dist/esm/index.cjs`);require(`../../../constants/server-connection-error.cjs`);const l=require(`../../../stores/error-message-store.cjs`),u=require(`../../../stores/optimistic-user-message-store.cjs`),d=require(`../../../stores/model-store.cjs`),f=require(`../../../contexts/conversation-websocket-context.cjs`),p=require(`../../../hooks/use-send-message.cjs`),m=require(`../../../hooks/query/use-active-conversation.cjs`),h=require(`../../../hooks/use-agent-state.cjs`),ee=require(`../../../utils/convert-image-to-base-64.cjs`),te=require(`../../../utils/file-validation.cjs`),g=require(`../../../utils/pending-task-message-link.cjs`),ne=require(`../../../hooks/query/use-task-polling.cjs`),re=require(`../../../services/chat-service.cjs`),ie=require(`./btw-messages.cjs`),ae=require(`./model-messages.cjs`),oe=require(`../../shared/loading-spinner.cjs`),se=require(`./interactive-chat-box.cjs`),ce=require(`../../../hooks/use-filtered-events.cjs`),le=require(`../../../hooks/use-scroll-to-bottom.cjs`),ue=require(`../../../hooks/use-load-older-events.cjs`),de=require(`./typing-indicator.cjs`),fe=require(`./chat-suggestions.cjs`),pe=require(`../../../context/scroll-context.cjs`),me=require(`../../../stores/initial-query-store.cjs`),he=require(`../../../hooks/use-handle-build-plan-click.cjs`),ge=require(`../../shared/buttons/scroll-to-bottom-button.cjs`),_e=require(`./chat-messages-skeleton.cjs`),ve=require(`./error-message-banner.cjs`),ye=require(`../../conversation-events/chat/messages.cjs`),be=require(`./pending-user-messages.cjs`),xe=require(`../../../hooks/mutation/use-unified-upload-files.cjs`),Se=require(`./confirmation-mode-enabled.cjs`),Ce=require(`./chat-status-indicator.cjs`),we=require(`../../../hooks/mutation/use-new-conversation-command.cjs`);let _=require(`react`);_=e.__toESM(_,1);let v=require(`react/jsx-runtime`);function Te(e,t){return e?`github`:t?`replay`:`direct`}function y(){let e=c.usePostHog(),{setMessageToSend:y}=o.useConversationStore(),{errorMessage:b,removeErrorMessage:Ee,setErrorMessage:x}=l.useErrorMessageStore(),{isTask:S,taskStatus:C,taskDetail:De}=ne.useTaskPolling(),w=S,T=f.useConversationWebSocket(),{send:Oe}=p.useSendMessage(),{renderableEvents:E,allConversationEvents:ke,totalEvents:D,hasSubstantiveAgentActions:Ae,userEventsExist:je}=ce.useFilteredEvents(),Me=u.useOptimisticUserMessageStore(e=>e.enqueuePendingMessage),Ne=u.useOptimisticUserMessageStore(e=>e.markPendingMessageError),O=u.useOptimisticUserMessageStore(e=>e.pendingMessages),{t:k}=t.useTranslation(`openhands`),A=_.default.useRef(null),{scrollDomToBottom:j,onChatBodyScroll:M,hitBottom:N,autoScroll:P,setAutoScroll:Pe,setHitBottom:Fe}=le.useScrollToBottom(A),{mutate:Ie,isPending:F}=we.useNewConversationCommand(),{curAgentState:I}=h.useAgentState(),{handleBuildPlanClick:L}=he.useHandleBuildPlanClick(),{data:Le}=m.useActiveConversation(),R=Le?.sandbox_status??null,z=R===`MISSING`||R===`ERROR`,B=I===r.AgentState.RUNNING||I===r.AgentState.LOADING;_.default.useEffect(()=>{if(B)return;let e=e=>{(e.metaKey||e.ctrlKey)&&e.key===`Enter`&&(e.preventDefault(),e.stopPropagation(),L(e),j())};return document.addEventListener(`keydown`,e),()=>{document.removeEventListener(`keydown`,e)}},[B,L,j]);let{selectedRepository:Re,replayJson:V}=me.useInitialQueryStore(),{conversationId:H}=a.useOptionalConversationId(),{mutateAsync:ze}=xe.useUnifiedUploadFiles(),{isLoading:U,hasMore:W,loadOlder:G}=ue.useLoadOlderEvents(H),K=_.default.useRef(null),q=_.default.useCallback(e=>{if(w||U||!W)return;let t=e.scrollTop<=80,r=e.scrollHeight<=e.clientHeight+80;!t&&!r||(K.current={scrollHeight:e.scrollHeight,scrollTop:e.scrollTop},G().catch(e=>{K.current=null,x(e instanceof Error&&e.message?e.message:k(n.I18nKey.ERROR$GENERIC))}))},[W,U,w,G,x,k]),Be=_.default.useCallback(e=>{e.deltaY<0&&e.currentTarget.scrollTop<=0&&q(e.currentTarget)},[q]),J=_.default.useMemo(()=>H?O.some(e=>g.matchesPendingConversationId(H,e.conversationId)):!1,[O,H]),Y=ke.length>0||J||!T?.isLoadingHistory,X=!!H,Z=!Y&&!S,Ve=d.useModelStore(e=>H?(e.entriesByConversation[H]?.length??0)>0:!1),He=async(t,r,i)=>{if(t.trim()===`/new`){if(!H){s.displayErrorToast(k(n.I18nKey.CONVERSATION$CLEAR_NO_ID));return}if(D===0){s.displayErrorToast(k(n.I18nKey.CONVERSATION$CLEAR_EMPTY));return}if(F)return;Ie();return}let a=[...r],o=[...i];D===0?e.capture(`initial_query_submitted`,{entry_point:Te(Re!==null,V!==null),query_character_length:t.length,replay_json_size:V?.length}):e.capture(`user_message_sent`,{session_message_count:D,current_message_length:t.length});let c=te.validateFiles([...a,...o]);if(!c.isValid){s.displayErrorToast(`Error: ${c.errorMessage}`);return}let l=a.map(e=>ee.convertImageToBase64(e)),u=await Promise.all(l),d=new Date().toISOString(),{skipped_files:f,uploaded_files:p}=o.length>0?await ze({conversationId:H,files:o}):{skipped_files:[],uploaded_files:[]};f.forEach(e=>s.displayErrorToast(e.reason));let m=`${k(`CHAT_INTERFACE$AUGMENTED_PROMPT_FILES_TITLE`)}: ${p.join(`
1
+ const e=require(`../../../_virtual/_rolldown/runtime.cjs`),t=require(`../../../node_modules/react-i18next/dist/es/useTranslation.cjs`),n=require(`../../../i18n/declaration.cjs`),r=require(`../../../types/agent-state.cjs`),i=require(`../../../utils/utils.cjs`),a=require(`../../../hooks/use-conversation-id.cjs`),o=require(`../../../stores/conversation-store.cjs`),s=require(`../../../utils/custom-toast-handlers.cjs`),c=require(`../../../node_modules/posthog-js/react/dist/esm/index.cjs`);require(`../../../constants/server-connection-error.cjs`);const l=require(`../../../stores/error-message-store.cjs`),u=require(`../../../stores/optimistic-user-message-store.cjs`),d=require(`../../../stores/model-store.cjs`),f=require(`../../../contexts/conversation-websocket-context.cjs`),p=require(`../../../hooks/use-send-message.cjs`),m=require(`../../../hooks/query/use-active-conversation.cjs`),h=require(`../../../hooks/use-agent-state.cjs`),ee=require(`../../../utils/convert-image-to-base-64.cjs`),te=require(`../../../utils/file-validation.cjs`),g=require(`../../../utils/pending-task-message-link.cjs`),ne=require(`../../../hooks/query/use-task-polling.cjs`),re=require(`../../../services/chat-service.cjs`),ie=require(`./btw-messages.cjs`),ae=require(`./model-messages.cjs`),oe=require(`../../shared/loading-spinner.cjs`),se=require(`../../../hooks/use-scroll-to-bottom.cjs`),ce=require(`../../../context/scroll-context.cjs`),le=require(`./interactive-chat-box.cjs`),ue=require(`../../../hooks/use-filtered-events.cjs`),de=require(`../../../hooks/use-load-older-events.cjs`),fe=require(`./typing-indicator.cjs`),pe=require(`./chat-suggestions.cjs`),me=require(`../../../stores/initial-query-store.cjs`),he=require(`../../../hooks/use-handle-build-plan-click.cjs`),ge=require(`../../shared/buttons/scroll-to-bottom-button.cjs`),_e=require(`./chat-messages-skeleton.cjs`),ve=require(`./error-message-banner.cjs`),ye=require(`../../conversation-events/chat/messages.cjs`),be=require(`./pending-user-messages.cjs`),xe=require(`../../../hooks/mutation/use-unified-upload-files.cjs`),Se=require(`./confirmation-mode-enabled.cjs`),Ce=require(`./chat-status-indicator.cjs`),we=require(`../../../hooks/mutation/use-new-conversation-command.cjs`);let _=require(`react`);_=e.__toESM(_,1);let v=require(`react/jsx-runtime`);function Te(e,t){return e?`github`:t?`replay`:`direct`}function y(){let e=c.usePostHog(),{setMessageToSend:y}=o.useConversationStore(),{errorMessage:b,removeErrorMessage:Ee,setErrorMessage:x}=l.useErrorMessageStore(),{isTask:S,taskStatus:C,taskDetail:De}=ne.useTaskPolling(),w=S,T=f.useConversationWebSocket(),{send:Oe}=p.useSendMessage(),{renderableEvents:E,allConversationEvents:ke,totalEvents:D,hasSubstantiveAgentActions:Ae,userEventsExist:je}=ue.useFilteredEvents(),Me=u.useOptimisticUserMessageStore(e=>e.enqueuePendingMessage),Ne=u.useOptimisticUserMessageStore(e=>e.markPendingMessageError),O=u.useOptimisticUserMessageStore(e=>e.pendingMessages),{t:k}=t.useTranslation(`openhands`),A=_.default.useRef(null),{scrollDomToBottom:j,onChatBodyScroll:M,hitBottom:N,autoScroll:P,setAutoScroll:Pe,setHitBottom:Fe}=se.useScrollToBottom(A),{mutate:Ie,isPending:F}=we.useNewConversationCommand(),{curAgentState:I}=h.useAgentState(),{handleBuildPlanClick:L}=he.useHandleBuildPlanClick(),{data:Le}=m.useActiveConversation(),R=Le?.sandbox_status??null,z=R===`MISSING`||R===`ERROR`,B=I===r.AgentState.RUNNING||I===r.AgentState.LOADING;_.default.useEffect(()=>{if(B)return;let e=e=>{(e.metaKey||e.ctrlKey)&&e.key===`Enter`&&(e.preventDefault(),e.stopPropagation(),L(e),j())};return document.addEventListener(`keydown`,e),()=>{document.removeEventListener(`keydown`,e)}},[B,L,j]);let{selectedRepository:Re,replayJson:V}=me.useInitialQueryStore(),{conversationId:H}=a.useOptionalConversationId(),{mutateAsync:ze}=xe.useUnifiedUploadFiles(),{isLoading:U,hasMore:W,loadOlder:G}=de.useLoadOlderEvents(H),K=_.default.useRef(null),q=_.default.useCallback(e=>{if(w||U||!W)return;let t=e.scrollTop<=80,r=e.scrollHeight<=e.clientHeight+80;!t&&!r||(K.current={scrollHeight:e.scrollHeight,scrollTop:e.scrollTop},G().catch(e=>{K.current=null,x(e instanceof Error&&e.message?e.message:k(n.I18nKey.ERROR$GENERIC))}))},[W,U,w,G,x,k]),Be=_.default.useCallback(e=>{e.deltaY<0&&e.currentTarget.scrollTop<=0&&q(e.currentTarget)},[q]),J=_.default.useMemo(()=>H?O.some(e=>g.matchesPendingConversationId(H,e.conversationId)):!1,[O,H]),Y=ke.length>0||J||!T?.isLoadingHistory,X=!!H,Z=!Y&&!S,Ve=d.useModelStore(e=>H?(e.entriesByConversation[H]?.length??0)>0:!1),He=async(t,r,i)=>{if(t.trim()===`/new`){if(!H){s.displayErrorToast(k(n.I18nKey.CONVERSATION$CLEAR_NO_ID));return}if(D===0){s.displayErrorToast(k(n.I18nKey.CONVERSATION$CLEAR_EMPTY));return}if(F)return;Ie();return}let a=[...r],o=[...i];D===0?e.capture(`initial_query_submitted`,{entry_point:Te(Re!==null,V!==null),query_character_length:t.length,replay_json_size:V?.length}):e.capture(`user_message_sent`,{session_message_count:D,current_message_length:t.length});let c=te.validateFiles([...a,...o]);if(!c.isValid){s.displayErrorToast(`Error: ${c.errorMessage}`);return}let l=a.map(e=>ee.convertImageToBase64(e)),u=await Promise.all(l),d=new Date().toISOString(),{skipped_files:f,uploaded_files:p}=o.length>0?await ze({conversationId:H,files:o}):{skipped_files:[],uploaded_files:[]};f.forEach(e=>s.displayErrorToast(e.reason));let m=`${k(`CHAT_INTERFACE$AUGMENTED_PROMPT_FILES_TITLE`)}: ${p.join(`
2
2
 
3
- `)}`,h=p.length>0?`${t}\n\n${m}`:t,g=Me({conversationId:H,text:t,content:h,imageUrls:u,fileUrls:p,timestamp:d});y(``);try{await Oe(re.createChatMessage(h,u,p,d))}catch(e){Ne(g,e instanceof Error?e.message:`Failed to send message`)}};_.default.useEffect(()=>{if(K.current&&A.current){let{scrollHeight:e,scrollTop:t}=K.current,n=A.current,r=n.scrollHeight-e;r>0&&(n.scrollTop=t+r),K.current=null;return}P&&j()},[E.length,J,j]);let Ue=_.default.useRef(q);_.default.useEffect(()=>{Ue.current=q}),_.default.useEffect(()=>{let e=A.current;e&&Ue.current(e)},[E.length,W]);let We={scrollRef:A,autoScroll:P,setAutoScroll:Pe,scrollDomToBottom:j,hitBottom:N,setHitBottom:Fe,onChatBodyScroll:M},Q=I===r.AgentState.LOADING||I===r.AgentState.INIT,Ge=I===r.AgentState.STOPPED,$=I===r.AgentState.PAUSED,Ke=i.getStatusColor({isPausing:$,isTask:S,taskStatus:C,isStartingStatus:Q,isStopStatus:Ge,curAgentState:I}),qe=i.getStatusText({isPausing:$,isTask:S,taskStatus:C,taskDetail:De,isStartingStatus:Q,isStopStatus:Ge,curAgentState:I,errorMessage:b,t:k});return(0,v.jsx)(pe.ScrollProvider,{value:We,children:(0,v.jsxs)(`div`,{className:`relative flex h-full flex-col justify-between px-4`,"data-testid":`chat-interface`,children:[!Ae&&!J&&!je&&!Ve&&!Z&&!w&&D===0&&!z&&(0,v.jsx)(fe.ChatSuggestions,{onSuggestionsClick:e=>y(e)}),(0,v.jsxs)(`div`,{ref:A,onScroll:e=>{M(e.currentTarget),q(e.currentTarget)},onWheel:Be,className:`custom-scrollbar-always flex min-h-0 grow flex-col gap-2 overflow-x-hidden overflow-y-auto px-0 pt-4 pb-8 md:px-4`,children:[Z&&X&&(0,v.jsx)(_e.ChatMessagesSkeleton,{}),Z&&!X&&(0,v.jsx)(`div`,{className:`flex justify-center`,"data-testid":`loading-spinner`,children:(0,v.jsx)(oe.LoadingSpinner,{size:`small`})}),U&&(0,v.jsxs)(`div`,{className:`flex items-center justify-center gap-2 py-3 text-sm text-neutral-400`,"data-testid":`loading-older-events`,children:[(0,v.jsx)(oe.LoadingSpinner,{size:`small`}),(0,v.jsx)(`span`,{children:k(n.I18nKey.CHAT_INTERFACE$FETCHING_OLDER_MESSAGES)})]}),(0,v.jsx)(ae.ModelMessages,{conversationId:H,anchorEventId:null}),Y&&E.length>0&&(0,v.jsx)(ye.Messages,{messages:E,allEvents:ke}),(0,v.jsx)(be.PendingUserMessages,{})]}),(0,v.jsxs)(`div`,{className:`flex shrink-0 flex-col gap-[6px]`,children:[(0,v.jsx)(ie.BtwMessages,{conversationId:H}),b&&(0,v.jsx)(ve.ErrorMessageBanner,{message:b,onDismiss:Ee,onRetry:b===`Unable to connect to server`?()=>T?.reconnect():void 0}),z?(0,v.jsxs)(`div`,{"data-testid":`archived-conversation-banner`,className:`mx-1 px-4 py-3 rounded-lg bg-[var(--oh-surface)] border border-[var(--oh-border-subtle)]`,children:[(0,v.jsx)(`p`,{className:`text-xs font-semibold text-[var(--oh-foreground)]`,children:k(R===`ERROR`?n.I18nKey.CHAT_INTERFACE$ERROR_SANDBOX_TITLE:n.I18nKey.CHAT_INTERFACE$ARCHIVED_SANDBOX_TITLE)}),(0,v.jsx)(`p`,{className:`text-xs text-[var(--oh-muted)] mt-0.5`,children:k(R===`ERROR`?n.I18nKey.CHAT_INTERFACE$ERROR_SANDBOX_DESCRIPTION:n.I18nKey.CHAT_INTERFACE$ARCHIVED_SANDBOX_DESCRIPTION)})]}):(0,v.jsxs)(`div`,{className:`relative`,children:[(0,v.jsx)(`div`,{className:`pointer-events-none absolute inset-x-0 bottom-full mb-1 z-20`,children:(0,v.jsxs)(`div`,{className:`flex justify-between relative`,children:[(0,v.jsxs)(`div`,{className:`flex items-end gap-1 pointer-events-auto`,children:[(0,v.jsx)(Se.default,{}),Q&&(0,v.jsx)(Ce.default,{statusColor:Ke,status:qe})]}),N?I===r.AgentState.RUNNING&&(0,v.jsx)(`div`,{className:`absolute left-1/2 transform -translate-x-1/2 bottom-0 pointer-events-auto`,children:(0,v.jsx)(de.TypingIndicator,{})}):(0,v.jsx)(`div`,{className:`absolute left-1/2 transform -translate-x-1/2 bottom-0 pointer-events-auto`,children:(0,v.jsx)(ge.ScrollToBottomButton,{onClick:j})})]})}),(0,v.jsx)(se.InteractiveChatBox,{onSubmit:He,disabled:F})]})]})]})})}exports.ChatInterface=y;
3
+ `)}`,h=p.length>0?`${t}\n\n${m}`:t,g=Me({conversationId:H,text:t,content:h,imageUrls:u,fileUrls:p,timestamp:d});j(),y(``);try{await Oe(re.createChatMessage(h,u,p,d))}catch(e){Ne(g,e instanceof Error?e.message:`Failed to send message`)}};_.default.useEffect(()=>{if(K.current&&A.current){let{scrollHeight:e,scrollTop:t}=K.current,n=A.current,r=n.scrollHeight-e;r>0&&(n.scrollTop=t+r),K.current=null;return}P&&j()},[E.length,J,j]);let Ue=_.default.useRef(q);_.default.useEffect(()=>{Ue.current=q}),_.default.useEffect(()=>{let e=A.current;e&&Ue.current(e)},[E.length,W]);let We={scrollRef:A,autoScroll:P,setAutoScroll:Pe,scrollDomToBottom:j,hitBottom:N,setHitBottom:Fe,onChatBodyScroll:M},Q=I===r.AgentState.LOADING||I===r.AgentState.INIT,Ge=I===r.AgentState.STOPPED,$=I===r.AgentState.PAUSED,Ke=i.getStatusColor({isPausing:$,isTask:S,taskStatus:C,isStartingStatus:Q,isStopStatus:Ge,curAgentState:I}),qe=i.getStatusText({isPausing:$,isTask:S,taskStatus:C,taskDetail:De,isStartingStatus:Q,isStopStatus:Ge,curAgentState:I,errorMessage:b,t:k});return(0,v.jsx)(ce.ScrollProvider,{value:We,children:(0,v.jsxs)(`div`,{className:`relative flex h-full flex-col justify-between px-4`,"data-testid":`chat-interface`,children:[!Ae&&!J&&!je&&!Ve&&!Z&&!w&&D===0&&!z&&(0,v.jsx)(pe.ChatSuggestions,{onSuggestionsClick:e=>y(e)}),(0,v.jsxs)(`div`,{ref:A,"data-testid":`chat-scroll-container`,onScroll:e=>{M(e.currentTarget),q(e.currentTarget)},onWheel:Be,className:`custom-scrollbar-always flex min-h-0 grow flex-col gap-2 overflow-x-hidden overflow-y-auto px-0 pt-4 pb-8 md:px-4`,children:[Z&&X&&(0,v.jsx)(_e.ChatMessagesSkeleton,{}),Z&&!X&&(0,v.jsx)(`div`,{className:`flex justify-center`,"data-testid":`loading-spinner`,children:(0,v.jsx)(oe.LoadingSpinner,{size:`small`})}),U&&(0,v.jsxs)(`div`,{className:`flex items-center justify-center gap-2 py-3 text-sm text-neutral-400`,"data-testid":`loading-older-events`,children:[(0,v.jsx)(oe.LoadingSpinner,{size:`small`}),(0,v.jsx)(`span`,{children:k(n.I18nKey.CHAT_INTERFACE$FETCHING_OLDER_MESSAGES)})]}),(0,v.jsx)(ae.ModelMessages,{conversationId:H,anchorEventId:null}),Y&&E.length>0&&(0,v.jsx)(ye.Messages,{messages:E,allEvents:ke}),(0,v.jsx)(be.PendingUserMessages,{})]}),(0,v.jsxs)(`div`,{className:`flex shrink-0 flex-col gap-[6px]`,children:[(0,v.jsx)(ie.BtwMessages,{conversationId:H}),b&&(0,v.jsx)(ve.ErrorMessageBanner,{message:b,onDismiss:Ee,onRetry:b===`Unable to connect to server`?()=>T?.reconnect():void 0}),z?(0,v.jsxs)(`div`,{"data-testid":`archived-conversation-banner`,className:`mx-1 px-4 py-3 rounded-lg bg-[var(--oh-surface)] border border-[var(--oh-border-subtle)]`,children:[(0,v.jsx)(`p`,{className:`text-xs font-semibold text-[var(--oh-foreground)]`,children:k(R===`ERROR`?n.I18nKey.CHAT_INTERFACE$ERROR_SANDBOX_TITLE:n.I18nKey.CHAT_INTERFACE$ARCHIVED_SANDBOX_TITLE)}),(0,v.jsx)(`p`,{className:`text-xs text-[var(--oh-muted)] mt-0.5`,children:k(R===`ERROR`?n.I18nKey.CHAT_INTERFACE$ERROR_SANDBOX_DESCRIPTION:n.I18nKey.CHAT_INTERFACE$ARCHIVED_SANDBOX_DESCRIPTION)})]}):(0,v.jsxs)(`div`,{className:`relative`,children:[(0,v.jsx)(`div`,{className:`pointer-events-none absolute inset-x-0 bottom-full mb-1 z-20`,children:(0,v.jsxs)(`div`,{className:`flex justify-between relative`,children:[(0,v.jsxs)(`div`,{className:`flex items-end gap-1 pointer-events-auto`,children:[(0,v.jsx)(Se.default,{}),Q&&(0,v.jsx)(Ce.default,{statusColor:Ke,status:qe})]}),N?I===r.AgentState.RUNNING&&(0,v.jsx)(`div`,{className:`absolute left-1/2 transform -translate-x-1/2 bottom-0 pointer-events-auto`,children:(0,v.jsx)(fe.TypingIndicator,{})}):(0,v.jsx)(`div`,{className:`absolute left-1/2 transform -translate-x-1/2 bottom-0 pointer-events-auto`,children:(0,v.jsx)(ge.ScrollToBottomButton,{onClick:j})})]})}),(0,v.jsx)(le.InteractiveChatBox,{onSubmit:He,disabled:F})]})]})]})})}exports.ChatInterface=y;
4
4
  //# sourceMappingURL=chat-interface.cjs.map