@openhands/agent-canvas 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (674) hide show
  1. package/README.md +11 -12
  2. package/README.windows.md +4 -2
  3. package/build/assets/{Trans-DY6toRDu.js → Trans-DqF_OEZB.js} +1 -1
  4. package/build/assets/{acp-providers-Djl6vNn-.js → acp-providers-BQwoUBpe.js} +1 -1
  5. package/build/assets/active-backend-context-BCXRv5pm.js +1 -0
  6. package/build/assets/{add-backend-modal-DljoP9lc.js → add-backend-modal-BKHzq5no.js} +1 -1
  7. package/build/assets/{agent-profiles-settings-BJMmTZgv.js → agent-profiles-settings-CEp5CIz8.js} +1 -1
  8. package/build/assets/agent-server-compatibility-D6DSanlx.js +1 -0
  9. package/build/assets/agent-server-conversation-service.api-cylugfDz.js +41 -0
  10. package/build/assets/{agent-settings-lUknCeaF.js → agent-settings-C-tann3x.js} +2 -2
  11. package/build/assets/agent-settings-DGUKNSnU.js +1 -0
  12. package/build/assets/{alert-banner-Bpf2NQJq.js → alert-banner-Dd4woGbm.js} +1 -1
  13. package/build/assets/api-key-entry-screen-Bll_CkuQ.js +1 -0
  14. package/build/assets/app-settings-BpViWwpC.js +1 -0
  15. package/build/assets/automation-detail-Z9dN2f5l.js +2 -0
  16. package/build/assets/automation-export-D5uL0Tf8.js +2 -0
  17. package/build/assets/automations-list-BMOWcqzZ.js +1 -0
  18. package/build/assets/{back-nav-button-CUS2mi-U.js → back-nav-button-ZUDTMOTB.js} +1 -1
  19. package/build/assets/backend-form-modal-DhBT8P4g.js +1 -0
  20. package/build/assets/{backend-synced-settings-badge-CanzmG12.js → backend-synced-settings-badge-Db_REKVw.js} +1 -1
  21. package/build/assets/{base-modal-BuF2f0YL.js → base-modal-Cb0C6m0Q.js} +1 -1
  22. package/build/assets/{bot-D7eUAuSB.js → bot-C-EA6685.js} +1 -1
  23. package/build/assets/{brand-button-vMVuyDXu.js → brand-button-2Tp3aXk1.js} +1 -1
  24. package/build/assets/{browser-BifzWIBd.js → browser-QYLVr1kS.js} +2 -2
  25. package/build/assets/browser-store-BGXOGo-R.js +1 -0
  26. package/build/assets/{browser-tab-CkkqJnqw.js → browser-tab-BTTP1OE2.js} +1 -1
  27. package/build/assets/canvas-ui-BhxjoA1f.js +1 -0
  28. package/build/assets/{chat-send-button-B_jc5z5C.js → chat-send-button-BZHG2hAW.js} +1 -1
  29. package/build/assets/check-TbOEtHKj.js +1 -0
  30. package/build/assets/{chevron-down-CI8A6tet.js → chevron-down-D7IvFMBM.js} +1 -1
  31. package/build/assets/{circle-plus-check-toggle-C5YxjxvI.js → circle-plus-check-toggle-QQJKUnF6.js} +1 -1
  32. package/build/assets/client-source-Biqarhgr.js +1 -0
  33. package/build/assets/cloud-funnel-analytics-D-27T5Ao.js +1 -0
  34. package/build/assets/{combobox-caret-DoObzqf4.js → combobox-caret-A5jMVHgE.js} +1 -1
  35. package/build/assets/{command-menu-D-JV3Wqm.js → command-menu-BMVEme4H.js} +1 -1
  36. package/build/assets/{command-store-D8J5LMW1.js → command-store-jrWX_CcW.js} +1 -1
  37. package/build/assets/condenser-settings-CIa6eyB4.js +1 -0
  38. package/build/assets/{confirmation-modal-BGLu6XJN.js → confirmation-modal-4n_944zq.js} +1 -1
  39. package/build/assets/{context-menu-list-item-BD5_EaKN.js → context-menu-list-item-DvfFic5I.js} +1 -1
  40. package/build/assets/conversation-CHnEXGRM.js +1 -0
  41. package/build/assets/conversation-D4o4dG2t.js +89 -0
  42. package/build/assets/conversation-panel-11FjLCId.js +1 -0
  43. package/build/assets/conversation-service.api-0JG_fF9d.js +1 -0
  44. package/build/assets/conversation-state-store-JiUQp02U.js +1 -0
  45. package/build/assets/{conversation-store-LptbOvKa.js → conversation-store-BCSpLuEf.js} +1 -1
  46. package/build/assets/{conversation-tab-empty-state-B2dDYEwf.js → conversation-tab-empty-state-BUhKVwoi.js} +1 -1
  47. package/build/assets/{copy-3JCw_XFB.js → copy-D1YGjP-C.js} +1 -1
  48. package/build/assets/{copy-to-clipboard-button-CaR52OnA.js → copy-to-clipboard-button-Dp4Q_hXi.js} +1 -1
  49. package/build/assets/declaration-BGsHjPEW.js +1 -0
  50. package/build/assets/{device-verify-BsznkV-a.js → device-verify-CM086oKs.js} +1 -1
  51. package/build/assets/{dropdown-classes-DJSXeLqc.js → dropdown-classes-DZq0BQjb.js} +1 -1
  52. package/build/assets/{ellipsis-button-C5Z-tPFp.js → ellipsis-button-TPJdyxnK.js} +1 -1
  53. package/build/assets/{entry.client-JixNvFrr.js → entry.client-DypYHsYm.js} +2 -2
  54. package/build/assets/{enum-filter-dropdown-DXbVwiNZ.js → enum-filter-dropdown-CW_mBg0e.js} +1 -1
  55. package/build/assets/{environment-switch-overlay-DZQfRGTx.js → environment-switch-overlay-6laJch-9.js} +1 -1
  56. package/build/assets/{extensions-hub-DfvgqzTc.js → extensions-hub-BJFbFfKS.js} +1 -1
  57. package/build/assets/{extensions-navigation-D9i0DL62.js → extensions-navigation-DqSl7CJw.js} +1 -1
  58. package/build/assets/{external-link-D2zJjE9G.js → external-link-lhdITPqq.js} +1 -1
  59. package/build/assets/files-tab-c316dKAq.js +1 -0
  60. package/build/assets/{files-tab-store-DJsPxYdg.js → files-tab-store-tfCav6bB.js} +1 -1
  61. package/build/assets/{form-control-classes-ChpNBe9n.js → form-control-classes-CvUaw8_L.js} +1 -1
  62. package/build/assets/format-time-delta-DhDbkD7V.js +1 -0
  63. package/build/assets/git-provider-icon-DUb2pEos.js +1 -0
  64. package/build/assets/home-BQ-DC06B.js +1 -0
  65. package/build/assets/home-D7ds4Jyw.js +1 -0
  66. package/build/assets/index-home-BRFDWs_4.js +1 -0
  67. package/build/assets/install-server-modal-CvHvzZj3.js +1 -0
  68. package/build/assets/{launch-BgIlZLSX.js → launch-A47TK2Me.js} +1 -1
  69. package/build/assets/lesson-plan-DSf95kQ2.js +4 -0
  70. package/build/assets/{list-todo-BfH6yYUK.js → list-todo-CAtvkzcy.js} +1 -1
  71. package/build/assets/llm-not-configured-banner-B7DR8SPs.js +27 -0
  72. package/build/assets/llm-settings-Ch4ZbW3c.js +1 -0
  73. package/build/assets/llm-settings-Cvi7q4ox.js +1 -0
  74. package/build/assets/llm-subscription-service-Cz1yBBvE.js +1 -0
  75. package/build/assets/loader-circle-CsAsfLIs.js +1 -0
  76. package/build/assets/{loading-spinner-BLdswi6q.js → loading-spinner-Txxx1I1p.js} +1 -1
  77. package/build/assets/manage-backends-modal-DAVhNUCe.js +1 -0
  78. package/build/assets/manifest-958c741a.js +1 -0
  79. package/build/assets/{markdown-renderer-DMT7Zkpd.js → markdown-renderer-B6cJJ_MN.js} +1 -1
  80. package/build/assets/{mcp-CHkklDMv.js → mcp-BwssgMpg.js} +2 -2
  81. package/build/assets/{messages-B3RugH7P.js → messages-D8MeG2ZQ.js} +26 -26
  82. package/build/assets/{modal-body-DouOE5KH.js → modal-body-CDZdZ-eT.js} +1 -1
  83. package/build/assets/{modal-classes-Cf-4tbHz.js → modal-classes-B4oit_4c.js} +1 -1
  84. package/build/assets/{modal-close-button-B6CfxxJj.js → modal-close-button-DQElFMPo.js} +1 -1
  85. package/build/assets/model-selector-BxTbbKub.js +1 -0
  86. package/build/assets/{navigation-link-D8hfwvxI.js → navigation-link-imH6S7h2.js} +1 -1
  87. package/build/assets/onboarding-CyicadGt.js +1 -0
  88. package/build/assets/onboarding-modal-DQwihcTz.js +1 -0
  89. package/build/assets/option-service.api-DAkg_F7p.js +1 -0
  90. package/build/assets/organization-service.api-QknzKDh3.js +1 -0
  91. package/build/assets/package-Dk_VtWJ4.js +1 -0
  92. package/build/assets/path-utils-BECGet7G.js +1 -0
  93. package/build/assets/{pencil-Dj2XjKmI.js → pencil-CWhApFIT.js} +1 -1
  94. package/build/assets/{plan-components-CcCBmCzW.js → plan-components-CgPHWz3E.js} +1 -1
  95. package/build/assets/{planner-tab-CCqdXxkL.js → planner-tab-DPKHmMAX.js} +1 -1
  96. package/build/assets/plugins-management-service-DuTTxquo.js +1 -0
  97. package/build/assets/profiles-service.api-D6jvZOWu.js +1 -0
  98. package/build/assets/providers-B8pxQK8x.js +1 -0
  99. package/build/assets/proxy-CuhhyjdX.js +1 -0
  100. package/build/assets/{recommended-automations-launcher-CVEF_1pc.js → recommended-automations-launcher-DA6DWS7V.js} +1 -1
  101. package/build/assets/{refresh-cw-DM82EIyx.js → refresh-cw-B9B7-vsy.js} +1 -1
  102. package/build/assets/root-BhP6bTBB.js +2 -0
  103. package/build/assets/root-CYWeTrWE.css +1 -0
  104. package/build/assets/root-layout-oBaHHW4s.js +2 -0
  105. package/build/assets/{runtime-waiting-state-BsXLElvN.js → runtime-waiting-state-DeD9G7yJ.js} +1 -1
  106. package/build/assets/schema-field-BOLdL_U7.js +1 -0
  107. package/build/assets/sdk-section-page-ZIltERxf.js +1 -0
  108. package/build/assets/{sdk-settings-schema-Cv7M9eSe.js → sdk-settings-schema-Ba_Pa9uf.js} +1 -1
  109. package/build/assets/search-dIQ09UY2.js +1 -0
  110. package/build/assets/secrets-service-50DElFny.js +1 -0
  111. package/build/assets/{secrets-settings-DxTx9HgU.js → secrets-settings-Digl7JLe.js} +1 -1
  112. package/build/assets/{segmented-toggle-DyQqPhoD.js → segmented-toggle-C1-ZVyr5.js} +1 -1
  113. package/build/assets/settings-BfgLHsgd.js +1 -0
  114. package/build/assets/{settings-dropdown-input-BjunGXJb.js → settings-dropdown-input-BD5C9fBn.js} +1 -1
  115. package/build/assets/{settings-index-BjeuYFFa.js → settings-index-CODBijya.js} +1 -1
  116. package/build/assets/{settings-input-bD6npsDm.js → settings-input-CzNOq-Pj.js} +1 -1
  117. package/build/assets/{settings-list-classes-Dp_OgzN0.js → settings-list-classes-CuxH9ZoR.js} +1 -1
  118. package/build/assets/settings-modal-BcSWpKI0.js +1 -0
  119. package/build/assets/settings-service.api-Bsu1PvYO.js +1 -0
  120. package/build/assets/{settings-switch-5cuxl8Dc.js → settings-switch-DqmHAfWJ.js} +1 -1
  121. package/build/assets/{settings-utils-BMdG65By.js → settings-utils-B1lBErvV.js} +1 -1
  122. package/build/assets/shared-conversation-CDskdmrb.js +1 -0
  123. package/build/assets/{sidebar-layout-DuzJMMw-.js → sidebar-layout-Cn6eQaEI.js} +1 -1
  124. package/build/assets/{sidebar-mobile-menu-toggle-CMmAYkh8.js → sidebar-mobile-menu-toggle-DmCmZgq1.js} +1 -1
  125. package/build/assets/{sidebar-nav-link-5AlTT5-j.js → sidebar-nav-link-DMc8AIe7.js} +1 -1
  126. package/build/assets/{sidebar-store-CZuE8AH5.js → sidebar-store-DXWSCFpa.js} +1 -1
  127. package/build/assets/{skill-card-pill-row-eTIkE4nz.js → skill-card-pill-row-DOIWjiMF.js} +1 -1
  128. package/build/assets/skills-plugins-DLgINYuY.js +1 -0
  129. package/build/assets/{skills-settings-BYn4-AQQ.js → skills-settings-DPiCWalR.js} +2 -2
  130. package/build/assets/{square-chevron-right-Czw3FFWc.js → square-chevron-right-DE-JN-2Z.js} +1 -1
  131. package/build/assets/{styled-tooltip-CgX2oRaK.js → styled-tooltip-CvsjHuIf.js} +1 -1
  132. package/build/assets/{suspense-X5dBsJzn.js → suspense-DmZ3MSSh.js} +1 -1
  133. package/build/assets/{task-list-tab-0k9PhuqO.js → task-list-tab-CuhcDycu.js} +1 -1
  134. package/build/assets/telemetry-DHiTRl5_.js +2 -0
  135. package/build/assets/{terminal-BsGcSpRS.js → terminal-CVqF-tCD.js} +1 -1
  136. package/build/assets/{toggle-switch-2j5wwR85.js → toggle-switch-CS0ClOy2.js} +1 -1
  137. package/build/assets/{trash-2-Be_7y3Mn.js → trash-2-BU6BlW4i.js} +1 -1
  138. package/build/assets/{typography-D8mHDeNG.js → typography-CQn9wyEX.js} +1 -1
  139. package/build/assets/use-acp-credential-form-LlfZO_DD.js +1 -0
  140. package/build/assets/{use-activate-agent-profile-WaAZYz4E.js → use-activate-agent-profile-DpQjsXM0.js} +1 -1
  141. package/build/assets/{use-active-agent-profile-CYY3vGar.js → use-active-agent-profile-Gw_uJujV.js} +1 -1
  142. package/build/assets/{use-active-conversation-D-r929nx.js → use-active-conversation-B0sttISF.js} +1 -1
  143. package/build/assets/use-agent-profiles-LHZEK0Gg.js +1 -0
  144. package/build/assets/{use-agent-state-DijdVAQ0.js → use-agent-state-C5uA0bRj.js} +1 -1
  145. package/build/assets/use-backends-health-DKt1SmiU.js +1 -0
  146. package/build/assets/{use-can-manage-org-profiles-BEo0peGn.js → use-can-manage-org-profiles-BAtqsbCi.js} +1 -1
  147. package/build/assets/use-cloud-current-user-id-C8m1oBy4.js +1 -0
  148. package/build/assets/use-config-CXy4vD0H.js +1 -0
  149. package/build/assets/use-create-conversation-CWQGNQ9J.js +1 -0
  150. package/build/assets/{use-create-secret-D5O5qdWC.js → use-create-secret-BIrsX3OB.js} +1 -1
  151. package/build/assets/{use-event-store-DjgU4wfO.js → use-event-store-CsD17BKu.js} +1 -1
  152. package/build/assets/{use-handle-plan-click-Mn_SNTCh.js → use-handle-plan-click-DEuO7Byo.js} +1 -1
  153. package/build/assets/use-is-authed-Dvbpiu3B.js +1 -0
  154. package/build/assets/{use-launch-skill-in-chat-BnoDgvAy.js → use-launch-skill-in-chat-CdHOoQGM.js} +1 -1
  155. package/build/assets/use-llm-profiles-DQpQxVOD.js +1 -0
  156. package/build/assets/use-plugins-marketplace-Bkk07W_M.js +1 -0
  157. package/build/assets/use-runtime-is-ready-D4pkGT6E.js +1 -0
  158. package/build/assets/use-save-agent-profile-BxEsjnW0.js +1 -0
  159. package/build/assets/{use-save-settings-D1HoCDbn.js → use-save-settings-ioSUMqbE.js} +1 -1
  160. package/build/assets/use-settings-DNJC4gqu.js +1 -0
  161. package/build/assets/use-settings-nav-items-BUsrDbVR.js +16 -0
  162. package/build/assets/use-skills-BsmKm23M.js +1 -0
  163. package/build/assets/{use-task-list-AVBLbbcR.js → use-task-list-rs7Xbzl8.js} +1 -1
  164. package/build/assets/{use-tracking-2ZwQwpg_.js → use-tracking-poxQHMwR.js} +1 -1
  165. package/build/assets/{use-user-conversation-OAfenBRG.js → use-user-conversation-B337kUKB.js} +1 -1
  166. package/build/assets/{useMutation-DCE9RcgK.js → useMutation-u8UgRgDK.js} +1 -1
  167. package/build/assets/{useMutationState-BUab8Kxr.js → useMutationState-OnAsCLA_.js} +1 -1
  168. package/build/assets/{useQueries-CRzaAqzH.js → useQueries-BpIlT8Mt.js} +1 -1
  169. package/build/assets/{useQuery-CpjHYtZc.js → useQuery-D5pEZbY0.js} +1 -1
  170. package/build/assets/{useTranslation-CDRCKC9-.js → useTranslation-Cbf5AGg_.js} +1 -1
  171. package/build/assets/{utils-D3U3rlqr.js → utils-DB9LsAzA.js} +1 -1
  172. package/build/assets/{vendor~browser-Cvg7jXCP.js → vendor~browser-5Njjw1Cl.js} +1 -1
  173. package/build/assets/{vendor~browser-tab-Di0kh5Zw.js → vendor~browser-tab-Xn94EtUo.js} +1 -1
  174. package/build/assets/{vendor~entry.client-9tWQ_Ugw.js → vendor~entry.client-DDuH4--y.js} +1 -1
  175. package/build/assets/{vendor~entry.client-D6BtSOtn.js → vendor~entry.client-DQGrNspu.js} +1 -1
  176. package/build/assets/vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~dhilvkxv-BIieS_OD.js +2 -0
  177. package/build/assets/vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~iztiaf2o-rqo6vRFz.js +185 -0
  178. package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~nn5zty47-Zl0G1QCy.js → vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~ljq5gbus-B2XD4bi2.js} +1 -1
  179. package/build/assets/{vendor~files-tab-B02k3xvx.js → vendor~files-tab-CiC3-lGh.js} +1 -1
  180. package/build/assets/{vendor~home~conversation-panel~conversation-CYMF9JYB.js → vendor~index-home~home~conversation-panel~conversation-ChmYLVgz.js} +1 -1
  181. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-9UMeuPV6.js → vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-B8XNNEQZ.js} +1 -1
  182. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-d8aETPbZ.js → vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-CnJRLn5s.js} +1 -1
  183. package/build/assets/vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DWteoTyr.js +2 -0
  184. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-D7EUmQ8Y.js → vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-Dc5nKwLO.js} +1 -1
  185. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-BD0GaRGa.js → vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-tlf6AnDe.js} +1 -1
  186. package/build/assets/{vendor~launch-CHXA9cJu.js → vendor~launch-28DK5Rsl.js} +1 -1
  187. package/build/assets/{vendor~root-layout~conversation-panel~conversation-CpiTHpHl.js → vendor~root-layout~conversation-panel~conversation-8tIsyrPj.js} +1 -1
  188. package/build/assets/{vendor~root-layout~conversation-panel~conversation~shared-conversation-_TdZcNMD.js → vendor~root-layout~conversation-panel~conversation~shared-conversation-lYNG9C1U.js} +1 -1
  189. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation-Cn2jwSga.js → vendor~root-layout~index-home~home~conversation-panel~conversation-Zhq6xAxR.js} +1 -1
  190. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~shared-conversation~alert-banner~pl~rqjteh0a-CZM4hwUT.js → vendor~root-layout~index-home~home~conversation-panel~conversation~shared-conversation~aler~gfu7qdtz-B81b08bw.js} +1 -1
  191. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~launch~settings~settings-index~agen~enjl5xdm-mMKDm94D.js → vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~ftka0fnu-jpyLM1Nn.js} +2 -2
  192. package/build/assets/{verification-settings-DnXS6VWv.js → verification-settings-HRgEM-_3.js} +1 -1
  193. package/build/assets/x-ZE4iplpF.js +1 -0
  194. package/build/index.html +4 -4
  195. package/build/locales/ar/openhands.json +9 -0
  196. package/build/locales/ca/openhands.json +9 -0
  197. package/build/locales/de/openhands.json +9 -0
  198. package/build/locales/en/openhands.json +10 -1
  199. package/build/locales/es/openhands.json +9 -0
  200. package/build/locales/fr/openhands.json +9 -0
  201. package/build/locales/it/openhands.json +9 -0
  202. package/build/locales/ja/openhands.json +9 -0
  203. package/build/locales/ko-KR/openhands.json +9 -0
  204. package/build/locales/no/openhands.json +9 -0
  205. package/build/locales/pt/openhands.json +9 -0
  206. package/build/locales/tr/openhands.json +9 -0
  207. package/build/locales/uk/openhands.json +9 -0
  208. package/build/locales/zh-CN/openhands.json +9 -0
  209. package/build/locales/zh-TW/openhands.json +9 -0
  210. package/config/defaults.json +5 -4
  211. package/dist/api/agent-server-adapter.cjs +3 -3
  212. package/dist/api/agent-server-adapter.cjs.map +1 -1
  213. package/dist/api/agent-server-adapter.d.ts +9 -1
  214. package/dist/api/agent-server-adapter.js +105 -102
  215. package/dist/api/agent-server-adapter.js.map +1 -1
  216. package/dist/api/agent-server-config.cjs +1 -1
  217. package/dist/api/agent-server-config.cjs.map +1 -1
  218. package/dist/api/agent-server-config.d.ts +3 -0
  219. package/dist/api/agent-server-config.js +45 -23
  220. package/dist/api/agent-server-config.js.map +1 -1
  221. package/dist/api/backend-registry/auth.cjs +1 -1
  222. package/dist/api/backend-registry/auth.cjs.map +1 -1
  223. package/dist/api/backend-registry/auth.js +1 -1
  224. package/dist/api/backend-registry/auth.js.map +1 -1
  225. package/dist/api/backend-registry/default-backend.cjs +1 -1
  226. package/dist/api/backend-registry/default-backend.cjs.map +1 -1
  227. package/dist/api/backend-registry/default-backend.d.ts +3 -0
  228. package/dist/api/backend-registry/default-backend.js +22 -10
  229. package/dist/api/backend-registry/default-backend.js.map +1 -1
  230. package/dist/api/backend-registry/storage.cjs +1 -1
  231. package/dist/api/backend-registry/storage.cjs.map +1 -1
  232. package/dist/api/backend-registry/storage.js +38 -33
  233. package/dist/api/backend-registry/storage.js.map +1 -1
  234. package/dist/api/backend-registry/types.d.ts +2 -0
  235. package/dist/api/canvas-ui-client-tool.cjs +38 -0
  236. package/dist/api/canvas-ui-client-tool.cjs.map +1 -0
  237. package/dist/api/canvas-ui-client-tool.d.ts +14 -0
  238. package/dist/api/canvas-ui-client-tool.js +47 -0
  239. package/dist/api/canvas-ui-client-tool.js.map +1 -0
  240. package/dist/api/client-source.cjs +2 -0
  241. package/dist/api/client-source.cjs.map +1 -0
  242. package/dist/api/client-source.d.ts +9 -0
  243. package/dist/api/client-source.js +10 -0
  244. package/dist/api/client-source.js.map +1 -0
  245. package/dist/api/cloud/client.cjs +2 -0
  246. package/dist/api/cloud/client.cjs.map +1 -0
  247. package/dist/api/cloud/client.d.ts +4 -0
  248. package/dist/api/cloud/client.js +38 -0
  249. package/dist/api/cloud/client.js.map +1 -0
  250. package/dist/api/cloud/conversation-service.api.cjs +1 -1
  251. package/dist/api/cloud/conversation-service.api.cjs.map +1 -1
  252. package/dist/api/cloud/conversation-service.api.js +33 -31
  253. package/dist/api/cloud/conversation-service.api.js.map +1 -1
  254. package/dist/api/cloud/organization-service.api.cjs +1 -1
  255. package/dist/api/cloud/organization-service.api.cjs.map +1 -1
  256. package/dist/api/cloud/organization-service.api.js +11 -10
  257. package/dist/api/cloud/organization-service.api.js.map +1 -1
  258. package/dist/api/cloud/proxy.cjs +1 -1
  259. package/dist/api/cloud/proxy.cjs.map +1 -1
  260. package/dist/api/cloud/proxy.d.ts +2 -40
  261. package/dist/api/cloud/proxy.js +14 -39
  262. package/dist/api/cloud/proxy.js.map +1 -1
  263. package/dist/api/conversation-metadata-store.cjs +1 -1
  264. package/dist/api/conversation-metadata-store.cjs.map +1 -1
  265. package/dist/api/conversation-metadata-store.d.ts +2 -9
  266. package/dist/api/conversation-metadata-store.js +13 -9
  267. package/dist/api/conversation-metadata-store.js.map +1 -1
  268. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs +1 -1
  269. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs.map +1 -1
  270. package/dist/api/conversation-service/agent-server-conversation-service.api.d.ts +2 -1
  271. package/dist/api/conversation-service/agent-server-conversation-service.api.js +98 -88
  272. package/dist/api/conversation-service/agent-server-conversation-service.api.js.map +1 -1
  273. package/dist/api/conversation-service/agent-server-conversation-service.types.d.ts +5 -0
  274. package/dist/api/device-flow-client.cjs +1 -1
  275. package/dist/api/device-flow-client.cjs.map +1 -1
  276. package/dist/api/device-flow-client.d.ts +4 -58
  277. package/dist/api/device-flow-client.js +8 -98
  278. package/dist/api/device-flow-client.js.map +1 -1
  279. package/dist/api/git-service/agent-server-git-service.api.cjs +1 -1
  280. package/dist/api/git-service/agent-server-git-service.api.cjs.map +1 -1
  281. package/dist/api/git-service/agent-server-git-service.api.d.ts +10 -2
  282. package/dist/api/git-service/agent-server-git-service.api.js +107 -40
  283. package/dist/api/git-service/agent-server-git-service.api.js.map +1 -1
  284. package/dist/api/open-hands.types.d.ts +11 -0
  285. package/dist/api/secrets-service.cjs +1 -1
  286. package/dist/api/secrets-service.cjs.map +1 -1
  287. package/dist/api/secrets-service.js +15 -14
  288. package/dist/api/secrets-service.js.map +1 -1
  289. package/dist/components/conversation-events/chat/event-content-helpers/get-event-content.cjs +1 -1
  290. package/dist/components/conversation-events/chat/event-content-helpers/get-event-content.cjs.map +1 -1
  291. package/dist/components/conversation-events/chat/event-content-helpers/get-event-content.js +73 -64
  292. package/dist/components/conversation-events/chat/event-content-helpers/get-event-content.js.map +1 -1
  293. package/dist/components/conversation-events/chat/event-content-helpers/get-observation-content.cjs +2 -2
  294. package/dist/components/conversation-events/chat/event-content-helpers/get-observation-content.cjs.map +1 -1
  295. package/dist/components/conversation-events/chat/event-content-helpers/get-observation-content.js +2 -0
  296. package/dist/components/conversation-events/chat/event-content-helpers/get-observation-content.js.map +1 -1
  297. package/dist/components/features/backends/backend-form-modal.cjs +1 -1
  298. package/dist/components/features/backends/backend-form-modal.cjs.map +1 -1
  299. package/dist/components/features/backends/backend-form-modal.d.ts +7 -3
  300. package/dist/components/features/backends/backend-form-modal.js +216 -201
  301. package/dist/components/features/backends/backend-form-modal.js.map +1 -1
  302. package/dist/components/features/backends/backend-row.cjs +1 -1
  303. package/dist/components/features/backends/backend-row.cjs.map +1 -1
  304. package/dist/components/features/backends/backend-row.js +2 -1
  305. package/dist/components/features/backends/backend-row.js.map +1 -1
  306. package/dist/components/features/backends/backend-selector.cjs +1 -1
  307. package/dist/components/features/backends/backend-selector.cjs.map +1 -1
  308. package/dist/components/features/backends/backend-selector.js +51 -51
  309. package/dist/components/features/backends/backend-selector.js.map +1 -1
  310. package/dist/components/features/backends/device-flow-auth.cjs +1 -1
  311. package/dist/components/features/backends/device-flow-auth.cjs.map +1 -1
  312. package/dist/components/features/backends/device-flow-auth.d.ts +4 -1
  313. package/dist/components/features/backends/device-flow-auth.js +38 -38
  314. package/dist/components/features/backends/device-flow-auth.js.map +1 -1
  315. package/dist/components/features/chat/chat-interface.cjs +2 -2
  316. package/dist/components/features/chat/chat-interface.cjs.map +1 -1
  317. package/dist/components/features/chat/chat-interface.js +173 -165
  318. package/dist/components/features/chat/chat-interface.js.map +1 -1
  319. package/dist/components/features/chat/components/chat-input-actions.cjs +1 -1
  320. package/dist/components/features/chat/components/chat-input-actions.cjs.map +1 -1
  321. package/dist/components/features/chat/components/chat-input-actions.d.ts +2 -1
  322. package/dist/components/features/chat/components/chat-input-actions.js +44 -43
  323. package/dist/components/features/chat/components/chat-input-actions.js.map +1 -1
  324. package/dist/components/features/chat/components/chat-input-container.cjs +1 -1
  325. package/dist/components/features/chat/components/chat-input-container.cjs.map +1 -1
  326. package/dist/components/features/chat/components/chat-input-container.d.ts +2 -1
  327. package/dist/components/features/chat/components/chat-input-container.js +20 -19
  328. package/dist/components/features/chat/components/chat-input-container.js.map +1 -1
  329. package/dist/components/features/chat/components/chat-input-profile-picker.cjs +1 -1
  330. package/dist/components/features/chat/components/chat-input-profile-picker.cjs.map +1 -1
  331. package/dist/components/features/chat/components/chat-input-profile-picker.js +44 -32
  332. package/dist/components/features/chat/components/chat-input-profile-picker.js.map +1 -1
  333. package/dist/components/features/chat/components/resolve-picker-kind.cjs +1 -1
  334. package/dist/components/features/chat/components/resolve-picker-kind.cjs.map +1 -1
  335. package/dist/components/features/chat/components/resolve-picker-kind.d.ts +10 -22
  336. package/dist/components/features/chat/components/resolve-picker-kind.js +6 -3
  337. package/dist/components/features/chat/components/resolve-picker-kind.js.map +1 -1
  338. package/dist/components/features/chat/custom-chat-input.cjs +1 -1
  339. package/dist/components/features/chat/custom-chat-input.cjs.map +1 -1
  340. package/dist/components/features/chat/custom-chat-input.d.ts +2 -1
  341. package/dist/components/features/chat/custom-chat-input.js +52 -51
  342. package/dist/components/features/chat/custom-chat-input.js.map +1 -1
  343. package/dist/components/features/chat/interactive-chat-box.cjs +1 -1
  344. package/dist/components/features/chat/interactive-chat-box.cjs.map +1 -1
  345. package/dist/components/features/chat/interactive-chat-box.d.ts +2 -1
  346. package/dist/components/features/chat/interactive-chat-box.js +9 -8
  347. package/dist/components/features/chat/interactive-chat-box.js.map +1 -1
  348. package/dist/components/features/diff-viewer/commit-list.cjs +2 -0
  349. package/dist/components/features/diff-viewer/commit-list.cjs.map +1 -0
  350. package/dist/components/features/diff-viewer/commit-list.d.ts +13 -0
  351. package/dist/components/features/diff-viewer/commit-list.js +27 -0
  352. package/dist/components/features/diff-viewer/commit-list.js.map +1 -0
  353. package/dist/components/features/diff-viewer/commit-row.cjs +2 -0
  354. package/dist/components/features/diff-viewer/commit-row.cjs.map +1 -0
  355. package/dist/components/features/diff-viewer/commit-row.d.ts +14 -0
  356. package/dist/components/features/diff-viewer/commit-row.js +59 -0
  357. package/dist/components/features/diff-viewer/commit-row.js.map +1 -0
  358. package/dist/components/features/diff-viewer/file-diff-viewer.cjs +1 -1
  359. package/dist/components/features/diff-viewer/file-diff-viewer.cjs.map +1 -1
  360. package/dist/components/features/diff-viewer/file-diff-viewer.d.ts +7 -1
  361. package/dist/components/features/diff-viewer/file-diff-viewer.js +40 -39
  362. package/dist/components/features/diff-viewer/file-diff-viewer.js.map +1 -1
  363. package/dist/components/features/plugins/plugin-detail-modal.d.ts +2 -1
  364. package/dist/components/shared/modals/settings/settings-modal.cjs +1 -1
  365. package/dist/components/shared/modals/settings/settings-modal.cjs.map +1 -1
  366. package/dist/components/shared/modals/settings/settings-modal.js +23 -22
  367. package/dist/components/shared/modals/settings/settings-modal.js.map +1 -1
  368. package/dist/config/defaults.cjs +1 -1
  369. package/dist/config/defaults.cjs.map +1 -1
  370. package/dist/config/defaults.js +5 -4
  371. package/dist/config/defaults.js.map +1 -1
  372. package/dist/constants/acp-providers.cjs.map +1 -1
  373. package/dist/constants/acp-providers.d.ts +1 -1
  374. package/dist/constants/acp-providers.js.map +1 -1
  375. package/dist/constants/canvas-ui.cjs +2 -0
  376. package/dist/constants/canvas-ui.cjs.map +1 -0
  377. package/dist/constants/canvas-ui.d.ts +8 -0
  378. package/dist/constants/canvas-ui.js +6 -0
  379. package/dist/constants/canvas-ui.js.map +1 -0
  380. package/dist/contexts/conversation-websocket-context.cjs.map +1 -1
  381. package/dist/contexts/conversation-websocket-context.js.map +1 -1
  382. package/dist/hooks/mutation/use-create-conversation.cjs +1 -1
  383. package/dist/hooks/mutation/use-create-conversation.cjs.map +1 -1
  384. package/dist/hooks/mutation/use-create-conversation.d.ts +2 -1
  385. package/dist/hooks/mutation/use-create-conversation.js +52 -52
  386. package/dist/hooks/mutation/use-create-conversation.js.map +1 -1
  387. package/dist/hooks/query/query-keys.cjs +1 -1
  388. package/dist/hooks/query/query-keys.cjs.map +1 -1
  389. package/dist/hooks/query/query-keys.d.ts +2 -0
  390. package/dist/hooks/query/query-keys.js +4 -1
  391. package/dist/hooks/query/query-keys.js.map +1 -1
  392. package/dist/hooks/query/use-backends-health.cjs +1 -1
  393. package/dist/hooks/query/use-backends-health.cjs.map +1 -1
  394. package/dist/hooks/query/use-backends-health.js +50 -48
  395. package/dist/hooks/query/use-backends-health.js.map +1 -1
  396. package/dist/hooks/query/use-cloud-organizations.cjs +1 -1
  397. package/dist/hooks/query/use-cloud-organizations.cjs.map +1 -1
  398. package/dist/hooks/query/use-cloud-organizations.d.ts +1 -0
  399. package/dist/hooks/query/use-cloud-organizations.js +5 -2
  400. package/dist/hooks/query/use-cloud-organizations.js.map +1 -1
  401. package/dist/hooks/query/use-commit-changes.cjs +2 -0
  402. package/dist/hooks/query/use-commit-changes.cjs.map +1 -0
  403. package/dist/hooks/query/use-commit-changes.d.ts +5 -0
  404. package/dist/hooks/query/use-commit-changes.js +34 -0
  405. package/dist/hooks/query/use-commit-changes.js.map +1 -0
  406. package/dist/hooks/query/use-task-polling.cjs +1 -1
  407. package/dist/hooks/query/use-task-polling.cjs.map +1 -1
  408. package/dist/hooks/query/use-task-polling.d.ts +3 -2
  409. package/dist/hooks/query/use-task-polling.js +53 -40
  410. package/dist/hooks/query/use-task-polling.js.map +1 -1
  411. package/dist/hooks/query/use-unified-git-commits.cjs +2 -0
  412. package/dist/hooks/query/use-unified-git-commits.cjs.map +1 -0
  413. package/dist/hooks/query/use-unified-git-commits.d.ts +10 -0
  414. package/dist/hooks/query/use-unified-git-commits.js +41 -0
  415. package/dist/hooks/query/use-unified-git-commits.js.map +1 -0
  416. package/dist/hooks/query/use-unified-git-diff.cjs +1 -1
  417. package/dist/hooks/query/use-unified-git-diff.cjs.map +1 -1
  418. package/dist/hooks/query/use-unified-git-diff.d.ts +5 -0
  419. package/dist/hooks/query/use-unified-git-diff.js +11 -4
  420. package/dist/hooks/query/use-unified-git-diff.js.map +1 -1
  421. package/dist/hooks/use-acp-model-context.cjs +1 -1
  422. package/dist/hooks/use-acp-model-context.cjs.map +1 -1
  423. package/dist/hooks/use-acp-model-context.d.ts +4 -1
  424. package/dist/hooks/use-acp-model-context.js +9 -8
  425. package/dist/hooks/use-acp-model-context.js.map +1 -1
  426. package/dist/hooks/use-auto-refresh-files-on-edit.cjs +1 -1
  427. package/dist/hooks/use-auto-refresh-files-on-edit.cjs.map +1 -1
  428. package/dist/hooks/use-auto-refresh-files-on-edit.js +1 -1
  429. package/dist/hooks/use-auto-refresh-files-on-edit.js.map +1 -1
  430. package/dist/hooks/use-chat-input-model-state.cjs.map +1 -1
  431. package/dist/hooks/use-chat-input-model-state.d.ts +2 -1
  432. package/dist/hooks/use-chat-input-model-state.js.map +1 -1
  433. package/dist/hooks/use-chat-input-profile-state.cjs +1 -1
  434. package/dist/hooks/use-chat-input-profile-state.cjs.map +1 -1
  435. package/dist/hooks/use-chat-input-profile-state.d.ts +1 -10
  436. package/dist/hooks/use-chat-input-profile-state.js +42 -15
  437. package/dist/hooks/use-chat-input-profile-state.js.map +1 -1
  438. package/dist/hooks/use-device-flow.cjs +1 -1
  439. package/dist/hooks/use-device-flow.cjs.map +1 -1
  440. package/dist/hooks/use-device-flow.d.ts +4 -1
  441. package/dist/hooks/use-device-flow.js +42 -40
  442. package/dist/hooks/use-device-flow.js.map +1 -1
  443. package/dist/hooks/use-tracking.cjs.map +1 -1
  444. package/dist/hooks/use-tracking.d.ts +2 -1
  445. package/dist/hooks/use-tracking.js.map +1 -1
  446. package/dist/i18n/declaration.cjs +1 -1
  447. package/dist/i18n/declaration.cjs.map +1 -1
  448. package/dist/i18n/declaration.d.ts +9 -0
  449. package/dist/i18n/declaration.js +1 -1
  450. package/dist/i18n/declaration.js.map +1 -1
  451. package/dist/i18n/index.cjs +1 -1
  452. package/dist/i18n/index.cjs.map +1 -1
  453. package/dist/i18n/index.js +19 -18
  454. package/dist/i18n/index.js.map +1 -1
  455. package/dist/i18n/translation.cjs +3 -3
  456. package/dist/i18n/translation.cjs.map +1 -1
  457. package/dist/i18n/translation.js +154 -1
  458. package/dist/i18n/translation.js.map +1 -1
  459. package/dist/index.cjs +1 -1
  460. package/dist/index.js +32 -32
  461. package/dist/lib/index.cjs +1 -1
  462. package/dist/lib/index.js +1 -1
  463. package/dist/locales/ar/openhands.json +9 -0
  464. package/dist/locales/ca/openhands.json +9 -0
  465. package/dist/locales/de/openhands.json +9 -0
  466. package/dist/locales/en/openhands.json +10 -1
  467. package/dist/locales/es/openhands.json +9 -0
  468. package/dist/locales/fr/openhands.json +9 -0
  469. package/dist/locales/it/openhands.json +9 -0
  470. package/dist/locales/ja/openhands.json +9 -0
  471. package/dist/locales/ko-KR/openhands.json +9 -0
  472. package/dist/locales/no/openhands.json +9 -0
  473. package/dist/locales/pt/openhands.json +9 -0
  474. package/dist/locales/tr/openhands.json +9 -0
  475. package/dist/locales/uk/openhands.json +9 -0
  476. package/dist/locales/zh-CN/openhands.json +9 -0
  477. package/dist/locales/zh-TW/openhands.json +9 -0
  478. package/dist/node_modules/@openhands/typescript-client/dist/client/cloud-client.cjs +2 -0
  479. package/dist/node_modules/@openhands/typescript-client/dist/client/cloud-client.cjs.map +1 -0
  480. package/dist/node_modules/@openhands/typescript-client/dist/client/cloud-client.js +351 -0
  481. package/dist/node_modules/@openhands/typescript-client/dist/client/cloud-client.js.map +1 -0
  482. package/dist/node_modules/@openhands/typescript-client/dist/client/device-flow-client.cjs +2 -0
  483. package/dist/node_modules/@openhands/typescript-client/dist/client/device-flow-client.cjs.map +1 -0
  484. package/dist/node_modules/@openhands/typescript-client/dist/client/device-flow-client.js +106 -0
  485. package/dist/node_modules/@openhands/typescript-client/dist/client/device-flow-client.js.map +1 -0
  486. package/dist/node_modules/@openhands/typescript-client/dist/client/openhands-client.cjs +2 -0
  487. package/dist/node_modules/@openhands/typescript-client/dist/client/openhands-client.cjs.map +1 -0
  488. package/dist/node_modules/@openhands/typescript-client/dist/client/openhands-client.js +69 -0
  489. package/dist/node_modules/@openhands/typescript-client/dist/client/openhands-client.js.map +1 -0
  490. package/dist/node_modules/@openhands/typescript-client/dist/clients.cjs +1 -1
  491. package/dist/node_modules/@openhands/typescript-client/dist/clients.js +3 -0
  492. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.cjs +1 -1
  493. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.cjs.map +1 -1
  494. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.js +18 -2
  495. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.js.map +1 -1
  496. package/dist/node_modules/@openhands/typescript-client/dist/models/acp.cjs.map +1 -1
  497. package/dist/node_modules/@openhands/typescript-client/dist/models/acp.js.map +1 -1
  498. package/dist/node_modules/axios/index.cjs +1 -1
  499. package/dist/node_modules/axios/index.js +1 -1
  500. package/dist/package.cjs +1 -1
  501. package/dist/package.cjs.map +1 -1
  502. package/dist/package.js +2 -2
  503. package/dist/package.js.map +1 -1
  504. package/dist/routes/app-settings.cjs +1 -1
  505. package/dist/routes/app-settings.cjs.map +1 -1
  506. package/dist/routes/app-settings.js +67 -66
  507. package/dist/routes/app-settings.js.map +1 -1
  508. package/dist/routes/commits-tab.cjs +2 -0
  509. package/dist/routes/commits-tab.cjs.map +1 -0
  510. package/dist/routes/commits-tab.d.ts +8 -0
  511. package/dist/routes/commits-tab.js +45 -0
  512. package/dist/routes/commits-tab.js.map +1 -0
  513. package/dist/routes/files-tab.cjs +1 -1
  514. package/dist/routes/files-tab.cjs.map +1 -1
  515. package/dist/routes/files-tab.js +148 -127
  516. package/dist/routes/files-tab.js.map +1 -1
  517. package/dist/services/cloud-funnel-analytics.cjs +2 -0
  518. package/dist/services/cloud-funnel-analytics.cjs.map +1 -0
  519. package/dist/services/cloud-funnel-analytics.d.ts +12 -0
  520. package/dist/services/cloud-funnel-analytics.js +53 -0
  521. package/dist/services/cloud-funnel-analytics.js.map +1 -0
  522. package/dist/services/telemetry.cjs +1 -1
  523. package/dist/services/telemetry.cjs.map +1 -1
  524. package/dist/services/telemetry.js +49 -47
  525. package/dist/services/telemetry.js.map +1 -1
  526. package/dist/types/agent-server/core/base/action.d.ts +5 -4
  527. package/dist/types/agent-server/core/base/base.d.ts +3 -2
  528. package/dist/types/agent-server/core/base/observation.d.ts +1 -1
  529. package/dist/types/agent-server/type-guards.cjs +1 -1
  530. package/dist/types/agent-server/type-guards.cjs.map +1 -1
  531. package/dist/types/agent-server/type-guards.d.ts +3 -5
  532. package/dist/types/agent-server/type-guards.js +2 -1
  533. package/dist/types/agent-server/type-guards.js.map +1 -1
  534. package/dist/types/automation.d.ts +5 -0
  535. package/dist/utils/api-error-message.d.ts +11 -0
  536. package/dist/utils/automation-timeout.d.ts +19 -0
  537. package/dist/utils/base-path.cjs +2 -0
  538. package/dist/utils/base-path.cjs.map +1 -0
  539. package/dist/utils/base-path.d.ts +2 -0
  540. package/dist/utils/base-path.js +23 -0
  541. package/dist/utils/base-path.js.map +1 -0
  542. package/package.json +2 -2
  543. package/scripts/check-sdk-version-sync.mjs +6 -6
  544. package/scripts/dev-safe.mjs +7 -8
  545. package/scripts/dev-static.mjs +3 -0
  546. package/scripts/dev-with-automation.mjs +3 -0
  547. package/scripts/docker-build.mjs +4 -0
  548. package/scripts/static-server.mjs +93 -7
  549. package/tools/canvas_ui_tool.py +14 -8
  550. package/build/assets/active-backend-context-B3umL5R-.js +0 -1
  551. package/build/assets/agent-server-client-options-DVLRd9sw.js +0 -1
  552. package/build/assets/agent-server-conversation-service.api-D_ZvtJjG.js +0 -5
  553. package/build/assets/agent-settings-BVVFzBWS.js +0 -1
  554. package/build/assets/api-key-entry-screen-CWEHcPJA.js +0 -1
  555. package/build/assets/app-settings-Dj90qosy.js +0 -1
  556. package/build/assets/automation-detail-CXJU0_gF.js +0 -2
  557. package/build/assets/automation-export-FWY9LPsG.js +0 -2
  558. package/build/assets/automations-list-DDGBkWLC.js +0 -1
  559. package/build/assets/backend-form-modal-DSbrafX2.js +0 -1
  560. package/build/assets/browser-store-BI6uklCG.js +0 -1
  561. package/build/assets/check-Bvi71siz.js +0 -1
  562. package/build/assets/condenser-settings-30cX9SK6.js +0 -1
  563. package/build/assets/conversation-BltULtFA.js +0 -89
  564. package/build/assets/conversation-e0a0_X4S.js +0 -1
  565. package/build/assets/conversation-panel-Cr9_ZGI-.js +0 -1
  566. package/build/assets/conversation-service.api-DQaKzIRj.js +0 -1
  567. package/build/assets/conversation-state-store-B2Bp32XI.js +0 -1
  568. package/build/assets/declaration-gq8V5eTU.js +0 -1
  569. package/build/assets/files-tab-DDtEJcGE.js +0 -1
  570. package/build/assets/git-provider-icon-BjkecAuV.js +0 -1
  571. package/build/assets/home-BCKWpKpf.js +0 -1
  572. package/build/assets/index-redirect-CUUJiNki.js +0 -1
  573. package/build/assets/install-server-modal-BIugLhVB.js +0 -1
  574. package/build/assets/lesson-plan-DgpP80mJ.js +0 -4
  575. package/build/assets/llm-not-configured-banner-BlX8NifC.js +0 -27
  576. package/build/assets/llm-settings-DJmbryaE.js +0 -1
  577. package/build/assets/llm-settings-kU5v0H1Z.js +0 -1
  578. package/build/assets/llm-subscription-service-CKyaV24y.js +0 -1
  579. package/build/assets/loader-circle-BEykUKYG.js +0 -1
  580. package/build/assets/manage-backends-modal-C8FJQIZR.js +0 -1
  581. package/build/assets/manifest-56d40d7c.js +0 -1
  582. package/build/assets/model-selector-BOj1wBlq.js +0 -1
  583. package/build/assets/mouse-pointer-click-PdEQPL6v.js +0 -1
  584. package/build/assets/onboarding-DYhDxmI9.js +0 -1
  585. package/build/assets/onboarding-modal-CP_WxDC9.js +0 -1
  586. package/build/assets/option-service.api-C0tYT4-r.js +0 -1
  587. package/build/assets/organization-service.api-CnynNoT-.js +0 -1
  588. package/build/assets/path-utils-DWcgCGen.js +0 -1
  589. package/build/assets/plugins-management-service-BAp70KN7.js +0 -1
  590. package/build/assets/profiles-service.api-CeYEmSM3.js +0 -1
  591. package/build/assets/providers-BxCuC9bZ.js +0 -1
  592. package/build/assets/proxy-CHmFkV16.js +0 -1
  593. package/build/assets/root-V8fkplMy.css +0 -1
  594. package/build/assets/root-layout-CttG_lQi.js +0 -2
  595. package/build/assets/root-uJ2t9rCQ.js +0 -2
  596. package/build/assets/schema-field-xUr6rDd6.js +0 -1
  597. package/build/assets/sdk-section-page-CbLrVUa3.js +0 -1
  598. package/build/assets/search-4DHskuhE.js +0 -1
  599. package/build/assets/secrets-service-CZYjNxFw.js +0 -1
  600. package/build/assets/settings-DnlfS09K.js +0 -1
  601. package/build/assets/settings-modal-DfTcL-mV.js +0 -1
  602. package/build/assets/settings-service.api-K4ncGlBv.js +0 -1
  603. package/build/assets/shared-conversation-DWtBkJv7.js +0 -1
  604. package/build/assets/skills-plugins-BJ040luO.js +0 -1
  605. package/build/assets/use-acp-credential-form-EtnbtYt0.js +0 -1
  606. package/build/assets/use-agent-profiles-DEAMFp-W.js +0 -1
  607. package/build/assets/use-backends-health-DkC7tKkC.js +0 -1
  608. package/build/assets/use-cloud-current-user-id-Dm99wXp2.js +0 -1
  609. package/build/assets/use-config-CHzNIHpv.js +0 -1
  610. package/build/assets/use-create-conversation-CTsvZ96U.js +0 -1
  611. package/build/assets/use-is-authed-_dhQ2Xuj.js +0 -1
  612. package/build/assets/use-llm-profiles-BMhPDlwQ.js +0 -1
  613. package/build/assets/use-plugins-marketplace-BGb-KgfD.js +0 -1
  614. package/build/assets/use-runtime-is-ready-CC-KrLKe.js +0 -1
  615. package/build/assets/use-save-agent-profile-CLMmbx_X.js +0 -1
  616. package/build/assets/use-settings-BReAMxCG.js +0 -1
  617. package/build/assets/use-settings-nav-items-xe1YgLnE.js +0 -16
  618. package/build/assets/use-skills-Dqo-pDDx.js +0 -1
  619. package/build/assets/vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~d1e18dtv-5Q6lQJdE.js +0 -177
  620. package/build/assets/vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~ncdxw0bh-ClHnt5lR.js +0 -10
  621. package/build/assets/vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-CqXiHwjU.js +0 -2
  622. package/build/assets/x-Cb0WAtak.js +0 -1
  623. /package/build/assets/{__vite-browser-external-4xJsU2-u.js → __vite-browser-external-DU-Cb_sT.js} +0 -0
  624. /package/build/assets/{automation-BU8zu-FP.js → automation-BVEmGghX.js} +0 -0
  625. /package/build/assets/{checkmark-h7udgXMM.js → checkmark-DhcMGwtO.js} +0 -0
  626. /package/build/assets/{close-p3Op5lxI.js → close-DO5Rq_CS.js} +0 -0
  627. /package/build/assets/{code-tag-DYlAhEQY.js → code-tag-BvjtzUsr.js} +0 -0
  628. /package/build/assets/{color-themes-DPBzNtVg.js → color-themes-bVMmJJG6.js} +0 -0
  629. /package/build/assets/{common-Dh7OqABE.js → common-CxbUL3nR.js} +0 -0
  630. /package/build/assets/{conversation-local-storage-F6zVMM--.js → conversation-local-storage-B31voBg7.js} +0 -0
  631. /package/build/assets/{copy-BLmGeJcd.js → copy-DLUw2us-.js} +0 -0
  632. /package/build/assets/{createLucideIcon-CVAsW2Yo.js → createLucideIcon-D4Tak8A1.js} +0 -0
  633. /package/build/assets/{dist-CodhvuAP.js → dist-Dj01FXbZ.js} +0 -0
  634. /package/build/assets/{environment-switch-store-DkjlKWzN.js → environment-switch-store-D9hB9PvY.js} +0 -0
  635. /package/build/assets/{extension-module-card-classes-9V3J9J_b.js → extension-module-card-classes-BlO4w702.js} +0 -0
  636. /package/build/assets/{folder-mMWFvaw0.js → folder-ynxP2EIL.js} +0 -0
  637. /package/build/assets/{get-language-from-path-CPNnuVhI.js → get-language-from-path-rWEQrOGU.js} +0 -0
  638. /package/build/assets/{git-status-mapper-BI8FyUVp.js → git-status-mapper-C3rfzUex.js} +0 -0
  639. /package/build/assets/{handle-capture-consent-CPMXU29K.js → handle-capture-consent-DDnXMC9Y.js} +0 -0
  640. /package/build/assets/{iconBase-DaTRRUjy.js → iconBase-CuvxAQZ5.js} +0 -0
  641. /package/build/assets/{link-external-DfKQroKX.js → link-external-BVDiJfZt.js} +0 -0
  642. /package/build/assets/{llm-subscription-DtsX5Lhg.js → llm-subscription-BkdHwtQe.js} +0 -0
  643. /package/build/assets/{map-provider-BM2SJarp.js → map-provider-XSFHmdDs.js} +0 -0
  644. /package/build/assets/{middleware-DYHYNAnP.js → middleware-CWYDMVuG.js} +0 -0
  645. /package/build/assets/{modal-backdrop-zVwfOJZr.js → modal-backdrop-Dsmzgr5s.js} +0 -0
  646. /package/build/assets/{navigation-context-DPs2G0X8.js → navigation-context-SjzfpygH.js} +0 -0
  647. /package/build/assets/{objectWithoutPropertiesLoose-BgYIAs2y.js → objectWithoutPropertiesLoose-CQwg6tC0.js} +0 -0
  648. /package/build/assets/{openhands-logo-bcNw5bkY.js → openhands-logo-C-gDp1wr.js} +0 -0
  649. /package/build/assets/{react-DPDgL6du.js → react-ao3tWj6K.js} +0 -0
  650. /package/build/assets/{search-BsjCEFNf.js → search-pb4UKTfK.js} +0 -0
  651. /package/build/assets/{settings-mQUckT0g.js → settings-DksoDv5z.js} +0 -0
  652. /package/build/assets/{settings-gear-MXCyZW0x.js → settings-gear-D_HVvE5L.js} +0 -0
  653. /package/build/assets/{settings-like-page-layout-classes-DENKlZpD.js → settings-like-page-layout-classes-DLrsPCaI.js} +0 -0
  654. /package/build/assets/{settings-section-header-context-COMOIaxV.js → settings-section-header-context-C2MUIG88.js} +0 -0
  655. /package/build/assets/{skills-9cDZONKh.js → skills-CH4xgIh-.js} +0 -0
  656. /package/build/assets/{switch-skeleton-DqQwalyu.js → switch-skeleton-BpSOvZ-n.js} +0 -0
  657. /package/build/assets/{terminal-BuLtIrb9.js → terminal-Dokfkxn0.js} +0 -0
  658. /package/build/assets/{u-check-circle-BqoIxNz_.js → u-check-circle-DPWVO-9N.js} +0 -0
  659. /package/build/assets/{u-check-circle-half-LiwZkuFe.js → u-check-circle-half-BGNAAjOW.js} +0 -0
  660. /package/build/assets/{u-edit-DJ90xc8Z.js → u-edit-BIskOoEG.js} +0 -0
  661. /package/build/assets/{use-breakpoint-B-O0lQ84.js → use-breakpoint-OjLm94cF.js} +0 -0
  662. /package/build/assets/{use-click-outside-element-Bf4Omzot.js → use-click-outside-element-Jpt2WWd7.js} +0 -0
  663. /package/build/assets/{use-onboarding-completion-C_Swglzp.js → use-onboarding-completion-DkRpDTsD.js} +0 -0
  664. /package/build/assets/{v4-DbCkTSoU.js → v4-DPgam_jW.js} +0 -0
  665. /package/build/assets/{vendor~browser-Dqd33JyP.js → vendor~browser-BvEKaLBz.js} +0 -0
  666. /package/build/assets/{vendor~conversation-panel~conversation~alert-banner-DHDkknt5.js → vendor~conversation-panel~conversation~alert-banner-CznX01nZ.js} +0 -0
  667. /package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~i3v2mlbw-BrJQ3XZH.js → vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~e0djk9ee-Cw6LUe8p.js} +0 -0
  668. /package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~k6tszsdc-Bb-xMtbv.js → vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~g9hift2g-DmmpG9SI.js} +0 -0
  669. /package/build/assets/{vendor~entry.client~root~root-layout~index-redirect~home~conversation-panel~conversation~la~byh8a1g4-XNPdpuO8.js → vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~jkpzbynd-CkpBIhVe.js} +0 -0
  670. /package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DTzw2x50.js → vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-BuL5kjfS.js} +0 -0
  671. /package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~launch~skills-settings~automations-~ki5qnp0d-rV6d1Iv_.js → vendor~root-layout~index-home~home~conversation-panel~conversation~launch~skills-settings~a~j2jlu22h-DUYl8gbZ.js} +0 -0
  672. /package/build/assets/{vendor~root-layout~home~mcp~automations-list~onboarding-modal-CXyYYvYh.js → vendor~root-layout~index-home~home~mcp~automations-list~onboarding-modal-pIgQDxTc.js} +0 -0
  673. /package/build/assets/{vendor~terminal-aeP3PnKf.js → vendor~terminal-jAaNQWS9.js} +0 -0
  674. /package/build/assets/{x-mark-Batp6gXa.js → x-mark-C5przfXl.js} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"use-create-conversation.js","names":[],"sources":["../../../src/hooks/mutation/use-create-conversation.ts"],"sourcesContent":["import { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport AgentServerConversationService from \"#/api/conversation-service/agent-server-conversation-service.api\";\nimport { PluginSpec } from \"#/api/conversation-service/agent-server-conversation-service.types\";\nimport { SuggestedTask } from \"#/utils/types\";\nimport { Provider } from \"#/types/settings\";\nimport { useTracking } from \"#/hooks/use-tracking\";\nimport { useLlmProfiles } from \"#/hooks/query/use-llm-profiles\";\nimport { useAgentProfiles } from \"#/hooks/query/use-agent-profiles\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport ProfilesService from \"#/api/profiles-service/profiles-service.api\";\nimport AgentProfilesService, {\n WELL_KNOWN_DEFAULT_AGENT_PROFILE_NAME,\n type AgentProfileListResponse,\n} from \"#/api/agent-profiles-service/agent-profiles-service.api\";\nimport PluginsManagementService, {\n type InstalledPluginInfo,\n} from \"#/api/plugins-management-service\";\nimport {\n PLUGINS_QUERY_KEYS,\n LLM_PROFILES_QUERY_KEYS,\n AGENT_PROFILES_QUERY_KEYS,\n AGENT_PROFILES_RETRY_OPTIONS,\n} from \"#/hooks/query/query-keys\";\nimport { pluginReferenceKey } from \"#/utils/plugin-display\";\nimport {\n getStoredConversationMetadata,\n setStoredConversationMetadata,\n type WorkspaceMode,\n} from \"#/api/conversation-metadata-store\";\n\ninterface CreateConversationVariables {\n query?: string;\n repository?: {\n name: string;\n gitProvider: Provider;\n branch?: string;\n };\n suggestedTask?: SuggestedTask;\n conversationInstructions?: string;\n parentConversationId?: string;\n agentType?: \"default\" | \"plan\";\n plugins?: PluginSpec[];\n workingDir?: string;\n workspaceMode?: WorkspaceMode;\n // Launch from a specific AgentProfile (local backend). When omitted, the\n // active AgentProfile (if any) is used so home-composed conversations\n // launch from the user's selected profile (#3727).\n agentProfileId?: string;\n entryPoint?: string; // analytics only; not forwarded to the service\n}\n\ninterface CreateConversationResponse {\n conversation_id: string;\n session_api_key: string | null;\n url: string | null;\n task_id?: string;\n}\n\nexport const useCreateConversation = () => {\n const queryClient = useQueryClient();\n const { trackConversationCreated } = useTracking();\n // Cache-warm on the home page (the profile picker reads the same query).\n // Stamped onto the conversation at creation so the switcher can show the\n // exact profile even when several profiles share a model (#1082).\n const { data: llmProfiles } = useLlmProfiles();\n // Warm the agent-profiles cache too — the launch path below awaits the same\n // query via ensureQueryData, so a warm cache makes home-launch instant. The\n // hook's maybe-unresolved data is deliberately NOT read at launch time:\n // activation is pointer-only (it never writes agent_settings), so racing a\n // cold cache into the agent_settings fallback would silently launch the\n // wrong agent.\n const { backend, orgId } = useActiveBackend();\n useAgentProfiles();\n\n return useMutation({\n mutationKey: [\"create-conversation\"],\n mutationFn: async (\n variables: CreateConversationVariables,\n ): Promise<CreateConversationResponse> => {\n const {\n query,\n conversationInstructions,\n plugins,\n repository,\n workingDir,\n workspaceMode,\n parentConversationId,\n agentType,\n agentProfileId,\n } = variables;\n\n // The active AgentProfile is the default launch profile for new\n // conversations (#3727), on both local and cloud (cloud gained\n // /api/agent-profiles in OpenHands #15060, #3730). Await the list from\n // the shared query cache: a send fired before the home query resolves\n // must still launch from the active profile, not fall through to the\n // agent_settings path. Degrades safely: if the fetch errors (older\n // backend without the surface), this stays undefined and creation falls\n // back to the encrypted agent_settings launch path.\n let agentProfiles: AgentProfileListResponse | undefined;\n try {\n agentProfiles = await queryClient.ensureQueryData({\n queryKey: [...AGENT_PROFILES_QUERY_KEYS.all, backend.id, orgId],\n queryFn: AgentProfilesService.listProfiles,\n // Shared with useAgentProfiles and redirectIfAcpActive so the retry\n // policy for this surface can't drift between call sites (#1571\n // review): a backend without it fails every one of these on every\n // call, so degrade to the fallback immediately rather than sitting\n // through the default exponential-backoff retries each time.\n ...AGENT_PROFILES_RETRY_OPTIONS,\n });\n } catch {\n // Profiles unavailable → legacy agent_settings launch.\n }\n\n const requestedAgentProfileId =\n agentProfileId ?? agentProfiles?.active_agent_profile_id ?? undefined;\n\n // Fall back to the legacy agent_settings launch when the resolved agent\n // profile can't resolve its LLM. The agent-server seeds a `default`\n // openhands profile whose `llm_profile_ref` can point at an LLM profile\n // that doesn't exist (fresh store, or one configured with named profiles\n // only); launching from it 404s (\"LLM profile '<ref>' not found\") and\n // would brick home-launch. agent_settings reflects the active LLM, so the\n // fallback degrades cleanly until the seed mirrors it (SDK #3933).\n // ACP profiles carry no llm_profile_ref, so they're never gated here.\n const resolvedAgentProfile = requestedAgentProfileId\n ? agentProfiles?.profiles?.find(\n (profile) => profile.id === requestedAgentProfileId,\n )\n : undefined;\n // Cloud has no `agent_settings` payload to fall back to — the downgrade\n // below only makes sense on local, where it exists and carries the\n // canvas-only enrichments. Gating it here keeps cloud always launching\n // from the resolved profile id, so the conversation gets\n // `launched_agent_profile` stamped and the profile's config applied\n // (#1571 review).\n const isCloud = backend.kind === \"cloud\";\n let effectiveAgentProfileId = requestedAgentProfileId;\n if (\n !isCloud &&\n resolvedAgentProfile?.name === WELL_KNOWN_DEFAULT_AGENT_PROFILE_NAME &&\n resolvedAgentProfile?.agent_kind === \"openhands\"\n ) {\n // The seeded OpenHands `default` profile is the enriched baseline, not a\n // deliberate profile pick — it mirrors global agent_settings. Launch it\n // via agent_settings so the canvas-only enrichments the profile-resolution\n // path drops survive for the common home-launch: the <RUNTIME_SERVICES>\n // system-message suffix, the canvas_ui tool, and project-skill loading\n // (buildAgentContext). Named profiles are deliberate custom configs and\n // still use the profile path (accepting that enrichment boundary).\n // Trade-off: per-profile fields set on `default` itself don't apply on\n // home-launch — custom per-profile config belongs in a named profile.\n //\n // Scoped to OpenHands: an ACP `default` must keep the profile path.\n // Activation is pointer-only, so global agent_settings is stale (often\n // still OpenHands) when an ACP profile is active — launching it via\n // agent_settings would start the wrong agent. ACP also carries no\n // <RUNTIME_SERVICES>/canvas_ui enrichment, so there's nothing to preserve.\n //\n // Scoped to local: cloud never writes agent_settings, so it always\n // resolves `default` server-side via agent_profile_id (validated below).\n effectiveAgentProfileId = undefined;\n } else if (\n resolvedAgentProfile?.agent_kind === \"openhands\" &&\n resolvedAgentProfile.llm_profile_ref\n ) {\n // Await the LLM-profile list rather than reading the maybe-unresolved\n // `useLlmProfiles()` result: a send fired before that query loads (or\n // after it errors) must still validate the ref, not launch blind.\n let llmProfileExists = false;\n try {\n const llm = await queryClient.ensureQueryData({\n queryKey: [...LLM_PROFILES_QUERY_KEYS.all, backend.id, orgId],\n queryFn: ProfilesService.listProfiles,\n // Match the agent-profiles fetch above: on a backend where this\n // errors, fall back to agent_settings immediately rather than\n // stalling the send through the default exponential backoff.\n retry: false,\n });\n llmProfileExists = llm.profiles.some(\n (profile) => profile.name === resolvedAgentProfile.llm_profile_ref,\n );\n } catch {\n // List unavailable → can't validate → fall back to agent_settings.\n }\n if (!llmProfileExists) {\n // Downgrade is silent in the UI; leave a diagnosable trace.\n console.warn(\n `Agent profile \"${resolvedAgentProfile.name}\" references missing ` +\n `LLM profile \"${resolvedAgentProfile.llm_profile_ref}\"; ` +\n \"launching from agent_settings instead.\",\n );\n effectiveAgentProfileId = undefined;\n }\n }\n\n // Only extend the call with the [sandboxId, agentProfileId] tail when\n // launching from a profile, so a plain create stays byte-identical to\n // the legacy agent_settings path (#3727). sandboxId is unused here.\n // TODO(#1587): createConversation has grown to 10 positional params;\n // refactor it to an options object so this position-skipping tail isn't\n // needed.\n const profileArgs: [undefined, string] | [] = effectiveAgentProfileId\n ? [undefined, effectiveAgentProfileId]\n : [];\n\n const conversation =\n await AgentServerConversationService.createConversation(\n query,\n conversationInstructions,\n plugins,\n repository\n ? {\n selected_repository: repository.name,\n selected_branch: repository.branch ?? null,\n git_provider: repository.gitProvider,\n }\n : null,\n workingDir,\n workspaceMode,\n parentConversationId,\n agentType,\n ...profileArgs,\n );\n\n // Stamp the active LLM profile onto the (local) conversation so the\n // chat switcher shows the exact profile even when several profiles\n // share a model (#1082). Cloud conversations don't use local profiles\n // (app_conversation_id stays null until the sandbox is READY). Merge so\n // the repo/workspace metadata the service just persisted is preserved.\n const localConversationId = conversation.app_conversation_id;\n // Snapshot the conversation's plugins into client-side metadata so the\n // in-conversation plugins view can show what's loaded (coordinates only\n // — strip parameters, which may carry secrets). The agent-server doesn't\n // return a live conversation's loaded plugins, so this snapshot is the\n // source for that view. Two sources, deduped by coordinates:\n // 1. plugins explicitly attached at creation (e.g. the /launch flow);\n // 2. enabled installed plugins, which the SDK auto-loads into every new\n // local conversation (see use-set-plugin-enabled).\n const explicitPlugins =\n plugins?.map((plugin) => ({\n source: plugin.source,\n ref: plugin.ref ?? null,\n repo_path: plugin.repo_path ?? null,\n })) ?? [];\n let attachedPlugins: PluginSpec[] = explicitPlugins;\n if (localConversationId) {\n let installed: InstalledPluginInfo[] = [];\n try {\n installed = await queryClient.ensureQueryData({\n queryKey: PLUGINS_QUERY_KEYS.installed,\n queryFn: () => PluginsManagementService.listInstalledPlugins(),\n });\n } catch {\n // Best-effort: never let plugin lookup block conversation creation.\n }\n const seen = new Set(explicitPlugins.map(pluginReferenceKey));\n const enabledInstalled = installed\n .filter((plugin) => plugin.enabled)\n .map((plugin) => ({\n source: plugin.source,\n ref: plugin.resolved_ref ?? null,\n repo_path: plugin.repo_path ?? null,\n // Keep the human-friendly name so the plugins view shows e.g.\n // \"city-weather\" rather than deriving \"local\" from the source.\n name: plugin.name,\n }))\n .filter((plugin) => !seen.has(pluginReferenceKey(plugin)));\n attachedPlugins = [...explicitPlugins, ...enabledInstalled];\n }\n // A launch from a named OpenHands profile runs that profile's\n // `llm_profile_ref`, which can differ from the standalone active LLM\n // profile — stamp the ref so the switcher pill names the exact profile\n // the conversation runs (#1082). The agent_settings path (the `default`\n // baseline or a dangling ref, where effectiveAgentProfileId is cleared)\n // runs the active LLM, so it keeps `active_profile`. ACP profiles carry\n // no LLM profile, so they fall through to the active-profile stamp\n // (unused by the ACP model chip).\n const activeProfile =\n effectiveAgentProfileId &&\n resolvedAgentProfile?.agent_kind === \"openhands\"\n ? resolvedAgentProfile.llm_profile_ref\n : (llmProfiles?.active_profile ?? null);\n if (localConversationId && (activeProfile || attachedPlugins.length)) {\n const prev = getStoredConversationMetadata(localConversationId);\n setStoredConversationMetadata(localConversationId, {\n selected_repository: prev?.selected_repository ?? null,\n selected_branch: prev?.selected_branch ?? null,\n git_provider: prev?.git_provider ?? null,\n selected_workspace: prev?.selected_workspace ?? null,\n workspace_mode: prev?.workspace_mode ?? null,\n active_profile: activeProfile ?? prev?.active_profile ?? null,\n plugins: attachedPlugins.length\n ? attachedPlugins\n : (prev?.plugins ?? null),\n });\n }\n\n // OpenHands cloud pattern: when the start task isn't immediately\n // READY (cloud sandbox is still provisioning),\n // app_conversation_id is null. We return a `task-{id}` URL so the\n // conversation route's useTaskPolling can drive it to READY and\n // then redirect to the real `/conversations/{app_conversation_id}`.\n const conversationId = conversation.app_conversation_id\n ? conversation.app_conversation_id\n : `task-${conversation.id}`;\n\n return {\n conversation_id: conversationId,\n session_api_key: null,\n url: conversation.agent_server_url,\n task_id: conversation.id,\n };\n },\n onSuccess: async (data, variables) => {\n trackConversationCreated({\n conversationId: data.conversation_id,\n taskId: data.task_id,\n hasRepository: !!variables.repository,\n gitProvider: variables.repository?.gitProvider,\n hasWorkspace: !!variables.workingDir,\n workspaceMode: variables.workspaceMode,\n hasInitialQuery: !!variables.query,\n agentType: variables.agentType,\n hasParentConversation: !!variables.parentConversationId,\n entryPoint: variables.entryPoint,\n });\n\n // Invalidate (rather than remove) so the existing paginated list stays\n // rendered while a background refetch picks up the new conversation.\n // `removeQueries` would wipe the cache and force the panel back to its\n // initial loading state, dropping loaded pages and scroll position.\n queryClient.invalidateQueries({\n queryKey: [\"user\", \"conversations\"],\n });\n // The cloud path returns a start task (no app_conversation_id\n // yet); the sidebar surfaces those via `useStartTasks` which doesn't\n // poll, so invalidate it explicitly so the in-flight task shows up\n // in the conversation list immediately.\n queryClient.invalidateQueries({\n queryKey: [\"start-tasks\"],\n });\n },\n });\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-create-conversation.js","names":[],"sources":["../../../src/hooks/mutation/use-create-conversation.ts"],"sourcesContent":["import { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport AgentServerConversationService from \"#/api/conversation-service/agent-server-conversation-service.api\";\nimport { PluginSpec } from \"#/api/conversation-service/agent-server-conversation-service.types\";\nimport { SuggestedTask } from \"#/utils/types\";\nimport { AgentKind, Provider } from \"#/types/settings\";\nimport { useTracking } from \"#/hooks/use-tracking\";\nimport { useLlmProfiles } from \"#/hooks/query/use-llm-profiles\";\nimport { useAgentProfiles } from \"#/hooks/query/use-agent-profiles\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport ProfilesService from \"#/api/profiles-service/profiles-service.api\";\nimport AgentProfilesService, {\n WELL_KNOWN_DEFAULT_AGENT_PROFILE_NAME,\n type AgentProfileListResponse,\n} from \"#/api/agent-profiles-service/agent-profiles-service.api\";\nimport PluginsManagementService, {\n type InstalledPluginInfo,\n} from \"#/api/plugins-management-service\";\nimport {\n PLUGINS_QUERY_KEYS,\n LLM_PROFILES_QUERY_KEYS,\n AGENT_PROFILES_QUERY_KEYS,\n AGENT_PROFILES_RETRY_OPTIONS,\n} from \"#/hooks/query/query-keys\";\nimport { pluginReferenceKey } from \"#/utils/plugin-display\";\nimport {\n getStoredConversationMetadata,\n setStoredConversationMetadata,\n toPluginCoordinates,\n type WorkspaceMode,\n} from \"#/api/conversation-metadata-store\";\n\nexport interface CreateConversationVariables {\n query?: string;\n repository?: {\n name: string;\n gitProvider: Provider;\n branch?: string;\n };\n suggestedTask?: SuggestedTask;\n conversationInstructions?: string;\n parentConversationId?: string;\n agentType?: \"default\" | \"plan\";\n plugins?: PluginSpec[];\n workingDir?: string;\n workspaceMode?: WorkspaceMode;\n // Launch from a specific AgentProfile (local backend). When omitted, the\n // active AgentProfile (if any) is used so home-composed conversations\n // launch from the user's selected profile (#3727).\n agentProfileId?: string;\n entryPoint?: string; // analytics only; not forwarded to the service\n}\n\nexport const CREATE_CONVERSATION_MUTATION_KEY = [\"create-conversation\"];\n\ninterface CreateConversationResponse {\n conversation_id: string;\n session_api_key: string | null;\n url: string | null;\n task_id?: string;\n}\n\nexport const useCreateConversation = () => {\n const queryClient = useQueryClient();\n const { trackConversationCreated } = useTracking();\n // Cache-warm on the home page (the profile picker reads the same query).\n // Stamped onto the conversation at creation so the switcher can show the\n // exact profile even when several profiles share a model (#1082).\n const { data: llmProfiles } = useLlmProfiles();\n // Warm the agent-profiles cache too — the launch path below awaits the same\n // query via ensureQueryData, so a warm cache makes home-launch instant. The\n // hook's maybe-unresolved data is deliberately NOT read at launch time:\n // activation is pointer-only (it never writes agent_settings), so racing a\n // cold cache into the agent_settings fallback would silently launch the\n // wrong agent.\n const { backend, orgId } = useActiveBackend();\n useAgentProfiles();\n\n return useMutation({\n mutationKey: CREATE_CONVERSATION_MUTATION_KEY,\n mutationFn: async (\n variables: CreateConversationVariables,\n ): Promise<CreateConversationResponse> => {\n const {\n query,\n conversationInstructions,\n plugins,\n repository,\n workingDir,\n workspaceMode,\n parentConversationId,\n agentType,\n agentProfileId,\n } = variables;\n\n // The active AgentProfile is the default launch profile for new\n // conversations (#3727), on both local and cloud (cloud gained\n // /api/agent-profiles in OpenHands #15060, #3730). Await the list from\n // the shared query cache: a send fired before the home query resolves\n // must still launch from the active profile, not fall through to the\n // agent_settings path. Degrades safely: if the fetch errors (older\n // backend without the surface), this stays undefined and creation falls\n // back to the encrypted agent_settings launch path.\n let agentProfiles: AgentProfileListResponse | undefined;\n try {\n agentProfiles = await queryClient.ensureQueryData({\n queryKey: [...AGENT_PROFILES_QUERY_KEYS.all, backend.id, orgId],\n queryFn: AgentProfilesService.listProfiles,\n // Shared with useAgentProfiles and redirectIfAcpActive so the retry\n // policy for this surface can't drift between call sites (#1571\n // review): a backend without it fails every one of these on every\n // call, so degrade to the fallback immediately rather than sitting\n // through the default exponential-backoff retries each time.\n ...AGENT_PROFILES_RETRY_OPTIONS,\n });\n } catch {\n // Profiles unavailable → legacy agent_settings launch.\n }\n\n const requestedAgentProfileId =\n agentProfileId ?? agentProfiles?.active_agent_profile_id ?? undefined;\n\n // Fall back to the legacy agent_settings launch when the resolved agent\n // profile can't resolve its LLM. The agent-server seeds a `default`\n // openhands profile whose `llm_profile_ref` can point at an LLM profile\n // that doesn't exist (fresh store, or one configured with named profiles\n // only); launching from it 404s (\"LLM profile '<ref>' not found\") and\n // would brick home-launch. agent_settings reflects the active LLM, so the\n // fallback degrades cleanly until the seed mirrors it (SDK #3933).\n // ACP profiles carry no llm_profile_ref, so they're never gated here.\n const resolvedAgentProfile = requestedAgentProfileId\n ? agentProfiles?.profiles?.find(\n (profile) => profile.id === requestedAgentProfileId,\n )\n : undefined;\n // Cloud has no `agent_settings` payload to fall back to — the downgrade\n // below only makes sense on local, where it exists and carries the\n // canvas-only enrichments. Gating it here keeps cloud always launching\n // from the resolved profile id, so the conversation gets\n // `launched_agent_profile` stamped and the profile's config applied\n // (#1571 review).\n const isCloud = backend.kind === \"cloud\";\n let effectiveAgentProfileId = requestedAgentProfileId;\n if (\n !isCloud &&\n resolvedAgentProfile?.name === WELL_KNOWN_DEFAULT_AGENT_PROFILE_NAME &&\n resolvedAgentProfile?.agent_kind === \"openhands\"\n ) {\n // The seeded OpenHands `default` profile is the enriched baseline, not a\n // deliberate profile pick — it mirrors global agent_settings. Launch it\n // via agent_settings so the canvas-only enrichments the profile-resolution\n // path drops survive for the common home-launch: the <RUNTIME_SERVICES>\n // system-message suffix and project-skill loading (buildAgentContext).\n // Named profiles are deliberate custom configs and still use the profile\n // path (accepting that enrichment boundary).\n // Trade-off: per-profile fields set on `default` itself don't apply on\n // home-launch — custom per-profile config belongs in a named profile.\n //\n // Scoped to OpenHands: an ACP `default` must keep the profile path.\n // Activation is pointer-only, so global agent_settings is stale (often\n // still OpenHands) when an ACP profile is active — launching it via\n // agent_settings would start the wrong agent. ACP carries no\n // <RUNTIME_SERVICES> enrichment, so there's nothing to preserve.\n //\n // Scoped to local: cloud never writes agent_settings, so it always\n // resolves `default` server-side via agent_profile_id (validated below).\n effectiveAgentProfileId = undefined;\n } else if (\n resolvedAgentProfile?.agent_kind === \"openhands\" &&\n resolvedAgentProfile.llm_profile_ref\n ) {\n // Await the LLM-profile list rather than reading the maybe-unresolved\n // `useLlmProfiles()` result: a send fired before that query loads (or\n // after it errors) must still validate the ref, not launch blind.\n let llmProfileExists = false;\n try {\n const llm = await queryClient.ensureQueryData({\n queryKey: [...LLM_PROFILES_QUERY_KEYS.all, backend.id, orgId],\n queryFn: ProfilesService.listProfiles,\n // Match the agent-profiles fetch above: on a backend where this\n // errors, fall back to agent_settings immediately rather than\n // stalling the send through the default exponential backoff.\n retry: false,\n });\n llmProfileExists = llm.profiles.some(\n (profile) => profile.name === resolvedAgentProfile.llm_profile_ref,\n );\n } catch {\n // List unavailable → can't validate → fall back to agent_settings.\n }\n if (!llmProfileExists) {\n // Downgrade is silent in the UI; leave a diagnosable trace.\n console.warn(\n `Agent profile \"${resolvedAgentProfile.name}\" references missing ` +\n `LLM profile \"${resolvedAgentProfile.llm_profile_ref}\"; ` +\n \"launching from agent_settings instead.\",\n );\n effectiveAgentProfileId = undefined;\n }\n }\n\n // Only extend the call with the profile tail when launching from a\n // profile, so a plain create stays byte-identical to the legacy\n // agent_settings path (#3727). sandboxId is unused here.\n // TODO(#1587): createConversation has grown to 11 positional params;\n // refactor it to an options object so this position-skipping tail isn't\n // needed.\n const profileArgs: [undefined, string, AgentKind | undefined] | [] =\n effectiveAgentProfileId\n ? [\n undefined,\n effectiveAgentProfileId,\n resolvedAgentProfile?.agent_kind,\n ]\n : [];\n\n const conversation =\n await AgentServerConversationService.createConversation(\n query,\n conversationInstructions,\n plugins,\n repository\n ? {\n selected_repository: repository.name,\n selected_branch: repository.branch ?? null,\n git_provider: repository.gitProvider,\n }\n : null,\n workingDir,\n workspaceMode,\n parentConversationId,\n agentType,\n ...profileArgs,\n );\n\n // Stamp the active LLM profile onto the (local) conversation so the\n // chat switcher shows the exact profile even when several profiles\n // share a model (#1082). Cloud conversations don't use local profiles\n // (app_conversation_id stays null until the sandbox is READY). Merge so\n // the repo/workspace metadata the service just persisted is preserved.\n const localConversationId = conversation.app_conversation_id;\n // Snapshot the conversation's plugins into client-side metadata so the\n // in-conversation plugins view can show what's loaded (coordinates only\n // — strip parameters, which may carry secrets). The agent-server doesn't\n // return a live conversation's loaded plugins, so this snapshot is the\n // source for that view. Two sources, deduped by coordinates:\n // 1. plugins explicitly attached at creation (e.g. the /launch flow);\n // 2. enabled installed plugins, which the SDK auto-loads into every new\n // local conversation (see use-set-plugin-enabled).\n const explicitPlugins = plugins?.map(toPluginCoordinates) ?? [];\n let attachedPlugins: PluginSpec[] = explicitPlugins;\n if (localConversationId) {\n let installed: InstalledPluginInfo[] = [];\n try {\n installed = await queryClient.ensureQueryData({\n queryKey: PLUGINS_QUERY_KEYS.installed,\n queryFn: () => PluginsManagementService.listInstalledPlugins(),\n });\n } catch {\n // Best-effort: never let plugin lookup block conversation creation.\n }\n const seen = new Set(explicitPlugins.map(pluginReferenceKey));\n const enabledInstalled = installed\n .filter((plugin) => plugin.enabled)\n .map((plugin) => ({\n source: plugin.source,\n ref: plugin.resolved_ref ?? null,\n repo_path: plugin.repo_path ?? null,\n // Keep the human-friendly name so the plugins view shows e.g.\n // \"city-weather\" rather than deriving \"local\" from the source.\n name: plugin.name,\n }))\n .filter((plugin) => !seen.has(pluginReferenceKey(plugin)));\n attachedPlugins = [...explicitPlugins, ...enabledInstalled];\n }\n // A launch from a named OpenHands profile runs that profile's\n // `llm_profile_ref`, which can differ from the standalone active LLM\n // profile — stamp the ref so the switcher pill names the exact profile\n // the conversation runs (#1082). The agent_settings path (the `default`\n // baseline or a dangling ref, where effectiveAgentProfileId is cleared)\n // runs the active LLM, so it keeps `active_profile`. ACP profiles carry\n // no LLM profile, so they fall through to the active-profile stamp\n // (unused by the ACP model chip).\n const activeProfile =\n effectiveAgentProfileId &&\n resolvedAgentProfile?.agent_kind === \"openhands\"\n ? resolvedAgentProfile.llm_profile_ref\n : (llmProfiles?.active_profile ?? null);\n if (localConversationId && (activeProfile || attachedPlugins.length)) {\n const prev = getStoredConversationMetadata(localConversationId);\n setStoredConversationMetadata(localConversationId, {\n selected_repository: prev?.selected_repository ?? null,\n selected_branch: prev?.selected_branch ?? null,\n git_provider: prev?.git_provider ?? null,\n selected_workspace: prev?.selected_workspace ?? null,\n workspace_mode: prev?.workspace_mode ?? null,\n active_profile: activeProfile ?? prev?.active_profile ?? null,\n plugins: attachedPlugins.length\n ? attachedPlugins\n : (prev?.plugins ?? null),\n });\n }\n\n // OpenHands cloud pattern: when the start task isn't immediately\n // READY (cloud sandbox is still provisioning),\n // app_conversation_id is null. We return a `task-{id}` URL so the\n // conversation route's useTaskPolling can drive it to READY and\n // then redirect to the real `/conversations/{app_conversation_id}`.\n const conversationId = conversation.app_conversation_id\n ? conversation.app_conversation_id\n : `task-${conversation.id}`;\n\n return {\n conversation_id: conversationId,\n session_api_key: null,\n url: conversation.agent_server_url,\n task_id: conversation.id,\n };\n },\n onSuccess: async (data, variables) => {\n trackConversationCreated({\n conversationId: data.conversation_id,\n taskId: data.task_id,\n hasRepository: !!variables.repository,\n gitProvider: variables.repository?.gitProvider,\n hasWorkspace: !!variables.workingDir,\n workspaceMode: variables.workspaceMode,\n hasInitialQuery: !!variables.query,\n agentType: variables.agentType,\n hasParentConversation: !!variables.parentConversationId,\n entryPoint: variables.entryPoint,\n });\n\n // Invalidate (rather than remove) so the existing paginated list stays\n // rendered while a background refetch picks up the new conversation.\n // `removeQueries` would wipe the cache and force the panel back to its\n // initial loading state, dropping loaded pages and scroll position.\n queryClient.invalidateQueries({\n queryKey: [\"user\", \"conversations\"],\n });\n // The cloud path returns a start task (no app_conversation_id\n // yet); the sidebar surfaces those via `useStartTasks` which doesn't\n // poll, so invalidate it explicitly so the in-flight task shows up\n // in the conversation list immediately.\n queryClient.invalidateQueries({\n queryKey: [\"start-tasks\"],\n });\n },\n });\n};\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- require(`../../_virtual/_rolldown/runtime.cjs`);var e={WEB_CLIENT_CONFIG:[`web-client-config`]},t={all:[`settings`],byScope:e=>[`settings`,e],personal:()=>[`settings`,`personal`]},n={all:[`llm-profiles`]},r={all:[`agent-profiles`]},i={retry:!1},a={all:[`llm-subscription`],openaiStatus:[`llm-subscription`,`openai`,`status`],openaiModels:[`llm-subscription`,`openai`,`models`]},o={all:[`local-workspaces`]},s={marketplace:[`plugins-marketplace`],installed:[`plugins-installed`],local:[`plugins-local`]},c={staleTime:1e3*60*5,gcTime:1e3*60*15};exports.AGENT_PROFILES_QUERY_KEYS=r,exports.AGENT_PROFILES_RETRY_OPTIONS=i,exports.CONFIG_CACHE_OPTIONS=c,exports.LLM_PROFILES_QUERY_KEYS=n,exports.LLM_SUBSCRIPTION_QUERY_KEYS=a,exports.LOCAL_WORKSPACES_QUERY_KEYS=o,exports.PLUGINS_QUERY_KEYS=s,exports.QUERY_KEYS=e,exports.SETTINGS_QUERY_KEYS=t;
1
+ require(`../../_virtual/_rolldown/runtime.cjs`);var e={WEB_CLIENT_CONFIG:[`web-client-config`],MAIN_APP_COOKIE_AUTH:[`main-app-cookie-auth`]},t={all:[`settings`],byScope:e=>[`settings`,e],personal:()=>[`settings`,`personal`]},n={all:[`llm-profiles`]},r={all:[`agent-profiles`]},i={retry:!1},a={all:[`llm-subscription`],openaiStatus:[`llm-subscription`,`openai`,`status`],openaiModels:[`llm-subscription`,`openai`,`models`]},o={all:[`local-workspaces`]},s={marketplace:[`plugins-marketplace`],installed:[`plugins-installed`],local:[`plugins-local`]},c={staleTime:1e3*60*5,gcTime:1e3*60*15};exports.AGENT_PROFILES_QUERY_KEYS=r,exports.AGENT_PROFILES_RETRY_OPTIONS=i,exports.CONFIG_CACHE_OPTIONS=c,exports.LLM_PROFILES_QUERY_KEYS=n,exports.LLM_SUBSCRIPTION_QUERY_KEYS=a,exports.LOCAL_WORKSPACES_QUERY_KEYS=o,exports.PLUGINS_QUERY_KEYS=s,exports.QUERY_KEYS=e,exports.SETTINGS_QUERY_KEYS=t;
2
2
  //# sourceMappingURL=query-keys.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"query-keys.cjs","names":[],"sources":["../../../src/hooks/query/query-keys.ts"],"sourcesContent":["/**\n * Centralized query keys and cache configuration for TanStack Query.\n * Using constants ensures type safety and prevents typos.\n */\n\nimport { SettingsScope } from \"#/types/settings\";\n\nexport const QUERY_KEYS = {\n /** Web client configuration from the server */\n WEB_CLIENT_CONFIG: [\"web-client-config\"] as const,\n} as const;\n\nexport const SETTINGS_QUERY_KEYS = {\n all: [\"settings\"] as const,\n byScope: (scope: SettingsScope) => [\"settings\", scope] as const,\n personal: () => [\"settings\", \"personal\"] as const,\n} as const;\n\nexport const LLM_PROFILES_QUERY_KEYS = {\n all: [\"llm-profiles\"] as const,\n} as const;\n\nexport const AGENT_PROFILES_QUERY_KEYS = {\n all: [\"agent-profiles\"] as const,\n} as const;\n\n/**\n * Shared retry policy for every `/api/agent-profiles` fetch (the launch path\n * in `useCreateConversation`, `redirectIfAcpActive`'s route guard, and\n * `useAgentProfiles`). An older backend without the surface fails every one\n * of these on every call — `retry: false` degrades immediately instead of\n * sitting through the default exponential backoff each time (#1571 review).\n */\nexport const AGENT_PROFILES_RETRY_OPTIONS = {\n retry: false,\n} as const;\n\nexport const LLM_SUBSCRIPTION_QUERY_KEYS = {\n all: [\"llm-subscription\"] as const,\n openaiStatus: [\"llm-subscription\", \"openai\", \"status\"] as const,\n openaiModels: [\"llm-subscription\", \"openai\", \"models\"] as const,\n} as const;\n\nexport const LOCAL_WORKSPACES_QUERY_KEYS = {\n all: [\"local-workspaces\"] as const,\n} as const;\n\nexport const PLUGINS_QUERY_KEYS = {\n /** Dynamic marketplace catalog (used by `use-plugins-marketplace`). */\n marketplace: [\"plugins-marketplace\"] as const,\n /** Installed plugins from the local agent-server. */\n installed: [\"plugins-installed\"] as const,\n /** Locally-discovered ambient plugins (used by `use-local-plugins`). */\n local: [\"plugins-local\"] as const,\n} as const;\n\n/** Cache configuration shared across all config-related queries */\nexport const CONFIG_CACHE_OPTIONS = {\n staleTime: 1000 * 60 * 5, // 5 minutes\n gcTime: 1000 * 60 * 15, // 15 minutes\n} as const;\n\nexport type QueryKeys = (typeof QUERY_KEYS)[keyof typeof QUERY_KEYS];\n"],"mappings":"gDAOA,IAAa,EAAa,CAExB,kBAAmB,CAAC,oBAAoB,CACzC,CAEY,EAAsB,CACjC,IAAK,CAAC,WAAW,CACjB,QAAU,GAAyB,CAAC,WAAY,EAAM,CACtD,aAAgB,CAAC,WAAY,WAAW,CACzC,CAEY,EAA0B,CACrC,IAAK,CAAC,eAAe,CACtB,CAEY,EAA4B,CACvC,IAAK,CAAC,iBAAiB,CACxB,CASY,EAA+B,CAC1C,MAAO,GACR,CAEY,EAA8B,CACzC,IAAK,CAAC,mBAAmB,CACzB,aAAc,CAAC,mBAAoB,SAAU,SAAS,CACtD,aAAc,CAAC,mBAAoB,SAAU,SAAS,CACvD,CAEY,EAA8B,CACzC,IAAK,CAAC,mBAAmB,CAC1B,CAEY,EAAqB,CAEhC,YAAa,CAAC,sBAAsB,CAEpC,UAAW,CAAC,oBAAoB,CAEhC,MAAO,CAAC,gBAAgB,CACzB,CAGY,EAAuB,CAClC,UAAW,IAAO,GAAK,EACvB,OAAQ,IAAO,GAAK,GACrB"}
1
+ {"version":3,"file":"query-keys.cjs","names":[],"sources":["../../../src/hooks/query/query-keys.ts"],"sourcesContent":["/**\n * Centralized query keys and cache configuration for TanStack Query.\n * Using constants ensures type safety and prevents typos.\n */\n\nimport { SettingsScope } from \"#/types/settings\";\n\nexport const QUERY_KEYS = {\n /** Web client configuration from the server */\n WEB_CLIENT_CONFIG: [\"web-client-config\"] as const,\n /** Same-origin OpenHands app cookie authentication status */\n MAIN_APP_COOKIE_AUTH: [\"main-app-cookie-auth\"] as const,\n} as const;\n\nexport const SETTINGS_QUERY_KEYS = {\n all: [\"settings\"] as const,\n byScope: (scope: SettingsScope) => [\"settings\", scope] as const,\n personal: () => [\"settings\", \"personal\"] as const,\n} as const;\n\nexport const LLM_PROFILES_QUERY_KEYS = {\n all: [\"llm-profiles\"] as const,\n} as const;\n\nexport const AGENT_PROFILES_QUERY_KEYS = {\n all: [\"agent-profiles\"] as const,\n} as const;\n\n/**\n * Shared retry policy for every `/api/agent-profiles` fetch (the launch path\n * in `useCreateConversation`, `redirectIfAcpActive`'s route guard, and\n * `useAgentProfiles`). An older backend without the surface fails every one\n * of these on every call — `retry: false` degrades immediately instead of\n * sitting through the default exponential backoff each time (#1571 review).\n */\nexport const AGENT_PROFILES_RETRY_OPTIONS = {\n retry: false,\n} as const;\n\nexport const LLM_SUBSCRIPTION_QUERY_KEYS = {\n all: [\"llm-subscription\"] as const,\n openaiStatus: [\"llm-subscription\", \"openai\", \"status\"] as const,\n openaiModels: [\"llm-subscription\", \"openai\", \"models\"] as const,\n} as const;\n\nexport const LOCAL_WORKSPACES_QUERY_KEYS = {\n all: [\"local-workspaces\"] as const,\n} as const;\n\nexport const PLUGINS_QUERY_KEYS = {\n /** Dynamic marketplace catalog (used by `use-plugins-marketplace`). */\n marketplace: [\"plugins-marketplace\"] as const,\n /** Installed plugins from the local agent-server. */\n installed: [\"plugins-installed\"] as const,\n /** Locally-discovered ambient plugins (used by `use-local-plugins`). */\n local: [\"plugins-local\"] as const,\n} as const;\n\n/** Cache configuration shared across all config-related queries */\nexport const CONFIG_CACHE_OPTIONS = {\n staleTime: 1000 * 60 * 5, // 5 minutes\n gcTime: 1000 * 60 * 15, // 15 minutes\n} as const;\n\nexport type QueryKeys = (typeof QUERY_KEYS)[keyof typeof QUERY_KEYS];\n"],"mappings":"gDAOA,IAAa,EAAa,CAExB,kBAAmB,CAAC,oBAAoB,CAExC,qBAAsB,CAAC,uBAAuB,CAC/C,CAEY,EAAsB,CACjC,IAAK,CAAC,WAAW,CACjB,QAAU,GAAyB,CAAC,WAAY,EAAM,CACtD,aAAgB,CAAC,WAAY,WAAW,CACzC,CAEY,EAA0B,CACrC,IAAK,CAAC,eAAe,CACtB,CAEY,EAA4B,CACvC,IAAK,CAAC,iBAAiB,CACxB,CASY,EAA+B,CAC1C,MAAO,GACR,CAEY,EAA8B,CACzC,IAAK,CAAC,mBAAmB,CACzB,aAAc,CAAC,mBAAoB,SAAU,SAAS,CACtD,aAAc,CAAC,mBAAoB,SAAU,SAAS,CACvD,CAEY,EAA8B,CACzC,IAAK,CAAC,mBAAmB,CAC1B,CAEY,EAAqB,CAEhC,YAAa,CAAC,sBAAsB,CAEpC,UAAW,CAAC,oBAAoB,CAEhC,MAAO,CAAC,gBAAgB,CACzB,CAGY,EAAuB,CAClC,UAAW,IAAO,GAAK,EACvB,OAAQ,IAAO,GAAK,GACrB"}
@@ -6,6 +6,8 @@ import { SettingsScope } from "#/types/settings";
6
6
  export declare const QUERY_KEYS: {
7
7
  /** Web client configuration from the server */
8
8
  readonly WEB_CLIENT_CONFIG: readonly ["web-client-config"];
9
+ /** Same-origin OpenHands app cookie authentication status */
10
+ readonly MAIN_APP_COOKIE_AUTH: readonly ["main-app-cookie-auth"];
9
11
  };
10
12
  export declare const SETTINGS_QUERY_KEYS: {
11
13
  readonly all: readonly ["settings"];
@@ -1,5 +1,8 @@
1
1
  //#region src/hooks/query/query-keys.ts
2
- var e = { WEB_CLIENT_CONFIG: ["web-client-config"] }, t = {
2
+ var e = {
3
+ WEB_CLIENT_CONFIG: ["web-client-config"],
4
+ MAIN_APP_COOKIE_AUTH: ["main-app-cookie-auth"]
5
+ }, t = {
3
6
  all: ["settings"],
4
7
  byScope: (e) => ["settings", e],
5
8
  personal: () => ["settings", "personal"]
@@ -1 +1 @@
1
- {"version":3,"file":"query-keys.js","names":[],"sources":["../../../src/hooks/query/query-keys.ts"],"sourcesContent":["/**\n * Centralized query keys and cache configuration for TanStack Query.\n * Using constants ensures type safety and prevents typos.\n */\n\nimport { SettingsScope } from \"#/types/settings\";\n\nexport const QUERY_KEYS = {\n /** Web client configuration from the server */\n WEB_CLIENT_CONFIG: [\"web-client-config\"] as const,\n} as const;\n\nexport const SETTINGS_QUERY_KEYS = {\n all: [\"settings\"] as const,\n byScope: (scope: SettingsScope) => [\"settings\", scope] as const,\n personal: () => [\"settings\", \"personal\"] as const,\n} as const;\n\nexport const LLM_PROFILES_QUERY_KEYS = {\n all: [\"llm-profiles\"] as const,\n} as const;\n\nexport const AGENT_PROFILES_QUERY_KEYS = {\n all: [\"agent-profiles\"] as const,\n} as const;\n\n/**\n * Shared retry policy for every `/api/agent-profiles` fetch (the launch path\n * in `useCreateConversation`, `redirectIfAcpActive`'s route guard, and\n * `useAgentProfiles`). An older backend without the surface fails every one\n * of these on every call — `retry: false` degrades immediately instead of\n * sitting through the default exponential backoff each time (#1571 review).\n */\nexport const AGENT_PROFILES_RETRY_OPTIONS = {\n retry: false,\n} as const;\n\nexport const LLM_SUBSCRIPTION_QUERY_KEYS = {\n all: [\"llm-subscription\"] as const,\n openaiStatus: [\"llm-subscription\", \"openai\", \"status\"] as const,\n openaiModels: [\"llm-subscription\", \"openai\", \"models\"] as const,\n} as const;\n\nexport const LOCAL_WORKSPACES_QUERY_KEYS = {\n all: [\"local-workspaces\"] as const,\n} as const;\n\nexport const PLUGINS_QUERY_KEYS = {\n /** Dynamic marketplace catalog (used by `use-plugins-marketplace`). */\n marketplace: [\"plugins-marketplace\"] as const,\n /** Installed plugins from the local agent-server. */\n installed: [\"plugins-installed\"] as const,\n /** Locally-discovered ambient plugins (used by `use-local-plugins`). */\n local: [\"plugins-local\"] as const,\n} as const;\n\n/** Cache configuration shared across all config-related queries */\nexport const CONFIG_CACHE_OPTIONS = {\n staleTime: 1000 * 60 * 5, // 5 minutes\n gcTime: 1000 * 60 * 15, // 15 minutes\n} as const;\n\nexport type QueryKeys = (typeof QUERY_KEYS)[keyof typeof QUERY_KEYS];\n"],"mappings":";AAOA,IAAa,IAAa,EAExB,mBAAmB,CAAC,oBAAoB,EACzC,EAEY,IAAsB;CACjC,KAAK,CAAC,WAAW;CACjB,UAAU,MAAyB,CAAC,YAAY,EAAM;CACtD,gBAAgB,CAAC,YAAY,WAAW;CACzC,EAEY,IAA0B,EACrC,KAAK,CAAC,eAAe,EACtB,EAEY,IAA4B,EACvC,KAAK,CAAC,iBAAiB,EACxB,EASY,IAA+B,EAC1C,OAAO,IACR,EAEY,IAA8B;CACzC,KAAK,CAAC,mBAAmB;CACzB,cAAc;EAAC;EAAoB;EAAU;EAAS;CACtD,cAAc;EAAC;EAAoB;EAAU;EAAS;CACvD,EAEY,IAA8B,EACzC,KAAK,CAAC,mBAAmB,EAC1B,EAEY,IAAqB;CAEhC,aAAa,CAAC,sBAAsB;CAEpC,WAAW,CAAC,oBAAoB;CAEhC,OAAO,CAAC,gBAAgB;CACzB,EAGY,IAAuB;CAClC,WAAW,MAAO,KAAK;CACvB,QAAQ,MAAO,KAAK;CACrB"}
1
+ {"version":3,"file":"query-keys.js","names":[],"sources":["../../../src/hooks/query/query-keys.ts"],"sourcesContent":["/**\n * Centralized query keys and cache configuration for TanStack Query.\n * Using constants ensures type safety and prevents typos.\n */\n\nimport { SettingsScope } from \"#/types/settings\";\n\nexport const QUERY_KEYS = {\n /** Web client configuration from the server */\n WEB_CLIENT_CONFIG: [\"web-client-config\"] as const,\n /** Same-origin OpenHands app cookie authentication status */\n MAIN_APP_COOKIE_AUTH: [\"main-app-cookie-auth\"] as const,\n} as const;\n\nexport const SETTINGS_QUERY_KEYS = {\n all: [\"settings\"] as const,\n byScope: (scope: SettingsScope) => [\"settings\", scope] as const,\n personal: () => [\"settings\", \"personal\"] as const,\n} as const;\n\nexport const LLM_PROFILES_QUERY_KEYS = {\n all: [\"llm-profiles\"] as const,\n} as const;\n\nexport const AGENT_PROFILES_QUERY_KEYS = {\n all: [\"agent-profiles\"] as const,\n} as const;\n\n/**\n * Shared retry policy for every `/api/agent-profiles` fetch (the launch path\n * in `useCreateConversation`, `redirectIfAcpActive`'s route guard, and\n * `useAgentProfiles`). An older backend without the surface fails every one\n * of these on every call — `retry: false` degrades immediately instead of\n * sitting through the default exponential backoff each time (#1571 review).\n */\nexport const AGENT_PROFILES_RETRY_OPTIONS = {\n retry: false,\n} as const;\n\nexport const LLM_SUBSCRIPTION_QUERY_KEYS = {\n all: [\"llm-subscription\"] as const,\n openaiStatus: [\"llm-subscription\", \"openai\", \"status\"] as const,\n openaiModels: [\"llm-subscription\", \"openai\", \"models\"] as const,\n} as const;\n\nexport const LOCAL_WORKSPACES_QUERY_KEYS = {\n all: [\"local-workspaces\"] as const,\n} as const;\n\nexport const PLUGINS_QUERY_KEYS = {\n /** Dynamic marketplace catalog (used by `use-plugins-marketplace`). */\n marketplace: [\"plugins-marketplace\"] as const,\n /** Installed plugins from the local agent-server. */\n installed: [\"plugins-installed\"] as const,\n /** Locally-discovered ambient plugins (used by `use-local-plugins`). */\n local: [\"plugins-local\"] as const,\n} as const;\n\n/** Cache configuration shared across all config-related queries */\nexport const CONFIG_CACHE_OPTIONS = {\n staleTime: 1000 * 60 * 5, // 5 minutes\n gcTime: 1000 * 60 * 15, // 15 minutes\n} as const;\n\nexport type QueryKeys = (typeof QUERY_KEYS)[keyof typeof QUERY_KEYS];\n"],"mappings":";AAOA,IAAa,IAAa;CAExB,mBAAmB,CAAC,oBAAoB;CAExC,sBAAsB,CAAC,uBAAuB;CAC/C,EAEY,IAAsB;CACjC,KAAK,CAAC,WAAW;CACjB,UAAU,MAAyB,CAAC,YAAY,EAAM;CACtD,gBAAgB,CAAC,YAAY,WAAW;CACzC,EAEY,IAA0B,EACrC,KAAK,CAAC,eAAe,EACtB,EAEY,IAA4B,EACvC,KAAK,CAAC,iBAAiB,EACxB,EASY,IAA+B,EAC1C,OAAO,IACR,EAEY,IAA8B;CACzC,KAAK,CAAC,mBAAmB;CACzB,cAAc;EAAC;EAAoB;EAAU;EAAS;CACtD,cAAc;EAAC;EAAoB;EAAU;EAAS;CACvD,EAEY,IAA8B,EACzC,KAAK,CAAC,mBAAmB,EAC1B,EAEY,IAAqB;CAEhC,aAAa,CAAC,sBAAsB;CAEpC,WAAW,CAAC,oBAAoB;CAEhC,OAAO,CAAC,gBAAgB;CACzB,EAGY,IAAuB;CAClC,WAAW,MAAO,KAAK;CACvB,QAAQ,MAAO,KAAK;CACrB"}
@@ -1,2 +1,2 @@
1
- const e=require(`../../_virtual/_rolldown/runtime.cjs`),t=require(`../../node_modules/@openhands/typescript-client/dist/client/server-client.cjs`),n=require(`../../node_modules/@openhands/typescript-client/dist/client/settings-client.cjs`);require(`../../node_modules/@openhands/typescript-client/dist/clients.cjs`);const r=require(`../../api/agent-server-client-options.cjs`),i=require(`../../api/agent-server-compatibility.cjs`),a=require(`../../utils/user-facing-error.cjs`),o=require(`../../api/backend-registry/health-store.cjs`),s=require(`../../node_modules/@tanstack/react-query/build/modern/useQueries.cjs`),c=require(`../../node_modules/axios/lib/axios.cjs`),l=require(`../../api/cloud/organization-service.api.cjs`);let u=require(`react`);u=e.__toESM(u,1);var d=1e4,f=4e3,p=`Invalid API key`,m=`API key required`,h=`Cloud API key or network issue`,g=`Logged out`;function _(e){return e===p}function v(e){return e===m}function y(e){return e===h}function b(e){return e.kind===`cloud`&&!e.apiKey.trim()}function x(e){return e===g}async function S(e){if(e.kind===`cloud`){if(!e.apiKey?.trim())throw Error(m);try{await l.getCurrentCloudApiKey(e)}catch(e){throw c.default.isAxiosError(e)&&e.response?.status===401?Error(g):a.isCorsOrNetworkError(e)?Error(h):e}return!0}try{let a=r.getAgentServerClientOptions({host:e.host,sessionApiKey:e.apiKey||null,timeout:f});await new n.SettingsClient(a).getSettings(),i.assertAgentServerVersionIsSupported(await new t.ServerClient(a).getServerInfo())}catch(e){throw i.isSdkHttpStatusError(e,401)?Error(p):e}return!0}var C=2,w=300;function T(e){return e instanceof Error?e.message!==`Invalid API key`&&e.message!==`API key required`&&e.message!==`Logged out`:!0}async function E(e){for(let t=0;;t+=1)try{return await S(e)}catch(e){if(t>=C||!T(e))throw e;await new Promise(e=>{setTimeout(e,w)})}}function D(e,t={}){let{probeDisabledOnce:n=!1}=t,r=u.default.useSyncExternalStore(o.subscribeBackendHealth,o.getHealthSnapshot,o.getHealthSnapshot),i=s.useQueries({queries:e.map(e=>{let t=r[e.id],i=b(e),s=t?.disabled===!0,c=s&&e.kind===`cloud`&&a.isCorsOrNetworkErrorMessage(t?.lastError),l=!i&&(!s||n||c);return{queryKey:[`backend-health`,e.id,e.kind,e.host,e.apiKey??``],queryFn:async()=>{try{let t=await E(e);return o.recordBackendSuccess(e.id),t}catch(t){throw o.recordBackendFailure(e.id,t),t}},enabled:l,refetchInterval:s||i?!1:d,refetchIntervalInBackground:!1,refetchOnMount:s&&n?`always`:!0,refetchOnReconnect:!s&&!i,refetchOnWindowFocus:!s&&!i,retry:!1,staleTime:s?0:d,meta:{disableToast:!0}}})}),c={};return e.forEach((e,t)=>{let n=i[t],a=r[e.id],o=b(e),s=o?!1:a?.disabled===!0,l=o?0:a?.consecutiveFailures??0,u=o?m:a?.lastError??null,d;d=o||s?!1:n.isSuccess?!0:n.isError?!1:null,c[e.id]={isConnected:d,consecutiveFailures:l,lastError:u,disabled:s}}),c}exports.isCloudBackendApiKeyOrNetworkHealthError=y,exports.isCloudBackendLoggedOutHealthError=x,exports.isInvalidBackendApiKeyHealthError=_,exports.isMissingBackendApiKeyHealthError=v,exports.useBackendsHealth=D;
1
+ const e=require(`../../_virtual/_rolldown/runtime.cjs`),t=require(`../../node_modules/@openhands/typescript-client/dist/client/http-client.cjs`),n=require(`../../node_modules/@openhands/typescript-client/dist/client/server-client.cjs`),r=require(`../../node_modules/@openhands/typescript-client/dist/client/settings-client.cjs`);require(`../../node_modules/@openhands/typescript-client/dist/clients.cjs`);const i=require(`../../api/agent-server-client-options.cjs`),a=require(`../../api/agent-server-compatibility.cjs`),o=require(`../../utils/user-facing-error.cjs`),s=require(`../../api/backend-registry/health-store.cjs`),c=require(`../../node_modules/@tanstack/react-query/build/modern/useQueries.cjs`),l=require(`../../node_modules/axios/lib/axios.cjs`);require(`../../node_modules/@openhands/typescript-client/dist/index.cjs`);const u=require(`../../api/cloud/organization-service.api.cjs`);let d=require(`react`);d=e.__toESM(d,1);var f=1e4,p=4e3,m=`Invalid API key`,h=`API key required`,g=`Cloud API key or network issue`,_=`Logged out`;function v(e){return e===m}function y(e){return e===h}function b(e){return e===g}function x(e){return e.kind===`cloud`&&e.authMode!==`cookie`&&!e.apiKey.trim()}function S(e){return e===_}async function C(e){if(e.kind===`cloud`){if(e.authMode!==`cookie`&&!e.apiKey?.trim())throw Error(h);try{e.authMode===`cookie`?await u.getCloudOrganizations(e):await u.getCurrentCloudApiKey(e)}catch(e){throw l.default.isAxiosError(e)&&e.response?.status===401||e instanceof t.HttpError&&e.status===401?Error(_):o.isCorsOrNetworkError(e)?Error(g):e}return!0}try{let t=i.getAgentServerClientOptions({host:e.host,sessionApiKey:e.apiKey||null,timeout:p});await new r.SettingsClient(t).getSettings(),a.assertAgentServerVersionIsSupported(await new n.ServerClient(t).getServerInfo())}catch(e){throw a.isSdkHttpStatusError(e,401)?Error(m):e}return!0}var w=2,T=300;function E(e){return e instanceof Error?e.message!==`Invalid API key`&&e.message!==`API key required`&&e.message!==`Logged out`:!0}async function D(e){for(let t=0;;t+=1)try{return await C(e)}catch(e){if(t>=w||!E(e))throw e;await new Promise(e=>{setTimeout(e,T)})}}function O(e,t={}){let{probeDisabledOnce:n=!1}=t,r=d.default.useSyncExternalStore(s.subscribeBackendHealth,s.getHealthSnapshot,s.getHealthSnapshot),i=c.useQueries({queries:e.map(e=>{let t=r[e.id],i=x(e),a=t?.disabled===!0,c=a&&e.kind===`cloud`&&o.isCorsOrNetworkErrorMessage(t?.lastError),l=!i&&(!a||n||c);return{queryKey:[`backend-health`,e.id,e.kind,e.host,e.apiKey??``],queryFn:async()=>{try{let t=await D(e);return s.recordBackendSuccess(e.id),t}catch(t){throw s.recordBackendFailure(e.id,t),t}},enabled:l,refetchInterval:a||i?!1:f,refetchIntervalInBackground:!1,refetchOnMount:a&&n?`always`:!0,refetchOnReconnect:!a&&!i,refetchOnWindowFocus:!a&&!i,retry:!1,staleTime:a?0:f,meta:{disableToast:!0}}})}),a={};return e.forEach((e,t)=>{let n=i[t],o=r[e.id],s=x(e),c=s?!1:o?.disabled===!0,l=s?0:o?.consecutiveFailures??0,u=s?h:o?.lastError??null,d;d=s||c?!1:n.isSuccess?!0:n.isError?!1:null,a[e.id]={isConnected:d,consecutiveFailures:l,lastError:u,disabled:c}}),a}exports.isCloudBackendApiKeyOrNetworkHealthError=b,exports.isCloudBackendLoggedOutHealthError=S,exports.isInvalidBackendApiKeyHealthError=v,exports.isMissingBackendApiKeyHealthError=y,exports.useBackendsHealth=O;
2
2
  //# sourceMappingURL=use-backends-health.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-backends-health.cjs","names":[],"sources":["../../../src/hooks/query/use-backends-health.ts"],"sourcesContent":["import React from \"react\";\nimport axios from \"axios\";\nimport { useQueries } from \"@tanstack/react-query\";\nimport {\n ServerClient,\n SettingsClient,\n} from \"@openhands/typescript-client/clients\";\nimport { getCurrentCloudApiKey } from \"#/api/cloud/organization-service.api\";\nimport {\n assertAgentServerVersionIsSupported,\n isSdkHttpStatusError,\n} from \"#/api/agent-server-compatibility\";\nimport type { Backend } from \"#/api/backend-registry/types\";\nimport { getAgentServerClientOptions } from \"#/api/agent-server-client-options\";\nimport {\n isCorsOrNetworkError,\n isCorsOrNetworkErrorMessage,\n} from \"#/utils/user-facing-error\";\nimport {\n getHealthSnapshot,\n recordBackendFailure,\n recordBackendSuccess,\n subscribeBackendHealth,\n} from \"#/api/backend-registry/health-store\";\nimport { MAX_CONSECUTIVE_FAILURES } from \"#/api/backend-registry/health-storage\";\n\nconst REFRESH_INTERVAL_MS = 10000;\nconst PROBE_TIMEOUT_MS = 4000;\nexport const INVALID_BACKEND_API_KEY_ERROR = \"Invalid API key\";\nexport const MISSING_BACKEND_API_KEY_ERROR = \"API key required\";\nexport const CLOUD_BACKEND_API_KEY_OR_NETWORK_ERROR =\n \"Cloud API key or network issue\";\nexport const CLOUD_BACKEND_LOGGED_OUT_ERROR = \"Logged out\";\n\nexport function isInvalidBackendApiKeyHealthError(\n error: string | null | undefined,\n): boolean {\n return error === INVALID_BACKEND_API_KEY_ERROR;\n}\n\nexport function isMissingBackendApiKeyHealthError(\n error: string | null | undefined,\n): boolean {\n return error === MISSING_BACKEND_API_KEY_ERROR;\n}\n\nexport function isCloudBackendApiKeyOrNetworkHealthError(\n error: string | null | undefined,\n): boolean {\n return error === CLOUD_BACKEND_API_KEY_OR_NETWORK_ERROR;\n}\n\nfunction hasMissingBackendApiKey(backend: Backend): boolean {\n return backend.kind === \"cloud\" && !backend.apiKey.trim();\n}\n\nexport function isCloudBackendLoggedOutHealthError(\n error: string | null | undefined,\n): boolean {\n return error === CLOUD_BACKEND_LOGGED_OUT_ERROR;\n}\n\n/**\n * Probe a single backend for connectivity. The probe path differs by\n * backend kind:\n *\n * - Local agent-server: GET `/api/settings`, then `/server_info` via the\n * typescript-client. The settings call validates the configured session\n * API key; the server info call validates the version compatibility floor.\n * - Cloud: GET `/api/keys/current` directly against the cloud host. That\n * endpoint is lightweight, requires auth, and `getCurrentCloudApiKey`\n * already absorbs the legacy-key 400 fallback so we treat that as\n * \"connected\" too. Missing / rejected keys are reported explicitly instead\n * of falling through to the browser's opaque CORS/network error shape.\n *\n * Throws on failure so React Query marks the query as errored — the\n * dropdown reads `isSuccess` to flip the indicator green.\n */\nasync function probeBackend(backend: Backend): Promise<true> {\n if (backend.kind === \"cloud\") {\n if (!backend.apiKey?.trim()) {\n throw new Error(MISSING_BACKEND_API_KEY_ERROR);\n }\n\n try {\n await getCurrentCloudApiKey(backend);\n } catch (error) {\n if (axios.isAxiosError(error) && error.response?.status === 401) {\n throw new Error(CLOUD_BACKEND_LOGGED_OUT_ERROR);\n }\n if (isCorsOrNetworkError(error)) {\n throw new Error(CLOUD_BACKEND_API_KEY_OR_NETWORK_ERROR);\n }\n throw error;\n }\n return true;\n }\n\n try {\n const clientOptions = getAgentServerClientOptions({\n host: backend.host,\n sessionApiKey: backend.apiKey || null,\n timeout: PROBE_TIMEOUT_MS,\n });\n\n await new SettingsClient(clientOptions).getSettings();\n const serverInfo = await new ServerClient(clientOptions).getServerInfo();\n assertAgentServerVersionIsSupported(serverInfo);\n } catch (error) {\n if (isSdkHttpStatusError(error, 401)) {\n throw new Error(INVALID_BACKEND_API_KEY_ERROR);\n }\n throw error;\n }\n return true;\n}\n\n/**\n * How many extra times to re-run a failed probe before giving up, and how\n * long to wait between attempts.\n */\nconst PROBE_RETRY_ATTEMPTS = 2;\nconst PROBE_RETRY_DELAY_MS = 300;\n\n/**\n * Probe a backend, retrying a couple of times on failure before giving up.\n *\n * The connectivity indicator (and the onboarding \"backend connected\" banner)\n * only flips green once a probe succeeds. With `retry: false` at the query\n * level and a REFRESH_INTERVAL_MS (10s) poll, a single transient first-probe\n * miss — the agent-server still warming up right after navigation, a momentary\n * proxy 5xx, a dropped connection — would otherwise leave the banner stuck for\n * a full 10s until the next scheduled refetch. That is the root cause of the\n * flaky onboarding e2e \"backend health probe should report connected\" timeout.\n *\n * Retrying here, inside the query function rather than via React Query's\n * `retry`, is deliberate: the success/failure recording below runs once per\n * settled query, so a single logical probe still records exactly one outcome.\n * Retrying at the query level instead would call `recordBackendFailure` on\n * every internal attempt and reach the disabled cap several times too fast.\n *\n * Definitive auth failures (logged out, invalid/missing key) are NOT retried:\n * they are a decided server response, not a transient miss, so retrying only\n * delays surfacing the correct \"disconnected\" state (and the recovery UI).\n */\nfunction isRetryableProbeError(error: unknown): boolean {\n if (!(error instanceof Error)) return true;\n return (\n error.message !== INVALID_BACKEND_API_KEY_ERROR &&\n error.message !== MISSING_BACKEND_API_KEY_ERROR &&\n error.message !== CLOUD_BACKEND_LOGGED_OUT_ERROR\n );\n}\n\nasync function probeBackendWithQuickRetry(backend: Backend): Promise<true> {\n for (let attempt = 0; ; attempt += 1) {\n try {\n return await probeBackend(backend);\n } catch (error) {\n if (attempt >= PROBE_RETRY_ATTEMPTS || !isRetryableProbeError(error)) {\n throw error;\n }\n await new Promise((resolve) => {\n setTimeout(resolve, PROBE_RETRY_DELAY_MS);\n });\n }\n }\n}\n\nexport interface BackendHealth {\n /** `null` while the first probe is in flight; then `true` / `false`. */\n isConnected: boolean | null;\n /** Number of consecutive failed probes since the last success. */\n consecutiveFailures: number;\n /** Last error message captured from a failed probe, if any. */\n lastError: string | null;\n /**\n * `true` once `consecutiveFailures` reaches the cap. While disabled,\n * ordinary background polling stops and survives a page refresh in\n * that state.\n */\n disabled: boolean;\n}\n\nexport interface UseBackendsHealthOptions {\n /**\n * Re-probe disabled backends once when the hook mounts. Used by the\n * Manage Backends modal so a recovered backend can clear its stale\n * persisted error state without forcing the user to edit the config.\n */\n probeDisabledOnce?: boolean;\n}\n\n/**\n * Poll every backend in `backends` once every 10s and report a simple\n * connected / disconnected verdict per backend id.\n *\n * The query key includes `host` and `apiKey` so editing a backend's\n * connection details re-keys the query and triggers an immediate\n * refetch instead of waiting for the next tick.\n *\n * After `MAX_CONSECUTIVE_FAILURES` failures in a row, ordinary polling\n * stops for that backend until the user updates its host / apiKey.\n * Callers can still opt into a one-shot recheck for disabled backends\n * (for example when the user explicitly opens Manage Backends). The\n * failure count and last error live in localStorage so a page refresh\n * does not silently re-arm polling against a backend that's known to\n * be unreachable.\n */\nexport function useBackendsHealth(\n backends: Backend[],\n options: UseBackendsHealthOptions = {},\n): Record<string, BackendHealth> {\n const { probeDisabledOnce = false } = options;\n const healthMap = React.useSyncExternalStore(\n subscribeBackendHealth,\n getHealthSnapshot,\n getHealthSnapshot,\n );\n\n const results = useQueries({\n queries: backends.map((b) => {\n const entry = healthMap[b.id];\n const hasMissingCloudApiKey = hasMissingBackendApiKey(b);\n const isDisabled = entry?.disabled === true;\n const shouldReprobeStaleCloudNetworkError =\n isDisabled &&\n b.kind === \"cloud\" &&\n isCorsOrNetworkErrorMessage(entry?.lastError);\n const shouldProbe =\n !hasMissingCloudApiKey &&\n (!isDisabled ||\n probeDisabledOnce ||\n shouldReprobeStaleCloudNetworkError);\n return {\n queryKey: [\n \"backend-health\",\n b.id,\n b.kind,\n b.host,\n b.apiKey ?? \"\",\n ] as const,\n queryFn: async () => {\n try {\n const result = await probeBackendWithQuickRetry(b);\n recordBackendSuccess(b.id);\n return result;\n } catch (err) {\n recordBackendFailure(b.id, err);\n throw err;\n }\n },\n enabled: shouldProbe,\n refetchInterval:\n isDisabled || hasMissingCloudApiKey\n ? (false as const)\n : REFRESH_INTERVAL_MS,\n refetchIntervalInBackground: false,\n refetchOnMount: isDisabled && probeDisabledOnce ? \"always\" : true,\n refetchOnReconnect: !isDisabled && !hasMissingCloudApiKey,\n refetchOnWindowFocus: !isDisabled && !hasMissingCloudApiKey,\n retry: false,\n // Keep the previous verdict visible while the next probe is in\n // flight so the indicator doesn't flicker on routine polling.\n staleTime: isDisabled ? 0 : REFRESH_INTERVAL_MS,\n meta: { disableToast: true },\n };\n }),\n });\n\n const out: Record<string, BackendHealth> = {};\n backends.forEach((b, i) => {\n const r = results[i];\n const entry = healthMap[b.id];\n const hasMissingCloudApiKey = hasMissingBackendApiKey(b);\n const disabled = hasMissingCloudApiKey ? false : entry?.disabled === true;\n const consecutiveFailures = hasMissingCloudApiKey\n ? 0\n : (entry?.consecutiveFailures ?? 0);\n const lastError = hasMissingCloudApiKey\n ? MISSING_BACKEND_API_KEY_ERROR\n : (entry?.lastError ?? null);\n\n let isConnected: boolean | null;\n if (hasMissingCloudApiKey) {\n isConnected = false;\n } else if (disabled) {\n // Polling stopped after hitting the cap — treat as disconnected\n // so existing consumers (dot, badge) render red without needing\n // to know about the new fields.\n isConnected = false;\n } else if (r.isSuccess) isConnected = true;\n else if (r.isError) isConnected = false;\n else isConnected = null;\n\n out[b.id] = { isConnected, consecutiveFailures, lastError, disabled };\n });\n return out;\n}\n\nexport { MAX_CONSECUTIVE_FAILURES };\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-backends-health.cjs","names":[],"sources":["../../../src/hooks/query/use-backends-health.ts"],"sourcesContent":["import React from \"react\";\nimport axios from \"axios\";\nimport { useQueries } from \"@tanstack/react-query\";\nimport { HttpError } from \"@openhands/typescript-client\";\nimport {\n ServerClient,\n SettingsClient,\n} from \"@openhands/typescript-client/clients\";\nimport {\n getCloudOrganizations,\n getCurrentCloudApiKey,\n} from \"#/api/cloud/organization-service.api\";\nimport {\n assertAgentServerVersionIsSupported,\n isSdkHttpStatusError,\n} from \"#/api/agent-server-compatibility\";\nimport type { Backend } from \"#/api/backend-registry/types\";\nimport { getAgentServerClientOptions } from \"#/api/agent-server-client-options\";\nimport {\n isCorsOrNetworkError,\n isCorsOrNetworkErrorMessage,\n} from \"#/utils/user-facing-error\";\nimport {\n getHealthSnapshot,\n recordBackendFailure,\n recordBackendSuccess,\n subscribeBackendHealth,\n} from \"#/api/backend-registry/health-store\";\nimport { MAX_CONSECUTIVE_FAILURES } from \"#/api/backend-registry/health-storage\";\n\nconst REFRESH_INTERVAL_MS = 10000;\nconst PROBE_TIMEOUT_MS = 4000;\nexport const INVALID_BACKEND_API_KEY_ERROR = \"Invalid API key\";\nexport const MISSING_BACKEND_API_KEY_ERROR = \"API key required\";\nexport const CLOUD_BACKEND_API_KEY_OR_NETWORK_ERROR =\n \"Cloud API key or network issue\";\nexport const CLOUD_BACKEND_LOGGED_OUT_ERROR = \"Logged out\";\n\nexport function isInvalidBackendApiKeyHealthError(\n error: string | null | undefined,\n): boolean {\n return error === INVALID_BACKEND_API_KEY_ERROR;\n}\n\nexport function isMissingBackendApiKeyHealthError(\n error: string | null | undefined,\n): boolean {\n return error === MISSING_BACKEND_API_KEY_ERROR;\n}\n\nexport function isCloudBackendApiKeyOrNetworkHealthError(\n error: string | null | undefined,\n): boolean {\n return error === CLOUD_BACKEND_API_KEY_OR_NETWORK_ERROR;\n}\n\nfunction hasMissingBackendApiKey(backend: Backend): boolean {\n return (\n backend.kind === \"cloud\" &&\n backend.authMode !== \"cookie\" &&\n !backend.apiKey.trim()\n );\n}\n\nexport function isCloudBackendLoggedOutHealthError(\n error: string | null | undefined,\n): boolean {\n return error === CLOUD_BACKEND_LOGGED_OUT_ERROR;\n}\n\n/**\n * Probe a single backend for connectivity. The probe path differs by\n * backend kind:\n *\n * - Local agent-server: GET `/api/settings`, then `/server_info` via the\n * typescript-client. The settings call validates the configured session\n * API key; the server info call validates the version compatibility floor.\n * - Cloud: GET `/api/keys/current` directly against the cloud host. That\n * endpoint is lightweight, requires auth, and `getCurrentCloudApiKey`\n * already absorbs the legacy-key 400 fallback so we treat that as\n * \"connected\" too. Missing / rejected keys are reported explicitly instead\n * of falling through to the browser's opaque CORS/network error shape.\n *\n * Throws on failure so React Query marks the query as errored — the\n * dropdown reads `isSuccess` to flip the indicator green.\n */\nasync function probeBackend(backend: Backend): Promise<true> {\n if (backend.kind === \"cloud\") {\n if (backend.authMode !== \"cookie\" && !backend.apiKey?.trim()) {\n throw new Error(MISSING_BACKEND_API_KEY_ERROR);\n }\n\n try {\n if (backend.authMode === \"cookie\") {\n await getCloudOrganizations(backend);\n } else {\n await getCurrentCloudApiKey(backend);\n }\n } catch (error) {\n if (\n (axios.isAxiosError(error) && error.response?.status === 401) ||\n (error instanceof HttpError && error.status === 401)\n ) {\n throw new Error(CLOUD_BACKEND_LOGGED_OUT_ERROR);\n }\n if (isCorsOrNetworkError(error)) {\n throw new Error(CLOUD_BACKEND_API_KEY_OR_NETWORK_ERROR);\n }\n throw error;\n }\n return true;\n }\n\n try {\n const clientOptions = getAgentServerClientOptions({\n host: backend.host,\n sessionApiKey: backend.apiKey || null,\n timeout: PROBE_TIMEOUT_MS,\n });\n\n await new SettingsClient(clientOptions).getSettings();\n const serverInfo = await new ServerClient(clientOptions).getServerInfo();\n assertAgentServerVersionIsSupported(serverInfo);\n } catch (error) {\n if (isSdkHttpStatusError(error, 401)) {\n throw new Error(INVALID_BACKEND_API_KEY_ERROR);\n }\n throw error;\n }\n return true;\n}\n\n/**\n * How many extra times to re-run a failed probe before giving up, and how\n * long to wait between attempts.\n */\nconst PROBE_RETRY_ATTEMPTS = 2;\nconst PROBE_RETRY_DELAY_MS = 300;\n\n/**\n * Probe a backend, retrying a couple of times on failure before giving up.\n *\n * The connectivity indicator (and the onboarding \"backend connected\" banner)\n * only flips green once a probe succeeds. With `retry: false` at the query\n * level and a REFRESH_INTERVAL_MS (10s) poll, a single transient first-probe\n * miss — the agent-server still warming up right after navigation, a momentary\n * proxy 5xx, a dropped connection — would otherwise leave the banner stuck for\n * a full 10s until the next scheduled refetch. That is the root cause of the\n * flaky onboarding e2e \"backend health probe should report connected\" timeout.\n *\n * Retrying here, inside the query function rather than via React Query's\n * `retry`, is deliberate: the success/failure recording below runs once per\n * settled query, so a single logical probe still records exactly one outcome.\n * Retrying at the query level instead would call `recordBackendFailure` on\n * every internal attempt and reach the disabled cap several times too fast.\n *\n * Definitive auth failures (logged out, invalid/missing key) are NOT retried:\n * they are a decided server response, not a transient miss, so retrying only\n * delays surfacing the correct \"disconnected\" state (and the recovery UI).\n */\nfunction isRetryableProbeError(error: unknown): boolean {\n if (!(error instanceof Error)) return true;\n return (\n error.message !== INVALID_BACKEND_API_KEY_ERROR &&\n error.message !== MISSING_BACKEND_API_KEY_ERROR &&\n error.message !== CLOUD_BACKEND_LOGGED_OUT_ERROR\n );\n}\n\nasync function probeBackendWithQuickRetry(backend: Backend): Promise<true> {\n for (let attempt = 0; ; attempt += 1) {\n try {\n return await probeBackend(backend);\n } catch (error) {\n if (attempt >= PROBE_RETRY_ATTEMPTS || !isRetryableProbeError(error)) {\n throw error;\n }\n await new Promise((resolve) => {\n setTimeout(resolve, PROBE_RETRY_DELAY_MS);\n });\n }\n }\n}\n\nexport interface BackendHealth {\n /** `null` while the first probe is in flight; then `true` / `false`. */\n isConnected: boolean | null;\n /** Number of consecutive failed probes since the last success. */\n consecutiveFailures: number;\n /** Last error message captured from a failed probe, if any. */\n lastError: string | null;\n /**\n * `true` once `consecutiveFailures` reaches the cap. While disabled,\n * ordinary background polling stops and survives a page refresh in\n * that state.\n */\n disabled: boolean;\n}\n\nexport interface UseBackendsHealthOptions {\n /**\n * Re-probe disabled backends once when the hook mounts. Used by the\n * Manage Backends modal so a recovered backend can clear its stale\n * persisted error state without forcing the user to edit the config.\n */\n probeDisabledOnce?: boolean;\n}\n\n/**\n * Poll every backend in `backends` once every 10s and report a simple\n * connected / disconnected verdict per backend id.\n *\n * The query key includes `host` and `apiKey` so editing a backend's\n * connection details re-keys the query and triggers an immediate\n * refetch instead of waiting for the next tick.\n *\n * After `MAX_CONSECUTIVE_FAILURES` failures in a row, ordinary polling\n * stops for that backend until the user updates its host / apiKey.\n * Callers can still opt into a one-shot recheck for disabled backends\n * (for example when the user explicitly opens Manage Backends). The\n * failure count and last error live in localStorage so a page refresh\n * does not silently re-arm polling against a backend that's known to\n * be unreachable.\n */\nexport function useBackendsHealth(\n backends: Backend[],\n options: UseBackendsHealthOptions = {},\n): Record<string, BackendHealth> {\n const { probeDisabledOnce = false } = options;\n const healthMap = React.useSyncExternalStore(\n subscribeBackendHealth,\n getHealthSnapshot,\n getHealthSnapshot,\n );\n\n const results = useQueries({\n queries: backends.map((b) => {\n const entry = healthMap[b.id];\n const hasMissingCloudApiKey = hasMissingBackendApiKey(b);\n const isDisabled = entry?.disabled === true;\n const shouldReprobeStaleCloudNetworkError =\n isDisabled &&\n b.kind === \"cloud\" &&\n isCorsOrNetworkErrorMessage(entry?.lastError);\n const shouldProbe =\n !hasMissingCloudApiKey &&\n (!isDisabled ||\n probeDisabledOnce ||\n shouldReprobeStaleCloudNetworkError);\n return {\n queryKey: [\n \"backend-health\",\n b.id,\n b.kind,\n b.host,\n b.apiKey ?? \"\",\n ] as const,\n queryFn: async () => {\n try {\n const result = await probeBackendWithQuickRetry(b);\n recordBackendSuccess(b.id);\n return result;\n } catch (err) {\n recordBackendFailure(b.id, err);\n throw err;\n }\n },\n enabled: shouldProbe,\n refetchInterval:\n isDisabled || hasMissingCloudApiKey\n ? (false as const)\n : REFRESH_INTERVAL_MS,\n refetchIntervalInBackground: false,\n refetchOnMount: isDisabled && probeDisabledOnce ? \"always\" : true,\n refetchOnReconnect: !isDisabled && !hasMissingCloudApiKey,\n refetchOnWindowFocus: !isDisabled && !hasMissingCloudApiKey,\n retry: false,\n // Keep the previous verdict visible while the next probe is in\n // flight so the indicator doesn't flicker on routine polling.\n staleTime: isDisabled ? 0 : REFRESH_INTERVAL_MS,\n meta: { disableToast: true },\n };\n }),\n });\n\n const out: Record<string, BackendHealth> = {};\n backends.forEach((b, i) => {\n const r = results[i];\n const entry = healthMap[b.id];\n const hasMissingCloudApiKey = hasMissingBackendApiKey(b);\n const disabled = hasMissingCloudApiKey ? false : entry?.disabled === true;\n const consecutiveFailures = hasMissingCloudApiKey\n ? 0\n : (entry?.consecutiveFailures ?? 0);\n const lastError = hasMissingCloudApiKey\n ? MISSING_BACKEND_API_KEY_ERROR\n : (entry?.lastError ?? null);\n\n let isConnected: boolean | null;\n if (hasMissingCloudApiKey) {\n isConnected = false;\n } else if (disabled) {\n // Polling stopped after hitting the cap — treat as disconnected\n // so existing consumers (dot, badge) render red without needing\n // to know about the new fields.\n isConnected = false;\n } else if (r.isSuccess) isConnected = true;\n else if (r.isError) isConnected = false;\n else isConnected = null;\n\n out[b.id] = { isConnected, consecutiveFailures, lastError, disabled };\n });\n return out;\n}\n\nexport { MAX_CONSECUTIVE_FAILURES };\n"],"mappings":"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"}
@@ -1,70 +1,72 @@
1
- import { ServerClient as e } from "../../node_modules/@openhands/typescript-client/dist/client/server-client.js";
2
- import { SettingsClient as t } from "../../node_modules/@openhands/typescript-client/dist/client/settings-client.js";
1
+ import { HttpError as e } from "../../node_modules/@openhands/typescript-client/dist/client/http-client.js";
2
+ import { ServerClient as t } from "../../node_modules/@openhands/typescript-client/dist/client/server-client.js";
3
+ import { SettingsClient as n } from "../../node_modules/@openhands/typescript-client/dist/client/settings-client.js";
3
4
  import "../../node_modules/@openhands/typescript-client/dist/clients.js";
4
- import { getAgentServerClientOptions as n } from "../../api/agent-server-client-options.js";
5
- import { assertAgentServerVersionIsSupported as r, isSdkHttpStatusError as i } from "../../api/agent-server-compatibility.js";
6
- import { isCorsOrNetworkError as a, isCorsOrNetworkErrorMessage as o } from "../../utils/user-facing-error.js";
7
- import { getHealthSnapshot as s, recordBackendFailure as c, recordBackendSuccess as l, subscribeBackendHealth as u } from "../../api/backend-registry/health-store.js";
8
- import { useQueries as d } from "../../node_modules/@tanstack/react-query/build/modern/useQueries.js";
9
- import f from "../../node_modules/axios/lib/axios.js";
10
- import { getCurrentCloudApiKey as p } from "../../api/cloud/organization-service.api.js";
11
- import m from "react";
5
+ import { getAgentServerClientOptions as r } from "../../api/agent-server-client-options.js";
6
+ import { assertAgentServerVersionIsSupported as i, isSdkHttpStatusError as a } from "../../api/agent-server-compatibility.js";
7
+ import { isCorsOrNetworkError as o, isCorsOrNetworkErrorMessage as s } from "../../utils/user-facing-error.js";
8
+ import { getHealthSnapshot as c, recordBackendFailure as l, recordBackendSuccess as u, subscribeBackendHealth as d } from "../../api/backend-registry/health-store.js";
9
+ import { useQueries as f } from "../../node_modules/@tanstack/react-query/build/modern/useQueries.js";
10
+ import p from "../../node_modules/axios/lib/axios.js";
11
+ import "../../node_modules/@openhands/typescript-client/dist/index.js";
12
+ import { getCloudOrganizations as m, getCurrentCloudApiKey as h } from "../../api/cloud/organization-service.api.js";
13
+ import g from "react";
12
14
  //#region src/hooks/query/use-backends-health.ts
13
- var h = 1e4, g = 4e3, _ = "Invalid API key", v = "API key required", y = "Cloud API key or network issue", b = "Logged out";
14
- function x(e) {
15
- return e === _;
16
- }
17
- function S(e) {
18
- return e === v;
19
- }
15
+ var _ = 1e4, v = 4e3, y = "Invalid API key", b = "API key required", x = "Cloud API key or network issue", S = "Logged out";
20
16
  function C(e) {
21
17
  return e === y;
22
18
  }
23
19
  function w(e) {
24
- return e.kind === "cloud" && !e.apiKey.trim();
20
+ return e === b;
25
21
  }
26
22
  function T(e) {
27
- return e === b;
23
+ return e === x;
24
+ }
25
+ function E(e) {
26
+ return e.kind === "cloud" && e.authMode !== "cookie" && !e.apiKey.trim();
27
+ }
28
+ function D(e) {
29
+ return e === S;
28
30
  }
29
- async function E(o) {
30
- if (o.kind === "cloud") {
31
- if (!o.apiKey?.trim()) throw Error(v);
31
+ async function O(s) {
32
+ if (s.kind === "cloud") {
33
+ if (s.authMode !== "cookie" && !s.apiKey?.trim()) throw Error(b);
32
34
  try {
33
- await p(o);
34
- } catch (e) {
35
- throw f.isAxiosError(e) && e.response?.status === 401 ? Error(b) : a(e) ? Error(y) : e;
35
+ s.authMode === "cookie" ? await m(s) : await h(s);
36
+ } catch (t) {
37
+ throw p.isAxiosError(t) && t.response?.status === 401 || t instanceof e && t.status === 401 ? Error(S) : o(t) ? Error(x) : t;
36
38
  }
37
39
  return !0;
38
40
  }
39
41
  try {
40
- let i = n({
41
- host: o.host,
42
- sessionApiKey: o.apiKey || null,
43
- timeout: g
42
+ let e = r({
43
+ host: s.host,
44
+ sessionApiKey: s.apiKey || null,
45
+ timeout: v
44
46
  });
45
- await new t(i).getSettings(), r(await new e(i).getServerInfo());
47
+ await new n(e).getSettings(), i(await new t(e).getServerInfo());
46
48
  } catch (e) {
47
- throw i(e, 401) ? Error(_) : e;
49
+ throw a(e, 401) ? Error(y) : e;
48
50
  }
49
51
  return !0;
50
52
  }
51
- var D = 2, O = 300;
52
- function k(e) {
53
+ var k = 2, A = 300;
54
+ function j(e) {
53
55
  return e instanceof Error ? e.message !== "Invalid API key" && e.message !== "API key required" && e.message !== "Logged out" : !0;
54
56
  }
55
- async function A(e) {
57
+ async function M(e) {
56
58
  for (let t = 0;; t += 1) try {
57
- return await E(e);
59
+ return await O(e);
58
60
  } catch (e) {
59
- if (t >= D || !k(e)) throw e;
61
+ if (t >= k || !j(e)) throw e;
60
62
  await new Promise((e) => {
61
- setTimeout(e, O);
63
+ setTimeout(e, A);
62
64
  });
63
65
  }
64
66
  }
65
- function j(e, t = {}) {
66
- let { probeDisabledOnce: n = !1 } = t, r = m.useSyncExternalStore(u, s, s), i = d({ queries: e.map((e) => {
67
- let t = r[e.id], i = w(e), a = t?.disabled === !0, s = a && e.kind === "cloud" && o(t?.lastError), u = !i && (!a || n || s);
67
+ function N(e, t = {}) {
68
+ let { probeDisabledOnce: n = !1 } = t, r = g.useSyncExternalStore(d, c, c), i = f({ queries: e.map((e) => {
69
+ let t = r[e.id], i = E(e), a = t?.disabled === !0, o = a && e.kind === "cloud" && s(t?.lastError), c = !i && (!a || n || o);
68
70
  return {
69
71
  queryKey: [
70
72
  "backend-health",
@@ -75,25 +77,25 @@ function j(e, t = {}) {
75
77
  ],
76
78
  queryFn: async () => {
77
79
  try {
78
- let t = await A(e);
79
- return l(e.id), t;
80
+ let t = await M(e);
81
+ return u(e.id), t;
80
82
  } catch (t) {
81
- throw c(e.id, t), t;
83
+ throw l(e.id, t), t;
82
84
  }
83
85
  },
84
- enabled: u,
85
- refetchInterval: a || i ? !1 : h,
86
+ enabled: c,
87
+ refetchInterval: a || i ? !1 : _,
86
88
  refetchIntervalInBackground: !1,
87
89
  refetchOnMount: a && n ? "always" : !0,
88
90
  refetchOnReconnect: !a && !i,
89
91
  refetchOnWindowFocus: !a && !i,
90
92
  retry: !1,
91
- staleTime: a ? 0 : h,
93
+ staleTime: a ? 0 : _,
92
94
  meta: { disableToast: !0 }
93
95
  };
94
96
  }) }), a = {};
95
97
  return e.forEach((e, t) => {
96
- let n = i[t], o = r[e.id], s = w(e), c = s ? !1 : o?.disabled === !0, l = s ? 0 : o?.consecutiveFailures ?? 0, u = s ? v : o?.lastError ?? null, d;
98
+ let n = i[t], o = r[e.id], s = E(e), c = s ? !1 : o?.disabled === !0, l = s ? 0 : o?.consecutiveFailures ?? 0, u = s ? b : o?.lastError ?? null, d;
97
99
  d = s || c ? !1 : n.isSuccess ? !0 : n.isError ? !1 : null, a[e.id] = {
98
100
  isConnected: d,
99
101
  consecutiveFailures: l,
@@ -103,6 +105,6 @@ function j(e, t = {}) {
103
105
  }), a;
104
106
  }
105
107
  //#endregion
106
- export { C as isCloudBackendApiKeyOrNetworkHealthError, T as isCloudBackendLoggedOutHealthError, x as isInvalidBackendApiKeyHealthError, S as isMissingBackendApiKeyHealthError, j as useBackendsHealth };
108
+ export { T as isCloudBackendApiKeyOrNetworkHealthError, D as isCloudBackendLoggedOutHealthError, C as isInvalidBackendApiKeyHealthError, w as isMissingBackendApiKeyHealthError, N as useBackendsHealth };
107
109
 
108
110
  //# sourceMappingURL=use-backends-health.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-backends-health.js","names":[],"sources":["../../../src/hooks/query/use-backends-health.ts"],"sourcesContent":["import React from \"react\";\nimport axios from \"axios\";\nimport { useQueries } from \"@tanstack/react-query\";\nimport {\n ServerClient,\n SettingsClient,\n} from \"@openhands/typescript-client/clients\";\nimport { getCurrentCloudApiKey } from \"#/api/cloud/organization-service.api\";\nimport {\n assertAgentServerVersionIsSupported,\n isSdkHttpStatusError,\n} from \"#/api/agent-server-compatibility\";\nimport type { Backend } from \"#/api/backend-registry/types\";\nimport { getAgentServerClientOptions } from \"#/api/agent-server-client-options\";\nimport {\n isCorsOrNetworkError,\n isCorsOrNetworkErrorMessage,\n} from \"#/utils/user-facing-error\";\nimport {\n getHealthSnapshot,\n recordBackendFailure,\n recordBackendSuccess,\n subscribeBackendHealth,\n} from \"#/api/backend-registry/health-store\";\nimport { MAX_CONSECUTIVE_FAILURES } from \"#/api/backend-registry/health-storage\";\n\nconst REFRESH_INTERVAL_MS = 10000;\nconst PROBE_TIMEOUT_MS = 4000;\nexport const INVALID_BACKEND_API_KEY_ERROR = \"Invalid API key\";\nexport const MISSING_BACKEND_API_KEY_ERROR = \"API key required\";\nexport const CLOUD_BACKEND_API_KEY_OR_NETWORK_ERROR =\n \"Cloud API key or network issue\";\nexport const CLOUD_BACKEND_LOGGED_OUT_ERROR = \"Logged out\";\n\nexport function isInvalidBackendApiKeyHealthError(\n error: string | null | undefined,\n): boolean {\n return error === INVALID_BACKEND_API_KEY_ERROR;\n}\n\nexport function isMissingBackendApiKeyHealthError(\n error: string | null | undefined,\n): boolean {\n return error === MISSING_BACKEND_API_KEY_ERROR;\n}\n\nexport function isCloudBackendApiKeyOrNetworkHealthError(\n error: string | null | undefined,\n): boolean {\n return error === CLOUD_BACKEND_API_KEY_OR_NETWORK_ERROR;\n}\n\nfunction hasMissingBackendApiKey(backend: Backend): boolean {\n return backend.kind === \"cloud\" && !backend.apiKey.trim();\n}\n\nexport function isCloudBackendLoggedOutHealthError(\n error: string | null | undefined,\n): boolean {\n return error === CLOUD_BACKEND_LOGGED_OUT_ERROR;\n}\n\n/**\n * Probe a single backend for connectivity. The probe path differs by\n * backend kind:\n *\n * - Local agent-server: GET `/api/settings`, then `/server_info` via the\n * typescript-client. The settings call validates the configured session\n * API key; the server info call validates the version compatibility floor.\n * - Cloud: GET `/api/keys/current` directly against the cloud host. That\n * endpoint is lightweight, requires auth, and `getCurrentCloudApiKey`\n * already absorbs the legacy-key 400 fallback so we treat that as\n * \"connected\" too. Missing / rejected keys are reported explicitly instead\n * of falling through to the browser's opaque CORS/network error shape.\n *\n * Throws on failure so React Query marks the query as errored — the\n * dropdown reads `isSuccess` to flip the indicator green.\n */\nasync function probeBackend(backend: Backend): Promise<true> {\n if (backend.kind === \"cloud\") {\n if (!backend.apiKey?.trim()) {\n throw new Error(MISSING_BACKEND_API_KEY_ERROR);\n }\n\n try {\n await getCurrentCloudApiKey(backend);\n } catch (error) {\n if (axios.isAxiosError(error) && error.response?.status === 401) {\n throw new Error(CLOUD_BACKEND_LOGGED_OUT_ERROR);\n }\n if (isCorsOrNetworkError(error)) {\n throw new Error(CLOUD_BACKEND_API_KEY_OR_NETWORK_ERROR);\n }\n throw error;\n }\n return true;\n }\n\n try {\n const clientOptions = getAgentServerClientOptions({\n host: backend.host,\n sessionApiKey: backend.apiKey || null,\n timeout: PROBE_TIMEOUT_MS,\n });\n\n await new SettingsClient(clientOptions).getSettings();\n const serverInfo = await new ServerClient(clientOptions).getServerInfo();\n assertAgentServerVersionIsSupported(serverInfo);\n } catch (error) {\n if (isSdkHttpStatusError(error, 401)) {\n throw new Error(INVALID_BACKEND_API_KEY_ERROR);\n }\n throw error;\n }\n return true;\n}\n\n/**\n * How many extra times to re-run a failed probe before giving up, and how\n * long to wait between attempts.\n */\nconst PROBE_RETRY_ATTEMPTS = 2;\nconst PROBE_RETRY_DELAY_MS = 300;\n\n/**\n * Probe a backend, retrying a couple of times on failure before giving up.\n *\n * The connectivity indicator (and the onboarding \"backend connected\" banner)\n * only flips green once a probe succeeds. With `retry: false` at the query\n * level and a REFRESH_INTERVAL_MS (10s) poll, a single transient first-probe\n * miss — the agent-server still warming up right after navigation, a momentary\n * proxy 5xx, a dropped connection — would otherwise leave the banner stuck for\n * a full 10s until the next scheduled refetch. That is the root cause of the\n * flaky onboarding e2e \"backend health probe should report connected\" timeout.\n *\n * Retrying here, inside the query function rather than via React Query's\n * `retry`, is deliberate: the success/failure recording below runs once per\n * settled query, so a single logical probe still records exactly one outcome.\n * Retrying at the query level instead would call `recordBackendFailure` on\n * every internal attempt and reach the disabled cap several times too fast.\n *\n * Definitive auth failures (logged out, invalid/missing key) are NOT retried:\n * they are a decided server response, not a transient miss, so retrying only\n * delays surfacing the correct \"disconnected\" state (and the recovery UI).\n */\nfunction isRetryableProbeError(error: unknown): boolean {\n if (!(error instanceof Error)) return true;\n return (\n error.message !== INVALID_BACKEND_API_KEY_ERROR &&\n error.message !== MISSING_BACKEND_API_KEY_ERROR &&\n error.message !== CLOUD_BACKEND_LOGGED_OUT_ERROR\n );\n}\n\nasync function probeBackendWithQuickRetry(backend: Backend): Promise<true> {\n for (let attempt = 0; ; attempt += 1) {\n try {\n return await probeBackend(backend);\n } catch (error) {\n if (attempt >= PROBE_RETRY_ATTEMPTS || !isRetryableProbeError(error)) {\n throw error;\n }\n await new Promise((resolve) => {\n setTimeout(resolve, PROBE_RETRY_DELAY_MS);\n });\n }\n }\n}\n\nexport interface BackendHealth {\n /** `null` while the first probe is in flight; then `true` / `false`. */\n isConnected: boolean | null;\n /** Number of consecutive failed probes since the last success. */\n consecutiveFailures: number;\n /** Last error message captured from a failed probe, if any. */\n lastError: string | null;\n /**\n * `true` once `consecutiveFailures` reaches the cap. While disabled,\n * ordinary background polling stops and survives a page refresh in\n * that state.\n */\n disabled: boolean;\n}\n\nexport interface UseBackendsHealthOptions {\n /**\n * Re-probe disabled backends once when the hook mounts. Used by the\n * Manage Backends modal so a recovered backend can clear its stale\n * persisted error state without forcing the user to edit the config.\n */\n probeDisabledOnce?: boolean;\n}\n\n/**\n * Poll every backend in `backends` once every 10s and report a simple\n * connected / disconnected verdict per backend id.\n *\n * The query key includes `host` and `apiKey` so editing a backend's\n * connection details re-keys the query and triggers an immediate\n * refetch instead of waiting for the next tick.\n *\n * After `MAX_CONSECUTIVE_FAILURES` failures in a row, ordinary polling\n * stops for that backend until the user updates its host / apiKey.\n * Callers can still opt into a one-shot recheck for disabled backends\n * (for example when the user explicitly opens Manage Backends). The\n * failure count and last error live in localStorage so a page refresh\n * does not silently re-arm polling against a backend that's known to\n * be unreachable.\n */\nexport function useBackendsHealth(\n backends: Backend[],\n options: UseBackendsHealthOptions = {},\n): Record<string, BackendHealth> {\n const { probeDisabledOnce = false } = options;\n const healthMap = React.useSyncExternalStore(\n subscribeBackendHealth,\n getHealthSnapshot,\n getHealthSnapshot,\n );\n\n const results = useQueries({\n queries: backends.map((b) => {\n const entry = healthMap[b.id];\n const hasMissingCloudApiKey = hasMissingBackendApiKey(b);\n const isDisabled = entry?.disabled === true;\n const shouldReprobeStaleCloudNetworkError =\n isDisabled &&\n b.kind === \"cloud\" &&\n isCorsOrNetworkErrorMessage(entry?.lastError);\n const shouldProbe =\n !hasMissingCloudApiKey &&\n (!isDisabled ||\n probeDisabledOnce ||\n shouldReprobeStaleCloudNetworkError);\n return {\n queryKey: [\n \"backend-health\",\n b.id,\n b.kind,\n b.host,\n b.apiKey ?? \"\",\n ] as const,\n queryFn: async () => {\n try {\n const result = await probeBackendWithQuickRetry(b);\n recordBackendSuccess(b.id);\n return result;\n } catch (err) {\n recordBackendFailure(b.id, err);\n throw err;\n }\n },\n enabled: shouldProbe,\n refetchInterval:\n isDisabled || hasMissingCloudApiKey\n ? (false as const)\n : REFRESH_INTERVAL_MS,\n refetchIntervalInBackground: false,\n refetchOnMount: isDisabled && probeDisabledOnce ? \"always\" : true,\n refetchOnReconnect: !isDisabled && !hasMissingCloudApiKey,\n refetchOnWindowFocus: !isDisabled && !hasMissingCloudApiKey,\n retry: false,\n // Keep the previous verdict visible while the next probe is in\n // flight so the indicator doesn't flicker on routine polling.\n staleTime: isDisabled ? 0 : REFRESH_INTERVAL_MS,\n meta: { disableToast: true },\n };\n }),\n });\n\n const out: Record<string, BackendHealth> = {};\n backends.forEach((b, i) => {\n const r = results[i];\n const entry = healthMap[b.id];\n const hasMissingCloudApiKey = hasMissingBackendApiKey(b);\n const disabled = hasMissingCloudApiKey ? false : entry?.disabled === true;\n const consecutiveFailures = hasMissingCloudApiKey\n ? 0\n : (entry?.consecutiveFailures ?? 0);\n const lastError = hasMissingCloudApiKey\n ? MISSING_BACKEND_API_KEY_ERROR\n : (entry?.lastError ?? null);\n\n let isConnected: boolean | null;\n if (hasMissingCloudApiKey) {\n isConnected = false;\n } else if (disabled) {\n // Polling stopped after hitting the cap — treat as disconnected\n // so existing consumers (dot, badge) render red without needing\n // to know about the new fields.\n isConnected = false;\n } else if (r.isSuccess) isConnected = true;\n else if (r.isError) isConnected = false;\n else isConnected = null;\n\n out[b.id] = { isConnected, consecutiveFailures, lastError, disabled };\n });\n return out;\n}\n\nexport { MAX_CONSECUTIVE_FAILURES };\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-backends-health.js","names":[],"sources":["../../../src/hooks/query/use-backends-health.ts"],"sourcesContent":["import React from \"react\";\nimport axios from \"axios\";\nimport { useQueries } from \"@tanstack/react-query\";\nimport { HttpError } from \"@openhands/typescript-client\";\nimport {\n ServerClient,\n SettingsClient,\n} from \"@openhands/typescript-client/clients\";\nimport {\n getCloudOrganizations,\n getCurrentCloudApiKey,\n} from \"#/api/cloud/organization-service.api\";\nimport {\n assertAgentServerVersionIsSupported,\n isSdkHttpStatusError,\n} from \"#/api/agent-server-compatibility\";\nimport type { Backend } from \"#/api/backend-registry/types\";\nimport { getAgentServerClientOptions } from \"#/api/agent-server-client-options\";\nimport {\n isCorsOrNetworkError,\n isCorsOrNetworkErrorMessage,\n} from \"#/utils/user-facing-error\";\nimport {\n getHealthSnapshot,\n recordBackendFailure,\n recordBackendSuccess,\n subscribeBackendHealth,\n} from \"#/api/backend-registry/health-store\";\nimport { MAX_CONSECUTIVE_FAILURES } from \"#/api/backend-registry/health-storage\";\n\nconst REFRESH_INTERVAL_MS = 10000;\nconst PROBE_TIMEOUT_MS = 4000;\nexport const INVALID_BACKEND_API_KEY_ERROR = \"Invalid API key\";\nexport const MISSING_BACKEND_API_KEY_ERROR = \"API key required\";\nexport const CLOUD_BACKEND_API_KEY_OR_NETWORK_ERROR =\n \"Cloud API key or network issue\";\nexport const CLOUD_BACKEND_LOGGED_OUT_ERROR = \"Logged out\";\n\nexport function isInvalidBackendApiKeyHealthError(\n error: string | null | undefined,\n): boolean {\n return error === INVALID_BACKEND_API_KEY_ERROR;\n}\n\nexport function isMissingBackendApiKeyHealthError(\n error: string | null | undefined,\n): boolean {\n return error === MISSING_BACKEND_API_KEY_ERROR;\n}\n\nexport function isCloudBackendApiKeyOrNetworkHealthError(\n error: string | null | undefined,\n): boolean {\n return error === CLOUD_BACKEND_API_KEY_OR_NETWORK_ERROR;\n}\n\nfunction hasMissingBackendApiKey(backend: Backend): boolean {\n return (\n backend.kind === \"cloud\" &&\n backend.authMode !== \"cookie\" &&\n !backend.apiKey.trim()\n );\n}\n\nexport function isCloudBackendLoggedOutHealthError(\n error: string | null | undefined,\n): boolean {\n return error === CLOUD_BACKEND_LOGGED_OUT_ERROR;\n}\n\n/**\n * Probe a single backend for connectivity. The probe path differs by\n * backend kind:\n *\n * - Local agent-server: GET `/api/settings`, then `/server_info` via the\n * typescript-client. The settings call validates the configured session\n * API key; the server info call validates the version compatibility floor.\n * - Cloud: GET `/api/keys/current` directly against the cloud host. That\n * endpoint is lightweight, requires auth, and `getCurrentCloudApiKey`\n * already absorbs the legacy-key 400 fallback so we treat that as\n * \"connected\" too. Missing / rejected keys are reported explicitly instead\n * of falling through to the browser's opaque CORS/network error shape.\n *\n * Throws on failure so React Query marks the query as errored — the\n * dropdown reads `isSuccess` to flip the indicator green.\n */\nasync function probeBackend(backend: Backend): Promise<true> {\n if (backend.kind === \"cloud\") {\n if (backend.authMode !== \"cookie\" && !backend.apiKey?.trim()) {\n throw new Error(MISSING_BACKEND_API_KEY_ERROR);\n }\n\n try {\n if (backend.authMode === \"cookie\") {\n await getCloudOrganizations(backend);\n } else {\n await getCurrentCloudApiKey(backend);\n }\n } catch (error) {\n if (\n (axios.isAxiosError(error) && error.response?.status === 401) ||\n (error instanceof HttpError && error.status === 401)\n ) {\n throw new Error(CLOUD_BACKEND_LOGGED_OUT_ERROR);\n }\n if (isCorsOrNetworkError(error)) {\n throw new Error(CLOUD_BACKEND_API_KEY_OR_NETWORK_ERROR);\n }\n throw error;\n }\n return true;\n }\n\n try {\n const clientOptions = getAgentServerClientOptions({\n host: backend.host,\n sessionApiKey: backend.apiKey || null,\n timeout: PROBE_TIMEOUT_MS,\n });\n\n await new SettingsClient(clientOptions).getSettings();\n const serverInfo = await new ServerClient(clientOptions).getServerInfo();\n assertAgentServerVersionIsSupported(serverInfo);\n } catch (error) {\n if (isSdkHttpStatusError(error, 401)) {\n throw new Error(INVALID_BACKEND_API_KEY_ERROR);\n }\n throw error;\n }\n return true;\n}\n\n/**\n * How many extra times to re-run a failed probe before giving up, and how\n * long to wait between attempts.\n */\nconst PROBE_RETRY_ATTEMPTS = 2;\nconst PROBE_RETRY_DELAY_MS = 300;\n\n/**\n * Probe a backend, retrying a couple of times on failure before giving up.\n *\n * The connectivity indicator (and the onboarding \"backend connected\" banner)\n * only flips green once a probe succeeds. With `retry: false` at the query\n * level and a REFRESH_INTERVAL_MS (10s) poll, a single transient first-probe\n * miss — the agent-server still warming up right after navigation, a momentary\n * proxy 5xx, a dropped connection — would otherwise leave the banner stuck for\n * a full 10s until the next scheduled refetch. That is the root cause of the\n * flaky onboarding e2e \"backend health probe should report connected\" timeout.\n *\n * Retrying here, inside the query function rather than via React Query's\n * `retry`, is deliberate: the success/failure recording below runs once per\n * settled query, so a single logical probe still records exactly one outcome.\n * Retrying at the query level instead would call `recordBackendFailure` on\n * every internal attempt and reach the disabled cap several times too fast.\n *\n * Definitive auth failures (logged out, invalid/missing key) are NOT retried:\n * they are a decided server response, not a transient miss, so retrying only\n * delays surfacing the correct \"disconnected\" state (and the recovery UI).\n */\nfunction isRetryableProbeError(error: unknown): boolean {\n if (!(error instanceof Error)) return true;\n return (\n error.message !== INVALID_BACKEND_API_KEY_ERROR &&\n error.message !== MISSING_BACKEND_API_KEY_ERROR &&\n error.message !== CLOUD_BACKEND_LOGGED_OUT_ERROR\n );\n}\n\nasync function probeBackendWithQuickRetry(backend: Backend): Promise<true> {\n for (let attempt = 0; ; attempt += 1) {\n try {\n return await probeBackend(backend);\n } catch (error) {\n if (attempt >= PROBE_RETRY_ATTEMPTS || !isRetryableProbeError(error)) {\n throw error;\n }\n await new Promise((resolve) => {\n setTimeout(resolve, PROBE_RETRY_DELAY_MS);\n });\n }\n }\n}\n\nexport interface BackendHealth {\n /** `null` while the first probe is in flight; then `true` / `false`. */\n isConnected: boolean | null;\n /** Number of consecutive failed probes since the last success. */\n consecutiveFailures: number;\n /** Last error message captured from a failed probe, if any. */\n lastError: string | null;\n /**\n * `true` once `consecutiveFailures` reaches the cap. While disabled,\n * ordinary background polling stops and survives a page refresh in\n * that state.\n */\n disabled: boolean;\n}\n\nexport interface UseBackendsHealthOptions {\n /**\n * Re-probe disabled backends once when the hook mounts. Used by the\n * Manage Backends modal so a recovered backend can clear its stale\n * persisted error state without forcing the user to edit the config.\n */\n probeDisabledOnce?: boolean;\n}\n\n/**\n * Poll every backend in `backends` once every 10s and report a simple\n * connected / disconnected verdict per backend id.\n *\n * The query key includes `host` and `apiKey` so editing a backend's\n * connection details re-keys the query and triggers an immediate\n * refetch instead of waiting for the next tick.\n *\n * After `MAX_CONSECUTIVE_FAILURES` failures in a row, ordinary polling\n * stops for that backend until the user updates its host / apiKey.\n * Callers can still opt into a one-shot recheck for disabled backends\n * (for example when the user explicitly opens Manage Backends). The\n * failure count and last error live in localStorage so a page refresh\n * does not silently re-arm polling against a backend that's known to\n * be unreachable.\n */\nexport function useBackendsHealth(\n backends: Backend[],\n options: UseBackendsHealthOptions = {},\n): Record<string, BackendHealth> {\n const { probeDisabledOnce = false } = options;\n const healthMap = React.useSyncExternalStore(\n subscribeBackendHealth,\n getHealthSnapshot,\n getHealthSnapshot,\n );\n\n const results = useQueries({\n queries: backends.map((b) => {\n const entry = healthMap[b.id];\n const hasMissingCloudApiKey = hasMissingBackendApiKey(b);\n const isDisabled = entry?.disabled === true;\n const shouldReprobeStaleCloudNetworkError =\n isDisabled &&\n b.kind === \"cloud\" &&\n isCorsOrNetworkErrorMessage(entry?.lastError);\n const shouldProbe =\n !hasMissingCloudApiKey &&\n (!isDisabled ||\n probeDisabledOnce ||\n shouldReprobeStaleCloudNetworkError);\n return {\n queryKey: [\n \"backend-health\",\n b.id,\n b.kind,\n b.host,\n b.apiKey ?? \"\",\n ] as const,\n queryFn: async () => {\n try {\n const result = await probeBackendWithQuickRetry(b);\n recordBackendSuccess(b.id);\n return result;\n } catch (err) {\n recordBackendFailure(b.id, err);\n throw err;\n }\n },\n enabled: shouldProbe,\n refetchInterval:\n isDisabled || hasMissingCloudApiKey\n ? (false as const)\n : REFRESH_INTERVAL_MS,\n refetchIntervalInBackground: false,\n refetchOnMount: isDisabled && probeDisabledOnce ? \"always\" : true,\n refetchOnReconnect: !isDisabled && !hasMissingCloudApiKey,\n refetchOnWindowFocus: !isDisabled && !hasMissingCloudApiKey,\n retry: false,\n // Keep the previous verdict visible while the next probe is in\n // flight so the indicator doesn't flicker on routine polling.\n staleTime: isDisabled ? 0 : REFRESH_INTERVAL_MS,\n meta: { disableToast: true },\n };\n }),\n });\n\n const out: Record<string, BackendHealth> = {};\n backends.forEach((b, i) => {\n const r = results[i];\n const entry = healthMap[b.id];\n const hasMissingCloudApiKey = hasMissingBackendApiKey(b);\n const disabled = hasMissingCloudApiKey ? false : entry?.disabled === true;\n const consecutiveFailures = hasMissingCloudApiKey\n ? 0\n : (entry?.consecutiveFailures ?? 0);\n const lastError = hasMissingCloudApiKey\n ? MISSING_BACKEND_API_KEY_ERROR\n : (entry?.lastError ?? null);\n\n let isConnected: boolean | null;\n if (hasMissingCloudApiKey) {\n isConnected = false;\n } else if (disabled) {\n // Polling stopped after hitting the cap — treat as disconnected\n // so existing consumers (dot, badge) render red without needing\n // to know about the new fields.\n isConnected = false;\n } else if (r.isSuccess) isConnected = true;\n else if (r.isError) isConnected = false;\n else isConnected = null;\n\n out[b.id] = { isConnected, consecutiveFailures, lastError, disabled };\n });\n return out;\n}\n\nexport { MAX_CONSECUTIVE_FAILURES };\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- require(`../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../node_modules/@tanstack/react-query/build/modern/useQueries.cjs`),t=require(`../../contexts/active-backend-context.cjs`),n=require(`../../api/cloud/organization-service.api.cjs`);function r(){let{backends:r}=t.useActiveBackendContext(),i=r.filter(e=>e.kind===`cloud`),a=e.useQueries({queries:i.map(e=>({queryKey:[`cloud-organizations`,e.id],queryFn:async()=>{let[t,r]=await Promise.all([n.getCloudOrganizations(e),n.getCurrentCloudApiKey(e)]);return r.isLegacyKey||r.orgId===null?t:{...t,items:t.items.filter(e=>e.id===r.orgId)}},staleTime:1e3*60*5,retry:!1,meta:{disableToast:!0}}))}),o={};return i.forEach((e,t)=>{let n=a[t];o[e.id]={backend:e,isLoading:n.isLoading,orgs:n.data?.items??[]}}),o}exports.useAllCloudOrganizations=r;
1
+ require(`../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../node_modules/@tanstack/react-query/build/modern/useQueries.cjs`),t=require(`../../contexts/active-backend-context.cjs`),n=require(`../../api/cloud/organization-service.api.cjs`);function r(){let{backends:r}=t.useActiveBackendContext(),i=r.filter(e=>e.kind===`cloud`),a=e.useQueries({queries:i.map(e=>({queryKey:[`cloud-organizations`,e.id],queryFn:async()=>{let t=await n.getCloudOrganizations(e);if(e.authMode===`cookie`)return t;let r=await n.getCurrentCloudApiKey(e);return r.isLegacyKey||r.orgId===null?t:{...t,items:t.items.filter(e=>e.id===r.orgId)}},staleTime:1e3*60*5,retry:!1,meta:{disableToast:!0}}))}),o={};return i.forEach((e,t)=>{let n=a[t];o[e.id]={backend:e,isLoading:n.isLoading,orgs:n.data?.items??[],currentOrgId:n.data?.currentOrgId??null}}),o}exports.useAllCloudOrganizations=r;
2
2
  //# sourceMappingURL=use-cloud-organizations.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-cloud-organizations.cjs","names":[],"sources":["../../../src/hooks/query/use-cloud-organizations.ts"],"sourcesContent":["import { useQueries } from \"@tanstack/react-query\";\nimport { useActiveBackendContext } from \"#/contexts/active-backend-context\";\nimport {\n getCloudOrganizations,\n getCurrentCloudApiKey,\n} from \"#/api/cloud/organization-service.api\";\nimport type { Backend } from \"#/api/backend-registry/types\";\n\n/**\n * Fetch organizations for every registered cloud backend in parallel.\n *\n * Used by the BackendSelector to flatten each cloud backend into per-org\n * rows. Each query is keyed by the backend ID so React Query caches\n * responses independently and a switch (which clears the cache) refetches.\n */\nexport function useAllCloudOrganizations() {\n const { backends } = useActiveBackendContext();\n const cloudBackends = backends.filter((b) => b.kind === \"cloud\");\n\n const queries = useQueries({\n queries: cloudBackends.map((backend) => ({\n queryKey: [\"cloud-organizations\", backend.id],\n // Filter the user's full org membership down to the single org the\n // backend's API key is bound to. The cloud enforces one-key-one-org\n // server-side (HTTP 403 otherwise); without this filter the\n // selector would advertise orgs the key cannot use. Legacy keys\n // with no binding fall through unfiltered.\n queryFn: async () => {\n const [orgs, key] = await Promise.all([\n getCloudOrganizations(backend),\n getCurrentCloudApiKey(backend),\n ]);\n if (key.isLegacyKey || key.orgId === null) return orgs;\n return {\n ...orgs,\n items: orgs.items.filter((o) => o.id === key.orgId),\n };\n },\n staleTime: 1000 * 60 * 5,\n retry: false,\n meta: { disableToast: true },\n })),\n });\n\n // Map backend id -> result to make consumers easy to read.\n const byBackendId: Record<\n string,\n {\n backend: Backend;\n isLoading: boolean;\n orgs: { id: string; name: string; is_personal?: boolean }[];\n }\n > = {};\n cloudBackends.forEach((backend, index) => {\n const q = queries[index];\n byBackendId[backend.id] = {\n backend,\n isLoading: q.isLoading,\n orgs: q.data?.items ?? [],\n };\n });\n\n return byBackendId;\n}\n"],"mappings":"yPAeA,SAAgB,GAA2B,CACzC,GAAM,CAAE,YAAa,EAAA,yBAAyB,CACxC,EAAgB,EAAS,OAAQ,GAAM,EAAE,OAAS,QAAQ,CAE1D,EAAU,EAAA,WAAW,CACzB,QAAS,EAAc,IAAK,IAAa,CACvC,SAAU,CAAC,sBAAuB,EAAQ,GAAG,CAM7C,QAAS,SAAY,CACnB,GAAM,CAAC,EAAM,GAAO,MAAM,QAAQ,IAAI,CACpC,EAAA,sBAAsB,EAAQ,CAC9B,EAAA,sBAAsB,EAAQ,CAC/B,CAAC,CAEF,OADI,EAAI,aAAe,EAAI,QAAU,KAAa,EAC3C,CACL,GAAG,EACH,MAAO,EAAK,MAAM,OAAQ,GAAM,EAAE,KAAO,EAAI,MAAM,CACpD,EAEH,UAAW,IAAO,GAAK,EACvB,MAAO,GACP,KAAM,CAAE,aAAc,GAAM,CAC7B,EAAE,CACJ,CAAC,CAGI,EAOF,EAAE,CAUN,OATA,EAAc,SAAS,EAAS,IAAU,CACxC,IAAM,EAAI,EAAQ,GAClB,EAAY,EAAQ,IAAM,CACxB,UACA,UAAW,EAAE,UACb,KAAM,EAAE,MAAM,OAAS,EAAE,CAC1B,EACD,CAEK"}
1
+ {"version":3,"file":"use-cloud-organizations.cjs","names":[],"sources":["../../../src/hooks/query/use-cloud-organizations.ts"],"sourcesContent":["import { useQueries } from \"@tanstack/react-query\";\nimport { useActiveBackendContext } from \"#/contexts/active-backend-context\";\nimport {\n getCloudOrganizations,\n getCurrentCloudApiKey,\n} from \"#/api/cloud/organization-service.api\";\nimport type { Backend } from \"#/api/backend-registry/types\";\n\n/**\n * Fetch organizations for every registered cloud backend in parallel.\n *\n * Used by the BackendSelector to flatten each cloud backend into per-org\n * rows. Each query is keyed by the backend ID so React Query caches\n * responses independently and a switch (which clears the cache) refetches.\n */\nexport function useAllCloudOrganizations() {\n const { backends } = useActiveBackendContext();\n const cloudBackends = backends.filter((b) => b.kind === \"cloud\");\n\n const queries = useQueries({\n queries: cloudBackends.map((backend) => ({\n queryKey: [\"cloud-organizations\", backend.id],\n // Filter the user's full org membership down to the single org the\n // backend's API key is bound to. The cloud enforces one-key-one-org\n // server-side (HTTP 403 otherwise); without this filter the\n // selector would advertise orgs the key cannot use. Legacy keys\n // with no binding fall through unfiltered.\n queryFn: async () => {\n const orgs = await getCloudOrganizations(backend);\n if (backend.authMode === \"cookie\") return orgs;\n\n const key = await getCurrentCloudApiKey(backend);\n if (key.isLegacyKey || key.orgId === null) return orgs;\n return {\n ...orgs,\n items: orgs.items.filter((o) => o.id === key.orgId),\n };\n },\n staleTime: 1000 * 60 * 5,\n retry: false,\n meta: { disableToast: true },\n })),\n });\n\n // Map backend id -> result to make consumers easy to read.\n const byBackendId: Record<\n string,\n {\n backend: Backend;\n isLoading: boolean;\n orgs: { id: string; name: string; is_personal?: boolean }[];\n currentOrgId: string | null;\n }\n > = {};\n cloudBackends.forEach((backend, index) => {\n const q = queries[index];\n byBackendId[backend.id] = {\n backend,\n isLoading: q.isLoading,\n orgs: q.data?.items ?? [],\n currentOrgId: q.data?.currentOrgId ?? null,\n };\n });\n\n return byBackendId;\n}\n"],"mappings":"yPAeA,SAAgB,GAA2B,CACzC,GAAM,CAAE,YAAa,EAAA,yBAAyB,CACxC,EAAgB,EAAS,OAAQ,GAAM,EAAE,OAAS,QAAQ,CAE1D,EAAU,EAAA,WAAW,CACzB,QAAS,EAAc,IAAK,IAAa,CACvC,SAAU,CAAC,sBAAuB,EAAQ,GAAG,CAM7C,QAAS,SAAY,CACnB,IAAM,EAAO,MAAM,EAAA,sBAAsB,EAAQ,CACjD,GAAI,EAAQ,WAAa,SAAU,OAAO,EAE1C,IAAM,EAAM,MAAM,EAAA,sBAAsB,EAAQ,CAEhD,OADI,EAAI,aAAe,EAAI,QAAU,KAAa,EAC3C,CACL,GAAG,EACH,MAAO,EAAK,MAAM,OAAQ,GAAM,EAAE,KAAO,EAAI,MAAM,CACpD,EAEH,UAAW,IAAO,GAAK,EACvB,MAAO,GACP,KAAM,CAAE,aAAc,GAAM,CAC7B,EAAE,CACJ,CAAC,CAGI,EAQF,EAAE,CAWN,OAVA,EAAc,SAAS,EAAS,IAAU,CACxC,IAAM,EAAI,EAAQ,GAClB,EAAY,EAAQ,IAAM,CACxB,UACA,UAAW,EAAE,UACb,KAAM,EAAE,MAAM,OAAS,EAAE,CACzB,aAAc,EAAE,MAAM,cAAgB,KACvC,EACD,CAEK"}
@@ -14,4 +14,5 @@ export declare function useAllCloudOrganizations(): Record<string, {
14
14
  name: string;
15
15
  is_personal?: boolean;
16
16
  }[];
17
+ currentOrgId: string | null;
17
18
  }>;
@@ -6,7 +6,9 @@ function i() {
6
6
  let { backends: i } = t(), a = i.filter((e) => e.kind === "cloud"), o = e({ queries: a.map((e) => ({
7
7
  queryKey: ["cloud-organizations", e.id],
8
8
  queryFn: async () => {
9
- let [t, i] = await Promise.all([n(e), r(e)]);
9
+ let t = await n(e);
10
+ if (e.authMode === "cookie") return t;
11
+ let i = await r(e);
10
12
  return i.isLegacyKey || i.orgId === null ? t : {
11
13
  ...t,
12
14
  items: t.items.filter((e) => e.id === i.orgId)
@@ -21,7 +23,8 @@ function i() {
21
23
  s[e.id] = {
22
24
  backend: e,
23
25
  isLoading: n.isLoading,
24
- orgs: n.data?.items ?? []
26
+ orgs: n.data?.items ?? [],
27
+ currentOrgId: n.data?.currentOrgId ?? null
25
28
  };
26
29
  }), s;
27
30
  }
@@ -1 +1 @@
1
- {"version":3,"file":"use-cloud-organizations.js","names":[],"sources":["../../../src/hooks/query/use-cloud-organizations.ts"],"sourcesContent":["import { useQueries } from \"@tanstack/react-query\";\nimport { useActiveBackendContext } from \"#/contexts/active-backend-context\";\nimport {\n getCloudOrganizations,\n getCurrentCloudApiKey,\n} from \"#/api/cloud/organization-service.api\";\nimport type { Backend } from \"#/api/backend-registry/types\";\n\n/**\n * Fetch organizations for every registered cloud backend in parallel.\n *\n * Used by the BackendSelector to flatten each cloud backend into per-org\n * rows. Each query is keyed by the backend ID so React Query caches\n * responses independently and a switch (which clears the cache) refetches.\n */\nexport function useAllCloudOrganizations() {\n const { backends } = useActiveBackendContext();\n const cloudBackends = backends.filter((b) => b.kind === \"cloud\");\n\n const queries = useQueries({\n queries: cloudBackends.map((backend) => ({\n queryKey: [\"cloud-organizations\", backend.id],\n // Filter the user's full org membership down to the single org the\n // backend's API key is bound to. The cloud enforces one-key-one-org\n // server-side (HTTP 403 otherwise); without this filter the\n // selector would advertise orgs the key cannot use. Legacy keys\n // with no binding fall through unfiltered.\n queryFn: async () => {\n const [orgs, key] = await Promise.all([\n getCloudOrganizations(backend),\n getCurrentCloudApiKey(backend),\n ]);\n if (key.isLegacyKey || key.orgId === null) return orgs;\n return {\n ...orgs,\n items: orgs.items.filter((o) => o.id === key.orgId),\n };\n },\n staleTime: 1000 * 60 * 5,\n retry: false,\n meta: { disableToast: true },\n })),\n });\n\n // Map backend id -> result to make consumers easy to read.\n const byBackendId: Record<\n string,\n {\n backend: Backend;\n isLoading: boolean;\n orgs: { id: string; name: string; is_personal?: boolean }[];\n }\n > = {};\n cloudBackends.forEach((backend, index) => {\n const q = queries[index];\n byBackendId[backend.id] = {\n backend,\n isLoading: q.isLoading,\n orgs: q.data?.items ?? [],\n };\n });\n\n return byBackendId;\n}\n"],"mappings":";;;;AAeA,SAAgB,IAA2B;CACzC,IAAM,EAAE,gBAAa,GAAyB,EACxC,IAAgB,EAAS,QAAQ,MAAM,EAAE,SAAS,QAAQ,EAE1D,IAAU,EAAW,EACzB,SAAS,EAAc,KAAK,OAAa;EACvC,UAAU,CAAC,uBAAuB,EAAQ,GAAG;EAM7C,SAAS,YAAY;GACnB,IAAM,CAAC,GAAM,KAAO,MAAM,QAAQ,IAAI,CACpC,EAAsB,EAAQ,EAC9B,EAAsB,EAAQ,CAC/B,CAAC;AAEF,UADI,EAAI,eAAe,EAAI,UAAU,OAAa,IAC3C;IACL,GAAG;IACH,OAAO,EAAK,MAAM,QAAQ,MAAM,EAAE,OAAO,EAAI,MAAM;IACpD;;EAEH,WAAW,MAAO,KAAK;EACvB,OAAO;EACP,MAAM,EAAE,cAAc,IAAM;EAC7B,EAAE,EACJ,CAAC,EAGI,IAOF,EAAE;AAUN,QATA,EAAc,SAAS,GAAS,MAAU;EACxC,IAAM,IAAI,EAAQ;AAClB,IAAY,EAAQ,MAAM;GACxB;GACA,WAAW,EAAE;GACb,MAAM,EAAE,MAAM,SAAS,EAAE;GAC1B;GACD,EAEK"}
1
+ {"version":3,"file":"use-cloud-organizations.js","names":[],"sources":["../../../src/hooks/query/use-cloud-organizations.ts"],"sourcesContent":["import { useQueries } from \"@tanstack/react-query\";\nimport { useActiveBackendContext } from \"#/contexts/active-backend-context\";\nimport {\n getCloudOrganizations,\n getCurrentCloudApiKey,\n} from \"#/api/cloud/organization-service.api\";\nimport type { Backend } from \"#/api/backend-registry/types\";\n\n/**\n * Fetch organizations for every registered cloud backend in parallel.\n *\n * Used by the BackendSelector to flatten each cloud backend into per-org\n * rows. Each query is keyed by the backend ID so React Query caches\n * responses independently and a switch (which clears the cache) refetches.\n */\nexport function useAllCloudOrganizations() {\n const { backends } = useActiveBackendContext();\n const cloudBackends = backends.filter((b) => b.kind === \"cloud\");\n\n const queries = useQueries({\n queries: cloudBackends.map((backend) => ({\n queryKey: [\"cloud-organizations\", backend.id],\n // Filter the user's full org membership down to the single org the\n // backend's API key is bound to. The cloud enforces one-key-one-org\n // server-side (HTTP 403 otherwise); without this filter the\n // selector would advertise orgs the key cannot use. Legacy keys\n // with no binding fall through unfiltered.\n queryFn: async () => {\n const orgs = await getCloudOrganizations(backend);\n if (backend.authMode === \"cookie\") return orgs;\n\n const key = await getCurrentCloudApiKey(backend);\n if (key.isLegacyKey || key.orgId === null) return orgs;\n return {\n ...orgs,\n items: orgs.items.filter((o) => o.id === key.orgId),\n };\n },\n staleTime: 1000 * 60 * 5,\n retry: false,\n meta: { disableToast: true },\n })),\n });\n\n // Map backend id -> result to make consumers easy to read.\n const byBackendId: Record<\n string,\n {\n backend: Backend;\n isLoading: boolean;\n orgs: { id: string; name: string; is_personal?: boolean }[];\n currentOrgId: string | null;\n }\n > = {};\n cloudBackends.forEach((backend, index) => {\n const q = queries[index];\n byBackendId[backend.id] = {\n backend,\n isLoading: q.isLoading,\n orgs: q.data?.items ?? [],\n currentOrgId: q.data?.currentOrgId ?? null,\n };\n });\n\n return byBackendId;\n}\n"],"mappings":";;;;AAeA,SAAgB,IAA2B;CACzC,IAAM,EAAE,gBAAa,GAAyB,EACxC,IAAgB,EAAS,QAAQ,MAAM,EAAE,SAAS,QAAQ,EAE1D,IAAU,EAAW,EACzB,SAAS,EAAc,KAAK,OAAa;EACvC,UAAU,CAAC,uBAAuB,EAAQ,GAAG;EAM7C,SAAS,YAAY;GACnB,IAAM,IAAO,MAAM,EAAsB,EAAQ;AACjD,OAAI,EAAQ,aAAa,SAAU,QAAO;GAE1C,IAAM,IAAM,MAAM,EAAsB,EAAQ;AAEhD,UADI,EAAI,eAAe,EAAI,UAAU,OAAa,IAC3C;IACL,GAAG;IACH,OAAO,EAAK,MAAM,QAAQ,MAAM,EAAE,OAAO,EAAI,MAAM;IACpD;;EAEH,WAAW,MAAO,KAAK;EACvB,OAAO;EACP,MAAM,EAAE,cAAc,IAAM;EAC7B,EAAE,EACJ,CAAC,EAGI,IAQF,EAAE;AAWN,QAVA,EAAc,SAAS,GAAS,MAAU;EACxC,IAAM,IAAI,EAAQ;AAClB,IAAY,EAAQ,MAAM;GACxB;GACA,WAAW,EAAE;GACb,MAAM,EAAE,MAAM,SAAS,EAAE;GACzB,cAAc,EAAE,MAAM,gBAAgB;GACvC;GACD,EAEK"}
@@ -0,0 +1,2 @@
1
+ const e=require(`../../_virtual/_rolldown/runtime.cjs`),t=require(`../use-conversation-id.cjs`),n=require(`../../node_modules/@tanstack/react-query/build/modern/useQuery.cjs`),r=require(`./use-active-conversation.cjs`),i=require(`../use-runtime-is-ready.cjs`),a=require(`../../api/git-service/agent-server-git-service.api.cjs`),o=require(`../../utils/get-git-path.cjs`);let s=require(`react`);s=e.__toESM(s,1);var c=(e,c)=>{let{conversationId:l}=t.useConversationId(),{data:u}=r.useActiveConversation(),d=i.useRuntimeIsReady(),f=u?.conversation_url,p=u?.session_api_key,m=u?.selected_repository,h=u?.workspace?.working_dir?.trim(),g=s.default.useMemo(()=>o.getGitPath(m,h),[m,h]);return n.useQuery({queryKey:[`commit_changes`,l,f,p,g,e],queryFn:async()=>{if(!l)throw Error(`No conversation ID`);return a.default.getCommitChanges(f,p,g,e)},staleTime:1/0,gcTime:1e3*60*15,retry:!1,enabled:c.enabled&&d&&!!l,meta:{disableToast:!0}})};exports.useCommitChanges=c;
2
+ //# sourceMappingURL=use-commit-changes.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-commit-changes.cjs","names":[],"sources":["../../../src/hooks/query/use-commit-changes.ts"],"sourcesContent":["import React from \"react\";\nimport { useQuery } from \"@tanstack/react-query\";\nimport AgentServerGitService from \"#/api/git-service/agent-server-git-service.api\";\nimport { useConversationId } from \"#/hooks/use-conversation-id\";\nimport { useActiveConversation } from \"#/hooks/query/use-active-conversation\";\nimport { useRuntimeIsReady } from \"#/hooks/use-runtime-is-ready\";\nimport { getGitPath } from \"#/utils/get-git-path\";\n\ntype UseCommitChangesConfig = {\n enabled: boolean;\n};\n\nexport const useCommitChanges = (\n sha: string,\n config: UseCommitChangesConfig,\n) => {\n const { conversationId } = useConversationId();\n const { data: conversation } = useActiveConversation();\n const runtimeIsReady = useRuntimeIsReady();\n\n const conversationUrl = conversation?.conversation_url;\n const sessionApiKey = conversation?.session_api_key;\n const selectedRepository = conversation?.selected_repository;\n const workingDir = conversation?.workspace?.working_dir?.trim();\n\n const gitPath = React.useMemo(\n () => getGitPath(selectedRepository, workingDir),\n [selectedRepository, workingDir],\n );\n\n return useQuery({\n queryKey: [\n \"commit_changes\",\n conversationId,\n conversationUrl,\n sessionApiKey,\n gitPath,\n sha,\n ],\n queryFn: async () => {\n if (!conversationId) throw new Error(\"No conversation ID\");\n\n return AgentServerGitService.getCommitChanges(\n conversationUrl,\n sessionApiKey,\n gitPath,\n sha,\n );\n },\n // A commit's change list is sha-addressed and immutable — never stale,\n // and deliberately not invalidated by the bash-observation refresh.\n staleTime: Infinity,\n gcTime: 1000 * 60 * 15, // 15 minutes\n retry: false,\n enabled: config.enabled && runtimeIsReady && !!conversationId,\n meta: {\n disableToast: true,\n },\n });\n};\n"],"mappings":"0ZAYA,IAAa,GACX,EACA,IACG,CACH,GAAM,CAAE,kBAAmB,EAAA,mBAAmB,CACxC,CAAE,KAAM,GAAiB,EAAA,uBAAuB,CAChD,EAAiB,EAAA,mBAAmB,CAEpC,EAAkB,GAAc,iBAChC,EAAgB,GAAc,gBAC9B,EAAqB,GAAc,oBACnC,EAAa,GAAc,WAAW,aAAa,MAAM,CAEzD,EAAU,EAAA,QAAM,YACd,EAAA,WAAW,EAAoB,EAAW,CAChD,CAAC,EAAoB,EAAW,CACjC,CAED,OAAO,EAAA,SAAS,CACd,SAAU,CACR,iBACA,EACA,EACA,EACA,EACA,EACD,CACD,QAAS,SAAY,CACnB,GAAI,CAAC,EAAgB,MAAU,MAAM,qBAAqB,CAE1D,OAAO,EAAA,QAAsB,iBAC3B,EACA,EACA,EACA,EACD,EAIH,UAAW,IACX,OAAQ,IAAO,GAAK,GACpB,MAAO,GACP,QAAS,EAAO,SAAW,GAAkB,CAAC,CAAC,EAC/C,KAAM,CACJ,aAAc,GACf,CACF,CAAC"}
@@ -0,0 +1,5 @@
1
+ type UseCommitChangesConfig = {
2
+ enabled: boolean;
3
+ };
4
+ export declare const useCommitChanges: (sha: string, config: UseCommitChangesConfig) => import("@tanstack/react-query").UseQueryResult<import("../../api/open-hands.types").GitChange[], import("axios").AxiosError<unknown, any>>;
5
+ export {};