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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (385) hide show
  1. package/README.md +2 -2
  2. package/README.windows.md +2 -2
  3. package/build/assets/{QueryClientProvider-Cnr-Yl3j.js → QueryClientProvider-w1cZWY41.js} +1 -1
  4. package/build/assets/{Trans-4jmk54WC.js → Trans-BJeYqz2A.js} +1 -1
  5. package/build/assets/{acp-providers-CPdgcp13.js → acp-providers-DJr8DlNG.js} +1 -1
  6. package/build/assets/{acp-route-guard-BoVmCn0e.js → acp-route-guard-A__sWgbc.js} +1 -1
  7. package/build/assets/{active-backend-context-Beu-LZL-.js → active-backend-context-I2w666XY.js} +1 -1
  8. package/build/assets/add-backend-modal-BDBDBXsJ.js +1 -0
  9. package/build/assets/agent-server-client-options-9agOSarV.js +1 -0
  10. package/build/assets/{agent-server-compatibility-CdI3N7dr.js → agent-server-compatibility-B7QStIcH.js} +1 -1
  11. package/build/assets/agent-server-conversation-service.api-Cagoqq1V.js +5 -0
  12. package/build/assets/agent-settings-BXBaybB_.js +2 -0
  13. package/build/assets/{alert-banner-DFnn_lC6.js → alert-banner-NeUl1-PQ.js} +1 -1
  14. package/build/assets/analytics-consent-form-modal-CmWcFlc6.js +1 -0
  15. package/build/assets/{api-key-entry-screen-M6su2VSf.js → api-key-entry-screen-ByXA4hXH.js} +1 -1
  16. package/build/assets/{app-settings-BlvBhBdc.js → app-settings-C-U6jONZ.js} +1 -1
  17. package/build/assets/automation-detail-Dbmgt974.js +1 -0
  18. package/build/assets/automations-list-BLJzAd-p.js +1 -0
  19. package/build/assets/{back-nav-button-7dQJ2k3O.js → back-nav-button-DgkK0Ka6.js} +1 -1
  20. package/build/assets/{backend-form-modal-CDnEYjaU.js → backend-form-modal-CeB983Sj.js} +1 -1
  21. package/build/assets/{backend-synced-settings-badge-BTIj-Ffq.js → backend-synced-settings-badge-BktJcGgH.js} +1 -1
  22. package/build/assets/{base-modal-C2oy2EBG.js → base-modal-DZCNv0A4.js} +1 -1
  23. package/build/assets/{brand-button-DJ_S16rO.js → brand-button-LBFNic99.js} +1 -1
  24. package/build/assets/browser-D08Sp3ZY.js +5 -0
  25. package/build/assets/{browser-tab-dvSPdvkm.js → browser-tab-be3QvXg9.js} +1 -1
  26. package/build/assets/chat-send-button-5qz0zj6R.js +1 -0
  27. package/build/assets/{checkmark-Dus0b6jt.js → checkmark-Rmpruj7q.js} +1 -1
  28. package/build/assets/{chevron-left-small-_uvG7RVM.js → chevron-left-small-6nyFCWVQ.js} +1 -1
  29. package/build/assets/{circle-plus-check-toggle-DKS8MAVV.js → circle-plus-check-toggle-DquBwJ_6.js} +1 -1
  30. package/build/assets/{close-BU5iTc66.js → close-D_o3d8QM.js} +1 -1
  31. package/build/assets/{code-tag-BzyqOtPD.js → code-tag-DhsjDB-v.js} +1 -1
  32. package/build/assets/{combobox-caret-BJC7XJsz.js → combobox-caret-CO7eozIY.js} +1 -1
  33. package/build/assets/{condenser-settings-BolbDvm5.js → condenser-settings-BulzYEuW.js} +1 -1
  34. package/build/assets/{confirmation-modal-B5Ca6qFE.js → confirmation-modal-CMAtd9R0.js} +1 -1
  35. package/build/assets/{context-menu-list-item-7tAcm2c3.js → context-menu-list-item-D0swnhFt.js} +1 -1
  36. package/build/assets/conversation-BrjF2-Ky.js +1 -0
  37. package/build/assets/conversation-HgR_TTPE.js +19 -0
  38. package/build/assets/conversation-panel-BlRcO5AC.js +1 -0
  39. package/build/assets/conversation-service.api-B_Pdmwsa.js +1 -0
  40. package/build/assets/{conversation-tab-empty-state-CStQLPVW.js → conversation-tab-empty-state-DYjKsg_c.js} +1 -1
  41. package/build/assets/conversation-websocket-context-G95yfL81.js +3 -0
  42. package/build/assets/{copy-Chg-sFu3.js → copy-BM0RpLez.js} +1 -1
  43. package/build/assets/{custom-toast-handlers-ufGJ6_Rc.js → custom-toast-handlers-BohXx7uh.js} +1 -1
  44. package/build/assets/{declaration-CR6HMp29.js → declaration-DaUdB2Wg.js} +1 -1
  45. package/build/assets/{device-verify-C6mj28zv.js → device-verify-DiEJqpJb.js} +1 -1
  46. package/build/assets/dist-Bl-1K5Tv.js +1 -0
  47. package/build/assets/{dist-C3NfioQC.js → dist-xtCm0O6P.js} +1 -1
  48. package/build/assets/{dropdown-classes-BsVmxlNG.js → dropdown-classes-Vqz86I0R.js} +1 -1
  49. package/build/assets/{edit-automation-modal-BpX-t-HD.js → edit-automation-modal-CNZgSSiH.js} +1 -1
  50. package/build/assets/{entry.client-Ck9rQCg-.js → entry.client-BvKgdCQ9.js} +2 -2
  51. package/build/assets/{enum-filter-dropdown-5JeF2RLb.js → enum-filter-dropdown-DdFgk0EM.js} +1 -1
  52. package/build/assets/{environment-switch-overlay-Tf_BIfeR.js → environment-switch-overlay-CuBuZOaa.js} +1 -1
  53. package/build/assets/{extensions-hub-CE9QOb5n.js → extensions-hub-Dayqvv0n.js} +1 -1
  54. package/build/assets/{extensions-navigation-DSLGNGbS.js → extensions-navigation-yFLAU06N.js} +1 -1
  55. package/build/assets/{file-BTY6Gyy9.js → file-DwHCkWZT.js} +1 -1
  56. package/build/assets/files-tab-CMredyYX.js +1 -0
  57. package/build/assets/{folder-D1T2W1cj.js → folder-2h1hR1Qb.js} +1 -1
  58. package/build/assets/git-control-bar-branch-button-D8blTNXh.js +27 -0
  59. package/build/assets/{globe-Bzj_0oXT.js → globe-qFjFNG6J.js} +1 -1
  60. package/build/assets/home-TrU0fLgG.js +1 -0
  61. package/build/assets/{i18n-DET2iOyh.js → i18n-zDndR1Ne.js} +1 -1
  62. package/build/assets/install-server-modal-D8Q0xZcN.js +1 -0
  63. package/build/assets/{launch-CWz0dm4o.js → launch-I00QV8YT.js} +1 -1
  64. package/build/assets/{lesson-plan-duSsqWVs.js → lesson-plan-C18uB_56.js} +1 -1
  65. package/build/assets/{link-external-DGxVm4Ps.js → link-external-DtcdPFbw.js} +1 -1
  66. package/build/assets/{llm-client-CYEaUjGx.js → llm-client-BqyLKgUN.js} +1 -1
  67. package/build/assets/llm-settings-C4R4HMUO.js +1 -0
  68. package/build/assets/llm-settings-Dq3w2cob.js +1 -0
  69. package/build/assets/{loading-spinner-5GT9q1xy.js → loading-spinner-DNwR4--Z.js} +1 -1
  70. package/build/assets/{manage-backends-modal-DpBD_vR9.js → manage-backends-modal-Ceo_SOcf.js} +1 -1
  71. package/build/assets/manifest-8c2efa8a.js +1 -0
  72. package/build/assets/{markdown-renderer-B3IAVfv4.js → markdown-renderer-D6B-u2nM.js} +1 -1
  73. package/build/assets/{mcp-BUe7kiYM.js → mcp-EvrLVTla.js} +1 -1
  74. package/build/assets/messages-Bz9TWjlh.js +36 -0
  75. package/build/assets/modal-backdrop-BDqI1zBV.js +1 -0
  76. package/build/assets/{modal-body-aoa2fx5W.js → modal-body-CCLCqX1J.js} +1 -1
  77. package/build/assets/{modal-classes-6YqcqA6y.js → modal-classes-DwTdT3IK.js} +1 -1
  78. package/build/assets/{modal-close-button-CtWOUMmw.js → modal-close-button-gQgKqUf-.js} +1 -1
  79. package/build/assets/{model-selector-BvSTrkhT.js → model-selector-DoL0CL0_.js} +1 -1
  80. package/build/assets/{mutation-D0OogFCz.js → mutation-CaJwPR9O.js} +1 -1
  81. package/build/assets/{navigation-context-BdKYH32C.js → navigation-context-aNGUUtdq.js} +1 -1
  82. package/build/assets/{navigation-link-U4vY9i_C.js → navigation-link-CYkF2y3K.js} +1 -1
  83. package/build/assets/onboarding-DLr9jbKH.js +1 -0
  84. package/build/assets/{openhands-logo-CCo0wJZX.js → openhands-logo-CHmtDV-t.js} +1 -1
  85. package/build/assets/{option-service.api-DmNVxAvS.js → option-service.api-CGNANEcT.js} +1 -1
  86. package/build/assets/{organization-service.api-DbnougaQ.js → organization-service.api-Dn74hBTH.js} +1 -1
  87. package/build/assets/path-utils-BjxzIGLp.js +1 -0
  88. package/build/assets/{plan-components-CRDMQzsS.js → plan-components--aLlpASH.js} +1 -1
  89. package/build/assets/{planner-tab-CmIjLz7q.js → planner-tab-B-5EeCEm.js} +1 -1
  90. package/build/assets/{profiles-client-fEmgWkCW.js → profiles-client-BrqNmaDV.js} +1 -1
  91. package/build/assets/{providers-CbD7fiic.js → providers-DknP6O2g.js} +1 -1
  92. package/build/assets/{proxy-BAdHH8QB.js → proxy-sRh0WKI7.js} +1 -1
  93. package/build/assets/{query-client-config-CRnGSujB.js → query-client-config-CWWGQWvw.js} +1 -1
  94. package/build/assets/{recommended-automations-launcher-uTyODuzB.js → recommended-automations-launcher-BIul0osB.js} +3 -3
  95. package/build/assets/root-BietmyRa.js +2 -0
  96. package/build/assets/{root-Z2VHU4R3.css → root-CN7qsvxg.css} +1 -1
  97. package/build/assets/root-layout-BgPi-t57.js +2 -0
  98. package/build/assets/{sdk-section-page-BgDlMhcq.js → sdk-section-page-VmtJWH3A.js} +1 -1
  99. package/build/assets/{sdk-settings-schema-CLmJ9sho.js → sdk-settings-schema-DFievvEK.js} +1 -1
  100. package/build/assets/{search-SuJctqNJ.js → search-BeVRXvX7.js} +1 -1
  101. package/build/assets/{secrets-service-B7CxNinp.js → secrets-service-DVtlLWY8.js} +1 -1
  102. package/build/assets/{secrets-settings-yK7CqIpm.js → secrets-settings-BLMvCkKm.js} +1 -1
  103. package/build/assets/{server-client-Kh4QSwDJ.js → server-client-DYv_GHPl.js} +1 -1
  104. package/build/assets/{settings-DN5PpgRD.js → settings-CXvJUx_j.js} +1 -1
  105. package/build/assets/{settings-dropdown-input-BtoovFre.js → settings-dropdown-input-DA_pzHWE.js} +1 -1
  106. package/build/assets/{settings-gear-Dd8K2_8B.js → settings-gear-aNebYlCy.js} +1 -1
  107. package/build/assets/{settings-index-DKC8IY1P.js → settings-index-CycvkOoq.js} +1 -1
  108. package/build/assets/{settings-input-CehsXnb3.js → settings-input-8y5p4kze.js} +1 -1
  109. package/build/assets/{settings-list-classes-E3v_f6QG.js → settings-list-classes-Qk7zl0Wu.js} +1 -1
  110. package/build/assets/settings-modal-nJYxCsyp.js +1 -0
  111. package/build/assets/{settings-section-header-context-DewwJ0-F.js → settings-section-header-context-B77tsYlx.js} +1 -1
  112. package/build/assets/{settings-service.api-C3rxTtPj.js → settings-service.api-DxIEtvx6.js} +1 -1
  113. package/build/assets/{settings-switch-BiBuS3xa.js → settings-switch-ba4DuiNO.js} +1 -1
  114. package/build/assets/{settings-utils-DY04tWG1.js → settings-utils-BxzHqLmZ.js} +1 -1
  115. package/build/assets/{shared-conversation-h9YnBtCU.js → shared-conversation-x41nZQi7.js} +1 -1
  116. package/build/assets/{sidebar-mobile-menu-toggle-D0-AvsnT.js → sidebar-mobile-menu-toggle-C0mmabKj.js} +1 -1
  117. package/build/assets/{sidebar-nav-link-OhIeFyna.js → sidebar-nav-link-BsYdDFfb.js} +1 -1
  118. package/build/assets/{skill-card-pill-row-BW9qvhoK.js → skill-card-pill-row-BhUlGcYB.js} +1 -1
  119. package/build/assets/{skills-0GRKX5Xj.js → skills-TYjOUQ2d.js} +1 -1
  120. package/build/assets/{skills-plugins-DNcsNF88.js → skills-plugins-D0pdqgKa.js} +1 -1
  121. package/build/assets/{skills-settings-7liFiSY6.js → skills-settings-VqKTkmVl.js} +2 -2
  122. package/build/assets/{styled-tooltip-hdfMXPQC.js → styled-tooltip-TCp7svY3.js} +1 -1
  123. package/build/assets/{switch-skeleton-DSKqSx2A.js → switch-skeleton-cKrdaYGj.js} +1 -1
  124. package/build/assets/{task-list-tab-DT6_zfUs.js → task-list-tab-BiizRsY3.js} +1 -1
  125. package/build/assets/telemetry-3piyXm5H.js +2 -0
  126. package/build/assets/{terminal-CPYWdo4j.js → terminal-BSYITdM0.js} +1 -1
  127. package/build/assets/{terminal-CDhQGDua.js → terminal-CpgZx6go.js} +1 -1
  128. package/build/assets/{toggle-switch-T2v6sJ6l.js → toggle-switch-CUgOZqZu.js} +1 -1
  129. package/build/assets/{typography-BDgnT7Yp.js → typography-Bvw0IxaN.js} +1 -1
  130. package/build/assets/{u-check-circle-half-steSK_JB.js → u-check-circle-half-DjpjzWu3.js} +1 -1
  131. package/build/assets/{u-check-circle-DOauqQKb.js → u-check-circle-u9QiS4Fr.js} +1 -1
  132. package/build/assets/{u-circuit-x3ExjBbU.js → u-circuit-DlBlOwx9.js} +1 -1
  133. package/build/assets/{u-edit-BbrptMCa.js → u-edit-BIYzjs3v.js} +1 -1
  134. package/build/assets/{use-active-conversation-DHGcmjCK.js → use-active-conversation-q1wT8LI5.js} +1 -1
  135. package/build/assets/{use-agent-settings-schema-CLoTOSJI.js → use-agent-settings-schema-Yxf7KGyG.js} +1 -1
  136. package/build/assets/{use-agent-state-PKrUPMJ3.js → use-agent-state-CCHlVqvY.js} +1 -1
  137. package/build/assets/{use-cloud-current-user-id-Ddr75hEz.js → use-cloud-current-user-id-BAKf91Zx.js} +1 -1
  138. package/build/assets/{use-config-OIMQLQ2s.js → use-config-DwfigQ_Y.js} +1 -1
  139. package/build/assets/use-create-conversation-BEzddjXn.js +1 -0
  140. package/build/assets/{use-get-secrets-8Jby8ele.js → use-get-secrets-BlO1BfUo.js} +1 -1
  141. package/build/assets/{use-handle-plan-click-CohJPvvW.js → use-handle-plan-click-Bfl0zIBr.js} +1 -1
  142. package/build/assets/use-is-authed-hHndEep7.js +1 -0
  143. package/build/assets/{use-launch-skill-in-chat-sQNEOLGD.js → use-launch-skill-in-chat-3ydwpi_M.js} +1 -1
  144. package/build/assets/use-llm-profiles-E-jjZMZw.js +1 -0
  145. package/build/assets/use-runtime-is-ready-DBWzvAmc.js +1 -0
  146. package/build/assets/use-save-settings-rE9aA29R.js +1 -0
  147. package/build/assets/{use-settings-D5hbTS9t.js → use-settings-BPTbE7lg.js} +1 -1
  148. package/build/assets/{use-settings-nav-items-BcSbo02d.js → use-settings-nav-items-C7MOWj09.js} +1 -1
  149. package/build/assets/{use-skills-D7PS0fH0.js → use-skills-QhoaIYGF.js} +1 -1
  150. package/build/assets/{use-task-list-CsT10CBb.js → use-task-list-YMkSzdDv.js} +1 -1
  151. package/build/assets/use-tracking-DQYdZpxi.js +1 -0
  152. package/build/assets/{use-unified-vscode-url-DEoe-NRI.js → use-unified-vscode-url-DFtNIC1Q.js} +1 -1
  153. package/build/assets/{use-user-conversation-Cs5H1pUF.js → use-user-conversation-BRAseenw.js} +1 -1
  154. package/build/assets/{useMutation-GSSKKebK.js → useMutation-DDo48A8t.js} +1 -1
  155. package/build/assets/{useTranslation-B6voJV4y.js → useTranslation-CEcjrme-.js} +1 -1
  156. package/build/assets/{utils-DCVfKFRt.js → utils-CdgBzLA7.js} +1 -1
  157. package/build/assets/{vendor~browser-BrOJLj3y.js → vendor~browser-DWk6fNtJ.js} +1 -1
  158. package/build/assets/{vendor~browser-tab-BxhTtM9_.js → vendor~browser-tab-NZdVoI2Z.js} +1 -1
  159. package/build/assets/{vendor~conversation-panel~conversation-C9o-K1hW.js → vendor~conversation-panel~conversation-gp03cWZW.js} +1 -1
  160. package/build/assets/{vendor~conversation-panel~conversation~index-RXYdJYxU.js → vendor~conversation-panel~conversation~index-BZ5C6Xpz.js} +1 -1
  161. package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~jfc6hidu-DJS-rJdI.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~oli4dvxu-BodGsxSf.js} +1 -1
  162. package/build/assets/{vendor~files-tab-BtkpAiMX.js → vendor~files-tab-Buz36Y-q.js} +1 -1
  163. package/build/assets/{vendor~home~conversation-panel~conversation-PK1-gtXU.js → vendor~home~conversation-panel~conversation-DG0H5SkJ.js} +2 -2
  164. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-6ByzelMS.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-1pTajrpX.js} +1 -1
  165. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-BED5W_c4.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-9Il_wz8U.js} +1 -1
  166. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-CCbqAFiI.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-B7I1ZxCx.js} +1 -1
  167. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-E4d6IEfI.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-Ceeqkj0k.js} +1 -1
  168. package/build/assets/{vendor~launch-BXgl67Re.js → vendor~launch-DXL78kBf.js} +1 -1
  169. package/build/assets/{vendor~root-layout~conversation-panel~conversation~shared-conversation-DW31UyBp.js → vendor~root-layout~conversation-panel~conversation~shared-conversation-CfAc3nMS.js} +1 -1
  170. package/build/assets/vendor~root-layout~home~conversation-panel~conversation-DkwcKRtv.js +1 -0
  171. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-tTR8C6m0.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-BC9XTECT.js} +1 -1
  172. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-6Rm8U_Sr.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-DSqEbr0N.js} +1 -1
  173. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~k776hupu-BJbu9kpL.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~k776hupu-D0XUSHNN.js} +2 -2
  174. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~dp08i1qy-hTzSytKK.js → vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~dp08i1qy-D8soyAAx.js} +1 -1
  175. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~shared-conversation~alert-banner~pl~rqjteh0a-d2oallMa.js → vendor~root-layout~home~conversation-panel~conversation~shared-conversation~alert-banner~pl~rqjteh0a-CcFtthyg.js} +1 -1
  176. package/build/assets/vendor~root-layout~home~mcp~automations-list-BnIlGhjl.js +1 -0
  177. package/build/assets/{vendor~home~mcp~automations-list-BgV86Sti.js → vendor~root-layout~home~mcp~automations-list-cNHi83v_.js} +1 -1
  178. package/build/assets/{vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-CjJdFLoM.js → vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-BGWUbqUq.js} +1 -1
  179. package/build/assets/{vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-m8dOii0J.js → vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-BuCSnjsW.js} +2 -2
  180. package/build/assets/{vendor~root~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-s~f2l2lr17-DYXOLEck.js → vendor~root~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-s~jaomi49z-Cw89stA6.js} +1 -1
  181. package/build/assets/{verification-settings-Dlt8pINd.js → verification-settings-CIqtxWat.js} +1 -1
  182. package/build/assets/{vscode-tab-DgepcYtF.js → vscode-tab-DEt72yJX.js} +1 -1
  183. package/build/assets/{waiting-for-runtime-message-CdK3btDZ.js → waiting-for-runtime-message-DSjJfeoj.js} +1 -1
  184. package/build/assets/{x-mark-BrkSPIiT.js → x-mark-DsJ9tDD0.js} +1 -1
  185. package/build/index.html +4 -4
  186. package/build/locales/ar/openhands.json +4 -2
  187. package/build/locales/ca/openhands.json +4 -2
  188. package/build/locales/de/openhands.json +4 -2
  189. package/build/locales/en/openhands.json +4 -2
  190. package/build/locales/es/openhands.json +4 -2
  191. package/build/locales/fr/openhands.json +4 -2
  192. package/build/locales/it/openhands.json +4 -2
  193. package/build/locales/ja/openhands.json +4 -2
  194. package/build/locales/ko-KR/openhands.json +4 -2
  195. package/build/locales/no/openhands.json +4 -2
  196. package/build/locales/pt/openhands.json +4 -2
  197. package/build/locales/tr/openhands.json +4 -2
  198. package/build/locales/uk/openhands.json +4 -2
  199. package/build/locales/zh-CN/openhands.json +4 -2
  200. package/build/locales/zh-TW/openhands.json +4 -2
  201. package/config/defaults.json +1 -1
  202. package/dist/api/agent-server-config.cjs +1 -1
  203. package/dist/api/agent-server-config.cjs.map +1 -1
  204. package/dist/api/agent-server-config.d.ts +17 -0
  205. package/dist/api/agent-server-config.js +7 -1
  206. package/dist/api/agent-server-config.js.map +1 -1
  207. package/dist/api/agent-server-home.cjs +2 -0
  208. package/dist/api/agent-server-home.cjs.map +1 -0
  209. package/dist/api/agent-server-home.d.ts +34 -0
  210. package/dist/api/agent-server-home.js +33 -0
  211. package/dist/api/agent-server-home.js.map +1 -0
  212. package/dist/api/conversation-file-upload.api.cjs +1 -1
  213. package/dist/api/conversation-file-upload.api.cjs.map +1 -1
  214. package/dist/api/conversation-file-upload.api.js +4 -1
  215. package/dist/api/conversation-file-upload.api.js.map +1 -1
  216. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs +1 -1
  217. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs.map +1 -1
  218. package/dist/api/conversation-service/agent-server-conversation-service.api.js +101 -100
  219. package/dist/api/conversation-service/agent-server-conversation-service.api.js.map +1 -1
  220. package/dist/api/option-service/option-service.api.cjs.map +1 -1
  221. package/dist/api/option-service/option-service.api.js.map +1 -1
  222. package/dist/api/workspace-upload-path.cjs +1 -1
  223. package/dist/api/workspace-upload-path.cjs.map +1 -1
  224. package/dist/api/workspace-upload-path.d.ts +44 -2
  225. package/dist/api/workspace-upload-path.js +16 -14
  226. package/dist/api/workspace-upload-path.js.map +1 -1
  227. package/dist/components/features/automations/recommended-automations-launcher.d.ts +3 -1
  228. package/dist/components/features/automations/recommended-automations-section.d.ts +3 -1
  229. package/dist/components/features/backends/backend-form-modal.cjs +1 -1
  230. package/dist/components/features/backends/backend-form-modal.cjs.map +1 -1
  231. package/dist/components/features/backends/backend-form-modal.d.ts +7 -1
  232. package/dist/components/features/backends/backend-form-modal.js +94 -91
  233. package/dist/components/features/backends/backend-form-modal.js.map +1 -1
  234. package/dist/components/features/chat/chat-interface.cjs +2 -2
  235. package/dist/components/features/chat/chat-interface.cjs.map +1 -1
  236. package/dist/components/features/chat/chat-interface.js +66 -66
  237. package/dist/components/features/chat/chat-interface.js.map +1 -1
  238. package/dist/components/features/chat/confirmation-mode-enabled.cjs +1 -1
  239. package/dist/components/features/chat/confirmation-mode-enabled.js +4 -4
  240. package/dist/components/features/chat/switch-profile-button.cjs +1 -1
  241. package/dist/components/features/chat/switch-profile-button.js +3 -3
  242. package/dist/components/features/conversation-panel/conversation-card/conversation-card.cjs +1 -1
  243. package/dist/components/features/conversation-panel/conversation-card/conversation-card.cjs.map +1 -1
  244. package/dist/components/features/conversation-panel/conversation-card/conversation-card.js +5 -5
  245. package/dist/components/features/conversation-panel/conversation-card/conversation-card.js.map +1 -1
  246. package/dist/components/features/onboarding/index.d.ts +1 -0
  247. package/dist/components/features/onboarding/onboarding-host.d.ts +3 -1
  248. package/dist/components/features/onboarding/onboarding-modal.d.ts +7 -3
  249. package/dist/components/features/onboarding/onboarding-preview.d.ts +4 -0
  250. package/dist/components/features/onboarding/steps/say-hello-step.d.ts +3 -1
  251. package/dist/components/features/settings/llm-profiles/llm-settings-local-view.cjs +1 -1
  252. package/dist/components/features/settings/llm-profiles/llm-settings-local-view.js +1 -1
  253. package/dist/components/features/settings/sdk-settings/sdk-section-page.cjs +1 -1
  254. package/dist/components/features/settings/sdk-settings/sdk-section-page.cjs.map +1 -1
  255. package/dist/components/features/settings/sdk-settings/sdk-section-page.d.ts +3 -1
  256. package/dist/components/features/settings/sdk-settings/sdk-section-page.js +56 -56
  257. package/dist/components/features/settings/sdk-settings/sdk-section-page.js.map +1 -1
  258. package/dist/components/features/skills/extensions-navigation.cjs +1 -1
  259. package/dist/components/features/skills/extensions-navigation.js +7 -7
  260. package/dist/components/shared/modals/modal-backdrop.cjs +1 -1
  261. package/dist/components/shared/modals/modal-backdrop.cjs.map +1 -1
  262. package/dist/components/shared/modals/modal-backdrop.d.ts +3 -1
  263. package/dist/components/shared/modals/modal-backdrop.js +3 -3
  264. package/dist/components/shared/modals/modal-backdrop.js.map +1 -1
  265. package/dist/components/shared/modals/settings/settings-form.cjs +1 -1
  266. package/dist/components/shared/modals/settings/settings-form.cjs.map +1 -1
  267. package/dist/components/shared/modals/settings/settings-form.js +7 -7
  268. package/dist/components/shared/modals/settings/settings-form.js.map +1 -1
  269. package/dist/hooks/chat/use-model-interceptor.cjs +1 -1
  270. package/dist/hooks/chat/use-model-interceptor.js +4 -4
  271. package/dist/hooks/mutation/use-save-settings.cjs +1 -1
  272. package/dist/hooks/mutation/use-save-settings.cjs.map +1 -1
  273. package/dist/hooks/mutation/use-save-settings.js +13 -14
  274. package/dist/hooks/mutation/use-save-settings.js.map +1 -1
  275. package/dist/hooks/query/use-llm-profiles.cjs +1 -1
  276. package/dist/hooks/query/use-llm-profiles.js +5 -5
  277. package/dist/hooks/use-download-conversation.cjs +1 -1
  278. package/dist/hooks/use-download-conversation.cjs.map +1 -1
  279. package/dist/hooks/use-download-conversation.js +4 -4
  280. package/dist/hooks/use-download-conversation.js.map +1 -1
  281. package/dist/hooks/use-tracking.cjs +1 -1
  282. package/dist/hooks/use-tracking.cjs.map +1 -1
  283. package/dist/hooks/use-tracking.d.ts +31 -0
  284. package/dist/hooks/use-tracking.js +51 -14
  285. package/dist/hooks/use-tracking.js.map +1 -1
  286. package/dist/i18n/declaration.cjs +1 -1
  287. package/dist/i18n/declaration.cjs.map +1 -1
  288. package/dist/i18n/declaration.d.ts +2 -0
  289. package/dist/i18n/declaration.js +1 -1
  290. package/dist/i18n/declaration.js.map +1 -1
  291. package/dist/i18n/translation.cjs +1 -1
  292. package/dist/i18n/translation.cjs.map +1 -1
  293. package/dist/i18n/translation.js +64 -30
  294. package/dist/i18n/translation.js.map +1 -1
  295. package/dist/locales/ar/openhands.json +4 -2
  296. package/dist/locales/ca/openhands.json +4 -2
  297. package/dist/locales/de/openhands.json +4 -2
  298. package/dist/locales/en/openhands.json +4 -2
  299. package/dist/locales/es/openhands.json +4 -2
  300. package/dist/locales/fr/openhands.json +4 -2
  301. package/dist/locales/it/openhands.json +4 -2
  302. package/dist/locales/ja/openhands.json +4 -2
  303. package/dist/locales/ko-KR/openhands.json +4 -2
  304. package/dist/locales/no/openhands.json +4 -2
  305. package/dist/locales/pt/openhands.json +4 -2
  306. package/dist/locales/tr/openhands.json +4 -2
  307. package/dist/locales/uk/openhands.json +4 -2
  308. package/dist/locales/zh-CN/openhands.json +4 -2
  309. package/dist/locales/zh-TW/openhands.json +4 -2
  310. package/dist/package.cjs +1 -1
  311. package/dist/package.cjs.map +1 -1
  312. package/dist/package.js +1 -1
  313. package/dist/package.js.map +1 -1
  314. package/dist/routes/llm-settings.cjs +1 -1
  315. package/dist/routes/llm-settings.cjs.map +1 -1
  316. package/dist/routes/llm-settings.d.ts +3 -1
  317. package/dist/routes/llm-settings.js +17 -16
  318. package/dist/routes/llm-settings.js.map +1 -1
  319. package/package.json +1 -1
  320. package/scripts/dev-static.mjs +0 -2
  321. package/scripts/dev-with-automation.mjs +0 -2
  322. package/scripts/static-server.mjs +28 -6
  323. package/build/assets/add-backend-modal-BheqYXHK.js +0 -1
  324. package/build/assets/agent-server-client-options-HEOwGVIU.js +0 -1
  325. package/build/assets/agent-server-conversation-service.api-CORdqJZg.js +0 -5
  326. package/build/assets/agent-settings-UFvcGjoI.js +0 -2
  327. package/build/assets/analytics-consent-form-modal-CVNugqzu.js +0 -1
  328. package/build/assets/automation-detail-BWrQk4Oa.js +0 -1
  329. package/build/assets/automations-list-ux9KvYsU.js +0 -1
  330. package/build/assets/browser-CGM-k-sH.js +0 -5
  331. package/build/assets/conversation-D0N4dw_p.js +0 -19
  332. package/build/assets/conversation-DhRJuZLG.js +0 -1
  333. package/build/assets/conversation-panel-CNqHbS_Z.js +0 -1
  334. package/build/assets/conversation-service.api-BsJy6uuL.js +0 -1
  335. package/build/assets/conversation-websocket-context-DvHgx_FE.js +0 -3
  336. package/build/assets/dist-DNeWJ2bh.js +0 -1
  337. package/build/assets/ellipsis-button-Vh5MvRZa.js +0 -1
  338. package/build/assets/files-tab-cL668j1I.js +0 -1
  339. package/build/assets/git-branch-DQS2nMK4.js +0 -1
  340. package/build/assets/git-control-bar-branch-button-DtIrOrie.js +0 -27
  341. package/build/assets/git-provider-icon-CHdGBdU2.js +0 -1
  342. package/build/assets/home-Cz2Veg56.js +0 -1
  343. package/build/assets/install-server-modal-B9nXCS3u.js +0 -1
  344. package/build/assets/llm-settings-DFkXHuvT.js +0 -1
  345. package/build/assets/llm-settings-DhrdCXqX.js +0 -1
  346. package/build/assets/manage-workspaces-modal-CtRbxREx.js +0 -1
  347. package/build/assets/manifest-eed90ff5.js +0 -1
  348. package/build/assets/messages-dqp_KYyl.js +0 -36
  349. package/build/assets/modal-backdrop-RfNCrSpK.js +0 -1
  350. package/build/assets/path-utils-onx24uF5.js +0 -1
  351. package/build/assets/root-DmjpFpTu.js +0 -2
  352. package/build/assets/root-layout-DejMsKhy.js +0 -2
  353. package/build/assets/settings-modal-DJ4kGzUx.js +0 -1
  354. package/build/assets/use-create-conversation-Bszyp13O.js +0 -1
  355. package/build/assets/use-is-authed-dw2026rR.js +0 -1
  356. package/build/assets/use-is-creating-conversation-DX2qSlfL.js +0 -1
  357. package/build/assets/use-llm-profiles-C861aFAq.js +0 -1
  358. package/build/assets/use-runtime-is-ready-Do2h_hRl.js +0 -1
  359. package/build/assets/use-save-settings-DkAOEfD9.js +0 -1
  360. package/build/assets/vendor~home~mcp~automations-list-CZSK-lT2.js +0 -1
  361. package/build/assets/vendor~root-layout~home~conversation-panel~conversation-B5WNMnt4.js +0 -1
  362. /package/build/assets/{automation-XDPAjiZi.js → automation-DJ_3GeXD.js} +0 -0
  363. /package/build/assets/{browser-store-DAsixKdU.js → browser-store-JRrcGdlk.js} +0 -0
  364. /package/build/assets/{check-CYxAHs85.js → check-CZhEL6rP.js} +0 -0
  365. /package/build/assets/{chevron-down-Bnmd5iG-.js → chevron-down-KhWYEjeW.js} +0 -0
  366. /package/build/assets/{color-themes-B9pm9c-R.js → color-themes-0biOprdo.js} +0 -0
  367. /package/build/assets/{command-store-CE1weJy8.js → command-store-UzKGSUC2.js} +0 -0
  368. /package/build/assets/{files-tab-store-m0ARqX_E.js → files-tab-store-DLU28g8C.js} +0 -0
  369. /package/build/assets/{iconBase-DE30Zj_-.js → iconBase-BVhFI-0E.js} +0 -0
  370. /package/build/assets/{map-provider-BJ_8KZKU.js → map-provider-C3Z5Dx2J.js} +0 -0
  371. /package/build/assets/{sdk-settings-field-metadata-DQiaIBie.js → sdk-settings-field-metadata-C6KMD-jZ.js} +0 -0
  372. /package/build/assets/{settings-like-page-layout-classes-D7YjdTd0.js → settings-like-page-layout-classes-DNg2vKSM.js} +0 -0
  373. /package/build/assets/{use-breakpoint-DF_RiQ6s.js → use-breakpoint-DpxHDmuH.js} +0 -0
  374. /package/build/assets/{use-event-store-BomO7ywK.js → use-event-store-Cxqc45Sw.js} +0 -0
  375. /package/build/assets/{vendor~browser-DisFGEp9.js → vendor~browser-BDNLFng6.js} +0 -0
  376. /package/build/assets/{vendor~conversation-panel~conversation~alert-banner-w-I2sY6c.js → vendor~conversation-panel~conversation~alert-banner-D_hRW_zc.js} +0 -0
  377. /package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~g56ukk6u-DsSvIDZQ.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~h07fzaqi-D15MEcqi.js} +0 -0
  378. /package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~hkqzh1hb-BZ0HXuHD.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~j8sdb9mk-OFpe9fX_.js} +0 -0
  379. /package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~zm51vy4j-BClAMeFe.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~lpdshwee-BPuuVEqr.js} +0 -0
  380. /package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-CG96FCly.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-CXivI4Ym.js} +0 -0
  381. /package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-CyZ-3lDQ.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-Dr3Ow7Ms.js} +0 -0
  382. /package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~i4kjfqhl-CbAhtEMv.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~i4kjfqhl-B1TKKuuH.js} +0 -0
  383. /package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~ninslayh-CLlsvdNP.js → vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~e9ykmtgh-Fa-nXZ4M.js} +0 -0
  384. /package/build/assets/{vendor~terminal-DZaJIY8A.js → vendor~terminal-0ObOedYm.js} +0 -0
  385. /package/build/assets/{vscode-url-helper-Cwy1A62q.js → vscode-url-helper-BMq8JBhB.js} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"llm-settings.cjs","names":[],"sources":["../../src/routes/llm-settings.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { ModelSelector } from \"#/components/shared/modals/settings/model-selector\";\nimport { useAgentSettingsSchema } from \"#/hooks/query/use-agent-settings-schema\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { SettingsInput } from \"#/components/features/settings/settings-input\";\nimport { HelpLink } from \"#/ui/help-link\";\nimport { KeyStatusIcon } from \"#/components/features/settings/key-status-icon\";\nimport {\n SdkSectionHeaderProps,\n SdkSectionPage,\n SdkSectionSaveControl,\n} from \"#/components/features/settings/sdk-settings/sdk-section-page\";\nimport { LlmSettingsLocalView } from \"#/components/features/settings/llm-profiles\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { Settings, SettingsSchema, SettingsScope } from \"#/types/settings\";\nimport { extractModelAndProvider } from \"#/utils/extract-model-and-provider\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport {\n inferInitialView,\n type SettingsFormValues,\n type SettingsView,\n} from \"#/utils/sdk-settings-schema\";\nimport { DEFAULT_SETTINGS } from \"#/services/settings\";\nimport {\n OPENHANDS_LLM_PROXY_BASE_URL,\n isOpenHandsProviderModel,\n} from \"#/utils/openhands-llm\";\n\nconst LLM_EXCLUDED_KEYS = new Set([\"llm.model\", \"llm.api_key\", \"llm.base_url\"]);\n\nconst buildModelId = (provider: string | null, model: string | null) => {\n if (!provider || !model) return null;\n return `${provider}/${model}`;\n};\n\nconst getSchemaFieldDefaultValue = (\n schema: SettingsSchema | null | undefined,\n fieldKey: string,\n) =>\n schema?.sections\n .flatMap((section) => section.fields)\n .find((field) => field.key === fieldKey)?.default ?? null;\n\nconst KNOWN_PROVIDER_DEFAULT_BASE_URLS: Partial<Record<string, Set<string>>> = {\n openai: new Set([\"https://api.openai.com\", \"https://api.openai.com/v1\"]),\n openhands: new Set([\n OPENHANDS_LLM_PROXY_BASE_URL,\n \"https://llm-proxy.app.all-hands.dev/v1\",\n ]),\n litellm_proxy: new Set([\n OPENHANDS_LLM_PROXY_BASE_URL,\n \"https://llm-proxy.app.all-hands.dev/v1\",\n ]),\n};\n\nconst normalizeBaseUrl = (baseUrl: string) => {\n try {\n const parsedUrl = new URL(baseUrl);\n const normalizedPath = parsedUrl.pathname.replace(/\\/+$/, \"\") || \"\";\n return `${parsedUrl.origin}${normalizedPath}`;\n } catch {\n return baseUrl.trim().replace(/\\/+$/, \"\");\n }\n};\n\nconst isProviderDefaultBaseUrl = (model: string, baseUrl: string) => {\n const normalizedBaseUrl = normalizeBaseUrl(baseUrl);\n const { provider } = extractModelAndProvider(model);\n\n if (provider) {\n const knownDefaults = KNOWN_PROVIDER_DEFAULT_BASE_URLS[provider];\n if (knownDefaults) {\n return knownDefaults.has(normalizedBaseUrl);\n }\n }\n\n return Object.values(KNOWN_PROVIDER_DEFAULT_BASE_URLS).some((knownDefaults) =>\n knownDefaults?.has(normalizedBaseUrl),\n );\n};\n\ninterface OpenHandsApiKeyHelpProps {\n testId: string;\n}\n\nfunction OpenHandsApiKeyHelp({ testId }: OpenHandsApiKeyHelpProps) {\n const { t } = useTranslation(\"openhands\");\n\n return (\n <HelpLink\n testId={testId}\n text={t(I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_TEXT)}\n linkText={t(I18nKey.SETTINGS$NAV_API_KEYS)}\n href=\"https://app.all-hands.dev/settings/api-keys\"\n suffix={` ${t(I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_SUFFIX)}`}\n />\n );\n}\n\nexport function LlmSettingsScreen({\n scope = \"personal\",\n onSaveSuccess,\n initialValueOverrides,\n embedded,\n hideSaveButton,\n onSaveControlChange,\n}: {\n scope?: SettingsScope;\n /** Optional hook fired after a successful save (e.g. advance an onboarding step). */\n onSaveSuccess?: () => void;\n /** Forwarded to {@link SdkSectionPage}. */\n initialValueOverrides?: SettingsFormValues;\n /** Forwarded to {@link SdkSectionPage}. */\n embedded?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n hideSaveButton?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n onSaveControlChange?: (control: SdkSectionSaveControl) => void;\n}) {\n const { t } = useTranslation(\"openhands\");\n\n const { data: settings } = useSettings(scope);\n const { data: schema } = useAgentSettingsSchema(\n settings?.agent_settings_schema,\n );\n\n const defaultModel = String(\n (DEFAULT_SETTINGS.agent_settings?.llm as Record<string, unknown>)?.model ??\n \"\",\n );\n\n const getInitialView = React.useCallback(\n (\n currentSettings: Settings,\n filteredSchema: SettingsSchema,\n ): SettingsView => {\n const schemaView = inferInitialView(currentSettings, filteredSchema);\n if (schemaView !== \"basic\") {\n return schemaView;\n }\n\n const currentModel = currentSettings.llm_model ?? \"\";\n const trimmedBaseUrl = currentSettings.llm_base_url?.trim() ?? \"\";\n const hasCustomBaseUrl =\n trimmedBaseUrl.length > 0 &&\n !isProviderDefaultBaseUrl(currentModel, trimmedBaseUrl);\n\n return hasCustomBaseUrl ? \"all\" : \"basic\";\n },\n [],\n );\n\n const buildHeader = React.useCallback(\n ({ values, isDisabled, view, onChange }: SdkSectionHeaderProps) => {\n const modelValue =\n typeof values[\"llm.model\"] === \"string\" ? values[\"llm.model\"] : \"\";\n const baseUrlValue =\n typeof values[\"llm.base_url\"] === \"string\"\n ? values[\"llm.base_url\"]\n : \"\";\n const showOpenHandsApiKeyHelp = modelValue.startsWith(\"openhands/\");\n\n const apiKeyValue =\n typeof values[\"llm.api_key\"] === \"string\" ? values[\"llm.api_key\"] : \"\";\n // For embedded profile forms (create/edit) the global\n // `llm_api_key_set` flag is misleading: a brand-new profile would show a\n // \"key set\" indicator just because some other profile has a key. Reflect\n // the form's own key state instead so create mode starts visibly unset.\n const apiKeyIsSet = embedded\n ? apiKeyValue.length > 0\n : Boolean(settings?.llm_api_key_set);\n\n const renderApiKeyInput = (testId: string, helpTestId: string) => (\n <>\n <SettingsInput\n testId={testId}\n label={t(I18nKey.SETTINGS_FORM$API_KEY)}\n type=\"password\"\n className=\"w-full\"\n value={apiKeyValue}\n placeholder={apiKeyIsSet ? \"<hidden>\" : \"\"}\n onChange={(value) => onChange(\"llm.api_key\", value)}\n isDisabled={isDisabled}\n startContent={\n apiKeyIsSet ? <KeyStatusIcon isSet={apiKeyIsSet} /> : undefined\n }\n />\n\n <HelpLink\n testId={helpTestId}\n text={t(I18nKey.SETTINGS$DONT_KNOW_API_KEY)}\n linkText={t(I18nKey.SETTINGS$CLICK_FOR_INSTRUCTIONS)}\n href=\"https://docs.openhands.dev/usage/local-setup#getting-an-api-key\"\n />\n </>\n );\n\n return (\n <div className=\"flex flex-col gap-6\">\n {view === \"basic\" ? (\n <div\n className=\"flex flex-col gap-6\"\n data-testid=\"llm-settings-form-basic\"\n >\n <ModelSelector\n currentModel={modelValue || undefined}\n currentBaseUrl={baseUrlValue || undefined}\n onChange={(provider, model) => {\n const nextModel = buildModelId(provider, model);\n if (nextModel) {\n onChange(\"llm.model\", nextModel);\n }\n }}\n wrapperClassName=\"!flex-col !gap-6\"\n isDisabled={isDisabled}\n />\n\n {showOpenHandsApiKeyHelp ? (\n <OpenHandsApiKeyHelp testId=\"openhands-api-key-help\" />\n ) : null}\n\n {renderApiKeyInput(\n \"llm-api-key-input\",\n \"llm-api-key-help-anchor\",\n )}\n </div>\n ) : (\n <div\n className=\"flex flex-col gap-6\"\n data-testid=\"llm-settings-form-advanced\"\n >\n <SettingsInput\n testId=\"llm-custom-model-input\"\n label={t(I18nKey.SETTINGS$CUSTOM_MODEL)}\n type=\"text\"\n className=\"w-full\"\n value={modelValue}\n placeholder={defaultModel}\n onChange={(value) => onChange(\"llm.model\", value)}\n isDisabled={isDisabled}\n />\n\n {showOpenHandsApiKeyHelp ? (\n <OpenHandsApiKeyHelp testId=\"openhands-api-key-help-2\" />\n ) : null}\n\n <SettingsInput\n testId=\"base-url-input\"\n label={t(I18nKey.SETTINGS$BASE_URL)}\n type=\"text\"\n className=\"w-full\"\n value={baseUrlValue}\n placeholder=\"https://api.openai.com\"\n onChange={(value) => onChange(\"llm.base_url\", value)}\n isDisabled={isDisabled}\n />\n\n {renderApiKeyInput(\n \"llm-api-key-input\",\n \"llm-api-key-help-anchor-advanced\",\n )}\n </div>\n )}\n </div>\n );\n },\n [defaultModel, embedded, settings?.llm_api_key_set, t],\n );\n\n const buildPayload = React.useCallback(\n (\n basePayload: Record<string, unknown>,\n context: {\n values: Record<string, string | boolean>;\n view: SettingsView;\n },\n ) => {\n // basePayload is a nested dict (e.g. {llm: {model: \"gpt-4\"}})\n const agentSettings = structuredClone(basePayload);\n\n const llm = (agentSettings.llm ?? {}) as Record<string, unknown>;\n\n if (context.view === \"basic\") {\n const model = llm.model ?? context.values[\"llm.model\"];\n llm.base_url = isOpenHandsProviderModel(model)\n ? OPENHANDS_LLM_PROXY_BASE_URL\n : getSchemaFieldDefaultValue(schema, \"llm.base_url\");\n agentSettings.llm = llm;\n }\n\n return { agent_settings_diff: agentSettings };\n },\n [schema],\n );\n\n return (\n <SdkSectionPage\n scope={scope}\n sectionKeys={[\"llm\"]}\n excludeKeys={LLM_EXCLUDED_KEYS}\n header={buildHeader}\n buildPayload={buildPayload}\n getInitialView={getInitialView}\n forceShowAdvancedView\n allowAllView\n onSaveSuccess={onSaveSuccess}\n initialValueOverrides={initialValueOverrides}\n embedded={embedded}\n hideSaveButton={hideSaveButton}\n onSaveControlChange={onSaveControlChange}\n testId=\"llm-settings-screen\"\n />\n );\n}\n\n/**\n * Default export for the route renders different views based on backend type:\n * - Local backends: LlmSettingsLocalView with profile management\n * - Cloud backends: Standard LlmSettingsScreen (profiles are not supported)\n *\n * The LlmSettingsScreen component is also exported for embedded use cases\n * (e.g., onboarding, profile editing forms).\n *\n * Note: This is a route file, only the router should import the default export.\n * Other consumers should use the named export `LlmSettingsScreen` for embedded\n * use cases.\n */\nexport default function LlmSettingsRoute() {\n const { backend } = useActiveBackend();\n const isCloud = backend.kind === \"cloud\";\n\n // Cloud backends use the standard LLM settings form (no profiles support)\n if (isCloud) {\n return <LlmSettingsScreen />;\n }\n\n // Local backends use the profile management view\n return <LlmSettingsLocalView />;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"llm-settings.cjs","names":[],"sources":["../../src/routes/llm-settings.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { ModelSelector } from \"#/components/shared/modals/settings/model-selector\";\nimport { useAgentSettingsSchema } from \"#/hooks/query/use-agent-settings-schema\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { SettingsInput } from \"#/components/features/settings/settings-input\";\nimport { HelpLink } from \"#/ui/help-link\";\nimport { KeyStatusIcon } from \"#/components/features/settings/key-status-icon\";\nimport {\n SdkSectionHeaderProps,\n SdkSectionPage,\n SdkSectionSaveControl,\n} from \"#/components/features/settings/sdk-settings/sdk-section-page\";\nimport { LlmSettingsLocalView } from \"#/components/features/settings/llm-profiles\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { Settings, SettingsSchema, SettingsScope } from \"#/types/settings\";\nimport { extractModelAndProvider } from \"#/utils/extract-model-and-provider\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport {\n inferInitialView,\n type SettingsFormValues,\n type SettingsView,\n} from \"#/utils/sdk-settings-schema\";\nimport { DEFAULT_SETTINGS } from \"#/services/settings\";\nimport {\n OPENHANDS_LLM_PROXY_BASE_URL,\n isOpenHandsProviderModel,\n} from \"#/utils/openhands-llm\";\n\nconst LLM_EXCLUDED_KEYS = new Set([\"llm.model\", \"llm.api_key\", \"llm.base_url\"]);\n\nconst buildModelId = (provider: string | null, model: string | null) => {\n if (!provider || !model) return null;\n return `${provider}/${model}`;\n};\n\nconst getSchemaFieldDefaultValue = (\n schema: SettingsSchema | null | undefined,\n fieldKey: string,\n) =>\n schema?.sections\n .flatMap((section) => section.fields)\n .find((field) => field.key === fieldKey)?.default ?? null;\n\nconst KNOWN_PROVIDER_DEFAULT_BASE_URLS: Partial<Record<string, Set<string>>> = {\n openai: new Set([\"https://api.openai.com\", \"https://api.openai.com/v1\"]),\n openhands: new Set([\n OPENHANDS_LLM_PROXY_BASE_URL,\n \"https://llm-proxy.app.all-hands.dev/v1\",\n ]),\n litellm_proxy: new Set([\n OPENHANDS_LLM_PROXY_BASE_URL,\n \"https://llm-proxy.app.all-hands.dev/v1\",\n ]),\n};\n\nconst normalizeBaseUrl = (baseUrl: string) => {\n try {\n const parsedUrl = new URL(baseUrl);\n const normalizedPath = parsedUrl.pathname.replace(/\\/+$/, \"\") || \"\";\n return `${parsedUrl.origin}${normalizedPath}`;\n } catch {\n return baseUrl.trim().replace(/\\/+$/, \"\");\n }\n};\n\nconst isProviderDefaultBaseUrl = (model: string, baseUrl: string) => {\n const normalizedBaseUrl = normalizeBaseUrl(baseUrl);\n const { provider } = extractModelAndProvider(model);\n\n if (provider) {\n const knownDefaults = KNOWN_PROVIDER_DEFAULT_BASE_URLS[provider];\n if (knownDefaults) {\n return knownDefaults.has(normalizedBaseUrl);\n }\n }\n\n return Object.values(KNOWN_PROVIDER_DEFAULT_BASE_URLS).some((knownDefaults) =>\n knownDefaults?.has(normalizedBaseUrl),\n );\n};\n\ninterface OpenHandsApiKeyHelpProps {\n testId: string;\n}\n\nfunction OpenHandsApiKeyHelp({ testId }: OpenHandsApiKeyHelpProps) {\n const { t } = useTranslation(\"openhands\");\n\n return (\n <HelpLink\n testId={testId}\n text={t(I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_TEXT)}\n linkText={t(I18nKey.SETTINGS$NAV_API_KEYS)}\n href=\"https://app.all-hands.dev/settings/api-keys\"\n suffix={` ${t(I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_SUFFIX)}`}\n />\n );\n}\n\nexport function LlmSettingsScreen({\n scope = \"personal\",\n onSaveSuccess,\n initialValueOverrides,\n embedded,\n hideSaveButton,\n suppressSuccessToast,\n onSaveControlChange,\n}: {\n scope?: SettingsScope;\n /** Optional hook fired after a successful save (e.g. advance an onboarding step). */\n onSaveSuccess?: () => void;\n /** Forwarded to {@link SdkSectionPage}. */\n initialValueOverrides?: SettingsFormValues;\n /** Forwarded to {@link SdkSectionPage}. */\n embedded?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n hideSaveButton?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n suppressSuccessToast?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n onSaveControlChange?: (control: SdkSectionSaveControl) => void;\n}) {\n const { t } = useTranslation(\"openhands\");\n\n const { data: settings } = useSettings(scope);\n const { data: schema } = useAgentSettingsSchema(\n settings?.agent_settings_schema,\n );\n\n const defaultModel = String(\n (DEFAULT_SETTINGS.agent_settings?.llm as Record<string, unknown>)?.model ??\n \"\",\n );\n\n const getInitialView = React.useCallback(\n (\n currentSettings: Settings,\n filteredSchema: SettingsSchema,\n ): SettingsView => {\n const schemaView = inferInitialView(currentSettings, filteredSchema);\n if (schemaView !== \"basic\") {\n return schemaView;\n }\n\n const currentModel = currentSettings.llm_model ?? \"\";\n const trimmedBaseUrl = currentSettings.llm_base_url?.trim() ?? \"\";\n const hasCustomBaseUrl =\n trimmedBaseUrl.length > 0 &&\n !isProviderDefaultBaseUrl(currentModel, trimmedBaseUrl);\n\n return hasCustomBaseUrl ? \"all\" : \"basic\";\n },\n [],\n );\n\n const buildHeader = React.useCallback(\n ({ values, isDisabled, view, onChange }: SdkSectionHeaderProps) => {\n const modelValue =\n typeof values[\"llm.model\"] === \"string\" ? values[\"llm.model\"] : \"\";\n const baseUrlValue =\n typeof values[\"llm.base_url\"] === \"string\"\n ? values[\"llm.base_url\"]\n : \"\";\n const showOpenHandsApiKeyHelp = modelValue.startsWith(\"openhands/\");\n\n const apiKeyValue =\n typeof values[\"llm.api_key\"] === \"string\" ? values[\"llm.api_key\"] : \"\";\n // For embedded profile forms (create/edit) the global\n // `llm_api_key_set` flag is misleading: a brand-new profile would show a\n // \"key set\" indicator just because some other profile has a key. Reflect\n // the form's own key state instead so create mode starts visibly unset.\n const apiKeyIsSet = embedded\n ? apiKeyValue.length > 0\n : Boolean(settings?.llm_api_key_set);\n\n const renderApiKeyInput = (testId: string, helpTestId: string) => (\n <>\n <SettingsInput\n testId={testId}\n label={t(I18nKey.SETTINGS_FORM$API_KEY)}\n type=\"password\"\n className=\"w-full\"\n value={apiKeyValue}\n placeholder={apiKeyIsSet ? \"<hidden>\" : \"\"}\n onChange={(value) => onChange(\"llm.api_key\", value)}\n isDisabled={isDisabled}\n startContent={\n apiKeyIsSet ? <KeyStatusIcon isSet={apiKeyIsSet} /> : undefined\n }\n />\n\n <HelpLink\n testId={helpTestId}\n text={t(I18nKey.SETTINGS$DONT_KNOW_API_KEY)}\n linkText={t(I18nKey.SETTINGS$CLICK_FOR_INSTRUCTIONS)}\n href=\"https://docs.openhands.dev/usage/local-setup#getting-an-api-key\"\n />\n </>\n );\n\n return (\n <div className=\"flex flex-col gap-6\">\n {view === \"basic\" ? (\n <div\n className=\"flex flex-col gap-6\"\n data-testid=\"llm-settings-form-basic\"\n >\n <ModelSelector\n currentModel={modelValue || undefined}\n currentBaseUrl={baseUrlValue || undefined}\n onChange={(provider, model) => {\n const nextModel = buildModelId(provider, model);\n if (nextModel) {\n onChange(\"llm.model\", nextModel);\n }\n }}\n wrapperClassName=\"!flex-col !gap-6\"\n isDisabled={isDisabled}\n />\n\n {showOpenHandsApiKeyHelp ? (\n <OpenHandsApiKeyHelp testId=\"openhands-api-key-help\" />\n ) : null}\n\n {renderApiKeyInput(\n \"llm-api-key-input\",\n \"llm-api-key-help-anchor\",\n )}\n </div>\n ) : (\n <div\n className=\"flex flex-col gap-6\"\n data-testid=\"llm-settings-form-advanced\"\n >\n <SettingsInput\n testId=\"llm-custom-model-input\"\n label={t(I18nKey.SETTINGS$CUSTOM_MODEL)}\n type=\"text\"\n className=\"w-full\"\n value={modelValue}\n placeholder={defaultModel}\n onChange={(value) => onChange(\"llm.model\", value)}\n isDisabled={isDisabled}\n />\n\n {showOpenHandsApiKeyHelp ? (\n <OpenHandsApiKeyHelp testId=\"openhands-api-key-help-2\" />\n ) : null}\n\n <SettingsInput\n testId=\"base-url-input\"\n label={t(I18nKey.SETTINGS$BASE_URL)}\n type=\"text\"\n className=\"w-full\"\n value={baseUrlValue}\n placeholder=\"https://api.openai.com\"\n onChange={(value) => onChange(\"llm.base_url\", value)}\n isDisabled={isDisabled}\n />\n\n {renderApiKeyInput(\n \"llm-api-key-input\",\n \"llm-api-key-help-anchor-advanced\",\n )}\n </div>\n )}\n </div>\n );\n },\n [defaultModel, embedded, settings?.llm_api_key_set, t],\n );\n\n const buildPayload = React.useCallback(\n (\n basePayload: Record<string, unknown>,\n context: {\n values: Record<string, string | boolean>;\n view: SettingsView;\n },\n ) => {\n // basePayload is a nested dict (e.g. {llm: {model: \"gpt-4\"}})\n const agentSettings = structuredClone(basePayload);\n\n const llm = (agentSettings.llm ?? {}) as Record<string, unknown>;\n\n if (context.view === \"basic\") {\n const model = llm.model ?? context.values[\"llm.model\"];\n llm.base_url = isOpenHandsProviderModel(model)\n ? OPENHANDS_LLM_PROXY_BASE_URL\n : getSchemaFieldDefaultValue(schema, \"llm.base_url\");\n agentSettings.llm = llm;\n }\n\n return { agent_settings_diff: agentSettings };\n },\n [schema],\n );\n\n return (\n <SdkSectionPage\n scope={scope}\n sectionKeys={[\"llm\"]}\n excludeKeys={LLM_EXCLUDED_KEYS}\n header={buildHeader}\n buildPayload={buildPayload}\n getInitialView={getInitialView}\n forceShowAdvancedView\n allowAllView\n onSaveSuccess={onSaveSuccess}\n initialValueOverrides={initialValueOverrides}\n embedded={embedded}\n hideSaveButton={hideSaveButton}\n suppressSuccessToast={suppressSuccessToast}\n onSaveControlChange={onSaveControlChange}\n testId=\"llm-settings-screen\"\n />\n );\n}\n\n/**\n * Default export for the route renders different views based on backend type:\n * - Local backends: LlmSettingsLocalView with profile management\n * - Cloud backends: Standard LlmSettingsScreen (profiles are not supported)\n *\n * The LlmSettingsScreen component is also exported for embedded use cases\n * (e.g., onboarding, profile editing forms).\n *\n * Note: This is a route file, only the router should import the default export.\n * Other consumers should use the named export `LlmSettingsScreen` for embedded\n * use cases.\n */\nexport default function LlmSettingsRoute() {\n const { backend } = useActiveBackend();\n const isCloud = backend.kind === \"cloud\";\n\n // Cloud backends use the standard LLM settings form (no profiles support)\n if (isCloud) {\n return <LlmSettingsScreen />;\n }\n\n // Local backends use the profile management view\n return <LlmSettingsLocalView />;\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { SdkSectionSaveControl } from "#/components/features/settings/sdk-settings/sdk-section-page";
2
2
  import { SettingsScope } from "#/types/settings";
3
3
  import { type SettingsFormValues } from "#/utils/sdk-settings-schema";
4
- export declare function LlmSettingsScreen({ scope, onSaveSuccess, initialValueOverrides, embedded, hideSaveButton, onSaveControlChange, }: {
4
+ export declare function LlmSettingsScreen({ scope, onSaveSuccess, initialValueOverrides, embedded, hideSaveButton, suppressSuccessToast, onSaveControlChange, }: {
5
5
  scope?: SettingsScope;
6
6
  /** Optional hook fired after a successful save (e.g. advance an onboarding step). */
7
7
  onSaveSuccess?: () => void;
@@ -12,6 +12,8 @@ export declare function LlmSettingsScreen({ scope, onSaveSuccess, initialValueOv
12
12
  /** Forwarded to {@link SdkSectionPage}. */
13
13
  hideSaveButton?: boolean;
14
14
  /** Forwarded to {@link SdkSectionPage}. */
15
+ suppressSuccessToast?: boolean;
16
+ /** Forwarded to {@link SdkSectionPage}. */
15
17
  onSaveControlChange?: (control: SdkSectionSaveControl) => void;
16
18
  }): import("react/jsx-runtime").JSX.Element;
17
19
  /**
@@ -49,8 +49,8 @@ function w({ testId: n }) {
49
49
  suffix: ` ${r(t.SETTINGS$OPENHANDS_API_KEY_HELP_SUFFIX)}`
50
50
  });
51
51
  }
52
- function T({ scope: a = "personal", onSaveSuccess: x, initialValueOverrides: S, embedded: T, hideSaveButton: E, onSaveControlChange: D }) {
53
- let { t: O } = e("openhands"), { data: k } = r(a), { data: A } = c(k?.agent_settings_schema), j = String(n.agent_settings?.llm?.model ?? ""), M = m.useCallback((e, t) => {
52
+ function T({ scope: a = "personal", onSaveSuccess: x, initialValueOverrides: S, embedded: T, hideSaveButton: E, suppressSuccessToast: D, onSaveControlChange: O }) {
53
+ let { t: k } = e("openhands"), { data: A } = r(a), { data: j } = c(A?.agent_settings_schema), M = String(n.agent_settings?.llm?.model ?? ""), N = m.useCallback((e, t) => {
54
54
  let n = u(e, t);
55
55
  if (n !== "basic") return n;
56
56
  let r = e.llm_model ?? "", i = e.llm_base_url?.trim() ?? "";
@@ -61,9 +61,9 @@ function T({ scope: a = "personal", onSaveSuccess: x, initialValueOverrides: S,
61
61
  sectionKeys: ["llm"],
62
62
  excludeKeys: v,
63
63
  header: m.useCallback(({ values: e, isDisabled: n, view: r, onChange: a }) => {
64
- let c = typeof e["llm.model"] == "string" ? e["llm.model"] : "", u = typeof e["llm.base_url"] == "string" ? e["llm.base_url"] : "", d = c.startsWith("openhands/"), f = typeof e["llm.api_key"] == "string" ? e["llm.api_key"] : "", p = T ? f.length > 0 : !!k?.llm_api_key_set, m = (e, r) => /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(i, {
64
+ let c = typeof e["llm.model"] == "string" ? e["llm.model"] : "", u = typeof e["llm.base_url"] == "string" ? e["llm.base_url"] : "", d = c.startsWith("openhands/"), f = typeof e["llm.api_key"] == "string" ? e["llm.api_key"] : "", p = T ? f.length > 0 : !!A?.llm_api_key_set, m = (e, r) => /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(i, {
65
65
  testId: e,
66
- label: O(t.SETTINGS_FORM$API_KEY),
66
+ label: k(t.SETTINGS_FORM$API_KEY),
67
67
  type: "password",
68
68
  className: "w-full",
69
69
  value: f,
@@ -73,8 +73,8 @@ function T({ scope: a = "personal", onSaveSuccess: x, initialValueOverrides: S,
73
73
  startContent: p ? /* @__PURE__ */ g(l, { isSet: p }) : void 0
74
74
  }), /* @__PURE__ */ g(o, {
75
75
  testId: r,
76
- text: O(t.SETTINGS$DONT_KNOW_API_KEY),
77
- linkText: O(t.SETTINGS$CLICK_FOR_INSTRUCTIONS),
76
+ text: k(t.SETTINGS$DONT_KNOW_API_KEY),
77
+ linkText: k(t.SETTINGS$CLICK_FOR_INSTRUCTIONS),
78
78
  href: "https://docs.openhands.dev/usage/local-setup#getting-an-api-key"
79
79
  })] });
80
80
  return /* @__PURE__ */ g("div", {
@@ -102,18 +102,18 @@ function T({ scope: a = "personal", onSaveSuccess: x, initialValueOverrides: S,
102
102
  children: [
103
103
  /* @__PURE__ */ g(i, {
104
104
  testId: "llm-custom-model-input",
105
- label: O(t.SETTINGS$CUSTOM_MODEL),
105
+ label: k(t.SETTINGS$CUSTOM_MODEL),
106
106
  type: "text",
107
107
  className: "w-full",
108
108
  value: c,
109
- placeholder: j,
109
+ placeholder: M,
110
110
  onChange: (e) => a("llm.model", e),
111
111
  isDisabled: n
112
112
  }),
113
113
  d ? /* @__PURE__ */ g(w, { testId: "openhands-api-key-help-2" }) : null,
114
114
  /* @__PURE__ */ g(i, {
115
115
  testId: "base-url-input",
116
- label: O(t.SETTINGS$BASE_URL),
116
+ label: k(t.SETTINGS$BASE_URL),
117
117
  type: "text",
118
118
  className: "w-full",
119
119
  value: u,
@@ -126,23 +126,24 @@ function T({ scope: a = "personal", onSaveSuccess: x, initialValueOverrides: S,
126
126
  })
127
127
  });
128
128
  }, [
129
- j,
129
+ M,
130
130
  T,
131
- k?.llm_api_key_set,
132
- O
131
+ A?.llm_api_key_set,
132
+ k
133
133
  ]),
134
134
  buildPayload: m.useCallback((e, t) => {
135
135
  let n = structuredClone(e), r = n.llm ?? {};
136
- return t.view === "basic" && (r.base_url = p(r.model ?? t.values["llm.model"]) ? f : b(A, "llm.base_url"), n.llm = r), { agent_settings_diff: n };
137
- }, [A]),
138
- getInitialView: M,
136
+ return t.view === "basic" && (r.base_url = p(r.model ?? t.values["llm.model"]) ? f : b(j, "llm.base_url"), n.llm = r), { agent_settings_diff: n };
137
+ }, [j]),
138
+ getInitialView: N,
139
139
  forceShowAdvancedView: !0,
140
140
  allowAllView: !0,
141
141
  onSaveSuccess: x,
142
142
  initialValueOverrides: S,
143
143
  embedded: T,
144
144
  hideSaveButton: E,
145
- onSaveControlChange: D,
145
+ suppressSuccessToast: D,
146
+ onSaveControlChange: O,
146
147
  testId: "llm-settings-screen"
147
148
  });
148
149
  }
@@ -1 +1 @@
1
- {"version":3,"file":"llm-settings.js","names":[],"sources":["../../src/routes/llm-settings.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { ModelSelector } from \"#/components/shared/modals/settings/model-selector\";\nimport { useAgentSettingsSchema } from \"#/hooks/query/use-agent-settings-schema\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { SettingsInput } from \"#/components/features/settings/settings-input\";\nimport { HelpLink } from \"#/ui/help-link\";\nimport { KeyStatusIcon } from \"#/components/features/settings/key-status-icon\";\nimport {\n SdkSectionHeaderProps,\n SdkSectionPage,\n SdkSectionSaveControl,\n} from \"#/components/features/settings/sdk-settings/sdk-section-page\";\nimport { LlmSettingsLocalView } from \"#/components/features/settings/llm-profiles\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { Settings, SettingsSchema, SettingsScope } from \"#/types/settings\";\nimport { extractModelAndProvider } from \"#/utils/extract-model-and-provider\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport {\n inferInitialView,\n type SettingsFormValues,\n type SettingsView,\n} from \"#/utils/sdk-settings-schema\";\nimport { DEFAULT_SETTINGS } from \"#/services/settings\";\nimport {\n OPENHANDS_LLM_PROXY_BASE_URL,\n isOpenHandsProviderModel,\n} from \"#/utils/openhands-llm\";\n\nconst LLM_EXCLUDED_KEYS = new Set([\"llm.model\", \"llm.api_key\", \"llm.base_url\"]);\n\nconst buildModelId = (provider: string | null, model: string | null) => {\n if (!provider || !model) return null;\n return `${provider}/${model}`;\n};\n\nconst getSchemaFieldDefaultValue = (\n schema: SettingsSchema | null | undefined,\n fieldKey: string,\n) =>\n schema?.sections\n .flatMap((section) => section.fields)\n .find((field) => field.key === fieldKey)?.default ?? null;\n\nconst KNOWN_PROVIDER_DEFAULT_BASE_URLS: Partial<Record<string, Set<string>>> = {\n openai: new Set([\"https://api.openai.com\", \"https://api.openai.com/v1\"]),\n openhands: new Set([\n OPENHANDS_LLM_PROXY_BASE_URL,\n \"https://llm-proxy.app.all-hands.dev/v1\",\n ]),\n litellm_proxy: new Set([\n OPENHANDS_LLM_PROXY_BASE_URL,\n \"https://llm-proxy.app.all-hands.dev/v1\",\n ]),\n};\n\nconst normalizeBaseUrl = (baseUrl: string) => {\n try {\n const parsedUrl = new URL(baseUrl);\n const normalizedPath = parsedUrl.pathname.replace(/\\/+$/, \"\") || \"\";\n return `${parsedUrl.origin}${normalizedPath}`;\n } catch {\n return baseUrl.trim().replace(/\\/+$/, \"\");\n }\n};\n\nconst isProviderDefaultBaseUrl = (model: string, baseUrl: string) => {\n const normalizedBaseUrl = normalizeBaseUrl(baseUrl);\n const { provider } = extractModelAndProvider(model);\n\n if (provider) {\n const knownDefaults = KNOWN_PROVIDER_DEFAULT_BASE_URLS[provider];\n if (knownDefaults) {\n return knownDefaults.has(normalizedBaseUrl);\n }\n }\n\n return Object.values(KNOWN_PROVIDER_DEFAULT_BASE_URLS).some((knownDefaults) =>\n knownDefaults?.has(normalizedBaseUrl),\n );\n};\n\ninterface OpenHandsApiKeyHelpProps {\n testId: string;\n}\n\nfunction OpenHandsApiKeyHelp({ testId }: OpenHandsApiKeyHelpProps) {\n const { t } = useTranslation(\"openhands\");\n\n return (\n <HelpLink\n testId={testId}\n text={t(I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_TEXT)}\n linkText={t(I18nKey.SETTINGS$NAV_API_KEYS)}\n href=\"https://app.all-hands.dev/settings/api-keys\"\n suffix={` ${t(I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_SUFFIX)}`}\n />\n );\n}\n\nexport function LlmSettingsScreen({\n scope = \"personal\",\n onSaveSuccess,\n initialValueOverrides,\n embedded,\n hideSaveButton,\n onSaveControlChange,\n}: {\n scope?: SettingsScope;\n /** Optional hook fired after a successful save (e.g. advance an onboarding step). */\n onSaveSuccess?: () => void;\n /** Forwarded to {@link SdkSectionPage}. */\n initialValueOverrides?: SettingsFormValues;\n /** Forwarded to {@link SdkSectionPage}. */\n embedded?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n hideSaveButton?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n onSaveControlChange?: (control: SdkSectionSaveControl) => void;\n}) {\n const { t } = useTranslation(\"openhands\");\n\n const { data: settings } = useSettings(scope);\n const { data: schema } = useAgentSettingsSchema(\n settings?.agent_settings_schema,\n );\n\n const defaultModel = String(\n (DEFAULT_SETTINGS.agent_settings?.llm as Record<string, unknown>)?.model ??\n \"\",\n );\n\n const getInitialView = React.useCallback(\n (\n currentSettings: Settings,\n filteredSchema: SettingsSchema,\n ): SettingsView => {\n const schemaView = inferInitialView(currentSettings, filteredSchema);\n if (schemaView !== \"basic\") {\n return schemaView;\n }\n\n const currentModel = currentSettings.llm_model ?? \"\";\n const trimmedBaseUrl = currentSettings.llm_base_url?.trim() ?? \"\";\n const hasCustomBaseUrl =\n trimmedBaseUrl.length > 0 &&\n !isProviderDefaultBaseUrl(currentModel, trimmedBaseUrl);\n\n return hasCustomBaseUrl ? \"all\" : \"basic\";\n },\n [],\n );\n\n const buildHeader = React.useCallback(\n ({ values, isDisabled, view, onChange }: SdkSectionHeaderProps) => {\n const modelValue =\n typeof values[\"llm.model\"] === \"string\" ? values[\"llm.model\"] : \"\";\n const baseUrlValue =\n typeof values[\"llm.base_url\"] === \"string\"\n ? values[\"llm.base_url\"]\n : \"\";\n const showOpenHandsApiKeyHelp = modelValue.startsWith(\"openhands/\");\n\n const apiKeyValue =\n typeof values[\"llm.api_key\"] === \"string\" ? values[\"llm.api_key\"] : \"\";\n // For embedded profile forms (create/edit) the global\n // `llm_api_key_set` flag is misleading: a brand-new profile would show a\n // \"key set\" indicator just because some other profile has a key. Reflect\n // the form's own key state instead so create mode starts visibly unset.\n const apiKeyIsSet = embedded\n ? apiKeyValue.length > 0\n : Boolean(settings?.llm_api_key_set);\n\n const renderApiKeyInput = (testId: string, helpTestId: string) => (\n <>\n <SettingsInput\n testId={testId}\n label={t(I18nKey.SETTINGS_FORM$API_KEY)}\n type=\"password\"\n className=\"w-full\"\n value={apiKeyValue}\n placeholder={apiKeyIsSet ? \"<hidden>\" : \"\"}\n onChange={(value) => onChange(\"llm.api_key\", value)}\n isDisabled={isDisabled}\n startContent={\n apiKeyIsSet ? <KeyStatusIcon isSet={apiKeyIsSet} /> : undefined\n }\n />\n\n <HelpLink\n testId={helpTestId}\n text={t(I18nKey.SETTINGS$DONT_KNOW_API_KEY)}\n linkText={t(I18nKey.SETTINGS$CLICK_FOR_INSTRUCTIONS)}\n href=\"https://docs.openhands.dev/usage/local-setup#getting-an-api-key\"\n />\n </>\n );\n\n return (\n <div className=\"flex flex-col gap-6\">\n {view === \"basic\" ? (\n <div\n className=\"flex flex-col gap-6\"\n data-testid=\"llm-settings-form-basic\"\n >\n <ModelSelector\n currentModel={modelValue || undefined}\n currentBaseUrl={baseUrlValue || undefined}\n onChange={(provider, model) => {\n const nextModel = buildModelId(provider, model);\n if (nextModel) {\n onChange(\"llm.model\", nextModel);\n }\n }}\n wrapperClassName=\"!flex-col !gap-6\"\n isDisabled={isDisabled}\n />\n\n {showOpenHandsApiKeyHelp ? (\n <OpenHandsApiKeyHelp testId=\"openhands-api-key-help\" />\n ) : null}\n\n {renderApiKeyInput(\n \"llm-api-key-input\",\n \"llm-api-key-help-anchor\",\n )}\n </div>\n ) : (\n <div\n className=\"flex flex-col gap-6\"\n data-testid=\"llm-settings-form-advanced\"\n >\n <SettingsInput\n testId=\"llm-custom-model-input\"\n label={t(I18nKey.SETTINGS$CUSTOM_MODEL)}\n type=\"text\"\n className=\"w-full\"\n value={modelValue}\n placeholder={defaultModel}\n onChange={(value) => onChange(\"llm.model\", value)}\n isDisabled={isDisabled}\n />\n\n {showOpenHandsApiKeyHelp ? (\n <OpenHandsApiKeyHelp testId=\"openhands-api-key-help-2\" />\n ) : null}\n\n <SettingsInput\n testId=\"base-url-input\"\n label={t(I18nKey.SETTINGS$BASE_URL)}\n type=\"text\"\n className=\"w-full\"\n value={baseUrlValue}\n placeholder=\"https://api.openai.com\"\n onChange={(value) => onChange(\"llm.base_url\", value)}\n isDisabled={isDisabled}\n />\n\n {renderApiKeyInput(\n \"llm-api-key-input\",\n \"llm-api-key-help-anchor-advanced\",\n )}\n </div>\n )}\n </div>\n );\n },\n [defaultModel, embedded, settings?.llm_api_key_set, t],\n );\n\n const buildPayload = React.useCallback(\n (\n basePayload: Record<string, unknown>,\n context: {\n values: Record<string, string | boolean>;\n view: SettingsView;\n },\n ) => {\n // basePayload is a nested dict (e.g. {llm: {model: \"gpt-4\"}})\n const agentSettings = structuredClone(basePayload);\n\n const llm = (agentSettings.llm ?? {}) as Record<string, unknown>;\n\n if (context.view === \"basic\") {\n const model = llm.model ?? context.values[\"llm.model\"];\n llm.base_url = isOpenHandsProviderModel(model)\n ? OPENHANDS_LLM_PROXY_BASE_URL\n : getSchemaFieldDefaultValue(schema, \"llm.base_url\");\n agentSettings.llm = llm;\n }\n\n return { agent_settings_diff: agentSettings };\n },\n [schema],\n );\n\n return (\n <SdkSectionPage\n scope={scope}\n sectionKeys={[\"llm\"]}\n excludeKeys={LLM_EXCLUDED_KEYS}\n header={buildHeader}\n buildPayload={buildPayload}\n getInitialView={getInitialView}\n forceShowAdvancedView\n allowAllView\n onSaveSuccess={onSaveSuccess}\n initialValueOverrides={initialValueOverrides}\n embedded={embedded}\n hideSaveButton={hideSaveButton}\n onSaveControlChange={onSaveControlChange}\n testId=\"llm-settings-screen\"\n />\n );\n}\n\n/**\n * Default export for the route renders different views based on backend type:\n * - Local backends: LlmSettingsLocalView with profile management\n * - Cloud backends: Standard LlmSettingsScreen (profiles are not supported)\n *\n * The LlmSettingsScreen component is also exported for embedded use cases\n * (e.g., onboarding, profile editing forms).\n *\n * Note: This is a route file, only the router should import the default export.\n * Other consumers should use the named export `LlmSettingsScreen` for embedded\n * use cases.\n */\nexport default function LlmSettingsRoute() {\n const { backend } = useActiveBackend();\n const isCloud = backend.kind === \"cloud\";\n\n // Cloud backends use the standard LLM settings form (no profiles support)\n if (isCloud) {\n return <LlmSettingsScreen />;\n }\n\n // Local backends use the profile management view\n return <LlmSettingsLocalView />;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"llm-settings.js","names":[],"sources":["../../src/routes/llm-settings.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { ModelSelector } from \"#/components/shared/modals/settings/model-selector\";\nimport { useAgentSettingsSchema } from \"#/hooks/query/use-agent-settings-schema\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { SettingsInput } from \"#/components/features/settings/settings-input\";\nimport { HelpLink } from \"#/ui/help-link\";\nimport { KeyStatusIcon } from \"#/components/features/settings/key-status-icon\";\nimport {\n SdkSectionHeaderProps,\n SdkSectionPage,\n SdkSectionSaveControl,\n} from \"#/components/features/settings/sdk-settings/sdk-section-page\";\nimport { LlmSettingsLocalView } from \"#/components/features/settings/llm-profiles\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { Settings, SettingsSchema, SettingsScope } from \"#/types/settings\";\nimport { extractModelAndProvider } from \"#/utils/extract-model-and-provider\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport {\n inferInitialView,\n type SettingsFormValues,\n type SettingsView,\n} from \"#/utils/sdk-settings-schema\";\nimport { DEFAULT_SETTINGS } from \"#/services/settings\";\nimport {\n OPENHANDS_LLM_PROXY_BASE_URL,\n isOpenHandsProviderModel,\n} from \"#/utils/openhands-llm\";\n\nconst LLM_EXCLUDED_KEYS = new Set([\"llm.model\", \"llm.api_key\", \"llm.base_url\"]);\n\nconst buildModelId = (provider: string | null, model: string | null) => {\n if (!provider || !model) return null;\n return `${provider}/${model}`;\n};\n\nconst getSchemaFieldDefaultValue = (\n schema: SettingsSchema | null | undefined,\n fieldKey: string,\n) =>\n schema?.sections\n .flatMap((section) => section.fields)\n .find((field) => field.key === fieldKey)?.default ?? null;\n\nconst KNOWN_PROVIDER_DEFAULT_BASE_URLS: Partial<Record<string, Set<string>>> = {\n openai: new Set([\"https://api.openai.com\", \"https://api.openai.com/v1\"]),\n openhands: new Set([\n OPENHANDS_LLM_PROXY_BASE_URL,\n \"https://llm-proxy.app.all-hands.dev/v1\",\n ]),\n litellm_proxy: new Set([\n OPENHANDS_LLM_PROXY_BASE_URL,\n \"https://llm-proxy.app.all-hands.dev/v1\",\n ]),\n};\n\nconst normalizeBaseUrl = (baseUrl: string) => {\n try {\n const parsedUrl = new URL(baseUrl);\n const normalizedPath = parsedUrl.pathname.replace(/\\/+$/, \"\") || \"\";\n return `${parsedUrl.origin}${normalizedPath}`;\n } catch {\n return baseUrl.trim().replace(/\\/+$/, \"\");\n }\n};\n\nconst isProviderDefaultBaseUrl = (model: string, baseUrl: string) => {\n const normalizedBaseUrl = normalizeBaseUrl(baseUrl);\n const { provider } = extractModelAndProvider(model);\n\n if (provider) {\n const knownDefaults = KNOWN_PROVIDER_DEFAULT_BASE_URLS[provider];\n if (knownDefaults) {\n return knownDefaults.has(normalizedBaseUrl);\n }\n }\n\n return Object.values(KNOWN_PROVIDER_DEFAULT_BASE_URLS).some((knownDefaults) =>\n knownDefaults?.has(normalizedBaseUrl),\n );\n};\n\ninterface OpenHandsApiKeyHelpProps {\n testId: string;\n}\n\nfunction OpenHandsApiKeyHelp({ testId }: OpenHandsApiKeyHelpProps) {\n const { t } = useTranslation(\"openhands\");\n\n return (\n <HelpLink\n testId={testId}\n text={t(I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_TEXT)}\n linkText={t(I18nKey.SETTINGS$NAV_API_KEYS)}\n href=\"https://app.all-hands.dev/settings/api-keys\"\n suffix={` ${t(I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_SUFFIX)}`}\n />\n );\n}\n\nexport function LlmSettingsScreen({\n scope = \"personal\",\n onSaveSuccess,\n initialValueOverrides,\n embedded,\n hideSaveButton,\n suppressSuccessToast,\n onSaveControlChange,\n}: {\n scope?: SettingsScope;\n /** Optional hook fired after a successful save (e.g. advance an onboarding step). */\n onSaveSuccess?: () => void;\n /** Forwarded to {@link SdkSectionPage}. */\n initialValueOverrides?: SettingsFormValues;\n /** Forwarded to {@link SdkSectionPage}. */\n embedded?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n hideSaveButton?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n suppressSuccessToast?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n onSaveControlChange?: (control: SdkSectionSaveControl) => void;\n}) {\n const { t } = useTranslation(\"openhands\");\n\n const { data: settings } = useSettings(scope);\n const { data: schema } = useAgentSettingsSchema(\n settings?.agent_settings_schema,\n );\n\n const defaultModel = String(\n (DEFAULT_SETTINGS.agent_settings?.llm as Record<string, unknown>)?.model ??\n \"\",\n );\n\n const getInitialView = React.useCallback(\n (\n currentSettings: Settings,\n filteredSchema: SettingsSchema,\n ): SettingsView => {\n const schemaView = inferInitialView(currentSettings, filteredSchema);\n if (schemaView !== \"basic\") {\n return schemaView;\n }\n\n const currentModel = currentSettings.llm_model ?? \"\";\n const trimmedBaseUrl = currentSettings.llm_base_url?.trim() ?? \"\";\n const hasCustomBaseUrl =\n trimmedBaseUrl.length > 0 &&\n !isProviderDefaultBaseUrl(currentModel, trimmedBaseUrl);\n\n return hasCustomBaseUrl ? \"all\" : \"basic\";\n },\n [],\n );\n\n const buildHeader = React.useCallback(\n ({ values, isDisabled, view, onChange }: SdkSectionHeaderProps) => {\n const modelValue =\n typeof values[\"llm.model\"] === \"string\" ? values[\"llm.model\"] : \"\";\n const baseUrlValue =\n typeof values[\"llm.base_url\"] === \"string\"\n ? values[\"llm.base_url\"]\n : \"\";\n const showOpenHandsApiKeyHelp = modelValue.startsWith(\"openhands/\");\n\n const apiKeyValue =\n typeof values[\"llm.api_key\"] === \"string\" ? values[\"llm.api_key\"] : \"\";\n // For embedded profile forms (create/edit) the global\n // `llm_api_key_set` flag is misleading: a brand-new profile would show a\n // \"key set\" indicator just because some other profile has a key. Reflect\n // the form's own key state instead so create mode starts visibly unset.\n const apiKeyIsSet = embedded\n ? apiKeyValue.length > 0\n : Boolean(settings?.llm_api_key_set);\n\n const renderApiKeyInput = (testId: string, helpTestId: string) => (\n <>\n <SettingsInput\n testId={testId}\n label={t(I18nKey.SETTINGS_FORM$API_KEY)}\n type=\"password\"\n className=\"w-full\"\n value={apiKeyValue}\n placeholder={apiKeyIsSet ? \"<hidden>\" : \"\"}\n onChange={(value) => onChange(\"llm.api_key\", value)}\n isDisabled={isDisabled}\n startContent={\n apiKeyIsSet ? <KeyStatusIcon isSet={apiKeyIsSet} /> : undefined\n }\n />\n\n <HelpLink\n testId={helpTestId}\n text={t(I18nKey.SETTINGS$DONT_KNOW_API_KEY)}\n linkText={t(I18nKey.SETTINGS$CLICK_FOR_INSTRUCTIONS)}\n href=\"https://docs.openhands.dev/usage/local-setup#getting-an-api-key\"\n />\n </>\n );\n\n return (\n <div className=\"flex flex-col gap-6\">\n {view === \"basic\" ? (\n <div\n className=\"flex flex-col gap-6\"\n data-testid=\"llm-settings-form-basic\"\n >\n <ModelSelector\n currentModel={modelValue || undefined}\n currentBaseUrl={baseUrlValue || undefined}\n onChange={(provider, model) => {\n const nextModel = buildModelId(provider, model);\n if (nextModel) {\n onChange(\"llm.model\", nextModel);\n }\n }}\n wrapperClassName=\"!flex-col !gap-6\"\n isDisabled={isDisabled}\n />\n\n {showOpenHandsApiKeyHelp ? (\n <OpenHandsApiKeyHelp testId=\"openhands-api-key-help\" />\n ) : null}\n\n {renderApiKeyInput(\n \"llm-api-key-input\",\n \"llm-api-key-help-anchor\",\n )}\n </div>\n ) : (\n <div\n className=\"flex flex-col gap-6\"\n data-testid=\"llm-settings-form-advanced\"\n >\n <SettingsInput\n testId=\"llm-custom-model-input\"\n label={t(I18nKey.SETTINGS$CUSTOM_MODEL)}\n type=\"text\"\n className=\"w-full\"\n value={modelValue}\n placeholder={defaultModel}\n onChange={(value) => onChange(\"llm.model\", value)}\n isDisabled={isDisabled}\n />\n\n {showOpenHandsApiKeyHelp ? (\n <OpenHandsApiKeyHelp testId=\"openhands-api-key-help-2\" />\n ) : null}\n\n <SettingsInput\n testId=\"base-url-input\"\n label={t(I18nKey.SETTINGS$BASE_URL)}\n type=\"text\"\n className=\"w-full\"\n value={baseUrlValue}\n placeholder=\"https://api.openai.com\"\n onChange={(value) => onChange(\"llm.base_url\", value)}\n isDisabled={isDisabled}\n />\n\n {renderApiKeyInput(\n \"llm-api-key-input\",\n \"llm-api-key-help-anchor-advanced\",\n )}\n </div>\n )}\n </div>\n );\n },\n [defaultModel, embedded, settings?.llm_api_key_set, t],\n );\n\n const buildPayload = React.useCallback(\n (\n basePayload: Record<string, unknown>,\n context: {\n values: Record<string, string | boolean>;\n view: SettingsView;\n },\n ) => {\n // basePayload is a nested dict (e.g. {llm: {model: \"gpt-4\"}})\n const agentSettings = structuredClone(basePayload);\n\n const llm = (agentSettings.llm ?? {}) as Record<string, unknown>;\n\n if (context.view === \"basic\") {\n const model = llm.model ?? context.values[\"llm.model\"];\n llm.base_url = isOpenHandsProviderModel(model)\n ? OPENHANDS_LLM_PROXY_BASE_URL\n : getSchemaFieldDefaultValue(schema, \"llm.base_url\");\n agentSettings.llm = llm;\n }\n\n return { agent_settings_diff: agentSettings };\n },\n [schema],\n );\n\n return (\n <SdkSectionPage\n scope={scope}\n sectionKeys={[\"llm\"]}\n excludeKeys={LLM_EXCLUDED_KEYS}\n header={buildHeader}\n buildPayload={buildPayload}\n getInitialView={getInitialView}\n forceShowAdvancedView\n allowAllView\n onSaveSuccess={onSaveSuccess}\n initialValueOverrides={initialValueOverrides}\n embedded={embedded}\n hideSaveButton={hideSaveButton}\n suppressSuccessToast={suppressSuccessToast}\n onSaveControlChange={onSaveControlChange}\n testId=\"llm-settings-screen\"\n />\n );\n}\n\n/**\n * Default export for the route renders different views based on backend type:\n * - Local backends: LlmSettingsLocalView with profile management\n * - Cloud backends: Standard LlmSettingsScreen (profiles are not supported)\n *\n * The LlmSettingsScreen component is also exported for embedded use cases\n * (e.g., onboarding, profile editing forms).\n *\n * Note: This is a route file, only the router should import the default export.\n * Other consumers should use the named export `LlmSettingsScreen` for embedded\n * use cases.\n */\nexport default function LlmSettingsRoute() {\n const { backend } = useActiveBackend();\n const isCloud = backend.kind === \"cloud\";\n\n // Cloud backends use the standard LLM settings form (no profiles support)\n if (isCloud) {\n return <LlmSettingsScreen />;\n }\n\n // Local backends use the profile management view\n return <LlmSettingsLocalView />;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openhands/agent-canvas",
3
- "version": "1.0.0-beta.7",
3
+ "version": "1.0.0-beta.9",
4
4
  "description": "Agent Canvas UI for OpenHands - run AI coding agents with a visual interface",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -384,8 +384,6 @@ function startStaticServer(config) {
384
384
  staticServerScript,
385
385
  "--dir",
386
386
  join(config.canvasPath, "build"),
387
- "--host",
388
- "0.0.0.0",
389
387
  "--port",
390
388
  String(config.vitePort),
391
389
  // Inject the API key so the pre-built frontend can authenticate
@@ -1277,8 +1277,6 @@ function startStaticFrontend(config, staticDir) {
1277
1277
  staticServerScript,
1278
1278
  "--dir",
1279
1279
  staticDir,
1280
- "--host",
1281
- "0.0.0.0",
1282
1280
  "--port",
1283
1281
  String(config.vitePort),
1284
1282
  // In local mode, inject the API key so the pre-built frontend can
@@ -20,7 +20,7 @@
20
20
  *
21
21
  * Usage (mirrors scripts/ingress.mjs's --route flag style):
22
22
  * node scripts/static-server.mjs \
23
- * --port 3001 --host 0.0.0.0 --dir build \
23
+ * --port 3001 --dir build \
24
24
  * --route "/api/automation=http://localhost:18001" \
25
25
  * --route "/api=http://localhost:18000" \
26
26
  * --route "/server_info=http://localhost:18000" \
@@ -69,7 +69,7 @@ const MIME = {
69
69
  export function parseArgs(argv = process.argv.slice(2)) {
70
70
  const config = {
71
71
  port: 3001,
72
- host: "0.0.0.0",
72
+ host: "::",
73
73
  dir: "build",
74
74
  routes: {},
75
75
  rejectPrefixes: [],
@@ -157,7 +157,7 @@ USAGE:
157
157
 
158
158
  OPTIONS:
159
159
  -p, --port <port> Port to bind (default: 3001)
160
- -H, --host <host> Hostname to bind (default: 0.0.0.0)
160
+ -H, --host <host> Hostname to bind (default: :: dual-stack)
161
161
  -d, --dir <dir> Directory to serve (default: build)
162
162
  -r, --route <prefix=url> Proxy <prefix> (and subpaths) to <url>;
163
163
  may be repeated. WebSockets supported.
@@ -192,9 +192,18 @@ ROUTING:
192
192
  /**
193
193
  * Build a tiny inline script that seeds runtime config into the page.
194
194
  *
195
- * - `sessionApiKey`: written to `openhands-agent-server-config` in localStorage
196
- * so the pre-built frontend authenticates without VITE_SESSION_API_KEY baked in.
197
- * Only writes if no key is already stored — explicit user overrides are preserved.
195
+ * - `sessionApiKey`: exposed to the app two ways so a fresh-localStorage
196
+ * browser can authenticate even though the published bundle has no
197
+ * VITE_SESSION_API_KEY baked in:
198
+ * 1. `window.__AGENT_CANVAS_SESSION_API_KEY__` — read by
199
+ * `getBakedSessionApiKey()` in `agent-server-config.ts` as a fallback
200
+ * when the env var is empty. This is symmetric with how
201
+ * `__AGENT_CANVAS_AUTH_REQUIRED__` works for the auth-required flag.
202
+ * 2. Written to `openhands-agent-server-config.sessionApiKey` in
203
+ * localStorage for compatibility with the legacy storage key. Useful
204
+ * for any code path that still reads it (e.g. e2e test fixtures).
205
+ * Always overwrites when the stored value differs so a rotated key
206
+ * is not shadowed by a stale one.
198
207
  *
199
208
  * - `authRequired`: sets `window.__AGENT_CANVAS_AUTH_REQUIRED__ = true` so the
200
209
  * pre-built frontend shows the API key entry screen (public mode) without
@@ -205,6 +214,9 @@ function makeConfigInjectionScript(sessionApiKey, authRequired) {
205
214
 
206
215
  if (sessionApiKey) {
207
216
  const keyLiteral = JSON.stringify(sessionApiKey);
217
+ // Window global — read at module init by getBakedSessionApiKey().
218
+ // Set first so it's available even if the localStorage write throws.
219
+ parts.push(`window.__AGENT_CANVAS_SESSION_API_KEY__=${keyLiteral};`);
208
220
  // Always overwrite when the stored key differs from the runtime key.
209
221
  // A previous session may have persisted a now-stale key; the runtime
210
222
  // value (from --session-api-key) is the server's truth.
@@ -318,6 +330,11 @@ function proxyRequest(req, res, backendUrl) {
318
330
  },
319
331
  );
320
332
 
333
+ // Absorb client-disconnect errors (EPIPE/ECONNRESET) so the server
334
+ // process survives abrupt navigations and health-check probes.
335
+ req.on("error", () => {});
336
+ res.on("error", () => {});
337
+
321
338
  proxyReq.on("error", (err) => {
322
339
  console.error(`Proxy error for ${req.url} -> ${backendUrl}:`, err.message);
323
340
  if (!res.headersSent) {
@@ -343,7 +360,12 @@ function proxyWebSocket(req, socket, head, backendUrl) {
343
360
  },
344
361
  });
345
362
 
363
+ // Absorb socket errors so the process survives mid-flight disconnects.
364
+ socket.on("error", () => socket.destroy());
365
+
346
366
  proxyReq.on("upgrade", (proxyRes, proxySocket, proxyHead) => {
367
+ proxySocket.on("error", () => proxySocket.destroy());
368
+
347
369
  socket.write(
348
370
  `HTTP/${proxyRes.httpVersion} ${proxyRes.statusCode} ${proxyRes.statusMessage}\r\n`,
349
371
  );
@@ -1 +0,0 @@
1
- import{r as e}from"./rolldown-runtime-BFRubm34.js";import{o as t}from"./declaration-CR6HMp29.js";import{n}from"./backend-form-modal-CDnEYjaU.js";var r=e({AddBackendModal:()=>a}),i=t();function a({onClose:e}){return(0,i.jsx)(n,{mode:`add`,onClose:e})}export{r as n,a as t};
@@ -1 +0,0 @@
1
- var e=`workspace/project`;function t(e){return e?.trim()||null}function n(e){if(!e)return null;let t=e.trim().replace(/\/$/,``);return t?/^https?:\/\//i.test(t)?t:typeof window<`u`?`${window.location.protocol}//${t}`:`http://${t}`:null}function r(){return n(void 0)}function i(){return t(void 0)}function a(){return{baseUrl:o()??``,sessionApiKey:s()??``}}function o(){return r()||(typeof window<`u`?window.location.origin:null)}function s(){return i()}function c(){return(void 0)?.trim()||e}function ee(e){return`${c().replace(/\/+$/,``)}/${e.replace(/-/g,``)}`}function l(){let e=s();return e?{"X-Session-API-Key":e}:{}}function te(){return!0}function u(){return typeof window<`u`&&window.__AGENT_CANVAS_AUTH_REQUIRED__===!0}function ne(){return u()?!s():!1}var d=`default-local`,f=`Local`;function p(){let e=o(),t=s();return!e||!t?null:{id:d,name:f,host:e,apiKey:t,kind:`local`}}var m=`openhands-backends`,h=`openhands-active-backend`,g=`openhands-agent-server-config`;function _(e){return e===`local`||e===`cloud`}function v(e){if(typeof e!=`object`||!e)return!1;let t=e;return typeof t.id==`string`&&t.id.length>0&&typeof t.name==`string`&&typeof t.host==`string`&&typeof t.apiKey==`string`&&_(t.kind)}function re(e){if(typeof e!=`string`)return null;let t=e.trim().replace(/\/+$/,``);return t?/^https?:\/\//i.test(t)?t:`http://${t}`:null}function y(){let e=window.localStorage.getItem(g);if(!e)return null;try{let t=JSON.parse(e),n=re(t.baseUrl),r=typeof t.sessionApiKey==`string`?t.sessionApiKey.trim():``;return!n||!r?null:{id:d,name:f,host:n,apiKey:r,kind:`local`}}catch{return null}}function b(){window.localStorage.removeItem(g)}function x(e){return T(e),b(),e}function S(e){try{let{hostname:t}=new URL(e);return t===`localhost`||t===`127.0.0.1`||t===`::1`||t===`[::1]`}catch{return!1}}function C(e,t){return e.id!==`default-local`||e.kind!==`local`?!1:e.host===t.host||S(e.host)&&S(t.host)}function w(e){let t=p();if(!t)return e;let n=!1,r=e.map(e=>!C(e,t)||e.apiKey===t.apiKey?e:(n=!0,{...e,apiKey:t.apiKey}));return n?(T(r),r):e}function T(e){if(!(typeof window>`u`))try{window.localStorage.setItem(m,JSON.stringify(e))}catch{}}function E(){if(typeof window>`u`)return[];try{let e=window.localStorage.getItem(m);if(e===null){let e=y();if(e)return x([e]);let t=p();return t?x([t]):[]}let t=JSON.parse(e);if(!Array.isArray(t))return[];let n=t.filter(v);if(n.length===0){let e=p();return e?x([e]):[]}let r=w(n);return b(),r}catch{return[]}}function D(){if(typeof window>`u`)return null;try{let e=window.localStorage.getItem(h);if(!e)return null;let t=JSON.parse(e);if(typeof t!=`object`||!t||typeof t.backendId!=`string`)return null;let n=t.orgId;return{backendId:t.backendId,orgId:typeof n==`string`&&n.length>0?n:null}}catch{return null}}function O(e){if(!(typeof window>`u`))try{if(!e){window.localStorage.removeItem(h);return}window.localStorage.setItem(h,JSON.stringify({backendId:e.backendId,orgId:e.orgId??null}))}catch{}}var k=`no-backend`,A={id:k,name:`No Backend Available`,host:``,apiKey:``,kind:`local`};function j(e){return e.id===k}function ie(e){return e[0]??A}function M(e,t){let n=null,r=null;if(t){let i=e.find(e=>e.id===t.backendId);i&&(n=i,r=t.orgId??null)}return n||(n=ie(e),r=null),{backends:e,selection:t,active:{backend:n,orgId:r}}}var N=M(E(),D()),P=new Set;function F(){P.forEach(e=>e())}function I(){return N.active}function L(){let e=N.active.backend;return e.kind===`local`&&!j(e)?e:null}function R(){return N.backends}function z(){return N.selection}function B(){return N}function V(e){O(e),N=M(N.backends,e),F()}function H(e){T(e);let t=N.selection;t&&!e.some(e=>e.id===t.backendId)&&(t=null,O(null)),N=M(e,t),F()}function U(e){return P.add(e),()=>{P.delete(e)}}var W=class extends Error{constructor(e,t,n,r){super(r||`HTTP ${e}: ${t}`),this.status=e,this.statusText=t,this.response=n,this.name=`HttpError`}},G=class{constructor(e){this.baseUrl=e.baseUrl.replace(/\/$/,``),this.apiKey=e.apiKey,this.timeout=e.timeout||6e4}async request(e){let t=e.url.startsWith(`/`)?e.url.slice(1):e.url,n=new URL(t,this.baseUrl+`/`);e.params&&Object.entries(e.params).forEach(([e,t])=>{t!=null&&(Array.isArray(t)?t.forEach(t=>n.searchParams.append(e,String(t))):n.searchParams.append(e,String(t)))});let r={"Content-Type":`application/json`,...e.headers};this.apiKey&&(r[`X-Session-API-Key`]=this.apiKey);let i={method:e.method,headers:r,signal:AbortSignal.timeout(e.timeout||this.timeout)};e.credentials&&(i.credentials=e.credentials),e.data&&e.method!==`GET`&&(e.data instanceof FormData?(delete r[`Content-Type`],i.body=e.data):i.body=JSON.stringify(e.data));try{let t=await fetch(n.toString(),i);if(!(e.acceptableStatusCodes?.has(t.status)||!e.acceptableStatusCodes&&t.ok)){let e;try{e=t.headers.get(`content-type`)?.includes(`application/json`)?await t.json():await t.text()}catch{e=null}throw new W(t.status,t.statusText,e,`HTTP request failed (${t.status} ${t.statusText}): ${JSON.stringify(e)}`)}let r=await this.parseResponse(t,e.responseType||`auto`),a={};return t.headers.forEach((e,t)=>{a[t]=e}),{data:r,status:t.status,statusText:t.statusText,headers:a}}catch(t){throw t instanceof W?t:t instanceof Error?t.name===`AbortError`?Error(`Request timeout after ${e.timeout||this.timeout}ms`,{cause:t}):Error(`Request failed: ${t.message}`,{cause:t}):Error(`Unknown request error`,{cause:t})}}async parseResponse(e,t){return t===`json`?await e.json():t===`text`?await e.text():t===`blob`?await e.blob():t===`arrayBuffer`?await e.arrayBuffer():e.headers.get(`content-type`)?.includes(`application/json`)?await e.json():await e.text()}async get(e,t){return this.request({method:`GET`,url:e,...t})}async post(e,t,n){return this.request({method:`POST`,url:e,data:t,...n})}async put(e,t,n){return this.request({method:`PUT`,url:e,data:t,...n})}async patch(e,t,n){return this.request({method:`PATCH`,url:e,data:t,...n})}async delete(e,t){return this.request({method:`DELETE`,url:e,...t})}close(){}},K=class{constructor(e){this.host=e.host.replace(/\/$/,``),this.apiKey=e.apiKey,this.client=new G({baseUrl:this.host,apiKey:this.apiKey,timeout:e.timeout||6e4})}async getAgentSchema(){return(await this.client.get(`/api/settings/agent-schema`)).data}async getSettings(e={}){return(await this.client.get(`/api/settings`,{headers:e.exposeSecrets?{"X-Expose-Secrets":e.exposeSecrets}:void 0})).data}async updateSettings(e){return(await this.client.patch(`/api/settings`,e)).data}async listSecrets(){return(await this.client.get(`/api/settings/secrets`)).data}async upsertSecret(e){return(await this.client.put(`/api/settings/secrets`,e)).data}async getSecret(e){return(await this.client.get(`/api/settings/secrets/${encodeURIComponent(e)}`,{responseType:`text`})).data}async deleteSecret(e){return(await this.client.delete(`/api/settings/secrets/${encodeURIComponent(e)}`)).data}async getConversationSchema(){return(await this.client.get(`/api/settings/conversation-schema`)).data}async listProfiles(){return(await this.client.get(`/api/profiles`)).data}async getProfile(e,t={}){return(await this.client.get(`/api/profiles/${encodeURIComponent(e)}`,{headers:t.exposeSecrets?{"X-Expose-Secrets":t.exposeSecrets}:void 0})).data}async saveProfile(e,t){return(await this.client.post(`/api/profiles/${encodeURIComponent(e)}`,t)).data}async deleteProfile(e){return(await this.client.delete(`/api/profiles/${encodeURIComponent(e)}`)).data}async renameProfile(e,t){return(await this.client.post(`/api/profiles/${encodeURIComponent(e)}/rename`,{new_name:t})).data}close(){this.client.close()}};function q(e){if(e&&!e.startsWith(`/`))try{let t=new URL(e),n=t.hostname,r=window.location.hostname??window.location.host?.split(`:`)[0];return r&&(n===`localhost`||n===`127.0.0.1`)&&r!==`localhost`&&r!==`127.0.0.1`?`${r}:${t.port}`:t.host}catch{return window.location.host}return window.location.host}function J(e){if(e&&!e.startsWith(`/`))try{return(new URL(e).pathname.split(`/api/conversations`)[0]||``).replace(/\/$/,``)}catch{return``}return``}function Y(e){let t=q(e),n=J(e);return`${window.location.protocol===`https:`?`https:`:`http:`}//${t}${n}`}function X(e){if(!e||e.startsWith(`/`))return null;try{return new URL(e).protocol}catch{return null}}function ae(e,t){let n=q(e),r=J(e),i=window.location.protocol===`https:`,a=X(e)===`https:`,o=`${i||a?`wss:`:`ws:`}//${n}${r}/sockets/bash-events`;return t?`${o}?session_api_key=${encodeURIComponent(t)}`:o}function oe(e,t){if(!e)return null;let n=q(t),r=J(t),i=window.location.protocol===`https:`,a=X(t)===`https:`;return`${i||a?`wss:`:`ws:`}//${n}${r}/sockets/events/${e}`}var Z=class extends Error{constructor(){super(`No backend is configured.`),this.name=`NoBackendAvailableError`}};function Q(e){return e.replace(/\/+$/,``)}function se(e,t){return e.host?Q(e.host):e.conversationUrl?Q(Y(e.conversationUrl)):Q(t?.host??``)}function $(e={}){let t=L();if(!t&&!e.host&&!e.conversationUrl)throw new Z;let n=e.sessionApiKey??e.apiKey??t?.apiKey??void 0;return{host:se(e,t),...n?{apiKey:n}:{},workingDir:e.workingDir??c(),...e.timeout===void 0?{}:{timeout:e.timeout}}}function ce(e){let{host:t,apiKey:n,timeout:r}=$(e);return{baseUrl:t,...n?{apiKey:n}:{},timeout:r??6e4}}export{te as A,ee as C,c as D,l as E,u as O,e as S,a as T,V as _,Y as a,f as b,G as c,I as d,z as f,j as g,B as h,ae as i,ne as k,W as l,R as m,$ as n,oe as o,L as p,ce as r,K as s,Z as t,A as u,H as v,o as w,p as x,U as y};
@@ -1,5 +0,0 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/secrets-service-B7CxNinp.js","assets/rolldown-runtime-BFRubm34.js","assets/agent-server-client-options-HEOwGVIU.js","assets/proxy-BAdHH8QB.js","assets/vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~ninslayh-CLlsvdNP.js"])))=>i.map(i=>d[i]);
2
- import{t as e}from"./preload-helper-CT1Z6Pdu.js";import{t}from"./common-DqjLSBOt.js";import{A as n,C as r,D as i,a,c as o,d as s,l as c,n as l,p as u,t as ee}from"./agent-server-client-options-HEOwGVIU.js";import{n as d,s as f,u as p}from"./vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~dp08i1qy-hTzSytKK.js";import{t as m}from"./profiles-client-fEmgWkCW.js";import{n as h}from"./agent-server-compatibility-CdI3N7dr.js";import{n as g,t as _}from"./proxy-BAdHH8QB.js";import{t as v}from"./v4-khGvL7i2.js";import{t as y}from"./settings-DGY6n4J2.js";import{a as b,u as x}from"./acp-providers-CPdgcp13.js";import{t as S}from"./settings-service.api-C3rxTtPj.js";var C=class{constructor(e){this.host=e.host.replace(/\/$/,``),this.apiKey=e.apiKey,this.client=new o({baseUrl:this.host,apiKey:this.apiKey,timeout:e.timeout||6e4})}async createConversation(e){return(await this.client.post(`/api/conversations`,e)).data}async searchConversations(e={}){return(await this.client.get(`/api/conversations/search`,{params:e})).data}async countConversations(e={}){return(await this.client.get(`/api/conversations/count`,{params:e})).data}async getConversations(e){return(await this.client.get(`/api/conversations`,{params:{ids:e}})).data}async getConversation(e){return(await this.client.get(`/api/conversations/${e}`)).data}async searchEvents(e,t={}){return(await this.client.get(`/api/conversations/${e}/events/search`,{params:t})).data}async getEvent(e,t){return(await this.client.get(`/api/conversations/${e}/events/${t}`)).data}async getEvents(e,t){return Promise.all(t.map(async t=>{try{return await this.getEvent(e,t)}catch(e){if(e instanceof c&&e.status===404)return null;throw e}}))}async sendEvent(e,t,n={}){await this.client.post(`/api/conversations/${e}/events`,{...t,...n.run===void 0?{}:{run:n.run}})}async pauseConversation(e){return(await this.client.post(`/api/conversations/${e}/pause`,{})).data}async interruptConversation(e){return(await this.client.post(`/api/conversations/${e}/interrupt`,{})).data}async runConversation(e){return(await this.client.post(`/api/conversations/${e}/run`,{})).data}async askAgent(e,t){return(await this.client.post(`/api/conversations/${e}/ask_agent`,{question:t})).data}async getEventCount(e,t={}){return(await this.client.get(`/api/conversations/${e}/events/count`,{params:t})).data}async respondToConfirmation(e,t){return(await this.client.post(`/api/conversations/${e}/events/respond_to_confirmation`,t)).data}async getAgentFinalResponse(e){return(await this.client.get(`/api/conversations/${e}/agent_final_response`)).data}async setConfirmationPolicy(e,t){let n=`policy`in t?t:{policy:t};return(await this.client.post(`/api/conversations/${e}/confirmation_policy`,n)).data}async condenseConversation(e){return(await this.client.post(`/api/conversations/${e}/condense`,{})).data}async setSecurityAnalyzer(e,t){let n=te(t)?t:{security_analyzer:t};return(await this.client.post(`/api/conversations/${e}/security_analyzer`,n)).data}async updateSecrets(e,t){return(await this.client.post(`/api/conversations/${e}/secrets`,t)).data}async forkConversation(e,t={},n={}){return(await this.client.post(`/api/conversations/${e}/fork`,t,{params:n.includeSkills===void 0?void 0:{include_skills:n.includeSkills}})).data}async switchProfile(e,t){await this.client.post(`/api/conversations/${e}/switch_profile`,{profile_name:t})}async switchLLM(e,t){await this.client.post(`/api/conversations/${e}/switch_llm`,{llm:t})}async switchAcpModel(e,t){await this.client.post(`/api/conversations/${e}/switch_acp_model`,{model:t})}async deleteConversation(e){await this.client.delete(`/api/conversations/${e}`)}async updateConversation(e,t){return(await this.client.patch(`/api/conversations/${e}`,t)).data}close(){this.client.close()}};function te(e){return typeof e==`object`&&!!e&&`security_analyzer`in e}var w=`openhands-agent-server-conversation-metadata`,T=()=>{if(typeof window>`u`)return{};try{let e=window.localStorage.getItem(w);if(!e)return{};let t=JSON.parse(e);return!t||typeof t!=`object`?{}:t}catch{return{}}},E=e=>{if(!(typeof window>`u`)){if(Object.keys(e).length===0){window.localStorage.removeItem(w);return}window.localStorage.setItem(w,JSON.stringify(e))}},D=e=>T()[e]??null,O=(e,t)=>{let n=T();n[e]=t,E(n)},k=e=>{let t=T();e in t&&(delete t[e],E(t))};function A(e){if(!e?.id)return e;let t=D(e.id);return t?{...e,selected_repository:e.selected_repository??t.selected_repository??null,selected_branch:e.selected_branch??t.selected_branch??null,git_provider:e.git_provider??t.git_provider??null,selected_workspace:e.selected_workspace??t.selected_workspace??null}:e}function j(){let e=s().backend;if(e.kind!==`cloud`)throw Error(`Cloud conversations call requires a cloud backend.`);return e}async function ne(e=20,t){let n=j(),r=new URLSearchParams;r.set(`limit`,String(e)),t&&r.set(`page_id`,t),r.set(`sort_order`,`UPDATED_AT_DESC`);let i=await _({backend:n,method:`GET`,path:`/api/v1/app-conversations/search?${r.toString()}`});return{items:(i?.items??[]).map(e=>A(e)),next_page_id:i?.next_page_id??null}}async function M(e){if(e.length===0)return[];let t=j(),n=new URLSearchParams;for(let t of e)n.append(`ids`,t);return(await _({backend:t,method:`GET`,path:`/api/v1/app-conversations?${n.toString()}`})??[]).map(A)}async function re(e){return await _({backend:j(),method:`POST`,path:`/api/v1/app-conversations`,body:e})}async function ie(e){return _({backend:j(),method:`GET`,path:`/api/v1/app-conversations/${e}/download`,responseType:`blob`})}async function ae(e){await _({backend:j(),method:`DELETE`,path:`/api/v1/app-conversations/${e}`})}async function oe(e,t){return await _({backend:j(),method:`PATCH`,path:`/api/v1/app-conversations/${e}`,body:{public:t}})}async function se(e){await _({backend:j(),method:`POST`,path:`/api/v1/sandboxes/${e}/pause`})}async function ce(e){await _({backend:j(),method:`POST`,path:`/api/v1/sandboxes/${e}/resume`})}async function le(e,t){let n=j(),r=new URLSearchParams;return r.append(`file_path`,t),await _({backend:n,method:`GET`,path:`/api/v1/app-conversations/${e}/file?${r.toString()}`})??``}async function ue(e){let t=j(),n=new URLSearchParams;return n.set(`ids`,e),(await _({backend:t,method:`GET`,path:`/api/v1/app-conversations/start-tasks?${n.toString()}`}))?.[0]??null}var N=`canvas_ui`,de=`canvas_ui_tool`,fe=[`terminal`,`file_editor`,`task_tracker`,N],P=`browser_tool_set`,F=`task_tool_set`;function pe(){return!0}function me(){let e=(void 0)?.trim();if(!e)return null;try{let t=JSON.parse(e);return!t||typeof t!=`object`?null:t}catch{return null}}function he(){let e=me();if(!e?.services)return;let t=[];t.push(`<RUNTIME_SERVICES>`),e.mode?t.push(`You are running inside an agent-canvas dev stack started in '${e.mode}' mode.`):t.push(`You are running inside an agent-canvas dev stack.`),t.push(`The following services are reachable from your sandbox. URLs are written`,`from your point of view (i.e., as you should curl/fetch them).`,``);let{agent_server:n,ingress:r,automation:i}=e.services,a=e.services.frontend??e.services.vite;n?.url_from_agent&&t.push(`* Agent Server (you): ${n.url_from_agent}`,` ${n.description??`The agent-server hosting your tool calls.`}`),r?.url_from_agent&&t.push(`* Ingress: ${r.url_from_agent}`,` ${r.description??`Unified entry point for browser-facing traffic.`}`),a?.url_from_agent&&t.push(`* Frontend: ${a.url_from_agent}`,` ${a.description??`Frontend dev server.`}`),i?.url_from_agent?(t.push(`* Automation backend: ${i.url_from_agent}`,` ${i.description??`OpenHands Automations service.`}`),i.docs_url&&t.push(` Docs: ${i.docs_url}`),i.openapi_url&&t.push(` OpenAPI: ${i.openapi_url}`),i.auth_env_var&&t.push(` Auth: header 'X-Session-API-Key: $${i.auth_env_var}'`)):t.push(`* Automation backend: not running in this dev mode (skip /api/automation calls).`);let o=n?.url_from_agent;return t.push(``,`Trust this block over guessing: do not assume any other URLs are running.`),o&&t.push(`In particular, ${o} inside your sandbox is the Agent Server`,`you are running inside of — NOT the automation backend.`),t.push(`</RUNTIME_SERVICES>`),t.join(`
3
- `)}function ge(e){let{host:t}=l();return`${t}/api/conversations/${e}`}function I(e){return`Conversation ${e.slice(0,5)}`}function L(e){let n=D(e.id),r=e.agent?.kind===`ACPAgent`,a=r?e.tags?.acpserver??null:null;return{id:e.id,created_by_user_id:null,selected_repository:n?.selected_repository??null,selected_branch:n?.selected_branch??null,git_provider:n?.git_provider??null,selected_workspace:n?.selected_workspace??null,title:e.title?.trim()?e.title:I(e.id),trigger:null,pr_number:[],agent_kind:r?`acp`:`openhands`,acp_server:a,llm_model:r?x({runtimeName:e.current_model_name,runtimeId:e.current_model_id,configured:e.agent?.acp_model,sdkLlm:e.agent?.llm?.model}):e.agent?.llm?.model??y.llm_model,metrics:e.metrics?{accumulated_cost:e.metrics.accumulated_cost??null,max_budget_per_task:e.metrics.max_budget_per_task??null,accumulated_token_usage:e.metrics.accumulated_token_usage?{prompt_tokens:e.metrics.accumulated_token_usage.prompt_tokens??0,completion_tokens:e.metrics.accumulated_token_usage.completion_tokens??0,cache_read_tokens:e.metrics.accumulated_token_usage.cache_read_tokens??0,cache_write_tokens:e.metrics.accumulated_token_usage.cache_write_tokens??0,context_window:e.metrics.accumulated_token_usage.context_window??0,per_turn_token:e.metrics.accumulated_token_usage.per_turn_token??0}:null}:null,created_at:e.created_at,updated_at:e.updated_at,execution_status:e.execution_status??t.IDLE,sandbox_status:e.sandbox_status??null,conversation_url:ge(e.id),session_api_key:l().apiKey??null,sandbox_id:null,workspace:{working_dir:e.workspace?.working_dir??i()},public:!1,sub_conversation_ids:[]}}function _e(e){return{items:e.items.map(L),next_page_id:e.next_page_id??null}}var R=[`acp_command`,`acp_args`,`acp_model`,`acp_session_mode`,`acp_prompt_timeout`],ve=`acpserver`,ye=new Set([`schema_version`,`agent_settings`,`workspace`,`conversation_id`,`initial_message`,`plugins`]);function z(e){return!e||typeof e!=`object`||Array.isArray(e)?{}:structuredClone(e)}function B(e){if(typeof e!=`string`)return;let t=e.trim();return t.length>0?t:void 0}function be(e){return e.confirmation_mode===!0?e.security_analyzer===`llm`?{kind:`ConfirmRisky`,threshold:`HIGH`,confirm_unknown:!0}:{kind:`AlwaysConfirm`}:{kind:`NeverConfirm`}}function xe(e){switch(e.security_analyzer){case`llm`:return{kind:`LLMSecurityAnalyzer`};case`pattern`:return{kind:`PatternSecurityAnalyzer`};case`policy_rail`:return{kind:`PolicyRailSecurityAnalyzer`};default:return}}function Se(e){return!!e&&typeof e==`object`&&!Array.isArray(e)&&typeof e.name==`string`}function Ce(e,t){return e===P?pe()&&h(e):e===F?t.enable_sub_agents===!0&&h(e):!0}function we(e){let t=new Map;for(let e of fe)t.set(e,{name:e,params:{}});for(let n of[P,F])Ce(n,e)&&t.set(n,{name:n,params:{}});let n=e.tools;if(Array.isArray(n)&&n.every(e=>Se(e)))for(let r of n)Ce(r.name,e)&&t.set(r.name,{name:r.name,params:z(r.params)});return Array.from(t.values())}function Te(e,t){let n=[e?.trim(),t?.trim()].filter(Boolean);return n.length===0?null:{role:`user`,content:[{type:`text`,text:n.join(`
4
-
5
- `)}],run:!0}}function V(e){let t=he();return{...z(e.agent_context),load_public_skills:n(),load_user_skills:!0,load_project_skills:!0,...t?{system_message_suffix:t}:{}}}function H(e){return z(e.agent_settings).agent_kind===`acp`}function Ee(e){let t=z(e.agent_settings).acp_server;return typeof t==`string`&&t.length>0?t:void 0}function De(e){let t=e.acp_command;if(!(Array.isArray(t)&&t.length===0)&&t!==void 0)return t;let n=b(typeof e.acp_server==`string`?e.acp_server:void 0);return n?[...n.default_command]:t}function Oe(e){let t=z(e.agent_settings),n={agent_kind:`acp`,agent_context:V(t)};for(let e of R){if(e===`acp_model`)continue;let r=e===`acp_command`?De(t):t[e];r!=null&&(n[e]=r)}let r=b(typeof t.acp_server==`string`?t.acp_server:void 0),i=x({configured:t.acp_model,providerDefault:r?.default_model});return i&&(n.acp_model=i),n}function ke(e){let t=z(e.agent_settings),n=z(t.llm);n.model=typeof n.model==`string`&&n.model.trim().length>0?n.model:y.llm_model;let r=B(n.api_key);r?n.api_key=r:delete n.api_key;let i=B(n.base_url);i?n.base_url=i:delete n.base_url;let a=z(t.mcp_config);(Object.keys(a).length===0||!(`mcpServers`in a))&&delete t.mcp_config,delete t.acp_server;for(let e of R)delete t[e];return delete t.acp_env,{...t,llm:n,agent_context:V(t),tools:we(t)}}function Ae(e){return H(e)?Oe(e):ke(e)}function je(e){let{settings:t,query:n,conversationInstructions:r,plugins:a,workingDir:o}=e,s=z(t.conversation_settings),c=Te(n,r);return ye.forEach(e=>delete s[e]),{...s,workspace:{kind:`LocalWorkspace`,working_dir:o??i()},...c?{initial_message:c}:{},...a?.length?{plugins:a.map(e=>({source:e.source,...e.ref?{ref:e.ref}:{},...e.repo_path?{repo_path:e.repo_path}:{}}))}:{}}}function Me(e){let t=e.encryptedAgentSettings?{...e.settings,agent_settings:e.encryptedAgentSettings}:e.settings,n=H(t),r=Ae(t),i=n?Ee(t):void 0,a=je(e.encryptedConversationSettings?{...e,settings:{...e.settings,conversation_settings:e.encryptedConversationSettings}}:e),o={agent_settings:r,workspace:a.workspace,confirmation_policy:be(a),max_iterations:typeof a.max_iterations==`number`?a.max_iterations:500,stuck_detection:!0,autotitle:!0,worktree:!0};i&&(o.tags={[ve]:i}),e.secretsEncrypted&&(o.secrets_encrypted=!0),e.conversationId&&(o.conversation_id=e.conversationId);let s=xe(a);if(s&&(o.security_analyzer=s),a.initial_message&&(o.initial_message=a.initial_message),a.plugins&&(o.plugins=a.plugins),a.hook_config&&(o.hook_config=a.hook_config),o.tool_module_qualnames={[N]:de,...a.tool_module_qualnames??{}},a.agent_definitions&&(o.agent_definitions=a.agent_definitions),e.customSecrets&&e.customSecrets.length>0){let t=u(),r=t?g(t):{},i={};for(let t of e.customSecrets){let e={kind:`LookupSecret`,url:`/api/settings/secrets/${encodeURIComponent(t.name)}`,description:t.description};Object.keys(r).length>0&&(e.headers=r),i[t.name]=e}o.secrets=i,n&&(o.agent_settings.agent_context={...o.agent_settings.agent_context,secrets:i})}return o}async function Ne(t){let{SecretsService:n}=await e(async()=>{let{SecretsService:e}=await import(`./secrets-service-B7CxNinp.js`).then(e=>e.n);return{SecretsService:e}},__vite__mapDeps([0,1,2,3,4])),[r,i]=await Promise.all([S.getSettingsForConversation(),n.getSecrets()]),{agentSettings:a,conversationSettings:o,secretsEncrypted:s}=r;return Me({...t,encryptedAgentSettings:a,encryptedConversationSettings:o,secretsEncrypted:s,customSecrets:i})}function Pe(){return{hooks:[]}}var Fe=`1970-01-01T00:00:00.000Z`,Ie=`Unable to load conversations because the selected agent server returned data this UI does not understand. Check the backend URL/session key and update the agent server if needed.`;function U(){return Error(Ie)}function W(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function G(e){return typeof e==`number`?e:null}function K(e){return typeof e==`number`?e:0}function q(e){return typeof e==`string`?e:null}function J(e,t,n){let r=e[t]??e[n];return typeof r==`string`&&r.trim()?r:Fe}function Le(e){return W(e)?{prompt_tokens:K(e.prompt_tokens),completion_tokens:K(e.completion_tokens),cache_read_tokens:K(e.cache_read_tokens),cache_write_tokens:K(e.cache_write_tokens),context_window:K(e.context_window),per_turn_token:K(e.per_turn_token)}:null}function Y(e){return W(e)?{accumulated_cost:G(e.accumulated_cost),max_budget_per_task:G(e.max_budget_per_task),accumulated_token_usage:Le(e.accumulated_token_usage)}:null}function Re(e){if(!W(e))return null;let t=W(e.llm)?{model:q(e.llm.model)}:null;return{kind:q(e.kind),acp_model:q(e.acp_model),llm:t}}function ze(e){return W(e)?{working_dir:q(e.working_dir)}:null}function Be(e){if(!W(e))return null;let t={};for(let[n,r]of Object.entries(e))typeof r==`string`&&(t[n]=r);return t}function X(e){if(!e.startsWith(`/`))return null;let t=[];for(let n of e.split(`/`))if(n&&n!==`.`)if(n===`..`){if(!t.length)return null;t.pop()}else t.push(n);return`/${t.join(`/`)}`}function Z(e,t){let n=X(e),r=X(t);if(!n||!r||n!==r&&!n.startsWith(`${r}/`))throw Error(`Conversation file path must stay inside the workspace`);return n}function Q(e){if(!W(e)||typeof e.id!=`string`||!e.id.trim())throw U();return{id:e.id.trim(),title:q(e.title),created_at:J(e,`created_at`,`createdAt`),updated_at:J(e,`updated_at`,`updatedAt`),execution_status:q(e.execution_status),sandbox_status:q(e.sandbox_status),metrics:Y(e.metrics),agent:Re(e.agent),workspace:ze(e.workspace),tags:Be(e.tags),current_model_id:q(e.current_model_id),current_model_name:q(e.current_model_name)}}function $(e){if(!Array.isArray(e))throw U();return e.map(Q)}function Ve(e){if(Array.isArray(e))return{items:$(e),next_page_id:null};if(!W(e))throw U();return{items:$(e.items),next_page_id:typeof e.next_page_id==`string`?e.next_page_id:null}}var He=new Set([`idle`,`running`,`paused`,`waiting_for_confirmation`,`finished`,`error`,`stuck`]);function Ue(e){let t=e??`idle`;return He.has(t)?t:`idle`}function We(e,t){if(!e)throw Error(`Conversation ${t} was not found`);return e}var Ge=class{static async sendMessage(e,t,n){let r=s().backend,i=n?.conversationUrl??null,o=n?.sessionApiKey??null;if(r.kind===`cloud`){if(!i||!o){let[t]=await M([e]);i=t?.conversation_url?.trim()??null,o=t?.session_api_key?.trim()??null}if(!i||!o)throw Error(`Conversation sandbox is still starting. Wait for it to finish, then try again.`);return await _({backend:r,method:`POST`,hostOverride:a(i),path:`/api/conversations/${e}/events`,body:{...t,run:!0},authMode:`session-api-key`,sessionApiKey:o}),t}return await new C(l({conversationUrl:i,sessionApiKey:o})).sendEvent(e,t,{run:!0}),t}static async createConversation(e,t,n,i,a,o,c,d){if(s().backend.kind===`cloud`)return re({initial_message:e?{role:`user`,content:[{type:`text`,text:e}]}:null,title:t??null,selected_repository:i?.selected_repository??null,selected_branch:i?.selected_branch??null,git_provider:i?.git_provider??null,plugins:n??null,parent_conversation_id:o??null,agent_type:c,sandbox_id:d??null});let f=await S.getSettings(),p=v(),m=await Ne({settings:f,query:e,conversationInstructions:t,plugins:n,conversationId:p,workingDir:a??r(p)}),h=await new C(l()).createConversation(m),g=u();if(!g)throw new ee;return(i?.selected_repository||a)&&O(h.id,{selected_repository:i?.selected_repository??null,selected_branch:i?.selected_branch??null,git_provider:i?.git_provider??null,selected_workspace:a??null}),{id:h.id,created_by_user_id:null,status:`READY`,detail:null,app_conversation_id:h.id,agent_server_url:g.host,request:{initial_message:m.initial_message,plugins:n??null},created_at:h.created_at,updated_at:h.updated_at}}static async getStartTask(e){return s().backend.kind===`cloud`?ue(e):null}static async getVSCodeUrl(e,t,n){let r=await this.resolveConversationWorkingDir(e);return{vscode_url:await new f(l({conversationUrl:t,sessionApiKey:n})).getUrl({baseUrl:typeof window<`u`?window.location.origin:void 0,workspaceDir:r})}}static async resolveConversationWorkingDir(e){let[t]=await this.batchGetAppConversations([e]);return t?.workspace?.working_dir??i()}static async batchGetAppConversations(e){return e.length===0?[]:s().backend.kind===`cloud`?M(e):$(await new C(l()).getConversations(e)).map(e=>L(e))}static async updateConversationPublicFlag(e,t){if(s().backend.kind!==`cloud`)throw Error(`Public sharing requires a cloud backend.`);return oe(e,t)}static async updateConversationRepository(e,t,n,r){t?O(e,{...D(e)??{},selected_repository:t,selected_branch:n??null,git_provider:r??null}):k(e);let[i]=await this.batchGetAppConversations([e]);return We(i,e)}static async readConversationFile(e,t){if(s().backend.kind===`cloud`)return le(e,Z(t??`/workspace/project/.agents_tmp/PLAN.md`,`/workspace/project`));let n=await this.resolveConversationWorkingDir(e),r=Z(t??`${n}/.agents_tmp/PLAN.md`,n);return new p(l()).downloadTextFile(r)}static async downloadConversation(e){return s().backend.kind===`cloud`?ie(e):new p(l()).downloadTrajectory(e)}static async getHooks(e){return Pe()}static async getRuntimeConversation(e,t,n){let r=s().backend,i=r.kind===`cloud`&&t?await _({backend:r,method:`GET`,hostOverride:a(t),path:`/api/conversations/${e}`,authMode:`session-api-key`,sessionApiKey:n}):await new C(l({conversationUrl:t,sessionApiKey:n})).getConversation(e),o=Q(i),c=W(i)?i.stats:null;return{id:o.id,title:o.title?.trim()?o.title:I(o.id),metrics:Y(o.metrics),created_at:o.created_at,updated_at:o.updated_at,status:Ue(o.execution_status),stats:W(c)?c:{usage_to_metrics:{}}}}static async searchConversations(e=20,t){return s().backend.kind===`cloud`?ne(e,t):_e(Ve(await new C(l()).searchConversations({limit:e,page_id:t,sort_order:d.UPDATED_AT_DESC})))}static async deleteConversation(e){s().backend.kind===`cloud`?await ae(e):await new C(l()).deleteConversation(e),k(e)}static async updateConversationTitle(e,t){await new C(l()).updateConversation(e,{title:t});let[n]=await this.batchGetAppConversations([e]);return We(n,e)}static async switchProfile(e,t){if(s().backend.kind===`cloud`)throw Error(`LLM profile switching is only supported for local agent-server backends.`);if(!e){await new m(l()).activateProfile(t);return}let n=l(),r=new C(n),i=await new m(n).getProfile(t,{exposeSecrets:`encrypted`}),a=typeof i.config.model==`string`?i.config.model:``;if(!a)throw Error(`Profile '${t}' has no model.`);await r.switchLLM(e,{...i.config,model:a,usage_id:`profile:${t}:${v()}`})}static async switchAcpModel(e,t){if(s().backend.kind===`cloud`)throw Error(`ACP model switching is only supported for local agent-server backends.`);await new C(l()).switchAcpModel(e,t)}};export{D as a,ce as i,M as n,C as o,se as r,Ge as t};
@@ -1,2 +0,0 @@
1
- import{a as e,t}from"./rolldown-runtime-BFRubm34.js";import{t as n}from"./react-CM_dJw1Z.js";import{L as r}from"./vendor~entry.client~root~root-layout~index-redirect~home~conversation-panel~conversation~la~cnj3raoq-DTEXlLSB.js";import{o as i,t as a}from"./declaration-CR6HMp29.js";import{t as o}from"./useTranslation-B6voJV4y.js";import{t as s}from"./retrieve-axios-error-message-BY-yIkIq.js";import{n as c,r as l}from"./custom-toast-handlers-ufGJ6_Rc.js";import{t as u}from"./utils-DCVfKFRt.js";import{t as d}from"./brand-button-DJ_S16rO.js";import{t as f}from"./settings-input-CehsXnb3.js";import{a as p,i as m,n as h,t as g}from"./acp-providers-CPdgcp13.js";import{r as _}from"./use-settings-D5hbTS9t.js";import{t as v}from"./use-save-settings-DkAOEfD9.js";import{r as y}from"./typography-BDgnT7Yp.js";import{t as ee}from"./use-agent-settings-schema-CLoTOSJI.js";import{i as te,r as ne}from"./sdk-settings-field-metadata-DQiaIBie.js";import{t as b}from"./settings-dropdown-input-BtoovFre.js";import{t as re}from"./settings-switch-BiBuS3xa.js";var x=t(((e,t)=>{t.exports=function(e){return e.map(function(e){return e===``?`''`:e&&typeof e==`object`?e.op.replace(/(.)/g,`\\$1`):/["\s\\]/.test(e)&&!/'/.test(e)?`'`+e.replace(/(['])/g,`\\$1`)+`'`:/["'\s]/.test(e)?`"`+e.replace(/(["\\$`!])/g,`\\$1`)+`"`:String(e).replace(/([A-Za-z]:)?([#!"$&'()*,:;<=>?@[\\\]^`{|}])/g,`$1\\$2`)}).join(` `)}})),S=t(((e,t)=>{for(var n=`(?:`+[`\\|\\|`,`\\&\\&`,`;;`,`\\|\\&`,`\\<\\(`,`\\<\\<\\<`,`>>`,`>\\&`,`<\\&`,`[&;()|<>]`].join(`|`)+`)`,r=RegExp(`^`+n+`$`),i=`|&;()<> \\t`,a=`"((\\\\"|[^"])*?)"`,o=`'((\\\\'|[^'])*?)'`,s=/^#$/,c=`'`,l=`"`,u=`$`,d=``,f=4294967296,p=0;p<4;p++)d+=(f*Math.random()).toString(16);var m=RegExp(`^`+d);function h(e,t){for(var n=t.lastIndex,r=[],i;i=t.exec(e);)r.push(i),t.lastIndex===i.index&&(t.lastIndex+=1);return t.lastIndex=n,r}function g(e,t,n){var r=typeof e==`function`?e(n):e[n];return r===void 0&&n!=``?r=``:r===void 0&&(r=`$`),typeof r==`object`?t+d+JSON.stringify(r)+d:t+r}function _(e,t,d){d||={};var f=d.escape||`\\`,p=`(\\`+f+`['"`+i+`]|[^\\s'"`+i+`])+`,m=h(e,new RegExp([`(`+n+`)`,`(`+p+`|`+a+`|`+o+`)+`].join(`|`),`g`));if(m.length===0)return[];t||={};var _=!1;return m.map(function(n){var i=n[0];if(!i||_)return;if(r.test(i))return{op:i};var a=!1,o=!1,d=``,p=!1,m;function h(){m+=1;var e,n,r=i.charAt(m);if(r===`{`){if(m+=1,i.charAt(m)===`}`)throw Error(`Bad substitution: `+i.slice(m-2,m+1));if(e=i.indexOf(`}`,m),e<0)throw Error(`Bad substitution: `+i.slice(m));n=i.slice(m,e),m=e}else if(/[*@#?$!_-]/.test(r))n=r,m+=1;else{var a=i.slice(m);e=a.match(/[^\w\d_]/),e?(n=a.slice(0,e.index),m+=e.index-1):(n=a,m=i.length)}return g(t,``,n)}for(m=0;m<i.length;m++){var v=i.charAt(m);if(p||=!a&&(v===`*`||v===`?`),o)d+=v,o=!1;else if(a)v===a?a=!1:a==c?d+=v:v===f?(m+=1,v=i.charAt(m),v===l||v===f||v===u?d+=v:d+=f+v):v===u?d+=h():d+=v;else if(v===l||v===c)a=v;else if(r.test(v))return{op:i};else if(s.test(v)){_=!0;var y={comment:e.slice(n.index+m+1)};return d.length?[d,y]:[y]}else v===f?o=!0:v===u?d+=h():d+=v}return p?{op:`glob`,pattern:d}:d}).reduce(function(e,t){return t===void 0?e:e.concat(t)},[])}t.exports=function(e,t,n){var r=_(e,t,n);return typeof t==`function`?r.reduce(function(e,t){if(typeof t==`object`)return e.concat(t);var n=t.split(RegExp(`(`+d+`.*?`+d+`)`,`g`));return n.length===1?e.concat(n[0]):e.concat(n.filter(Boolean).map(function(e){return m.test(e)?JSON.parse(e.split(d)[1]):e}))},[]):r}})),C=t((e=>{e.quote=x(),e.parse=S()})),w=e(n(),1),{quote:T}=e(C(),1);function E(e){let t=[],n=0,r=``,i=!1;for(;n<e.length;){let a=e[n];if(a===` `||a===` `||a===`
2
- `||a===`\r`){i&&=(t.push(r),r=``,!1),n+=1;continue}if(a===`'`){for(i=!0,n+=1;n<e.length&&e[n]!==`'`;)r+=e[n],n+=1;n<e.length&&(n+=1);continue}if(a===`"`){for(i=!0,n+=1;n<e.length&&e[n]!==`"`;){if(e[n]===`\\`&&n+1<e.length){let t=e[n+1];if(t===`"`||t===`\\`){r+=t,n+=2;continue}}r+=e[n],n+=1}n<e.length&&(n+=1);continue}if(a===`\\`&&n+1<e.length){i=!0,r+=e[n+1],n+=2;continue}i=!0,r+=a,n+=1}return i&&t.push(r),t}var D=/[\s"'\\$`&|;<>(){}*?#!~[\]]/;function O(e){return e.map(e=>D.test(e)||e===``?T([e]):e).join(` `)}var k=i(),A={hideTitle:!0},j=`enable_sub_agents`,ie=`npx -y <package-name>`,M=`__custom_model__`;function N(e){return Array.isArray(e)?e.filter(e=>typeof e==`string`):[]}function P(e,t){let n=E(e).join(` `);for(let e of t)if(n===e.default_command.join(` `))return e.key;return g}function ae(e){return e?.find(e=>e.key===j)}function oe(e,t){return typeof e==`boolean`?e:t?.default===!0}function F(e,t){return e?.available_models?.some(({id:e})=>e===t.trim())??!1}function I(){let{t:e}=o(`openhands`),{data:t,isLoading:n}=_(),{mutate:r,isPending:i}=v(),{data:x}=ee(t?.agent_settings_schema),S=ae(w.useMemo(()=>x?.sections.flatMap(e=>e.fields),[x])),C=w.useMemo(()=>oe(t?.agent_settings?.[j],S),[S,t?.agent_settings]),[T,D]=(0,w.useState)(C),[A,I]=(0,w.useState)(`openhands`),[L,R]=(0,w.useState)(``),[z,B]=(0,w.useState)(``),[se,V]=(0,w.useState)(!1),[ce,H]=(0,w.useState)(!1),U=(0,w.useRef)(null),W=(0,w.useRef)(null),G=(0,w.useRef)(``);if((0,w.useEffect)(()=>{if(t&&U.current!==t){if(U.current=t,t.agent_settings?.agent_kind===`acp`){I(`acp`);let e=t.agent_settings?.acp_server,n=typeof e==`string`?e:void 0,r=p(n),i=N(t.agent_settings?.acp_command),a=[...i.length>0?i:r?.default_command??[],...N(t.agent_settings?.acp_args)],o=a.length>0?O(a):``;R(o),W.current=n??null,G.current=o;let s=t.agent_settings?.acp_model,c=typeof s==`string`?s.trim():``;B(c||r?.default_model||``),V(!!c&&(!r||!F(r,c)))}else I(`openhands`),R(``),B(``),W.current=null,G.current=``,V(!1);H(!1)}},[t]),(0,w.useEffect)(()=>{D(C)},[C]),n)return null;let K=A===`acp`,q=E(L),le=K&&q.length===0,J=P(L,h),Y=p(J),X=Y?.available_models??[],Z=X.length>0,ue=F(Y,z),Q=se||!ue?M:z,$=!!Y&&q.join(` `)===Y.default_command.join(` `),de=O(h[0]?.default_command??[])||ie,fe=ce||!K&&T!==C,pe=()=>{if(K){let t=!!(Y&&$),n=W.current,i=L===G.current,o=!!n&&n!==`custom`&&!h.some(e=>e.key===n),u=K&&i&&o,d=m(u?n:Y&&$?Y.key:g,{command:t?[]:q,model:z.trim()||void 0,allowUnknownServer:u});if(!d)return;r({agent_settings_diff:d},{onError:t=>{c(s(t)||e(a.ERROR$GENERIC))},onSuccess:()=>{l(e(a.SETTINGS$SAVED)),H(!1)}})}else r({agent_settings_diff:{agent_kind:`openhands`,enable_sub_agents:T}},{onError:t=>{c(s(t)||e(a.ERROR$GENERIC))},onSuccess:()=>{l(e(a.SETTINGS$SAVED)),H(!1)}})},me=S?te(e,S.key,S.label):e(a.SCHEMA$ENABLE_SUB_AGENTS$LABEL),he=S?ne(e,S.key,S.description):e(a.SCHEMA$ENABLE_SUB_AGENTS$DESCRIPTION);return(0,k.jsxs)(`div`,{"data-testid":`agent-settings-screen`,className:`flex flex-col gap-6 pb-8 max-w-2xl`,children:[(0,k.jsxs)(`div`,{children:[(0,k.jsx)(y.H2,{className:`mb-2`,children:e(a.SETTINGS$NAV_AGENT)}),(0,k.jsx)(y.Paragraph,{className:`text-sm text-[#A3A3A3]`,children:e(a.SETTINGS$AGENT_PAGE_DESCRIPTION)})]}),(0,k.jsx)(b,{testId:`agent-type-selector`,name:`agent-type`,label:e(a.SETTINGS$NAV_AGENT),items:[{key:`openhands`,label:e(a.SETTINGS$AGENT_TYPE_OPENHANDS)},{key:`acp`,label:e(a.SETTINGS$AGENT_TYPE_ACP)}],selectedKey:A,onSelectionChange:e=>{if(!e)return;let t=e;if(I(t),t===`acp`&&!L){let e=h[0];e&&(R(O(e.default_command)),B(e.default_model??``),V(!1))}else t===`openhands`&&V(!1);H(!0)}}),!K&&(0,k.jsxs)(`div`,{className:`flex flex-col gap-1.5`,children:[(0,k.jsx)(re,{testId:`agent-settings-enable-sub-agents`,isToggled:T,onToggle:e=>{D(e)},children:me}),he?(0,k.jsx)(y.Paragraph,{className:u(`pl-12`,`text-tertiary-alt text-xs leading-5`),children:he}):null]}),K&&(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(b,{testId:`agent-preset-selector`,name:`agent-preset`,label:e(a.SETTINGS$AGENT_PRESET),items:[...h.map(e=>({key:e.key,label:e.display_name})),{key:`custom`,label:e(a.SETTINGS$AGENT_PRESET_CUSTOM)}],selectedKey:J,onSelectionChange:e=>{if(!e)return;let t=String(e),n=p(t);n?(R(O(n.default_command)),B(n.default_model??``),V(!1)):t===`custom`&&(R(``),B(``),V(!0)),H(!0)}}),(0,k.jsxs)(`div`,{className:`flex flex-col gap-2.5`,children:[(0,k.jsx)(y.Text,{className:`text-sm`,children:e(a.SETTINGS$AGENT_COMMAND)}),(0,k.jsx)(`textarea`,{"data-testid":`agent-command-input`,className:`bg-tertiary border border-[#717888] rounded-sm p-2 text-sm font-mono text-white placeholder:text-[#717888] min-h-[60px] resize-y focus:outline-none focus:border-white`,value:L,placeholder:de,onChange:e=>{let t=e.target.value,n=P(L,h),r=P(t,h);r!==n&&(B(p(r)?.default_model??``),V(!1)),R(t),H(!0)}}),(0,k.jsx)(y.Text,{className:`text-xs text-[#717888]`,children:e(a.SETTINGS$AGENT_COMMAND_HINT)})]}),(0,k.jsxs)(`div`,{className:`flex flex-col gap-1.5`,children:[Z&&(0,k.jsx)(b,{testId:`agent-model-selector`,name:`agent-model`,label:e(a.SETTINGS$AGENT_MODEL),items:[...X.map(e=>({key:e.id,label:e.label})),{key:M,label:e(a.SETTINGS$AGENT_PRESET_CUSTOM)}],selectedKey:Q,onSelectionChange:e=>{if(!e)return;let t=String(e);t===M?(V(!0),B(``)):(V(!1),B(t)),H(!0)}}),Q===M&&(0,k.jsx)(f,{testId:`agent-model-input`,label:e(Z?a.SETTINGS$AGENT_CUSTOM_MODEL:a.SETTINGS$AGENT_MODEL),type:`text`,className:`w-full`,value:z,showOptionalTag:!0,onChange:e=>{B(e),H(!0)}}),(0,k.jsx)(y.Text,{className:`text-xs text-[#717888]`,children:e(a.SETTINGS$AGENT_MODEL_HINT)})]})]}),(0,k.jsx)(`div`,{children:(0,k.jsx)(d,{testId:`agent-save-button`,type:`button`,variant:`primary`,isDisabled:i||!fe||le,onClick:pe,children:e(i?a.SETTINGS$SAVING:a.SETTINGS$SAVE_CHANGES)})})]})}var L=r(I);export{L as default,A as handle};
@@ -1 +0,0 @@
1
- import{o as e,t}from"./declaration-CR6HMp29.js";import{t as n}from"./useTranslation-B6voJV4y.js";import{n as r}from"./vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~jfc6hidu-DJS-rJdI.js";import{t as i}from"./modal-backdrop-RfNCrSpK.js";import{n as a}from"./modal-body-aoa2fx5W.js";import{n as o,r as s}from"./base-modal-C2oy2EBG.js";import{t as c}from"./brand-button-DJ_S16rO.js";import{t as l}from"./handle-capture-consent-3XrjZ8wi.js";import{t as u}from"./use-save-settings-DkAOEfD9.js";var d=e();function f({onClose:e}){let f=r(),{t:p}=n(`openhands`),{mutate:m}=u();return(0,d.jsx)(i,{children:(0,d.jsx)(`form`,{"data-testid":`user-capture-consent-form`,onSubmit:async t=>{t.preventDefault();let n=new FormData(t.currentTarget).get(`analytics`)===`on`;m({user_consents_to_analytics:n},{onSuccess:()=>{l(f,n),e()}})},className:`flex flex-col gap-2`,children:(0,d.jsxs)(a,{className:`border border-[var(--oh-border)]`,children:[(0,d.jsx)(s,{title:p(t.ANALYTICS$TITLE)}),(0,d.jsx)(o,{children:p(t.ANALYTICS$DESCRIPTION)}),(0,d.jsxs)(`label`,{className:`flex gap-2 items-center self-start text-sm`,children:[(0,d.jsx)(`input`,{name:`analytics`,type:`checkbox`,defaultChecked:!0}),p(t.ANALYTICS$SEND_ANONYMOUS_DATA)]}),(0,d.jsx)(c,{testId:`confirm-preferences`,type:`submit`,variant:`primary`,className:`w-full`,children:p(t.ANALYTICS$CONFIRM_PREFERENCES)})]})})})}export{f as AnalyticsConsentFormModal};
@@ -1 +0,0 @@
1
- import{a as e}from"./rolldown-runtime-BFRubm34.js";import{t}from"./react-CM_dJw1Z.js";import{L as n,P as r}from"./vendor~entry.client~root~root-layout~index-redirect~home~conversation-panel~conversation~la~cnj3raoq-DTEXlLSB.js";import{t as i}from"./vendor~root~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-s~f2l2lr17-DYXOLEck.js";import{o as a,t as o}from"./declaration-CR6HMp29.js";import{t as s}from"./useTranslation-B6voJV4y.js";import{t as c}from"./back-nav-button-7dQJ2k3O.js";import{n as l,r as u}from"./custom-toast-handlers-ufGJ6_Rc.js";import{t as d}from"./utils-DCVfKFRt.js";import{a as f,d as p,n as m}from"./agent-server-client-options-HEOwGVIU.js";import{n as h}from"./active-backend-context-Beu-LZL-.js";import{f as g}from"./vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~dp08i1qy-hTzSytKK.js";import{r as _}from"./modal-classes-6YqcqA6y.js";import{n as v}from"./navigation-context-BdKYH32C.js";import{n as y,r as b}from"./vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~ninslayh-CLlsvdNP.js";import{t as x}from"./proxy-BAdHH8QB.js";import{t as S}from"./u-edit-BbrptMCa.js";import{t as C}from"./terminal-CPYWdo4j.js";import{t as w}from"./use-user-conversation-Cs5H1pUF.js";import{t as T}from"./code-tag-BzyqOtPD.js";import{t as E}from"./link-external-DGxVm4Ps.js";import{t as D}from"./toggle-switch-T2v6sJ6l.js";import{t as O}from"./x-mark-BrkSPIiT.js";import{t as k}from"./globe-Bzj_0oXT.js";import{C as A,S as j,a as M,b as ee,c as N,d as te,f as ne,g as P,i as F,l as re,n as ie,o as ae,p as oe,r as se,s as ce,t as le,u as I,v as ue,x as de,y as fe}from"./edit-automation-modal-BpX-t-HD.js";import{t as L}from"./automation-XDPAjiZi.js";var R=e(t()),z=a();function B(){let{t:e}=s(`openhands`);return(0,z.jsx)(c,{to:`/automations`,children:e(o.AUTOMATIONS$DETAIL$BACK_TO_LIST)})}var V=e=>(0,z.jsx)(`svg`,{xmlns:`http://www.w3.org/2000/svg`,fill:`none`,viewBox:`0 0 24 24`,stroke:`currentColor`,strokeWidth:2,...e,children:(0,z.jsx)(`path`,{strokeLinecap:`round`,strokeLinejoin:`round`,d:`M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3`})});function pe({active:e}){let{t}=s(`openhands`);return(0,z.jsx)(`span`,{"data-testid":e?`active-status-badge-active`:`active-status-badge-inactive`,className:d(`inline-flex items-center rounded-full px-3 py-1 text-xs font-medium`,e?`bg-[var(--oh-success)]/15 text-[var(--oh-success)]`:`bg-surface-raised text-muted`),children:t(e?o.AUTOMATIONS$DETAIL$ACTIVE:o.AUTOMATIONS$DETAIL$INACTIVE)})}function me({automation:e,onToggle:t,onEdit:n,onDelete:r,onRunNow:i,isRunningNow:a=!1}){let{t:c}=s(`openhands`),l=ne(`manage_automations`),u=[...n?[{label:c(o.AUTOMATIONS$EDIT),icon:(0,z.jsx)(S,{className:`size-4`}),onClick:n}]:[],{label:e.enabled?c(o.AUTOMATIONS$TURN_OFF):c(o.AUTOMATIONS$TURN_ON),icon:(0,z.jsx)(ce,{className:`size-4`}),onClick:t},{label:c(o.AUTOMATIONS$DOWNLOAD_TARBALL),icon:(0,z.jsx)(V,{className:`size-4`}),onClick:()=>{A.downloadTarball(e.id,e.name)}},{label:c(o.AUTOMATIONS$DELETE),icon:(0,z.jsx)(ae,{className:`size-4`}),onClick:r}];return(0,z.jsx)(`div`,{className:`flex flex-col gap-4`,children:(0,z.jsxs)(`div`,{className:`flex items-start justify-between`,children:[(0,z.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,z.jsx)(`h1`,{className:`text-xl font-medium text-content`,children:e.name}),(0,z.jsx)(pe,{active:e.enabled})]}),(0,z.jsxs)(`div`,{className:`flex items-center gap-2`,children:[l&&i&&(0,z.jsxs)(`button`,{type:`button`,className:`inline-flex items-center gap-1.5 rounded-md border border-[var(--oh-border)] px-3 py-1.5 text-sm font-medium text-content transition-colors hover:bg-surface-raised disabled:cursor-not-allowed disabled:opacity-60`,disabled:a||!e.enabled,onClick:i,children:[(0,z.jsx)(te,{className:`size-3.5 shrink-0`,"aria-hidden":!0}),a?`Starting…`:c(o.AUTOMATIONS$RUN_NOW)]}),l&&(0,z.jsx)(D,{enabled:e.enabled,label:e.enabled?c(o.AUTOMATIONS$TURN_OFF):c(o.AUTOMATIONS$TURN_ON),onToggle:t}),l&&(0,z.jsx)(oe,{items:u})]})]})})}function H({icon:e,title:t,children:n}){return(0,z.jsxs)(`div`,{className:`rounded-2xl border border-[var(--oh-border)] bg-[var(--oh-surface)]`,children:[(0,z.jsxs)(`div`,{className:`flex items-center gap-2 border-b border-[var(--oh-border)] px-5 py-3`,children:[(0,z.jsx)(`span`,{className:`size-4 text-muted`,children:e}),(0,z.jsx)(`h3`,{className:`text-sm font-medium text-content`,children:t})]}),(0,z.jsx)(`div`,{className:`px-5 py-5`,children:n})]})}var he=240,ge=`max-h-60`;function _e({prompt:e}){let{t}=s(`openhands`),[n,r]=R.useState(!1),[i,a]=R.useState(!1),c=R.useRef(null),l=i&&!n;return R.useLayoutEffect(()=>{let e=c.current;if(!e)return;let t=()=>{a(e.scrollHeight>he)};t();let n=new ResizeObserver(t);return n.observe(e),()=>n.disconnect()},[e]),(0,z.jsx)(H,{icon:(0,z.jsx)(C,{className:`size-4`}),title:t(o.AUTOMATIONS$DETAIL$PROMPT),children:(0,z.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[(0,z.jsxs)(`div`,{className:`relative`,children:[(0,z.jsx)(`p`,{ref:c,className:d(`whitespace-pre-wrap text-sm leading-6 text-content`,l&&d(ge,`overflow-hidden`)),"data-testid":`automation-prompt-content`,children:e}),l?(0,z.jsx)(`div`,{className:`pointer-events-none absolute inset-x-0 bottom-0 h-20 bg-gradient-to-t from-[var(--oh-surface)] to-transparent`,"aria-hidden":!0,"data-testid":`automation-prompt-fade`}):null]}),i?(0,z.jsx)(`button`,{type:`button`,className:`self-start cursor-pointer text-sm font-normal text-[var(--oh-muted)] hover:text-white`,onClick:()=>r(e=>!e),"data-testid":`automation-prompt-toggle`,children:t(n?o.COMMON$VIEW_LESS:o.COMMON$VIEW_MORE)}):null]})})}var ve=e=>(0,z.jsxs)(`svg`,{xmlns:`http://www.w3.org/2000/svg`,fill:`none`,viewBox:`0 0 24 24`,strokeWidth:2,stroke:`currentColor`,...e,children:[(0,z.jsx)(`path`,{strokeLinecap:`round`,strokeLinejoin:`round`,d:`M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 0 1 1.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 0 1-1.449.12l-.738-.527c-.35-.25-.806-.272-1.204-.107-.397.165-.71.505-.78.929l-.15.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 0 1-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.506-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.108-1.204l-.526-.738a1.125 1.125 0 0 1 .12-1.45l.773-.773a1.125 1.125 0 0 1 1.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894Z`}),(0,z.jsx)(`path`,{strokeLinecap:`round`,strokeLinejoin:`round`,d:`M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z`})]}),ye=e=>(0,z.jsxs)(`svg`,{xmlns:`http://www.w3.org/2000/svg`,fill:`none`,viewBox:`0 0 24 24`,strokeWidth:2,stroke:`currentColor`,...e,children:[(0,z.jsx)(`path`,{strokeLinecap:`round`,strokeLinejoin:`round`,d:`M6 3v12m0 0a3 3 0 1 0 3 3M6 15a3 3 0 0 1 3-3h6a3 3 0 0 0 3-3V3m0 0a3 3 0 1 0 0 0`}),(0,z.jsx)(`circle`,{cx:6,cy:3,r:2}),(0,z.jsx)(`circle`,{cx:18,cy:3,r:2}),(0,z.jsx)(`circle`,{cx:9,cy:18,r:2})]}),U=e=>(0,z.jsx)(`svg`,{xmlns:`http://www.w3.org/2000/svg`,fill:`none`,viewBox:`0 0 24 24`,strokeWidth:2,stroke:`currentColor`,...e,children:(0,z.jsx)(`path`,{strokeLinecap:`round`,strokeLinejoin:`round`,d:`M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z`})}),W=e=>(0,z.jsx)(`svg`,{xmlns:`http://www.w3.org/2000/svg`,fill:`none`,viewBox:`0 0 24 24`,strokeWidth:2,stroke:`currentColor`,...e,children:(0,z.jsx)(`path`,{strokeLinecap:`round`,strokeLinejoin:`round`,d:`M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 0 1 2.25-2.25h13.5A2.25 2.25 0 0 1 21 7.5v11.25m-18 0A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75m-18 0v-7.5A2.25 2.25 0 0 1 5.25 9h13.5A2.25 2.25 0 0 1 21 11.25v7.5`})}),be=e=>(0,z.jsx)(`svg`,{xmlns:`http://www.w3.org/2000/svg`,fill:`none`,viewBox:`0 0 24 24`,strokeWidth:2,stroke:`currentColor`,...e,children:(0,z.jsx)(`path`,{strokeLinecap:`round`,strokeLinejoin:`round`,d:`M14.857 17.082a23.848 23.848 0 0 0 5.454-1.31A8.967 8.967 0 0 1 18 9.75V9A6 6 0 0 0 6 9v.75a8.967 8.967 0 0 1-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 0 1-5.714 0m5.714 0a3 3 0 1 1-5.714 0`})});function G({icon:e,label:t,children:n}){return(0,z.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[(0,z.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,z.jsx)(`span`,{className:`size-3.5 text-muted`,children:e}),(0,z.jsx)(`span`,{className:`text-xs font-medium text-muted`,children:t})]}),(0,z.jsx)(`div`,{className:`text-sm text-content`,children:n})]})}function xe({branch:e}){return(0,z.jsx)(`span`,{className:`inline-flex items-center rounded-full border border-[var(--oh-border)] bg-surface-raised px-2.5 py-0.5 text-xs text-muted`,children:e})}var K=60;function Se({filter:e}){let{t}=s(`openhands`),[n,r]=(0,R.useState)(!1),i=e.length>K;return(0,z.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,z.jsx)(`span`,{className:`break-all`,children:i&&!n?`${e.slice(0,K)}…`:e}),i&&(0,z.jsx)(`button`,{type:`button`,onClick:()=>r(!n),"aria-expanded":n,className:`text-xs text-muted hover:text-content self-start`,children:t(n?o.SETTINGS$SKILLS_SHOW_LESS:o.SETTINGS$SKILLS_SHOW_MORE)})]})}function Ce({automation:e}){let{t}=s(`openhands`),n=e.trigger.type===`event`,r=e.trigger.schedule??``;e.trigger.schedule_human&&(r=e.timezone?`${e.trigger.schedule_human} (${e.timezone})`:e.trigger.schedule_human);let i=t(n?o.AUTOMATIONS$DETAIL$TRIGGER_EVENT:o.AUTOMATIONS$DETAIL$TRIGGER_SCHEDULE);return(0,z.jsx)(H,{icon:(0,z.jsx)(ve,{className:`size-4`}),title:t(o.AUTOMATIONS$DETAIL$CONFIGURATION),children:(0,z.jsxs)(`div`,{className:`grid grid-cols-2 gap-x-4 gap-y-5`,children:[e.repository&&(0,z.jsx)(G,{icon:(0,z.jsx)(ye,{className:`size-3.5`}),label:t(o.AUTOMATIONS$DETAIL$REPOSITORIES),children:(0,z.jsxs)(`span`,{className:`flex items-center gap-1`,children:[e.repository,e.branch&&(0,z.jsx)(xe,{branch:e.branch})]})}),(0,z.jsx)(G,{icon:(0,z.jsx)(U,{className:`size-3.5`}),label:t(o.AUTOMATIONS$DETAIL$TRIGGER),children:i}),!n&&(0,z.jsx)(G,{icon:(0,z.jsx)(W,{className:`size-3.5`}),label:t(o.AUTOMATIONS$DETAIL$SCHEDULE),children:r}),n&&e.trigger.source&&(0,z.jsx)(G,{icon:(0,z.jsx)(k,{className:`size-3.5`}),label:t(o.AUTOMATIONS$DETAIL$EVENT_SOURCE),children:e.trigger.source}),n&&e.trigger.on&&(0,z.jsx)(G,{icon:(0,z.jsx)(E,{className:`size-3.5`}),label:t(o.AUTOMATIONS$DETAIL$EVENT_TYPE),children:N(e.trigger.on)}),n&&e.trigger.filter&&(0,z.jsx)(G,{icon:(0,z.jsx)(T,{className:`size-3.5`}),label:t(o.AUTOMATIONS$DETAIL$EVENT_FILTER),children:(0,z.jsx)(Se,{filter:e.trigger.filter})}),(0,z.jsx)(G,{icon:(0,z.jsx)(re,{className:`size-3.5`}),label:t(o.AUTOMATIONS$DETAIL$MODEL),children:e.model??`Active profile`}),e.notification&&(0,z.jsx)(G,{icon:(0,z.jsx)(be,{className:`size-3.5`}),label:t(o.AUTOMATIONS$DETAIL$NOTIFICATION),children:e.notification})]})})}var we=e=>(0,z.jsx)(`svg`,{xmlns:`http://www.w3.org/2000/svg`,fill:`none`,viewBox:`0 0 24 24`,strokeWidth:2,stroke:`currentColor`,...e,children:(0,z.jsx)(`path`,{strokeLinecap:`round`,strokeLinejoin:`round`,d:`M14.25 6.087c0-.355.186-.676.401-.959.221-.29.349-.634.349-1.003 0-1.036-1.007-1.875-2.25-1.875s-2.25.84-2.25 1.875c0 .369.128.713.349 1.003.215.283.401.604.401.959v0a.64.64 0 0 1-.657.643 48.39 48.39 0 0 1-4.163-.3c.186 1.613.293 3.25.315 4.907a.656.656 0 0 1-.658.663v0c-.355 0-.676-.186-.959-.401a1.647 1.647 0 0 0-1.003-.349c-1.036 0-1.875 1.007-1.875 2.25s.84 2.25 1.875 2.25c.369 0 .713-.128 1.003-.349.283-.215.604-.401.959-.401v0c.31 0 .555.26.532.57a48.039 48.039 0 0 1-.642 5.056c1.518.19 3.058.309 4.616.354a.64.64 0 0 0 .657-.643v0c0-.355-.186-.676-.401-.959a1.647 1.647 0 0 1-.349-1.003c0-1.035 1.008-1.875 2.25-1.875 1.243 0 2.25.84 2.25 1.875 0 .369-.128.713-.349 1.003-.215.283-.4.604-.4.959v0c0 .333.277.599.61.58a48.1 48.1 0 0 0 5.427-.63 48.05 48.05 0 0 0 .582-4.717.532.532 0 0 0-.533-.57v0c-.355 0-.676.186-.959.401-.29.221-.634.349-1.003.349-1.035 0-1.875-1.007-1.875-2.25s.84-2.25 1.875-2.25c.37 0 .713.128 1.003.349.283.215.604.401.96.401v0a.656.656 0 0 0 .658-.663 48.422 48.422 0 0 0-.37-5.36c-1.886.342-3.81.574-5.766.689a.578.578 0 0 1-.61-.58v0Z`})});function Te({name:e}){return(0,z.jsx)(`span`,{className:`inline-flex items-center rounded-full border border-[var(--oh-border)] bg-[var(--oh-surface-deep)] px-3.5 py-1.5 text-sm text-content`,children:e})}function Ee({plugins:e}){let{t}=s(`openhands`);return(0,z.jsx)(H,{icon:(0,z.jsx)(we,{className:`size-4`}),title:t(o.AUTOMATIONS$DETAIL$PLUGINS),children:(0,z.jsx)(`div`,{className:`flex flex-wrap gap-2`,children:e.map(e=>(0,z.jsx)(Te,{name:e},e))})})}var q=e=>(0,z.jsx)(`svg`,{xmlns:`http://www.w3.org/2000/svg`,fill:`none`,viewBox:`0 0 24 24`,strokeWidth:2,stroke:`currentColor`,...e,children:(0,z.jsx)(`path`,{strokeLinecap:`round`,strokeLinejoin:`round`,d:`M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182`})});function J(e,t){return new Date(e).toLocaleDateString(t,{year:`numeric`,month:`short`,day:`numeric`})}function De(e,t,n){let r=Date.now()-new Date(e).getTime(),i=Math.floor(r/6e4),a=Math.floor(r/36e5),s=Math.floor(r/864e5);return i<1?n(o.AUTOMATIONS$DETAIL$TIME_JUST_NOW):i<60?n(o.AUTOMATIONS$DETAIL$TIME_MINUTES_AGO,{count:i}):a<24?n(o.AUTOMATIONS$DETAIL$TIME_HOURS_AGO,{count:a}):s===1?n(o.AUTOMATIONS$DETAIL$TIME_YESTERDAY):s<7?n(o.AUTOMATIONS$DETAIL$TIME_DAYS_AGO,{count:s}):J(e,t)}function Oe({createdAt:e,lastRunAt:t}){let{t:n,i18n:r}=s(`openhands`),i=r.language;return(0,z.jsx)(H,{icon:(0,z.jsx)(q,{className:`size-4`}),title:n(o.AUTOMATIONS$DETAIL$ACTIVITY),children:(0,z.jsxs)(`div`,{className:`grid grid-cols-2 gap-x-4`,children:[(0,z.jsx)(G,{icon:(0,z.jsx)(W,{className:`size-3.5`}),label:n(o.AUTOMATIONS$DETAIL$CREATED),children:J(e,i)}),(0,z.jsx)(G,{icon:(0,z.jsx)(I,{className:`size-3.5`}),label:n(o.AUTOMATIONS$DETAIL$LAST_RUN),children:t?De(t,i,n):n(o.AUTOMATIONS$DETAIL$TIME_NEVER)})]})})}var ke=e=>(0,z.jsx)(`svg`,{xmlns:`http://www.w3.org/2000/svg`,fill:`none`,viewBox:`0 0 24 24`,strokeWidth:2,stroke:`currentColor`,...e,children:(0,z.jsx)(`path`,{strokeLinecap:`round`,strokeLinejoin:`round`,d:`m9.75 9.75 4.5 4.5m0-4.5-4.5 4.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z`})}),Ae={[L.COMPLETED]:{label:o.AUTOMATIONS$DETAIL$SUCCESSFUL,style:`border-[var(--oh-success)]/50 bg-[var(--oh-success)]/10 text-[var(--oh-success)]`},[L.FAILED]:{label:o.AUTOMATIONS$DETAIL$FAILED,style:`border-[var(--oh-danger)]/50 bg-[var(--oh-danger)]/10 text-danger`},[L.PENDING]:{label:o.AUTOMATIONS$DETAIL$PENDING,style:`border-[var(--oh-border)] bg-surface-raised text-muted`},[L.RUNNING]:{label:o.AUTOMATIONS$DETAIL$RUNNING,style:`border-[var(--oh-border)] bg-surface-raised text-muted`}};function je({status:e}){switch(e){case L.COMPLETED:return(0,z.jsx)(U,{"data-testid":`run-status-icon-completed`,className:`size-3.5`});case L.FAILED:return(0,z.jsx)(ke,{"data-testid":`run-status-icon-failed`,className:`size-3.5`});default:return(0,z.jsx)(I,{"data-testid":`run-status-icon-pending`,className:`size-3.5`})}}function Me({status:e}){let{t}=s(`openhands`),n=Ae[e];return(0,z.jsxs)(`span`,{className:d(`inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs font-medium`,n.style),children:[(0,z.jsx)(je,{status:e}),t(n.label)]})}var Ne=20;function Pe(e){return e.kind===`BashOutput`}var Fe=class e{static async listOutputs(t,n,r){let i=[],a;for(let o=0;o<Ne;o+=1){let o=await e.searchEvents(t,n,{kind__eq:`BashOutput`,command_id__eq:r,sort_order:`TIMESTAMP`,...a?{page_id:a}:{}});if(o.items.forEach(e=>{Pe(e)&&i.push(e)}),!o.next_page_id)break;a=o.next_page_id}return i}static async searchEvents(e,t,n){let r=p().backend;if(r.kind===`cloud`){if(!e)throw Error(`BashService.listOutputs requires a conversation URL on cloud backends`);let i=new URLSearchParams;return Object.entries(n).forEach(([e,t])=>{t!=null&&i.set(e,String(t))}),x({backend:r,method:`GET`,hostOverride:f(e),path:`/api/bash/bash_events/search?${i.toString()}`,authMode:`session-api-key`,sessionApiKey:t})}return new g(m({...e?{conversationUrl:e}:{},sessionApiKey:t})).searchEvents(n)}},Ie=[`bash-command-logs`];function Le(e){switch(e){case`MISSING`:return`missing`;case`PAUSED`:return`paused`;case`STARTING`:return`starting`;case`ERROR`:return`errored`;case`RUNNING`:case null:case void 0:default:return null}}function Re(e){if(!b.isAxiosError(e))return null;if(!e.response)return`unreachable`;let t=e.response.status;return t===404||t>=500?`unreachable`:null}function Y(e){let{conversationId:t,bashCommandId:n,enabled:r=!0}=e,a=h(),o=w(r?t??null:null),s=o.data,c=s?.conversation_url??null,l=s?.session_api_key??null,u=a.backend.kind===`cloud`,d=o.isFetched,f=null,p=!1;u&&d&&(s?f=Le(s.sandbox_status)??(s.conversation_url?null:`missing`):p=!0);let m=r&&!!n&&(u?!!c:!0)&&!f&&!p,g=i({queryKey:[...Ie,n,c,l,a.backend.id,a.orgId],queryFn:()=>Fe.listOutputs(c,l,n),enabled:m,staleTime:60*1e3,gcTime:300*1e3,retry:!1}),_=u?Re(g.error):null,v=f??_;return{data:g.data,error:_?null:g.error,isFetching:g.isFetching,isPending:g.isPending,isResolvingConversation:u&&o.isPending,conversationMissing:p,sandboxIssue:v}}var ze={missing:o.AUTOMATIONS$DETAIL$LOGS_SANDBOX_MISSING,paused:o.AUTOMATIONS$DETAIL$LOGS_SANDBOX_PAUSED,starting:o.AUTOMATIONS$DETAIL$LOGS_SANDBOX_STARTING,errored:o.AUTOMATIONS$DETAIL$LOGS_SANDBOX_ERROR,unreachable:o.AUTOMATIONS$DETAIL$LOGS_SANDBOX_UNREACHABLE};function X(e,t){return[...e].sort((e,t)=>{let n=e.timestamp.localeCompare(t.timestamp);return n===0?(e.order??0)-(t.order??0):n}).map(e=>e[t]??``).join(``)}function Be({conversationId:e,bashCommandId:t,isOpen:n,onClose:r}){let{t:i}=s(`openhands`),[a,c]=(0,R.useState)(`stdout`),{data:l,isFetching:u,isResolvingConversation:f,sandboxIssue:p,conversationMissing:m,error:h}=Y({conversationId:e,bashCommandId:t,enabled:n});(0,R.useEffect)(()=>{n&&c(`stdout`)},[n,t]),(0,R.useEffect)(()=>{if(!n)return;let e=e=>{e.key===`Escape`&&r()};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[n,r]);let{stdout:g,stderr:v}=(0,R.useMemo)(()=>l?{stdout:X(l,`stdout`),stderr:X(l,`stderr`)}:{stdout:``,stderr:``},[l]);if(!n)return null;let y=f||u&&!l,b=!t,x=a===`stdout`?g:v,S=`border-b-2 px-3 py-2 text-sm font-normal transition-colors focus:outline-none`,C=`border-[var(--oh-primary)] text-white`,w=`border-transparent text-muted hover:text-content`;return(0,z.jsxs)(`div`,{className:`fixed inset-0 z-50 flex items-center justify-center p-4`,role:`dialog`,"aria-modal":`true`,"aria-label":i(o.AUTOMATIONS$DETAIL$LOGS_TITLE),children:[(0,z.jsx)(`div`,{className:`absolute inset-0 bg-black/60`,onClick:r,onKeyDown:e=>{e.key===`Escape`&&r()},role:`presentation`}),(0,z.jsxs)(`div`,{className:`relative flex max-h-[80vh] w-full max-w-3xl flex-col rounded-xl border border-[var(--oh-border)] bg-[var(--oh-surface)] p-6`,children:[(0,z.jsx)(`button`,{type:`button`,onClick:r,className:`absolute right-4 top-4 text-muted hover:text-foreground`,"aria-label":i(o.AUTOMATIONS$CANCEL),children:(0,z.jsx)(O,{className:`size-5`})}),(0,z.jsx)(`h2`,{className:d(`pr-8`,_),children:i(o.AUTOMATIONS$DETAIL$LOGS_TITLE)}),(0,z.jsxs)(`div`,{role:`tablist`,"aria-label":i(o.AUTOMATIONS$DETAIL$LOGS_TITLE),className:`mt-4 flex gap-1 border-b border-[var(--oh-border)]`,children:[(0,z.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":a===`stdout`,"aria-controls":`run-logs-panel-stdout`,id:`run-logs-tab-stdout`,tabIndex:a===`stdout`?0:-1,onClick:()=>c(`stdout`),className:`${S} ${a===`stdout`?C:w}`,children:i(o.AUTOMATIONS$DETAIL$LOGS_TAB_OUTPUT)}),(0,z.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":a===`stderr`,"aria-controls":`run-logs-panel-stderr`,id:`run-logs-tab-stderr`,tabIndex:a===`stderr`?0:-1,onClick:()=>c(`stderr`),className:`${S} ${a===`stderr`?C:w}`,children:i(o.AUTOMATIONS$DETAIL$LOGS_TAB_ERROR)})]}),(0,z.jsxs)(`div`,{role:`tabpanel`,id:`run-logs-panel-${a}`,"aria-labelledby":`run-logs-tab-${a}`,className:`mt-3 min-h-[12rem] flex-1 overflow-auto rounded-lg border border-[var(--oh-border)] bg-black/40 p-4 font-mono text-xs`,children:[b&&(0,z.jsx)(`p`,{className:`text-muted italic`,children:i(o.AUTOMATIONS$DETAIL$LOGS_NO_COMMAND)}),!b&&m&&(0,z.jsx)(`p`,{className:`text-muted italic`,children:i(o.AUTOMATIONS$DETAIL$LOGS_CONVERSATION_MISSING)}),!b&&!m&&p&&(0,z.jsx)(`p`,{"data-testid":`run-logs-sandbox-issue-${p}`,className:`text-muted italic`,children:i(ze[p])}),!b&&!m&&!p&&y&&(0,z.jsx)(`p`,{className:`text-muted italic`,children:i(o.AUTOMATIONS$DETAIL$LOGS_LOADING)}),!b&&!m&&!p&&!y&&h&&!l&&(0,z.jsxs)(`p`,{className:`text-danger`,children:[i(o.AUTOMATIONS$DETAIL$LOGS_ERROR),`: `,String(h)]}),!y&&!p&&l&&(0,z.jsx)(`pre`,{"data-testid":`run-logs-output-${a}`,className:`whitespace-pre-wrap break-words ${a===`stderr`?`text-danger`:`text-content`}`,children:x.length>0?x:(0,z.jsx)(`span`,{className:`text-muted italic`,children:i(o.AUTOMATIONS$DETAIL$LOGS_EMPTY)})})]})]})]})}function Ve(e,t){return new Date(e).toLocaleDateString(t,{weekday:`long`,year:`numeric`,month:`long`,day:`numeric`,hour:`numeric`,minute:`2-digit`})}function He(e){if(!e)return!0;let t=new Date(e).getTime();return Number.isNaN(t)||t===0}function Ue(e){return`/conversations/${e}`}function We({run:e}){let{t,i18n:n}=s(`openhands`),r=!!e.conversation_id,i=!!e.bash_command_id,a=e.status===L.COMPLETED||e.status===L.FAILED,c=!r&&a,[l,u]=(0,R.useState)(!1),[d]=(0,R.useState)(()=>new Date().toISOString()),f=Ve(He(e.started_at)?d:e.started_at,n.language),p=i?(0,z.jsx)(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),e.preventDefault(),u(!0)},className:`rounded-md p-1 text-muted hover:bg-surface-raised hover:text-foreground focus:bg-surface-raised focus:outline-none`,"aria-label":t(o.AUTOMATIONS$DETAIL$LOGS_VIEW,{timestamp:f}),title:t(o.AUTOMATIONS$DETAIL$LOGS_VIEW_SHORT),children:(0,z.jsx)(C,{className:`size-4`})}):null,m=(0,z.jsxs)(z.Fragment,{children:[(0,z.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,z.jsx)(`span`,{className:`text-sm text-content`,children:f}),c&&(0,z.jsxs)(`span`,{className:`text-xs text-muted italic`,children:[`(`,t(o.AUTOMATIONS$DETAIL$NO_CONVERSATION),`)`]})]}),(0,z.jsxs)(`div`,{className:`flex items-center gap-2`,children:[p,(0,z.jsx)(Me,{status:e.status})]})]});return(0,z.jsxs)(z.Fragment,{children:[r&&e.conversation_id?(0,z.jsx)(`a`,{href:Ue(e.conversation_id),className:`flex items-center justify-between px-5 py-3 transition-colors cursor-pointer hover:bg-surface-raised focus:bg-surface-raised focus:outline-none`,"aria-label":`View conversation for run at ${f}`,children:m}):(0,z.jsx)(`div`,{className:`flex items-center justify-between px-5 py-3 cursor-default`,children:m}),i&&(0,z.jsx)(Be,{conversationId:e.conversation_id,bashCommandId:e.bash_command_id,isOpen:l,onClose:()=>u(!1)})]})}var Z=20;function Ge({automationId:e}){let{t}=s(`openhands`),[n,r]=(0,R.useState)(Z),{data:i,isLoading:a}=j({id:e,limit:n,offset:0}),c=i?i.total>i.runs.length:!1;return(0,z.jsxs)(`div`,{className:`rounded-2xl border border-[var(--oh-border)] bg-[var(--oh-surface)]`,children:[(0,z.jsxs)(`div`,{className:`flex items-center gap-2 border-b border-[var(--oh-border)] px-5 py-3`,children:[(0,z.jsx)(`span`,{className:`size-4 text-muted`,children:(0,z.jsx)(q,{className:`size-4`})}),(0,z.jsx)(`h3`,{className:`text-sm font-medium text-content`,children:t(o.AUTOMATIONS$DETAIL$ACTIVITY_LOG)})]}),a&&(0,z.jsx)(`div`,{className:`space-y-1 p-5`,children:Array.from({length:3}).map((e,t)=>(0,z.jsxs)(`div`,{className:`flex items-center justify-between py-3`,children:[(0,z.jsx)(`div`,{className:`h-5 w-64 animate-pulse rounded bg-surface-raised`}),(0,z.jsx)(`div`,{className:`h-6 w-24 animate-pulse rounded-full bg-surface-raised`})]},`skeleton-${t}`))}),!a&&i?.runs.length===0&&(0,z.jsx)(`p`,{className:`px-5 py-8 text-center text-sm text-muted`,children:t(o.AUTOMATIONS$DETAIL$NO_RUNS)}),!a&&i&&i.runs.length>0&&(0,z.jsxs)(`div`,{children:[i.runs.map((e,t)=>(0,z.jsx)(`div`,{className:t>0?`border-t border-[var(--oh-border)]`:``,children:(0,z.jsx)(We,{run:e})},e.id)),c&&(0,z.jsx)(`div`,{className:`border-t border-[var(--oh-border)] px-5 py-3`,children:(0,z.jsx)(`button`,{type:`button`,onClick:()=>r(e=>e+Z),className:`text-sm text-muted hover:text-foreground`,children:t(o.AUTOMATIONS$DETAIL$LOAD_MORE_RUNS)})})]})]})}function Q({className:e}){return(0,z.jsx)(`div`,{className:d(`animate-pulse rounded bg-surface-raised`,e)})}function $(){return(0,z.jsxs)(`div`,{className:`flex flex-col gap-4`,"data-testid":`detail-skeleton`,children:[(0,z.jsx)(Q,{className:`h-5 w-40`}),(0,z.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,z.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,z.jsx)(Q,{className:`h-6 w-48`}),(0,z.jsx)(Q,{className:`h-6 w-16 rounded-full`})]}),(0,z.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,z.jsx)(Q,{className:`h-6 w-11 rounded-full`}),(0,z.jsx)(Q,{className:`h-8 w-8`})]})]}),(0,z.jsx)(Q,{className:`h-5 w-96`}),(0,z.jsx)(Q,{className:`h-36 w-full rounded-2xl`}),(0,z.jsx)(Q,{className:`h-72 w-full rounded-2xl`}),(0,z.jsx)(Q,{className:`h-32 w-full rounded-2xl`}),(0,z.jsx)(Q,{className:`h-40 w-full rounded-2xl`})]})}function Ke(){let{t:e}=s(`openhands`);return(0,z.jsxs)(`div`,{className:`flex flex-col items-center justify-center py-20`,children:[(0,z.jsx)(M,{className:`size-12 text-muted`}),(0,z.jsx)(`p`,{className:`mt-4 text-sm font-medium text-content`,children:e(o.AUTOMATIONS$DETAIL$NOT_FOUND_TITLE)}),(0,z.jsx)(`p`,{className:`mt-2 text-sm text-muted`,children:e(o.AUTOMATIONS$DETAIL$NOT_FOUND_MESSAGE)}),(0,z.jsx)(`div`,{className:`mt-6`,children:(0,z.jsx)(B,{})})]})}var qe=n(function(){let{t:e}=s(`openhands`),{automationId:t}=r(),{navigate:n}=v(),[i,a]=(0,R.useState)(!1),[c,d]=(0,R.useState)(!1),{data:f,isLoading:p,refetch:m}=P(),g=f?.status===`ok`,_=h(),b=(0,R.useRef)(_.backend.id).current!==_.backend.id,{data:x,isLoading:S,isError:C,error:w,refetch:T}=de({id:t??``,enabled:g&&!b}),E=ee(),D=ue(),O=fe(),k=C&&y(w)&&w.response?.status===404;if(p)return(0,z.jsx)(`div`,{className:`min-h-full`,children:(0,z.jsx)(`div`,{className:`p-6 max-w-4xl mx-auto`,children:(0,z.jsx)($,{})})});if(!g)return(0,z.jsx)(`div`,{className:`min-h-full`,children:(0,z.jsx)(`div`,{className:`p-6 max-w-4xl mx-auto`,children:(0,z.jsx)(se,{onRetry:m})})});if(S)return(0,z.jsx)(`div`,{className:`min-h-full`,children:(0,z.jsx)(`div`,{className:`p-6 max-w-4xl mx-auto`,children:(0,z.jsx)($,{})})});if(k)return(0,z.jsx)(`div`,{className:`min-h-full`,children:(0,z.jsx)(`div`,{className:`p-6 max-w-4xl mx-auto`,children:(0,z.jsx)(Ke,{})})});if(C||!x)return(0,z.jsx)(`div`,{className:`min-h-full`,children:(0,z.jsx)(`div`,{className:`p-6 max-w-4xl mx-auto`,children:(0,z.jsx)(F,{onRetry:()=>T()})})});let A=()=>{E.mutate({id:x.id,enabled:!x.enabled})},j=()=>{D.mutate(x.id,{onSuccess:()=>{n?.(`/automations`)}})},M=()=>{O.mutate(x.id,{onSuccess:()=>{u(e(o.AUTOMATIONS$RUN_NOW_SUCCESS))},onError:t=>{l(y(t)?t.response?.data?.message||t.message||e(o.AUTOMATIONS$RUN_NOW_ERROR):t.message||e(o.AUTOMATIONS$RUN_NOW_ERROR))}})},N=_.backend.kind===`local`;return(0,z.jsx)(`div`,{className:`min-h-full`,children:(0,z.jsx)(`div`,{className:`p-6 max-w-4xl mx-auto`,children:(0,z.jsxs)(`div`,{className:`flex flex-col gap-4`,children:[(0,z.jsx)(B,{}),(0,z.jsx)(me,{automation:x,onToggle:A,onEdit:N?()=>d(!0):void 0,onDelete:()=>a(!0),onRunNow:M,isRunningNow:O.isPending}),x.prompt&&(0,z.jsx)(_e,{prompt:x.prompt}),(0,z.jsx)(Ce,{automation:x}),x.plugins&&x.plugins.length>0&&(0,z.jsx)(Ee,{plugins:x.plugins}),(0,z.jsx)(Oe,{createdAt:x.created_at,lastRunAt:x.last_triggered_at}),(0,z.jsx)(Ge,{automationId:x.id}),(0,z.jsx)(ie,{automationName:x.name,isOpen:i,onConfirm:j,onCancel:()=>a(!1)}),N&&(0,z.jsx)(le,{automation:x,isOpen:c,onClose:()=>d(!1)})]})})})});export{qe as default};