@openhands/agent-canvas 1.0.0-beta.8 → 1.0.0-rc.1

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 (382) 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-BAX8OU5C.js → acp-providers-DJr8DlNG.js} +1 -1
  6. package/build/assets/{acp-route-guard-HPk6TV-L.js → acp-route-guard-A__sWgbc.js} +1 -1
  7. package/build/assets/{active-backend-context-BSPE-W72.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-conversation-service.api-Cagoqq1V.js +5 -0
  10. package/build/assets/agent-settings-BXBaybB_.js +2 -0
  11. package/build/assets/{alert-banner-DFnn_lC6.js → alert-banner-NeUl1-PQ.js} +1 -1
  12. package/build/assets/analytics-consent-form-modal-DxkThW4K.js +1 -0
  13. package/build/assets/{api-key-entry-screen-myuWMqzW.js → api-key-entry-screen-ByXA4hXH.js} +1 -1
  14. package/build/assets/{app-settings-CCcX8ZEH.js → app-settings-C-U6jONZ.js} +1 -1
  15. package/build/assets/automation-detail-Dbmgt974.js +1 -0
  16. package/build/assets/automations-list-BLJzAd-p.js +1 -0
  17. package/build/assets/{back-nav-button-7dQJ2k3O.js → back-nav-button-DgkK0Ka6.js} +1 -1
  18. package/build/assets/{backend-form-modal-D3bDMO3C.js → backend-form-modal-CeB983Sj.js} +1 -1
  19. package/build/assets/{backend-synced-settings-badge-BkW5evM0.js → backend-synced-settings-badge-BktJcGgH.js} +1 -1
  20. package/build/assets/{base-modal-C2oy2EBG.js → base-modal-DZCNv0A4.js} +1 -1
  21. package/build/assets/{brand-button-DJ_S16rO.js → brand-button-LBFNic99.js} +1 -1
  22. package/build/assets/browser-D08Sp3ZY.js +5 -0
  23. package/build/assets/{browser-tab-dvSPdvkm.js → browser-tab-be3QvXg9.js} +1 -1
  24. package/build/assets/chat-send-button-5qz0zj6R.js +1 -0
  25. package/build/assets/{checkmark-Dus0b6jt.js → checkmark-Rmpruj7q.js} +1 -1
  26. package/build/assets/{chevron-left-small-_uvG7RVM.js → chevron-left-small-6nyFCWVQ.js} +1 -1
  27. package/build/assets/{circle-plus-check-toggle-DKS8MAVV.js → circle-plus-check-toggle-DquBwJ_6.js} +1 -1
  28. package/build/assets/{close-BU5iTc66.js → close-D_o3d8QM.js} +1 -1
  29. package/build/assets/{code-tag-BzyqOtPD.js → code-tag-DhsjDB-v.js} +1 -1
  30. package/build/assets/{combobox-caret-BJC7XJsz.js → combobox-caret-CO7eozIY.js} +1 -1
  31. package/build/assets/{condenser-settings-DCTulgLO.js → condenser-settings-BulzYEuW.js} +1 -1
  32. package/build/assets/{confirmation-modal-B5Ca6qFE.js → confirmation-modal-CMAtd9R0.js} +1 -1
  33. package/build/assets/{context-menu-list-item-7tAcm2c3.js → context-menu-list-item-D0swnhFt.js} +1 -1
  34. package/build/assets/conversation-BrjF2-Ky.js +1 -0
  35. package/build/assets/conversation-HgR_TTPE.js +19 -0
  36. package/build/assets/conversation-panel-BlRcO5AC.js +1 -0
  37. package/build/assets/conversation-service.api-B_Pdmwsa.js +1 -0
  38. package/build/assets/{conversation-tab-empty-state-CStQLPVW.js → conversation-tab-empty-state-DYjKsg_c.js} +1 -1
  39. package/build/assets/conversation-websocket-context-G95yfL81.js +3 -0
  40. package/build/assets/{copy-Chg-sFu3.js → copy-BM0RpLez.js} +1 -1
  41. package/build/assets/{custom-toast-handlers-ufGJ6_Rc.js → custom-toast-handlers-BohXx7uh.js} +1 -1
  42. package/build/assets/{declaration-CR6HMp29.js → declaration-DaUdB2Wg.js} +1 -1
  43. package/build/assets/{device-verify-C6mj28zv.js → device-verify-DiEJqpJb.js} +1 -1
  44. package/build/assets/dist-Bl-1K5Tv.js +1 -0
  45. package/build/assets/{dist-C3NfioQC.js → dist-xtCm0O6P.js} +1 -1
  46. package/build/assets/{dropdown-classes-BsVmxlNG.js → dropdown-classes-Vqz86I0R.js} +1 -1
  47. package/build/assets/{edit-automation-modal-DamwL0s0.js → edit-automation-modal-CNZgSSiH.js} +1 -1
  48. package/build/assets/{entry.client-Cn71WM8q.js → entry.client-BvKgdCQ9.js} +2 -2
  49. package/build/assets/{enum-filter-dropdown-5JeF2RLb.js → enum-filter-dropdown-DdFgk0EM.js} +1 -1
  50. package/build/assets/{environment-switch-overlay-Tf_BIfeR.js → environment-switch-overlay-CuBuZOaa.js} +1 -1
  51. package/build/assets/{extensions-hub-CUEmfvGy.js → extensions-hub-Dayqvv0n.js} +1 -1
  52. package/build/assets/{extensions-navigation-VQ-3umJ7.js → extensions-navigation-yFLAU06N.js} +1 -1
  53. package/build/assets/{file-BTY6Gyy9.js → file-DwHCkWZT.js} +1 -1
  54. package/build/assets/files-tab-CMredyYX.js +1 -0
  55. package/build/assets/{folder-D1T2W1cj.js → folder-2h1hR1Qb.js} +1 -1
  56. package/build/assets/git-control-bar-branch-button-D8blTNXh.js +27 -0
  57. package/build/assets/{globe-Bzj_0oXT.js → globe-qFjFNG6J.js} +1 -1
  58. package/build/assets/home-CWw845Rz.js +1 -0
  59. package/build/assets/{i18n-DET2iOyh.js → i18n-zDndR1Ne.js} +1 -1
  60. package/build/assets/install-server-modal-D8Q0xZcN.js +1 -0
  61. package/build/assets/{launch-DGghLfGx.js → launch-I00QV8YT.js} +1 -1
  62. package/build/assets/{lesson-plan-duSsqWVs.js → lesson-plan-C18uB_56.js} +1 -1
  63. package/build/assets/{link-external-DGxVm4Ps.js → link-external-DtcdPFbw.js} +1 -1
  64. package/build/assets/llm-settings-CAnFYAEG.js +1 -0
  65. package/build/assets/llm-settings-DotqpmCF.js +1 -0
  66. package/build/assets/{loading-spinner-5GT9q1xy.js → loading-spinner-DNwR4--Z.js} +1 -1
  67. package/build/assets/{manage-backends-modal-CRMwyU0t.js → manage-backends-modal-Ceo_SOcf.js} +1 -1
  68. package/build/assets/manifest-61ec2d68.js +1 -0
  69. package/build/assets/{markdown-renderer-B3IAVfv4.js → markdown-renderer-D6B-u2nM.js} +1 -1
  70. package/build/assets/{mcp-CfDRAmPn.js → mcp-EvrLVTla.js} +1 -1
  71. package/build/assets/messages-Bz9TWjlh.js +36 -0
  72. package/build/assets/modal-backdrop-BDqI1zBV.js +1 -0
  73. package/build/assets/{modal-body-aoa2fx5W.js → modal-body-CCLCqX1J.js} +1 -1
  74. package/build/assets/{modal-classes-6YqcqA6y.js → modal-classes-DwTdT3IK.js} +1 -1
  75. package/build/assets/{modal-close-button-CtWOUMmw.js → modal-close-button-gQgKqUf-.js} +1 -1
  76. package/build/assets/model-selector-CZOi4V7r.js +1 -0
  77. package/build/assets/{mutation-D0OogFCz.js → mutation-CaJwPR9O.js} +1 -1
  78. package/build/assets/{navigation-context-BdKYH32C.js → navigation-context-aNGUUtdq.js} +1 -1
  79. package/build/assets/{navigation-link-U4vY9i_C.js → navigation-link-CYkF2y3K.js} +1 -1
  80. package/build/assets/onboarding-CPCKYvFh.js +1 -0
  81. package/build/assets/{openhands-logo-CCo0wJZX.js → openhands-logo-CHmtDV-t.js} +1 -1
  82. package/build/assets/{organization-service.api-BeuMC9QL.js → organization-service.api-Dn74hBTH.js} +1 -1
  83. package/build/assets/path-utils-BjxzIGLp.js +1 -0
  84. package/build/assets/{plan-components-CRDMQzsS.js → plan-components--aLlpASH.js} +1 -1
  85. package/build/assets/{planner-tab-Dte6Vzza.js → planner-tab-B-5EeCEm.js} +1 -1
  86. package/build/assets/{providers-eUyo6pgr.js → providers-DknP6O2g.js} +1 -1
  87. package/build/assets/{proxy-BqDMnUY-.js → proxy-sRh0WKI7.js} +1 -1
  88. package/build/assets/{query-client-config-CRnGSujB.js → query-client-config-CWWGQWvw.js} +1 -1
  89. package/build/assets/{recommended-automations-launcher-D5ADbXao.js → recommended-automations-launcher-BIul0osB.js} +3 -3
  90. package/build/assets/{root-Z2VHU4R3.css → root-CN7qsvxg.css} +1 -1
  91. package/build/assets/root-CklXEh3W.js +2 -0
  92. package/build/assets/root-layout-BCA_X8XL.js +2 -0
  93. package/build/assets/{sdk-section-page-CRCRY3PG.js → sdk-section-page-VmtJWH3A.js} +1 -1
  94. package/build/assets/{sdk-settings-schema-CLmJ9sho.js → sdk-settings-schema-DFievvEK.js} +1 -1
  95. package/build/assets/{search-SuJctqNJ.js → search-BeVRXvX7.js} +1 -1
  96. package/build/assets/{secrets-service-B9AFn9OE.js → secrets-service-DVtlLWY8.js} +1 -1
  97. package/build/assets/{secrets-settings-0UrKMS60.js → secrets-settings-BLMvCkKm.js} +1 -1
  98. package/build/assets/{settings-6t6LGW04.js → settings-CXvJUx_j.js} +1 -1
  99. package/build/assets/{settings-dropdown-input-BtoovFre.js → settings-dropdown-input-DA_pzHWE.js} +1 -1
  100. package/build/assets/{settings-gear-Dd8K2_8B.js → settings-gear-aNebYlCy.js} +1 -1
  101. package/build/assets/{settings-index-CR6Ou73o.js → settings-index-CycvkOoq.js} +1 -1
  102. package/build/assets/{settings-input-CehsXnb3.js → settings-input-8y5p4kze.js} +1 -1
  103. package/build/assets/{settings-list-classes-E3v_f6QG.js → settings-list-classes-Qk7zl0Wu.js} +1 -1
  104. package/build/assets/settings-modal-DdntdOGP.js +1 -0
  105. package/build/assets/{settings-section-header-context-DewwJ0-F.js → settings-section-header-context-B77tsYlx.js} +1 -1
  106. package/build/assets/{settings-service.api-DwtyDeGh.js → settings-service.api-DxIEtvx6.js} +1 -1
  107. package/build/assets/{settings-switch-BiBuS3xa.js → settings-switch-ba4DuiNO.js} +1 -1
  108. package/build/assets/{settings-utils-DY04tWG1.js → settings-utils-BxzHqLmZ.js} +1 -1
  109. package/build/assets/{shared-conversation-BzccsVej.js → shared-conversation-x41nZQi7.js} +1 -1
  110. package/build/assets/{sidebar-mobile-menu-toggle-DGlRg6jG.js → sidebar-mobile-menu-toggle-C0mmabKj.js} +1 -1
  111. package/build/assets/{sidebar-nav-link-dgVb8Fpy.js → sidebar-nav-link-BsYdDFfb.js} +1 -1
  112. package/build/assets/{skill-card-pill-row-BW9qvhoK.js → skill-card-pill-row-BhUlGcYB.js} +1 -1
  113. package/build/assets/{skills-0GRKX5Xj.js → skills-TYjOUQ2d.js} +1 -1
  114. package/build/assets/{skills-plugins-DctDrZ8Y.js → skills-plugins-D0pdqgKa.js} +1 -1
  115. package/build/assets/{skills-settings-rvxImDj_.js → skills-settings-VqKTkmVl.js} +2 -2
  116. package/build/assets/{styled-tooltip-hdfMXPQC.js → styled-tooltip-TCp7svY3.js} +1 -1
  117. package/build/assets/{switch-skeleton-DSKqSx2A.js → switch-skeleton-cKrdaYGj.js} +1 -1
  118. package/build/assets/{task-list-tab-DT6_zfUs.js → task-list-tab-BiizRsY3.js} +1 -1
  119. package/build/assets/telemetry-fQFd-8V3.js +2 -0
  120. package/build/assets/{terminal-CPYWdo4j.js → terminal-BSYITdM0.js} +1 -1
  121. package/build/assets/{terminal-KldRPIRT.js → terminal-CpgZx6go.js} +1 -1
  122. package/build/assets/{toggle-switch-T2v6sJ6l.js → toggle-switch-CUgOZqZu.js} +1 -1
  123. package/build/assets/{typography-BDgnT7Yp.js → typography-Bvw0IxaN.js} +1 -1
  124. package/build/assets/{u-check-circle-half-steSK_JB.js → u-check-circle-half-DjpjzWu3.js} +1 -1
  125. package/build/assets/{u-check-circle-DOauqQKb.js → u-check-circle-u9QiS4Fr.js} +1 -1
  126. package/build/assets/{u-circuit-x3ExjBbU.js → u-circuit-DlBlOwx9.js} +1 -1
  127. package/build/assets/{u-edit-BbrptMCa.js → u-edit-BIYzjs3v.js} +1 -1
  128. package/build/assets/{use-active-conversation-sPgfSkql.js → use-active-conversation-q1wT8LI5.js} +1 -1
  129. package/build/assets/{use-agent-settings-schema-B66kGIi_.js → use-agent-settings-schema-Yxf7KGyG.js} +1 -1
  130. package/build/assets/{use-agent-state-Dp3pD1h3.js → use-agent-state-CCHlVqvY.js} +1 -1
  131. package/build/assets/{use-cloud-current-user-id-ClKFPjFz.js → use-cloud-current-user-id-BAKf91Zx.js} +1 -1
  132. package/build/assets/{use-config-C9pvb0Sm.js → use-config-DwfigQ_Y.js} +1 -1
  133. package/build/assets/use-create-conversation-BEzddjXn.js +1 -0
  134. package/build/assets/{use-get-secrets-oyC7PFRz.js → use-get-secrets-BlO1BfUo.js} +1 -1
  135. package/build/assets/{use-handle-plan-click-DP6Rs-YP.js → use-handle-plan-click-Bfl0zIBr.js} +1 -1
  136. package/build/assets/use-is-authed-hHndEep7.js +1 -0
  137. package/build/assets/{use-launch-skill-in-chat-sQNEOLGD.js → use-launch-skill-in-chat-3ydwpi_M.js} +1 -1
  138. package/build/assets/use-llm-profiles-E-jjZMZw.js +1 -0
  139. package/build/assets/use-runtime-is-ready-DBWzvAmc.js +1 -0
  140. package/build/assets/use-save-settings-rE9aA29R.js +1 -0
  141. package/build/assets/{use-settings-DeO7nvpM.js → use-settings-BPTbE7lg.js} +1 -1
  142. package/build/assets/{use-settings-nav-items-BGMFn25b.js → use-settings-nav-items-C7MOWj09.js} +1 -1
  143. package/build/assets/{use-skills-DWIK3l3a.js → use-skills-QhoaIYGF.js} +1 -1
  144. package/build/assets/{use-task-list-CsT10CBb.js → use-task-list-YMkSzdDv.js} +1 -1
  145. package/build/assets/use-tracking-DQYdZpxi.js +1 -0
  146. package/build/assets/{use-unified-vscode-url-DXPtB317.js → use-unified-vscode-url-DFtNIC1Q.js} +1 -1
  147. package/build/assets/{use-user-conversation-DJen4YIP.js → use-user-conversation-BRAseenw.js} +1 -1
  148. package/build/assets/{useMutation-GSSKKebK.js → useMutation-DDo48A8t.js} +1 -1
  149. package/build/assets/{useTranslation-B6voJV4y.js → useTranslation-CEcjrme-.js} +1 -1
  150. package/build/assets/{utils-DCVfKFRt.js → utils-CdgBzLA7.js} +1 -1
  151. package/build/assets/{vendor~browser-BrOJLj3y.js → vendor~browser-DWk6fNtJ.js} +1 -1
  152. package/build/assets/{vendor~browser-tab-BxhTtM9_.js → vendor~browser-tab-NZdVoI2Z.js} +1 -1
  153. package/build/assets/{vendor~conversation-panel~conversation-C9o-K1hW.js → vendor~conversation-panel~conversation-gp03cWZW.js} +1 -1
  154. package/build/assets/{vendor~conversation-panel~conversation~index-RXYdJYxU.js → vendor~conversation-panel~conversation~index-BZ5C6Xpz.js} +1 -1
  155. 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
  156. package/build/assets/{vendor~files-tab-BtkpAiMX.js → vendor~files-tab-Buz36Y-q.js} +1 -1
  157. package/build/assets/{vendor~home~conversation-panel~conversation-PK1-gtXU.js → vendor~home~conversation-panel~conversation-DG0H5SkJ.js} +2 -2
  158. 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
  159. 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
  160. 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
  161. 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
  162. package/build/assets/{vendor~launch-BXgl67Re.js → vendor~launch-DXL78kBf.js} +1 -1
  163. 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
  164. package/build/assets/vendor~root-layout~home~conversation-panel~conversation-DkwcKRtv.js +1 -0
  165. 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
  166. 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
  167. 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
  168. 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
  169. package/build/assets/vendor~root-layout~home~mcp~automations-list-BnIlGhjl.js +1 -0
  170. package/build/assets/{vendor~home~mcp~automations-list-BgV86Sti.js → vendor~root-layout~home~mcp~automations-list-cNHi83v_.js} +1 -1
  171. 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
  172. 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
  173. 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
  174. package/build/assets/{verification-settings-C_zHuDx9.js → verification-settings-CIqtxWat.js} +1 -1
  175. package/build/assets/{vscode-tab-DH9x7xXS.js → vscode-tab-DEt72yJX.js} +1 -1
  176. package/build/assets/{waiting-for-runtime-message-CdK3btDZ.js → waiting-for-runtime-message-DSjJfeoj.js} +1 -1
  177. package/build/assets/{x-mark-BrkSPIiT.js → x-mark-DsJ9tDD0.js} +1 -1
  178. package/build/index.html +4 -4
  179. package/build/locales/ar/openhands.json +4 -2
  180. package/build/locales/ca/openhands.json +4 -2
  181. package/build/locales/de/openhands.json +4 -2
  182. package/build/locales/en/openhands.json +4 -2
  183. package/build/locales/es/openhands.json +4 -2
  184. package/build/locales/fr/openhands.json +4 -2
  185. package/build/locales/it/openhands.json +4 -2
  186. package/build/locales/ja/openhands.json +4 -2
  187. package/build/locales/ko-KR/openhands.json +4 -2
  188. package/build/locales/no/openhands.json +4 -2
  189. package/build/locales/pt/openhands.json +4 -2
  190. package/build/locales/tr/openhands.json +4 -2
  191. package/build/locales/uk/openhands.json +4 -2
  192. package/build/locales/zh-CN/openhands.json +4 -2
  193. package/build/locales/zh-TW/openhands.json +4 -2
  194. package/config/defaults.json +1 -1
  195. package/dist/api/agent-server-home.cjs +2 -0
  196. package/dist/api/agent-server-home.cjs.map +1 -0
  197. package/dist/api/agent-server-home.d.ts +34 -0
  198. package/dist/api/agent-server-home.js +33 -0
  199. package/dist/api/agent-server-home.js.map +1 -0
  200. package/dist/api/config-service/config-service.api.cjs +1 -1
  201. package/dist/api/config-service/config-service.api.cjs.map +1 -1
  202. package/dist/api/config-service/config-service.api.d.ts +12 -0
  203. package/dist/api/config-service/config-service.api.js +55 -18
  204. package/dist/api/config-service/config-service.api.js.map +1 -1
  205. package/dist/api/conversation-file-upload.api.cjs +1 -1
  206. package/dist/api/conversation-file-upload.api.cjs.map +1 -1
  207. package/dist/api/conversation-file-upload.api.js +4 -1
  208. package/dist/api/conversation-file-upload.api.js.map +1 -1
  209. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs +1 -1
  210. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs.map +1 -1
  211. package/dist/api/conversation-service/agent-server-conversation-service.api.js +101 -100
  212. package/dist/api/conversation-service/agent-server-conversation-service.api.js.map +1 -1
  213. package/dist/api/option-service/option-service.api.cjs.map +1 -1
  214. package/dist/api/option-service/option-service.api.js.map +1 -1
  215. package/dist/api/workspace-upload-path.cjs +1 -1
  216. package/dist/api/workspace-upload-path.cjs.map +1 -1
  217. package/dist/api/workspace-upload-path.d.ts +44 -2
  218. package/dist/api/workspace-upload-path.js +16 -14
  219. package/dist/api/workspace-upload-path.js.map +1 -1
  220. package/dist/components/features/automations/recommended-automations-launcher.d.ts +3 -1
  221. package/dist/components/features/automations/recommended-automations-section.d.ts +3 -1
  222. package/dist/components/features/backends/backend-form-modal.cjs +1 -1
  223. package/dist/components/features/backends/backend-form-modal.cjs.map +1 -1
  224. package/dist/components/features/backends/backend-form-modal.d.ts +7 -1
  225. package/dist/components/features/backends/backend-form-modal.js +94 -91
  226. package/dist/components/features/backends/backend-form-modal.js.map +1 -1
  227. package/dist/components/features/chat/chat-interface.cjs +2 -2
  228. package/dist/components/features/chat/chat-interface.cjs.map +1 -1
  229. package/dist/components/features/chat/chat-interface.js +66 -66
  230. package/dist/components/features/chat/chat-interface.js.map +1 -1
  231. package/dist/components/features/chat/confirmation-mode-enabled.cjs +1 -1
  232. package/dist/components/features/chat/confirmation-mode-enabled.js +4 -4
  233. package/dist/components/features/chat/switch-profile-button.cjs +1 -1
  234. package/dist/components/features/chat/switch-profile-button.js +3 -3
  235. package/dist/components/features/conversation-panel/conversation-card/conversation-card.cjs +1 -1
  236. package/dist/components/features/conversation-panel/conversation-card/conversation-card.cjs.map +1 -1
  237. package/dist/components/features/conversation-panel/conversation-card/conversation-card.js +5 -5
  238. package/dist/components/features/conversation-panel/conversation-card/conversation-card.js.map +1 -1
  239. package/dist/components/features/onboarding/index.d.ts +1 -0
  240. package/dist/components/features/onboarding/onboarding-host.d.ts +3 -1
  241. package/dist/components/features/onboarding/onboarding-modal.d.ts +7 -3
  242. package/dist/components/features/onboarding/onboarding-preview.d.ts +4 -0
  243. package/dist/components/features/onboarding/steps/say-hello-step.d.ts +3 -1
  244. package/dist/components/features/settings/llm-profiles/llm-settings-local-view.cjs +1 -1
  245. package/dist/components/features/settings/llm-profiles/llm-settings-local-view.js +1 -1
  246. package/dist/components/features/settings/sdk-settings/sdk-section-page.cjs +1 -1
  247. package/dist/components/features/settings/sdk-settings/sdk-section-page.cjs.map +1 -1
  248. package/dist/components/features/settings/sdk-settings/sdk-section-page.d.ts +3 -1
  249. package/dist/components/features/settings/sdk-settings/sdk-section-page.js +56 -56
  250. package/dist/components/features/settings/sdk-settings/sdk-section-page.js.map +1 -1
  251. package/dist/components/features/skills/extensions-navigation.cjs +1 -1
  252. package/dist/components/features/skills/extensions-navigation.js +7 -7
  253. package/dist/components/shared/modals/modal-backdrop.cjs +1 -1
  254. package/dist/components/shared/modals/modal-backdrop.cjs.map +1 -1
  255. package/dist/components/shared/modals/modal-backdrop.d.ts +3 -1
  256. package/dist/components/shared/modals/modal-backdrop.js +3 -3
  257. package/dist/components/shared/modals/modal-backdrop.js.map +1 -1
  258. package/dist/components/shared/modals/settings/settings-form.cjs +1 -1
  259. package/dist/components/shared/modals/settings/settings-form.cjs.map +1 -1
  260. package/dist/components/shared/modals/settings/settings-form.js +7 -7
  261. package/dist/components/shared/modals/settings/settings-form.js.map +1 -1
  262. package/dist/hooks/chat/use-model-interceptor.cjs +1 -1
  263. package/dist/hooks/chat/use-model-interceptor.js +4 -4
  264. package/dist/hooks/mutation/use-save-settings.cjs +1 -1
  265. package/dist/hooks/mutation/use-save-settings.cjs.map +1 -1
  266. package/dist/hooks/mutation/use-save-settings.js +13 -14
  267. package/dist/hooks/mutation/use-save-settings.js.map +1 -1
  268. package/dist/hooks/query/use-llm-profiles.cjs +1 -1
  269. package/dist/hooks/query/use-llm-profiles.js +5 -5
  270. package/dist/hooks/query/use-verified-models.cjs +1 -1
  271. package/dist/hooks/query/use-verified-models.cjs.map +1 -1
  272. package/dist/hooks/query/use-verified-models.js +7 -6
  273. package/dist/hooks/query/use-verified-models.js.map +1 -1
  274. package/dist/hooks/use-download-conversation.cjs +1 -1
  275. package/dist/hooks/use-download-conversation.cjs.map +1 -1
  276. package/dist/hooks/use-download-conversation.js +4 -4
  277. package/dist/hooks/use-download-conversation.js.map +1 -1
  278. package/dist/hooks/use-tracking.cjs +1 -1
  279. package/dist/hooks/use-tracking.cjs.map +1 -1
  280. package/dist/hooks/use-tracking.d.ts +31 -0
  281. package/dist/hooks/use-tracking.js +51 -14
  282. package/dist/hooks/use-tracking.js.map +1 -1
  283. package/dist/i18n/declaration.cjs +1 -1
  284. package/dist/i18n/declaration.cjs.map +1 -1
  285. package/dist/i18n/declaration.d.ts +2 -0
  286. package/dist/i18n/declaration.js +1 -1
  287. package/dist/i18n/declaration.js.map +1 -1
  288. package/dist/i18n/translation.cjs +1 -1
  289. package/dist/i18n/translation.cjs.map +1 -1
  290. package/dist/i18n/translation.js +64 -30
  291. package/dist/i18n/translation.js.map +1 -1
  292. package/dist/locales/ar/openhands.json +4 -2
  293. package/dist/locales/ca/openhands.json +4 -2
  294. package/dist/locales/de/openhands.json +4 -2
  295. package/dist/locales/en/openhands.json +4 -2
  296. package/dist/locales/es/openhands.json +4 -2
  297. package/dist/locales/fr/openhands.json +4 -2
  298. package/dist/locales/it/openhands.json +4 -2
  299. package/dist/locales/ja/openhands.json +4 -2
  300. package/dist/locales/ko-KR/openhands.json +4 -2
  301. package/dist/locales/no/openhands.json +4 -2
  302. package/dist/locales/pt/openhands.json +4 -2
  303. package/dist/locales/tr/openhands.json +4 -2
  304. package/dist/locales/uk/openhands.json +4 -2
  305. package/dist/locales/zh-CN/openhands.json +4 -2
  306. package/dist/locales/zh-TW/openhands.json +4 -2
  307. package/dist/package.cjs +1 -1
  308. package/dist/package.cjs.map +1 -1
  309. package/dist/package.js +1 -1
  310. package/dist/package.js.map +1 -1
  311. package/dist/routes/llm-settings.cjs +1 -1
  312. package/dist/routes/llm-settings.cjs.map +1 -1
  313. package/dist/routes/llm-settings.d.ts +3 -1
  314. package/dist/routes/llm-settings.js +17 -16
  315. package/dist/routes/llm-settings.js.map +1 -1
  316. package/package.json +1 -1
  317. package/scripts/dev-static.mjs +0 -2
  318. package/scripts/dev-with-automation.mjs +0 -2
  319. package/scripts/static-server.mjs +13 -3
  320. package/build/assets/add-backend-modal-mXKmfMI2.js +0 -1
  321. package/build/assets/agent-server-conversation-service.api-B9TUYJon.js +0 -5
  322. package/build/assets/agent-settings-g3F623RJ.js +0 -2
  323. package/build/assets/analytics-consent-form-modal-BQCNeNVt.js +0 -1
  324. package/build/assets/automation-detail-BDHLHSJd.js +0 -1
  325. package/build/assets/automations-list-CiNtQhq_.js +0 -1
  326. package/build/assets/browser-CGM-k-sH.js +0 -5
  327. package/build/assets/conversation-BKhikfYl.js +0 -1
  328. package/build/assets/conversation-DTn8jN8L.js +0 -19
  329. package/build/assets/conversation-panel-DfHR42mG.js +0 -1
  330. package/build/assets/conversation-service.api-B6CkzaKD.js +0 -1
  331. package/build/assets/conversation-websocket-context-DShEuLjh.js +0 -3
  332. package/build/assets/dist-DNeWJ2bh.js +0 -1
  333. package/build/assets/ellipsis-button-Vh5MvRZa.js +0 -1
  334. package/build/assets/files-tab-C47fQEeL.js +0 -1
  335. package/build/assets/git-branch-DQS2nMK4.js +0 -1
  336. package/build/assets/git-control-bar-branch-button-BT0aWH-o.js +0 -27
  337. package/build/assets/git-provider-icon-Pi-Cxpgv.js +0 -1
  338. package/build/assets/home-C3k6sFvB.js +0 -1
  339. package/build/assets/install-server-modal-6fuq-TU6.js +0 -1
  340. package/build/assets/llm-settings-BKraGtOu.js +0 -1
  341. package/build/assets/llm-settings-DRQTgOF1.js +0 -1
  342. package/build/assets/manage-workspaces-modal-BYmGD1W7.js +0 -1
  343. package/build/assets/manifest-99b06a11.js +0 -1
  344. package/build/assets/messages-Ba1vaw6t.js +0 -36
  345. package/build/assets/modal-backdrop-RfNCrSpK.js +0 -1
  346. package/build/assets/model-selector-DcztJSxT.js +0 -1
  347. package/build/assets/path-utils-z12iCrQO.js +0 -1
  348. package/build/assets/root-BmhaEJJ8.js +0 -2
  349. package/build/assets/root-layout-CNggm0d8.js +0 -2
  350. package/build/assets/settings-modal-T_Yk1Zfo.js +0 -1
  351. package/build/assets/use-create-conversation-B-lwTnfE.js +0 -1
  352. package/build/assets/use-is-authed-dw2026rR.js +0 -1
  353. package/build/assets/use-is-creating-conversation-DX2qSlfL.js +0 -1
  354. package/build/assets/use-llm-profiles-Bh5JqZUZ.js +0 -1
  355. package/build/assets/use-runtime-is-ready-BakOUVU-.js +0 -1
  356. package/build/assets/use-save-settings-uXXkqvD7.js +0 -1
  357. package/build/assets/vendor~home~mcp~automations-list-CZSK-lT2.js +0 -1
  358. package/build/assets/vendor~root-layout~home~conversation-panel~conversation-B5WNMnt4.js +0 -1
  359. /package/build/assets/{automation-XDPAjiZi.js → automation-DJ_3GeXD.js} +0 -0
  360. /package/build/assets/{browser-store-DAsixKdU.js → browser-store-JRrcGdlk.js} +0 -0
  361. /package/build/assets/{check-CYxAHs85.js → check-CZhEL6rP.js} +0 -0
  362. /package/build/assets/{chevron-down-Bnmd5iG-.js → chevron-down-KhWYEjeW.js} +0 -0
  363. /package/build/assets/{color-themes-B9pm9c-R.js → color-themes-0biOprdo.js} +0 -0
  364. /package/build/assets/{command-store-CE1weJy8.js → command-store-UzKGSUC2.js} +0 -0
  365. /package/build/assets/{files-tab-store-m0ARqX_E.js → files-tab-store-DLU28g8C.js} +0 -0
  366. /package/build/assets/{iconBase-DE30Zj_-.js → iconBase-BVhFI-0E.js} +0 -0
  367. /package/build/assets/{map-provider-BJ_8KZKU.js → map-provider-C3Z5Dx2J.js} +0 -0
  368. /package/build/assets/{sdk-settings-field-metadata-DQiaIBie.js → sdk-settings-field-metadata-C6KMD-jZ.js} +0 -0
  369. /package/build/assets/{settings-like-page-layout-classes-D7YjdTd0.js → settings-like-page-layout-classes-DNg2vKSM.js} +0 -0
  370. /package/build/assets/{use-breakpoint-DF_RiQ6s.js → use-breakpoint-DpxHDmuH.js} +0 -0
  371. /package/build/assets/{use-event-store-BomO7ywK.js → use-event-store-Cxqc45Sw.js} +0 -0
  372. /package/build/assets/{vendor~browser-DisFGEp9.js → vendor~browser-BDNLFng6.js} +0 -0
  373. /package/build/assets/{vendor~conversation-panel~conversation~alert-banner-w-I2sY6c.js → vendor~conversation-panel~conversation~alert-banner-D_hRW_zc.js} +0 -0
  374. /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
  375. /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
  376. /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
  377. /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
  378. /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
  379. /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
  380. /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
  381. /package/build/assets/{vendor~terminal-DZaJIY8A.js → vendor~terminal-0ObOedYm.js} +0 -0
  382. /package/build/assets/{vscode-url-helper-Cwy1A62q.js → vscode-url-helper-BMq8JBhB.js} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-card.js","names":[],"sources":["../../../../../src/components/features/conversation-panel/conversation-card/conversation-card.tsx"],"sourcesContent":["import React from \"react\";\nimport { usePostHog } from \"posthog-js/react\";\nimport { cn } from \"#/utils/utils\";\nimport { transformVSCodeUrl } from \"#/utils/vscode-url-helper\";\nimport ConversationService from \"#/api/conversation-service/conversation-service.api\";\nimport { ExecutionStatus } from \"#/types/agent-server/core/base/common\";\nimport { SandboxStatus } from \"#/api/conversation-service/agent-server-conversation-service.types\";\nimport { RepositorySelection } from \"#/api/open-hands.types\";\nimport { formatTimeDelta } from \"#/utils/format-time-delta\";\nimport { ConversationCardHeader } from \"./conversation-card-header\";\nimport { ConversationCardActions } from \"./conversation-card-actions\";\nimport { ConversationCardFooter } from \"./conversation-card-footer\";\nimport { ConversationStatusBadges } from \"./conversation-status-badges\";\nimport { useDownloadConversation } from \"#/hooks/use-download-conversation\";\n\ninterface ConversationCardProps {\n onClick?: () => void;\n onDelete?: () => void;\n onStop?: () => void;\n onChangeTitle?: (title: string) => void;\n showOptions?: boolean;\n title: string;\n selectedRepository: RepositorySelection | null;\n lastUpdatedAt: string;\n createdAt?: string;\n executionStatus?: ExecutionStatus | null;\n sandboxStatus?: SandboxStatus | null;\n conversationId?: string;\n contextMenuOpen?: boolean;\n onContextMenuToggle?: (isOpen: boolean) => void;\n isActive?: boolean;\n workspaceWorkingDir?: string | null;\n showRepositoryMetadata?: boolean;\n llmModel?: string | null;\n showLlmProfiles?: boolean;\n agentKind?: \"openhands\" | \"acp\" | null;\n acpServer?: string | null;\n}\n\nexport function ConversationCard({\n onClick,\n onDelete,\n onStop,\n onChangeTitle,\n showOptions,\n title,\n selectedRepository,\n lastUpdatedAt,\n createdAt,\n conversationId,\n executionStatus,\n sandboxStatus,\n contextMenuOpen = false,\n onContextMenuToggle,\n isActive = false,\n workspaceWorkingDir,\n showRepositoryMetadata = true,\n llmModel = null,\n showLlmProfiles = false,\n agentKind = null,\n acpServer = null,\n}: ConversationCardProps) {\n const posthog = usePostHog();\n const [titleMode, setTitleMode] = React.useState<\"view\" | \"edit\">(\"view\");\n const { mutateAsync: downloadConversation } = useDownloadConversation();\n\n const onTitleSave = (newTitle: string) => {\n if (newTitle !== \"\" && newTitle !== title) {\n onChangeTitle?.(newTitle);\n }\n setTitleMode(\"view\");\n };\n\n const handleDelete = (event: React.MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n event.stopPropagation();\n onDelete?.();\n onContextMenuToggle?.(false);\n };\n\n const handleStop = (event: React.MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n event.stopPropagation();\n onStop?.();\n onContextMenuToggle?.(false);\n };\n\n const handleEdit = (event: React.MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n event.stopPropagation();\n setTitleMode(\"edit\");\n onContextMenuToggle?.(false);\n };\n\n const handleDownloadViaVSCode = async (\n event: React.MouseEvent<HTMLButtonElement>,\n ) => {\n event.preventDefault();\n event.stopPropagation();\n posthog.capture(\"download_via_vscode_button_clicked\");\n\n // Fetch the VS Code URL from the API\n if (conversationId) {\n try {\n const data = await ConversationService.getVSCodeUrl(conversationId);\n if (data.vscode_url) {\n const transformedUrl = transformVSCodeUrl(data.vscode_url);\n if (transformedUrl) {\n window.open(transformedUrl, \"_blank\");\n }\n }\n // VS Code URL not available\n } catch {\n // Failed to fetch VS Code URL\n }\n }\n\n onContextMenuToggle?.(false);\n };\n\n const handleDownloadConversation = async (\n event: React.MouseEvent<HTMLButtonElement>,\n ) => {\n event.preventDefault();\n event.stopPropagation();\n\n if (conversationId) {\n await downloadConversation(conversationId);\n }\n onContextMenuToggle?.(false);\n };\n\n const hasContextMenu = !!(onDelete || onChangeTitle || showOptions);\n const shouldRenderFooter =\n showRepositoryMetadata ||\n (showLlmProfiles && (agentKind === \"acp\" || !!llmModel));\n\n return (\n <div\n data-testid=\"conversation-card\"\n data-context-menu-open={contextMenuOpen.toString()}\n data-active={isActive ? \"true\" : \"false\"}\n onClick={onClick}\n className={cn(\n \"group relative h-auto w-full cursor-pointer rounded-md py-1 pl-2 pr-1 transition-colors\",\n \"data-[context-menu-open=false]:hover:bg-[var(--oh-surface)]\",\n \"data-[active=true]:bg-[var(--oh-surface)]\",\n )}\n >\n <div className=\"flex items-center w-full min-w-0\">\n <div className=\"flex items-center gap-2 flex-1 min-w-0 overflow-hidden\">\n <ConversationCardHeader\n title={title}\n titleMode={titleMode}\n onTitleSave={onTitleSave}\n executionStatus={executionStatus}\n sandboxStatus={sandboxStatus}\n />\n {sandboxStatus === \"ERROR\" && <ConversationStatusBadges />}\n </div>\n\n <div className=\"relative ml-auto pl-2 flex items-center justify-end shrink-0\">\n {(createdAt ?? lastUpdatedAt) && (\n <p\n className={cn(\n \"text-xs text-[var(--oh-muted)] text-right whitespace-nowrap transition-opacity -translate-x-1.5\",\n hasContextMenu &&\n \"group-hover:opacity-0 group-focus-within:opacity-0\",\n contextMenuOpen && \"opacity-0\",\n )}\n >\n <time>{formatTimeDelta(lastUpdatedAt ?? createdAt)}</time>\n </p>\n )}\n\n {hasContextMenu && (\n <div\n className={cn(\n \"absolute right-0 top-1/2 -translate-y-1/2 transition-opacity\",\n \"opacity-0 invisible group-hover:opacity-100 group-hover:visible\",\n contextMenuOpen && \"visible opacity-100\",\n )}\n >\n <ConversationCardActions\n contextMenuOpen={contextMenuOpen}\n onContextMenuToggle={onContextMenuToggle || (() => {})}\n onDelete={onDelete && handleDelete}\n onStop={onStop && handleStop}\n onEdit={onChangeTitle && handleEdit}\n onDownloadViaVSCode={handleDownloadViaVSCode}\n onDownloadConversation={handleDownloadConversation}\n executionStatus={executionStatus}\n conversationId={conversationId}\n showOptions={showOptions}\n />\n </div>\n )}\n </div>\n </div>\n\n {shouldRenderFooter && (\n <ConversationCardFooter\n selectedRepository={selectedRepository}\n lastUpdatedAt={lastUpdatedAt}\n createdAt={createdAt}\n executionStatus={executionStatus}\n workspaceWorkingDir={workspaceWorkingDir}\n showRepositoryMetadata={showRepositoryMetadata}\n showTimestamp={false}\n llmModel={llmModel}\n showAgentChip={showLlmProfiles}\n agentKind={agentKind}\n acpServer={acpServer}\n />\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAuCA,SAAgB,EAAiB,EAC/B,YACA,aACA,WACA,kBACA,gBACA,UACA,uBACA,kBACA,cACA,mBACA,oBACA,kBACA,qBAAkB,IAClB,wBACA,cAAW,IACX,wBACA,4BAAyB,IACzB,cAAW,MACX,qBAAkB,IAClB,eAAY,MACZ,eAAY,QACY;CACxB,IAAM,IAAU,GAAY,EACtB,CAAC,GAAW,KAAgB,EAAM,SAA0B,OAAO,EACnE,EAAE,aAAa,MAAyB,GAAyB,EAEjE,KAAe,MAAqB;AAIxC,EAHI,MAAa,MAAM,MAAa,KAClC,IAAgB,EAAS,EAE3B,EAAa,OAAO;IAGhB,KAAgB,MAA+C;AAInE,EAHA,EAAM,gBAAgB,EACtB,EAAM,iBAAiB,EACvB,KAAY,EACZ,IAAsB,GAAM;IAGxB,KAAc,MAA+C;AAIjE,EAHA,EAAM,gBAAgB,EACtB,EAAM,iBAAiB,EACvB,KAAU,EACV,IAAsB,GAAM;IAGxB,KAAc,MAA+C;AAIjE,EAHA,EAAM,gBAAgB,EACtB,EAAM,iBAAiB,EACvB,EAAa,OAAO,EACpB,IAAsB,GAAM;IAGxB,IAA0B,OAC9B,MACG;AAMH,MALA,EAAM,gBAAgB,EACtB,EAAM,iBAAiB,EACvB,EAAQ,QAAQ,qCAAqC,EAGjD,EACF,KAAI;GACF,IAAM,IAAO,MAAM,EAAoB,aAAa,EAAe;AACnE,OAAI,EAAK,YAAY;IACnB,IAAM,IAAiB,EAAmB,EAAK,WAAW;AAC1D,IAAI,KACF,OAAO,KAAK,GAAgB,SAAS;;UAInC;AAKV,MAAsB,GAAM;IAGxB,IAA6B,OACjC,MACG;AAOH,EANA,EAAM,gBAAgB,EACtB,EAAM,iBAAiB,EAEnB,KACF,MAAM,EAAqB,EAAe,EAE5C,IAAsB,GAAM;IAGxB,IAAiB,CAAC,EAAE,KAAY,KAAiB,IACjD,IACJ,KACC,MAAoB,MAAc,SAAS,CAAC,CAAC;AAEhD,QACE,kBAAC,OAAD;EACE,eAAY;EACZ,0BAAwB,EAAgB,UAAU;EAClD,eAAa,IAAW,SAAS;EACxB;EACT,WAAW,EACT,2FACA,+DACA,4CACD;YATH,CAWE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KACS;KACI;KACE;KACI;KACF;KACf,CAAA,EACD,MAAkB,WAAW,kBAAC,GAAD,EAA4B,CAAA,CACtD;OAEN,kBAAC,OAAD;IAAK,WAAU;cAAf,EACI,KAAa,MACb,kBAAC,KAAD;KACE,WAAW,EACT,mGACA,KACE,sDACF,KAAmB,YACpB;eAED,kBAAC,QAAD,EAAA,UAAO,EAAgB,KAAiB,EAAU,EAAQ,CAAA;KACxD,CAAA,EAGL,KACC,kBAAC,OAAD;KACE,WAAW,EACT,gEACA,mEACA,KAAmB,sBACpB;eAED,kBAAC,GAAD;MACmB;MACjB,qBAAqB,YAA8B;MACnD,UAAU,KAAY;MACtB,QAAQ,KAAU;MAClB,QAAQ,KAAiB;MACzB,qBAAqB;MACrB,wBAAwB;MACP;MACD;MACH;MACb,CAAA;KACE,CAAA,CAEJ;MACF;MAEL,KACC,kBAAC,GAAD;GACsB;GACL;GACJ;GACM;GACI;GACG;GACxB,eAAe;GACL;GACV,eAAe;GACJ;GACA;GACX,CAAA,CAEA"}
1
+ {"version":3,"file":"conversation-card.js","names":[],"sources":["../../../../../src/components/features/conversation-panel/conversation-card/conversation-card.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTracking } from \"#/hooks/use-tracking\";\nimport { cn } from \"#/utils/utils\";\nimport { transformVSCodeUrl } from \"#/utils/vscode-url-helper\";\nimport ConversationService from \"#/api/conversation-service/conversation-service.api\";\nimport { ExecutionStatus } from \"#/types/agent-server/core/base/common\";\nimport { SandboxStatus } from \"#/api/conversation-service/agent-server-conversation-service.types\";\nimport { RepositorySelection } from \"#/api/open-hands.types\";\nimport { formatTimeDelta } from \"#/utils/format-time-delta\";\nimport { ConversationCardHeader } from \"./conversation-card-header\";\nimport { ConversationCardActions } from \"./conversation-card-actions\";\nimport { ConversationCardFooter } from \"./conversation-card-footer\";\nimport { ConversationStatusBadges } from \"./conversation-status-badges\";\nimport { useDownloadConversation } from \"#/hooks/use-download-conversation\";\n\ninterface ConversationCardProps {\n onClick?: () => void;\n onDelete?: () => void;\n onStop?: () => void;\n onChangeTitle?: (title: string) => void;\n showOptions?: boolean;\n title: string;\n selectedRepository: RepositorySelection | null;\n lastUpdatedAt: string;\n createdAt?: string;\n executionStatus?: ExecutionStatus | null;\n sandboxStatus?: SandboxStatus | null;\n conversationId?: string;\n contextMenuOpen?: boolean;\n onContextMenuToggle?: (isOpen: boolean) => void;\n isActive?: boolean;\n workspaceWorkingDir?: string | null;\n showRepositoryMetadata?: boolean;\n llmModel?: string | null;\n showLlmProfiles?: boolean;\n agentKind?: \"openhands\" | \"acp\" | null;\n acpServer?: string | null;\n}\n\nexport function ConversationCard({\n onClick,\n onDelete,\n onStop,\n onChangeTitle,\n showOptions,\n title,\n selectedRepository,\n lastUpdatedAt,\n createdAt,\n conversationId,\n executionStatus,\n sandboxStatus,\n contextMenuOpen = false,\n onContextMenuToggle,\n isActive = false,\n workspaceWorkingDir,\n showRepositoryMetadata = true,\n llmModel = null,\n showLlmProfiles = false,\n agentKind = null,\n acpServer = null,\n}: ConversationCardProps) {\n const { trackDownloadVsCodeButtonClicked } = useTracking();\n const [titleMode, setTitleMode] = React.useState<\"view\" | \"edit\">(\"view\");\n const { mutateAsync: downloadConversation } = useDownloadConversation();\n\n const onTitleSave = (newTitle: string) => {\n if (newTitle !== \"\" && newTitle !== title) {\n onChangeTitle?.(newTitle);\n }\n setTitleMode(\"view\");\n };\n\n const handleDelete = (event: React.MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n event.stopPropagation();\n onDelete?.();\n onContextMenuToggle?.(false);\n };\n\n const handleStop = (event: React.MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n event.stopPropagation();\n onStop?.();\n onContextMenuToggle?.(false);\n };\n\n const handleEdit = (event: React.MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n event.stopPropagation();\n setTitleMode(\"edit\");\n onContextMenuToggle?.(false);\n };\n\n const handleDownloadViaVSCode = async (\n event: React.MouseEvent<HTMLButtonElement>,\n ) => {\n event.preventDefault();\n event.stopPropagation();\n trackDownloadVsCodeButtonClicked();\n\n // Fetch the VS Code URL from the API\n if (conversationId) {\n try {\n const data = await ConversationService.getVSCodeUrl(conversationId);\n if (data.vscode_url) {\n const transformedUrl = transformVSCodeUrl(data.vscode_url);\n if (transformedUrl) {\n window.open(transformedUrl, \"_blank\");\n }\n }\n // VS Code URL not available\n } catch {\n // Failed to fetch VS Code URL\n }\n }\n\n onContextMenuToggle?.(false);\n };\n\n const handleDownloadConversation = async (\n event: React.MouseEvent<HTMLButtonElement>,\n ) => {\n event.preventDefault();\n event.stopPropagation();\n\n if (conversationId) {\n await downloadConversation(conversationId);\n }\n onContextMenuToggle?.(false);\n };\n\n const hasContextMenu = !!(onDelete || onChangeTitle || showOptions);\n const shouldRenderFooter =\n showRepositoryMetadata ||\n (showLlmProfiles && (agentKind === \"acp\" || !!llmModel));\n\n return (\n <div\n data-testid=\"conversation-card\"\n data-context-menu-open={contextMenuOpen.toString()}\n data-active={isActive ? \"true\" : \"false\"}\n onClick={onClick}\n className={cn(\n \"group relative h-auto w-full cursor-pointer rounded-md py-1 pl-2 pr-1 transition-colors\",\n \"data-[context-menu-open=false]:hover:bg-[var(--oh-surface)]\",\n \"data-[active=true]:bg-[var(--oh-surface)]\",\n )}\n >\n <div className=\"flex items-center w-full min-w-0\">\n <div className=\"flex items-center gap-2 flex-1 min-w-0 overflow-hidden\">\n <ConversationCardHeader\n title={title}\n titleMode={titleMode}\n onTitleSave={onTitleSave}\n executionStatus={executionStatus}\n sandboxStatus={sandboxStatus}\n />\n {sandboxStatus === \"ERROR\" && <ConversationStatusBadges />}\n </div>\n\n <div className=\"relative ml-auto pl-2 flex items-center justify-end shrink-0\">\n {(createdAt ?? lastUpdatedAt) && (\n <p\n className={cn(\n \"text-xs text-[var(--oh-muted)] text-right whitespace-nowrap transition-opacity -translate-x-1.5\",\n hasContextMenu &&\n \"group-hover:opacity-0 group-focus-within:opacity-0\",\n contextMenuOpen && \"opacity-0\",\n )}\n >\n <time>{formatTimeDelta(lastUpdatedAt ?? createdAt)}</time>\n </p>\n )}\n\n {hasContextMenu && (\n <div\n className={cn(\n \"absolute right-0 top-1/2 -translate-y-1/2 transition-opacity\",\n \"opacity-0 invisible group-hover:opacity-100 group-hover:visible\",\n contextMenuOpen && \"visible opacity-100\",\n )}\n >\n <ConversationCardActions\n contextMenuOpen={contextMenuOpen}\n onContextMenuToggle={onContextMenuToggle || (() => {})}\n onDelete={onDelete && handleDelete}\n onStop={onStop && handleStop}\n onEdit={onChangeTitle && handleEdit}\n onDownloadViaVSCode={handleDownloadViaVSCode}\n onDownloadConversation={handleDownloadConversation}\n executionStatus={executionStatus}\n conversationId={conversationId}\n showOptions={showOptions}\n />\n </div>\n )}\n </div>\n </div>\n\n {shouldRenderFooter && (\n <ConversationCardFooter\n selectedRepository={selectedRepository}\n lastUpdatedAt={lastUpdatedAt}\n createdAt={createdAt}\n executionStatus={executionStatus}\n workspaceWorkingDir={workspaceWorkingDir}\n showRepositoryMetadata={showRepositoryMetadata}\n showTimestamp={false}\n llmModel={llmModel}\n showAgentChip={showLlmProfiles}\n agentKind={agentKind}\n acpServer={acpServer}\n />\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAuCA,SAAgB,EAAiB,EAC/B,YACA,aACA,WACA,kBACA,gBACA,UACA,uBACA,kBACA,cACA,mBACA,oBACA,kBACA,qBAAkB,IAClB,wBACA,cAAW,IACX,wBACA,4BAAyB,IACzB,cAAW,MACX,qBAAkB,IAClB,eAAY,MACZ,eAAY,QACY;CACxB,IAAM,EAAE,wCAAqC,GAAa,EACpD,CAAC,GAAW,KAAgB,EAAM,SAA0B,OAAO,EACnE,EAAE,aAAa,MAAyB,GAAyB,EAEjE,KAAe,MAAqB;AAIxC,EAHI,MAAa,MAAM,MAAa,KAClC,IAAgB,EAAS,EAE3B,EAAa,OAAO;IAGhB,KAAgB,MAA+C;AAInE,EAHA,EAAM,gBAAgB,EACtB,EAAM,iBAAiB,EACvB,KAAY,EACZ,IAAsB,GAAM;IAGxB,KAAc,MAA+C;AAIjE,EAHA,EAAM,gBAAgB,EACtB,EAAM,iBAAiB,EACvB,KAAU,EACV,IAAsB,GAAM;IAGxB,KAAc,MAA+C;AAIjE,EAHA,EAAM,gBAAgB,EACtB,EAAM,iBAAiB,EACvB,EAAa,OAAO,EACpB,IAAsB,GAAM;IAGxB,IAA0B,OAC9B,MACG;AAMH,MALA,EAAM,gBAAgB,EACtB,EAAM,iBAAiB,EACvB,GAAkC,EAG9B,EACF,KAAI;GACF,IAAM,IAAO,MAAM,EAAoB,aAAa,EAAe;AACnE,OAAI,EAAK,YAAY;IACnB,IAAM,IAAiB,EAAmB,EAAK,WAAW;AAC1D,IAAI,KACF,OAAO,KAAK,GAAgB,SAAS;;UAInC;AAKV,MAAsB,GAAM;IAGxB,IAA6B,OACjC,MACG;AAOH,EANA,EAAM,gBAAgB,EACtB,EAAM,iBAAiB,EAEnB,KACF,MAAM,EAAqB,EAAe,EAE5C,IAAsB,GAAM;IAGxB,IAAiB,CAAC,EAAE,KAAY,KAAiB,IACjD,IACJ,KACC,MAAoB,MAAc,SAAS,CAAC,CAAC;AAEhD,QACE,kBAAC,OAAD;EACE,eAAY;EACZ,0BAAwB,EAAgB,UAAU;EAClD,eAAa,IAAW,SAAS;EACxB;EACT,WAAW,EACT,2FACA,+DACA,4CACD;YATH,CAWE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KACS;KACI;KACE;KACI;KACF;KACf,CAAA,EACD,MAAkB,WAAW,kBAAC,GAAD,EAA4B,CAAA,CACtD;OAEN,kBAAC,OAAD;IAAK,WAAU;cAAf,EACI,KAAa,MACb,kBAAC,KAAD;KACE,WAAW,EACT,mGACA,KACE,sDACF,KAAmB,YACpB;eAED,kBAAC,QAAD,EAAA,UAAO,EAAgB,KAAiB,EAAU,EAAQ,CAAA;KACxD,CAAA,EAGL,KACC,kBAAC,OAAD;KACE,WAAW,EACT,gEACA,mEACA,KAAmB,sBACpB;eAED,kBAAC,GAAD;MACmB;MACjB,qBAAqB,YAA8B;MACnD,UAAU,KAAY;MACtB,QAAQ,KAAU;MAClB,QAAQ,KAAiB;MACzB,qBAAqB;MACrB,wBAAwB;MACP;MACD;MACH;MACb,CAAA;KACE,CAAA,CAEJ;MACF;MAEL,KACC,kBAAC,GAAD;GACsB;GACL;GACJ;GACM;GACI;GACG;GACxB,eAAe;GACL;GACV,eAAe;GACJ;GACA;GACX,CAAA,CAEA"}
@@ -2,3 +2,4 @@ export { OnboardingModal } from "./onboarding-modal";
2
2
  export { OnboardingHost } from "./onboarding-host";
3
3
  export { OnboardingProgressBar } from "./onboarding-progress-bar";
4
4
  export { useOnboardingCompletion, ONBOARDING_COMPLETED_STORAGE_KEY, } from "./use-onboarding-completion";
5
+ export { ONBOARDING_PREVIEW_STEP_QUERY_PARAM, isOnboardingPreviewActive, readOnboardingPreviewStep, } from "./onboarding-preview";
@@ -4,6 +4,8 @@
4
4
  * isn't set yet). Closing or completing the flow marks it done so the
5
5
  * modal won't re-appear on subsequent visits.
6
6
  *
7
- * Renders nothing once onboarding has been completed.
7
+ * With `?previewOnboardingStep=<0-3>` the modal opens on that slide for
8
+ * design review without persisting completion (works on any route when
9
+ * mounted from the root layout).
8
10
  */
9
11
  export declare function OnboardingHost(): import("react/jsx-runtime").JSX.Element | null;
@@ -1,13 +1,17 @@
1
1
  interface OnboardingModalProps {
2
2
  /** Called when the user dismisses the modal (skip / X / launch). */
3
3
  onClose: () => void;
4
+ /** Optional slide index for dev preview (`?previewOnboardingStep=`). */
5
+ initialStep?: number;
6
+ /** When true, skip/close does not persist onboarding completion. */
7
+ isPreview?: boolean;
4
8
  }
5
9
  /**
6
10
  * Top-level onboarding modal for first-time users.
7
11
  *
8
12
  * The flow is a fixed sequence of four steps:
9
- * 0. Check backend
10
- * 1. Choose agent
13
+ * 0. Choose agent
14
+ * 1. Check backend
11
15
  * 2. Set up LLM
12
16
  * 3. Say hello (creates a fresh conversation, then closes)
13
17
  *
@@ -15,5 +19,5 @@ interface OnboardingModalProps {
15
19
  * the rail is translated horizontally by step index, so transitioning
16
20
  * between steps animates the new step in from the right.
17
21
  */
18
- export declare function OnboardingModal({ onClose }: OnboardingModalProps): import("react/jsx-runtime").JSX.Element;
22
+ export declare function OnboardingModal({ onClose, initialStep, isPreview, }: OnboardingModalProps): import("react/jsx-runtime").JSX.Element;
19
23
  export {};
@@ -0,0 +1,4 @@
1
+ export declare const ONBOARDING_PREVIEW_STEP_QUERY_PARAM = "previewOnboardingStep";
2
+ /** Reads `?previewOnboardingStep=<0-3>` for dev/design review of a single slide. */
3
+ export declare function readOnboardingPreviewStep(search?: string): number | null;
4
+ export declare function isOnboardingPreviewActive(search?: string): boolean;
@@ -1,5 +1,7 @@
1
1
  interface SayHelloStepProps {
2
2
  onBack: () => void;
3
+ /** Dismisses onboarding without launching a conversation. */
4
+ onClose: () => void;
3
5
  /** Called once the conversation has been created — used by the parent
4
6
  * modal to mark the onboarding as complete before unmounting. */
5
7
  onLaunched: () => void;
@@ -9,5 +11,5 @@ interface SayHelloStepProps {
9
11
  * launches a brand-new conversation with no workspace and navigates
10
12
  * to it. Completing this step finishes the onboarding flow.
11
13
  */
12
- export declare function SayHelloStep({ onBack, onLaunched }: SayHelloStepProps): import("react/jsx-runtime").JSX.Element;
14
+ export declare function SayHelloStep({ onBack, onClose, onLaunched, }: SayHelloStepProps): import("react/jsx-runtime").JSX.Element;
13
15
  export {};
@@ -1 +1 @@
1
- const e=require(`../../../../_virtual/_rolldown/runtime.cjs`);require(`../../../../utils/custom-toast-handlers.cjs`),require(`../../../../api/profiles-service/profiles-service.api.cjs`),require(`../../../../hooks/query/use-llm-profiles.cjs`),require(`../../../../hooks/query/use-settings.cjs`),require(`../../../../ui/typography.cjs`),require(`../brand-button.cjs`),require(`../../../../hooks/query/use-agent-settings-schema.cjs`),require(`./profile-name-input.cjs`),require(`../../../../hooks/mutation/use-activate-llm-profile.cjs`),require(`./llm-profiles-manager.cjs`),require(`../../../../hooks/mutation/use-save-llm-profile.cjs`),require(`../../../shared/buttons/back-nav-button.cjs`),require(`../../../../contexts/settings-section-header-context.cjs`),require(`../../../../routes/llm-settings.cjs`);let t=require(`react`);t=e.__toESM(t,1),require(`react/jsx-runtime`);
1
+ const e=require(`../../../../_virtual/_rolldown/runtime.cjs`);require(`../../../../utils/custom-toast-handlers.cjs`),require(`../../../../hooks/query/use-settings.cjs`),require(`../../../../api/profiles-service/profiles-service.api.cjs`),require(`../../../../hooks/query/use-llm-profiles.cjs`),require(`../../../../ui/typography.cjs`),require(`../brand-button.cjs`),require(`../../../../hooks/query/use-agent-settings-schema.cjs`),require(`./profile-name-input.cjs`),require(`../../../../hooks/mutation/use-activate-llm-profile.cjs`),require(`./llm-profiles-manager.cjs`),require(`../../../../hooks/mutation/use-save-llm-profile.cjs`),require(`../../../shared/buttons/back-nav-button.cjs`),require(`../../../../contexts/settings-section-header-context.cjs`),require(`../../../../routes/llm-settings.cjs`);let t=require(`react`);t=e.__toESM(t,1),require(`react/jsx-runtime`);
@@ -1,7 +1,7 @@
1
1
  import "../../../../utils/custom-toast-handlers.js";
2
+ import "../../../../hooks/query/use-settings.js";
2
3
  import "../../../../api/profiles-service/profiles-service.api.js";
3
4
  import "../../../../hooks/query/use-llm-profiles.js";
4
- import "../../../../hooks/query/use-settings.js";
5
5
  import "../../../../ui/typography.js";
6
6
  import "../brand-button.js";
7
7
  import "../../../../hooks/query/use-agent-settings-schema.js";
@@ -1,2 +1,2 @@
1
- const e=require(`../../../../_virtual/_rolldown/runtime.cjs`),t=require(`../../../../node_modules/react-i18next/dist/es/useTranslation.cjs`),n=require(`../../../../i18n/declaration.cjs`),r=require(`../../../../utils/custom-toast-handlers.cjs`),i=require(`../../../../node_modules/axios/index.cjs`),a=require(`../../../../hooks/query/use-settings.cjs`),o=require(`../../../../ui/typography.cjs`),s=require(`../brand-button.cjs`),c=require(`../../../../hooks/mutation/use-save-settings.cjs`),l=require(`../../../../utils/retrieve-axios-error-message.cjs`),u=require(`../../../../hooks/query/use-agent-settings-schema.cjs`),d=require(`../llm-settings/llm-settings-inputs-skeleton.cjs`),f=require(`../../../../utils/sdk-settings-schema.cjs`),p=require(`./schema-field.cjs`),m=require(`./view-toggle.cjs`);let h=require(`react`);h=e.__toESM(h,1);let g=require(`react/jsx-runtime`);var _=new Set,v={basic:0,advanced:1,all:2},ee=(e,t)=>v[t]<v[e]?t:e,te=(e,{showAdvanced:t,showAll:n})=>e===`all`?n?`all`:t?`advanced`:`basic`:e===`advanced`?t?`advanced`:n?`all`:`basic`:`basic`,y=(e,t)=>e instanceof i.AxiosError?e.response?.status===401?`${t} This agent server requires X-Session-API-Key. Set VITE_SESSION_API_KEY in the frontend to the same value used by the backend SESSION_API_KEY or OH_SESSION_API_KEYS_0.`:e.response?.status===404?`${t} This backend does not expose /api/settings/* schema endpoints. Upgrade to a recent openhands-agent-server release.`:t:t;function b({sectionKeys:e,excludeKeys:i=_,scope:v=`personal`,settingsSource:b=`agent_settings`,header:ne,extraDirty:x=!1,buildPayload:S,onSaveSuccess:C,getInitialView:w,forceShowAdvancedView:re=!1,allowAllView:ie=!0,initialValueOverrides:T,embedded:E=!1,hideSaveButton:D=!1,onSaveControlChange:O,testId:ae=`sdk-section-settings-screen`}){let{t:k}=t.useTranslation(`openhands`),{mutate:oe,isPending:A}=c.useSaveSettings(v),{data:j,isLoading:se,isFetching:ce}=a.useSettings(v),le=u.useAgentSettingsSchema(j?.agent_settings_schema),ue=u.useConversationSettingsSchema(j?.conversation_settings_schema),M=b===`conversation_settings`?ue:le,N=M.data,P=M.isLoading,[F,I]=h.default.useState(`basic`),[L,R]=h.default.useState({}),[z,B]=h.default.useState({}),V=h.default.useRef(!1),H=h.default.useMemo(()=>JSON.stringify(e),[e]),U=h.default.useMemo(()=>JSON.parse(H),[H]),W=h.default.useMemo(()=>{if(!f.isValidSettingsSchema(N))return null;let e=new Set(U);return{...N,sections:N.sections.filter(t=>e.has(t.key))}},[N,U]),G=re||f.hasAdvancedSettings(W),K=ie&&f.hasMinorSettings(W),de=h.default.useMemo(()=>y(M.error,k(n.I18nKey.SETTINGS$SDK_SCHEMA_UNAVAILABLE)),[M.error,k]),fe=h.default.useMemo(()=>T?JSON.stringify(T):``,[T]),q=h.default.useMemo(()=>{if(!j||!W)return null;let e=f.buildInitialSettingsFormValues(j,W,b);return T?{...e,...T}:e},[j,W,b,fe]),J=h.default.useMemo(()=>!j||!W?null:te(w?w(j,W):f.inferInitialView(j,W,b),{showAdvanced:G,showAll:K}),[j,W,w,b,G,K]);h.default.useEffect(()=>{V.current=!1,I(`basic`),R({}),B({})},[v,b,H]),h.default.useEffect(()=>{!q||!J||(R(q),B(T?Object.fromEntries(Object.keys(T).map(e=>[e,!0])):{}),I(e=>V.current?ee(e,J):(V.current=!0,J)))},[q,J]);let pe=h.default.useMemo(()=>W?f.getVisibleSettingsSections(W,L,F,i):[],[W,L,F,i]),Y=h.default.useCallback((e,t)=>{R(n=>({...n,[e]:t})),B(t=>({...t,[e]:!0}))},[]),me=h.default.useCallback(e=>{r.displayErrorToast(l.retrieveAxiosErrorMessage(e)||k(n.I18nKey.ERROR$GENERIC))},[k]),X=h.default.useRef(()=>{}),he=h.default.useCallback(()=>{X.current()},[]),Z=h.default.useRef(()=>({})),ge=h.default.useCallback(()=>Z.current(),[]),Q=()=>{if(!W)return;let e;try{let t=f.buildSdkSettingsPayloadForView(W,L,z,F),n;n=b===`conversation_settings`?{conversation_settings_diff:t}:{agent_settings_diff:t},e=S?S(t,{values:L,dirty:z,view:F}):n}catch(e){r.displayErrorToast(e instanceof Error?e.message:k(n.I18nKey.ERROR$GENERIC));return}Object.keys(e).length!==0&&oe(e,{onError:me,onSuccess:()=>{r.displaySuccessToast(k(n.I18nKey.SETTINGS$SAVED_WARNING)),B({}),C?.()}})};X.current=Q,Z.current=()=>W?f.buildSdkSettingsPayload(W,L,z):{};let $=Object.keys(z).length>0||x;return h.default.useEffect(()=>{O&&O({save:he,isSaving:A,isDirty:$,values:L,view:F,getDirtyPayload:ge})},[A,$,L,F]),se||ce||P?(0,g.jsx)(d.LlmSettingsInputsSkeleton,{}):!W||W.sections.length===0?(0,g.jsx)(o.Typography.Paragraph,{className:`text-tertiary-alt`,children:de}):Object.keys(L).length===0?(0,g.jsx)(d.LlmSettingsInputsSkeleton,{}):(0,g.jsxs)(`div`,{"data-testid":ae,className:E?`relative flex min-h-0 w-full flex-1 flex-col`:`relative w-full min-h-0`,children:[(0,g.jsx)(m.ViewToggle,{view:F,setView:I,showAdvanced:G,showAll:K,isDisabled:!1}),(0,g.jsxs)(`div`,{className:`flex flex-col gap-8`,children:[ne?.({values:L,isDisabled:!1,view:F,onChange:Y}),pe.map((e,t)=>(0,g.jsx)(`section`,{className:`flex flex-col gap-4`,children:(0,g.jsx)(`div`,{className:`flex flex-col gap-4`,children:e.fields.map(e=>(0,g.jsx)(p.SchemaField,{field:e,value:L[e.key],isDisabled:!1,onChange:t=>Y(e.key,t)},e.key))})},`${e.key}-${t}`)),D?null:(0,g.jsx)(`div`,{className:`flex justify-start pt-2`,children:(0,g.jsx)(s.BrandButton,{testId:`save-button`,type:`button`,variant:`primary`,isDisabled:A||Object.keys(z).length===0&&!x,onClick:Q,children:k(A?n.I18nKey.SETTINGS$SAVING:n.I18nKey.SETTINGS$SAVE_CHANGES)})})]})]})}exports.SdkSectionPage=b;
1
+ const e=require(`../../../../_virtual/_rolldown/runtime.cjs`),t=require(`../../../../node_modules/react-i18next/dist/es/useTranslation.cjs`),n=require(`../../../../i18n/declaration.cjs`),r=require(`../../../../utils/custom-toast-handlers.cjs`),i=require(`../../../../node_modules/axios/index.cjs`),ee=require(`../../../../hooks/query/use-settings.cjs`),a=require(`../../../../ui/typography.cjs`),o=require(`../brand-button.cjs`),te=require(`../../../../hooks/mutation/use-save-settings.cjs`),ne=require(`../../../../utils/retrieve-axios-error-message.cjs`),s=require(`../../../../hooks/query/use-agent-settings-schema.cjs`),c=require(`../llm-settings/llm-settings-inputs-skeleton.cjs`),l=require(`../../../../utils/sdk-settings-schema.cjs`),u=require(`./schema-field.cjs`),d=require(`./view-toggle.cjs`);let f=require(`react`);f=e.__toESM(f,1);let p=require(`react/jsx-runtime`);var re=new Set,m={basic:0,advanced:1,all:2},ie=(e,t)=>m[t]<m[e]?t:e,h=(e,{showAdvanced:t,showAll:n})=>e===`all`?n?`all`:t?`advanced`:`basic`:e===`advanced`?t?`advanced`:n?`all`:`basic`:`basic`,g=(e,t)=>e instanceof i.AxiosError?e.response?.status===401?`${t} This agent server requires X-Session-API-Key. Set VITE_SESSION_API_KEY in the frontend to the same value used by the backend SESSION_API_KEY or OH_SESSION_API_KEYS_0.`:e.response?.status===404?`${t} This backend does not expose /api/settings/* schema endpoints. Upgrade to a recent openhands-agent-server release.`:t:t;function _({sectionKeys:e,excludeKeys:i=re,scope:m=`personal`,settingsSource:_=`agent_settings`,header:v,extraDirty:y=!1,buildPayload:b,onSaveSuccess:x,getInitialView:S,forceShowAdvancedView:C=!1,allowAllView:ae=!0,initialValueOverrides:w,embedded:oe=!1,hideSaveButton:se=!1,suppressSuccessToast:ce=!1,onSaveControlChange:T,testId:le=`sdk-section-settings-screen`}){let{t:E}=t.useTranslation(`openhands`),{mutate:ue,isPending:D}=te.useSaveSettings(m),{data:O,isLoading:de,isFetching:fe}=ee.useSettings(m),k=s.useAgentSettingsSchema(O?.agent_settings_schema),A=s.useConversationSettingsSchema(O?.conversation_settings_schema),j=_===`conversation_settings`?A:k,M=j.data,N=j.isLoading,[P,F]=f.default.useState(`basic`),[I,L]=f.default.useState({}),[R,z]=f.default.useState({}),B=f.default.useRef(!1),V=f.default.useMemo(()=>JSON.stringify(e),[e]),H=f.default.useMemo(()=>JSON.parse(V),[V]),U=f.default.useMemo(()=>{if(!l.isValidSettingsSchema(M))return null;let e=new Set(H);return{...M,sections:M.sections.filter(t=>e.has(t.key))}},[M,H]),W=C||l.hasAdvancedSettings(U),G=ae&&l.hasMinorSettings(U),pe=f.default.useMemo(()=>g(j.error,E(n.I18nKey.SETTINGS$SDK_SCHEMA_UNAVAILABLE)),[j.error,E]),me=f.default.useMemo(()=>w?JSON.stringify(w):``,[w]),K=f.default.useMemo(()=>{if(!O||!U)return null;let e=l.buildInitialSettingsFormValues(O,U,_);return w?{...e,...w}:e},[O,U,_,me]),q=f.default.useMemo(()=>!O||!U?null:h(S?S(O,U):l.inferInitialView(O,U,_),{showAdvanced:W,showAll:G}),[O,U,S,_,W,G]);f.default.useEffect(()=>{B.current=!1,F(`basic`),L({}),z({})},[m,_,V]),f.default.useEffect(()=>{!K||!q||(L(K),z(w?Object.fromEntries(Object.keys(w).map(e=>[e,!0])):{}),F(e=>B.current?ie(e,q):(B.current=!0,q)))},[K,q]);let he=f.default.useMemo(()=>U?l.getVisibleSettingsSections(U,I,P,i):[],[U,I,P,i]),J=f.default.useCallback((e,t)=>{L(n=>({...n,[e]:t})),z(t=>({...t,[e]:!0}))},[]),ge=f.default.useCallback(e=>{r.displayErrorToast(ne.retrieveAxiosErrorMessage(e)||E(n.I18nKey.ERROR$GENERIC))},[E]),Y=f.default.useRef(()=>{}),X=f.default.useCallback(()=>{Y.current()},[]),Z=f.default.useRef(()=>({})),_e=f.default.useCallback(()=>Z.current(),[]),Q=()=>{if(!U)return;let e;try{let t=l.buildSdkSettingsPayloadForView(U,I,R,P),n;n=_===`conversation_settings`?{conversation_settings_diff:t}:{agent_settings_diff:t},e=b?b(t,{values:I,dirty:R,view:P}):n}catch(e){r.displayErrorToast(e instanceof Error?e.message:E(n.I18nKey.ERROR$GENERIC));return}Object.keys(e).length!==0&&ue(e,{onError:ge,onSuccess:()=>{ce||r.displaySuccessToast(E(n.I18nKey.SETTINGS$SAVED_WARNING)),z({}),x?.()}})};Y.current=Q,Z.current=()=>U?l.buildSdkSettingsPayload(U,I,R):{};let $=Object.keys(R).length>0||y;return f.default.useEffect(()=>{T&&T({save:X,isSaving:D,isDirty:$,values:I,view:P,getDirtyPayload:_e})},[D,$,I,P]),(de||fe)&&!O||N?(0,p.jsx)(c.LlmSettingsInputsSkeleton,{}):!U||U.sections.length===0?(0,p.jsx)(a.Typography.Paragraph,{className:`text-tertiary-alt`,children:pe}):Object.keys(I).length===0?(0,p.jsx)(c.LlmSettingsInputsSkeleton,{}):(0,p.jsxs)(`div`,{"data-testid":le,className:oe?`relative flex min-h-0 w-full flex-1 flex-col`:`relative w-full min-h-0`,children:[(0,p.jsx)(d.ViewToggle,{view:P,setView:F,showAdvanced:W,showAll:G,isDisabled:!1}),(0,p.jsxs)(`div`,{className:`flex flex-col gap-8`,children:[v?.({values:I,isDisabled:!1,view:P,onChange:J}),he.map((e,t)=>(0,p.jsx)(`section`,{className:`flex flex-col gap-4`,children:(0,p.jsx)(`div`,{className:`flex flex-col gap-4`,children:e.fields.map(e=>(0,p.jsx)(u.SchemaField,{field:e,value:I[e.key],isDisabled:!1,onChange:t=>J(e.key,t)},e.key))})},`${e.key}-${t}`)),se?null:(0,p.jsx)(`div`,{className:`flex justify-start pt-2`,children:(0,p.jsx)(o.BrandButton,{testId:`save-button`,type:`button`,variant:`primary`,isDisabled:D||Object.keys(R).length===0&&!y,onClick:Q,children:E(D?n.I18nKey.SETTINGS$SAVING:n.I18nKey.SETTINGS$SAVE_CHANGES)})})]})]})}exports.SdkSectionPage=_;
2
2
  //# sourceMappingURL=sdk-section-page.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"sdk-section-page.cjs","names":[],"sources":["../../../../../src/components/features/settings/sdk-settings/sdk-section-page.tsx"],"sourcesContent":["import React from \"react\";\nimport { AxiosError } from \"axios\";\nimport { useTranslation } from \"react-i18next\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { LlmSettingsInputsSkeleton } from \"#/components/features/settings/llm-settings/llm-settings-inputs-skeleton\";\nimport { useSaveSettings } from \"#/hooks/mutation/use-save-settings\";\nimport {\n useAgentSettingsSchema,\n useConversationSettingsSchema,\n} from \"#/hooks/query/use-agent-settings-schema\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { Typography } from \"#/ui/typography\";\nimport { Settings, SettingsSchema, SettingsScope } from \"#/types/settings\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport {\n buildInitialSettingsFormValues,\n buildSdkSettingsPayload,\n buildSdkSettingsPayloadForView,\n getVisibleSettingsSections,\n hasAdvancedSettings,\n hasMinorSettings,\n inferInitialView,\n isValidSettingsSchema,\n SettingsDirtyState,\n SettingsFormValues,\n type SettingsValueSource,\n type SettingsView,\n} from \"#/utils/sdk-settings-schema\";\nimport { SchemaField } from \"./schema-field\";\nimport { ViewToggle } from \"./view-toggle\";\n\nconst EMPTY_EXCLUDE_KEYS = new Set<string>();\n\nconst VIEW_ORDER: Record<SettingsView, number> = {\n basic: 0,\n advanced: 1,\n all: 2,\n};\n\nconst getLessDetailedView = (\n currentView: SettingsView,\n nextView: SettingsView,\n): SettingsView =>\n VIEW_ORDER[nextView] < VIEW_ORDER[currentView] ? nextView : currentView;\n\nconst normalizeView = (\n view: SettingsView,\n {\n showAdvanced,\n showAll,\n }: {\n showAdvanced: boolean;\n showAll: boolean;\n },\n): SettingsView => {\n if (view === \"all\") {\n if (showAll) {\n return \"all\";\n }\n\n return showAdvanced ? \"advanced\" : \"basic\";\n }\n\n if (view === \"advanced\") {\n if (showAdvanced) {\n return \"advanced\";\n }\n\n return showAll ? \"all\" : \"basic\";\n }\n\n return \"basic\";\n};\n\nconst getSchemaUnavailableMessage = (\n error: unknown,\n fallbackMessage: string,\n): string => {\n if (!(error instanceof AxiosError)) {\n return fallbackMessage;\n }\n\n if (error.response?.status === 401) {\n return `${fallbackMessage} This agent server requires X-Session-API-Key. Set VITE_SESSION_API_KEY in the frontend to the same value used by the backend SESSION_API_KEY or OH_SESSION_API_KEYS_0.`;\n }\n\n if (error.response?.status === 404) {\n return `${fallbackMessage} This backend does not expose /api/settings/* schema endpoints. Upgrade to a recent openhands-agent-server release.`;\n }\n\n return fallbackMessage;\n};\n\nexport interface SdkSectionHeaderProps {\n values: SettingsFormValues;\n isDisabled: boolean;\n view: SettingsView;\n onChange: (key: string, value: string | boolean) => void;\n}\n\n/**\n * Snapshot of the page's save state, surfaced to the parent so it can\n * render its own Save/Next button (e.g. in onboarding) when\n * {@link SdkSectionPage}'s built-in button is hidden via\n * `hideSaveButton`.\n */\nexport interface SdkSectionSaveControl {\n /** Trigger a save of the currently-dirty fields. No-op while `isSaving` or `!isDirty`. */\n save: () => void;\n /** A save mutation is in flight. */\n isSaving: boolean;\n /** At least one field is dirty (or `extraDirty` was passed in). */\n isDirty: boolean;\n /** Current form values (for custom save flows). */\n values: SettingsFormValues;\n /** The active view tier (basic/advanced/all) the form is rendering. */\n view: SettingsView;\n /**\n * Returns the coerced, dirty-only payload as a nested object\n * (e.g. `{ llm: { temperature: 0.7 } }`). Lets a custom save flow persist\n * exactly the fields the user changed, with proper types, without\n * re-implementing schema-driven coercion. Throws if a field fails coercion.\n */\n getDirtyPayload: () => Record<string, unknown>;\n}\n\n/**\n * A generic SDK-schema–driven settings page that renders fields\n * from one or more schema sections.\n *\n * @param sectionKeys - which schema section(s) this page owns (e.g. [\"condenser\"])\n * @param excludeKeys - field keys to skip (rendered elsewhere by the caller)\n * @param header - optional render prop receiving shared state to render above fields\n * @param testId - data-testid for the page wrapper\n */\nexport function SdkSectionPage({\n sectionKeys,\n excludeKeys = EMPTY_EXCLUDE_KEYS,\n scope = \"personal\",\n settingsSource = \"agent_settings\",\n header,\n extraDirty = false,\n buildPayload,\n onSaveSuccess,\n getInitialView,\n forceShowAdvancedView = false,\n allowAllView = true,\n initialValueOverrides,\n embedded = false,\n hideSaveButton = false,\n onSaveControlChange,\n testId = \"sdk-section-settings-screen\",\n}: {\n sectionKeys: string[];\n excludeKeys?: Set<string>;\n scope?: SettingsScope;\n settingsSource?: SettingsValueSource;\n\n header?: (props: SdkSectionHeaderProps) => React.ReactNode;\n extraDirty?: boolean;\n buildPayload?: (\n payload: ReturnType<typeof buildSdkSettingsPayloadForView>,\n context: {\n values: SettingsFormValues;\n dirty: SettingsDirtyState;\n view: SettingsView;\n },\n ) => Record<string, unknown>;\n onSaveSuccess?: () => void;\n getInitialView?: (\n settings: Settings,\n filteredSchema: SettingsSchema,\n ) => SettingsView;\n forceShowAdvancedView?: boolean;\n allowAllView?: boolean;\n /**\n * Per-field initial value overrides that win over the values\n * derived from `useSettings`. The keys of each override are also\n * marked dirty on hydration so the user can save the form without\n * having to touch the prefilled fields. Useful when the page is\n * embedded in a flow that wants to nudge brand-new users toward a\n * particular default (e.g. onboarding pre-filling OpenHands/Opus).\n */\n initialValueOverrides?: SettingsFormValues;\n /**\n * When true, the Save button container is rendered inline (no\n * sticky positioning, no contrasting `bg-base` band) so the page\n * can be dropped into a modal/card without a hard footer break.\n */\n embedded?: boolean;\n /**\n * Suppress the built-in Save Changes button entirely. Pair with\n * {@link onSaveControlChange} to drive saving from a parent-rendered\n * action (e.g. an onboarding \"Next\" button).\n */\n hideSaveButton?: boolean;\n /**\n * Fires whenever the save state changes (a mutation starts/finishes,\n * dirty status flips). Provides a stable `save()` callback the\n * parent can wire to its own button. Useful when the form is\n * embedded in a custom flow and the built-in Save button is hidden.\n */\n onSaveControlChange?: (control: SdkSectionSaveControl) => void;\n testId?: string;\n}) {\n const { t } = useTranslation(\"openhands\");\n const { mutate: saveSettings, isPending } = useSaveSettings(scope);\n const { data: settings, isLoading, isFetching } = useSettings(scope);\n const agentSchemaQuery = useAgentSettingsSchema(\n settings?.agent_settings_schema,\n );\n const conversationSchemaQuery = useConversationSettingsSchema(\n settings?.conversation_settings_schema,\n );\n const activeSchemaQuery =\n settingsSource === \"conversation_settings\"\n ? conversationSchemaQuery\n : agentSchemaQuery;\n const schema = activeSchemaQuery.data;\n const isSchemaLoading = activeSchemaQuery.isLoading;\n const isReadOnly = false;\n\n const [view, setView] = React.useState<SettingsView>(\"basic\");\n const [values, setValues] = React.useState<SettingsFormValues>({});\n const [dirty, setDirty] = React.useState<SettingsDirtyState>({});\n const hasHydratedViewRef = React.useRef(false);\n\n const sectionKeysSignature = React.useMemo(\n () => JSON.stringify(sectionKeys),\n [sectionKeys],\n );\n const stableSectionKeys = React.useMemo(\n () => JSON.parse(sectionKeysSignature) as string[],\n [sectionKeysSignature],\n );\n\n // Build a filtered schema containing only the requested sections.\n // `isValidSettingsSchema` guards against truthy-but-malformed schema\n // responses (e.g. when the deployment is pointed at a host that does\n // not serve `/api/settings/agent-schema` and returns an SPA shell\n // that parses into an object without a `sections` array). Without\n // the guard, `schema.sections.filter(...)` would throw and React\n // Router would escalate the crash to a full-screen error.\n const filteredSchema = React.useMemo(() => {\n if (!isValidSettingsSchema(schema)) return null;\n const sectionSet = new Set(stableSectionKeys);\n return {\n ...schema,\n sections: schema.sections.filter((s) => sectionSet.has(s.key)),\n };\n }, [schema, stableSectionKeys]);\n\n const showAdvanced =\n forceShowAdvancedView || hasAdvancedSettings(filteredSchema);\n const showAll = allowAllView && hasMinorSettings(filteredSchema);\n const schemaUnavailableMessage = React.useMemo(\n () =>\n getSchemaUnavailableMessage(\n activeSchemaQuery.error,\n t(I18nKey.SETTINGS$SDK_SCHEMA_UNAVAILABLE),\n ),\n [activeSchemaQuery.error, t],\n );\n\n const overridesSignature = React.useMemo(\n () => (initialValueOverrides ? JSON.stringify(initialValueOverrides) : \"\"),\n [initialValueOverrides],\n );\n\n const initialValues = React.useMemo(() => {\n if (!settings || !filteredSchema) return null;\n const base = buildInitialSettingsFormValues(\n settings,\n filteredSchema,\n settingsSource,\n );\n if (!initialValueOverrides) return base;\n return { ...base, ...initialValueOverrides };\n // overridesSignature keeps the memo reactive without depending on\n // a (potentially recreated) object reference each render.\n }, [settings, filteredSchema, settingsSource, overridesSignature]);\n\n const initialView = React.useMemo(() => {\n if (!settings || !filteredSchema) return null;\n\n const resolvedInitialView = getInitialView\n ? getInitialView(settings, filteredSchema)\n : inferInitialView(settings, filteredSchema, settingsSource);\n\n return normalizeView(resolvedInitialView, { showAdvanced, showAll });\n }, [\n settings,\n filteredSchema,\n getInitialView,\n settingsSource,\n showAdvanced,\n showAll,\n ]);\n\n React.useEffect(() => {\n hasHydratedViewRef.current = false;\n setView(\"basic\");\n setValues({});\n setDirty({});\n }, [scope, settingsSource, sectionKeysSignature]);\n\n React.useEffect(() => {\n if (!initialValues || !initialView) return;\n\n setValues(initialValues);\n // Override-supplied keys are pre-populated for the user, so mark\n // them dirty up-front; otherwise the Save button stays disabled\n // until the user touches a field, defeating the point of the\n // override.\n const overrideDirty: SettingsDirtyState = initialValueOverrides\n ? Object.fromEntries(\n Object.keys(initialValueOverrides).map((key) => [key, true]),\n )\n : {};\n setDirty(overrideDirty);\n setView((currentView) => {\n if (!hasHydratedViewRef.current) {\n hasHydratedViewRef.current = true;\n return initialView;\n }\n\n return getLessDetailedView(currentView, initialView);\n });\n // initialValueOverrides is intentionally tracked via\n // overridesSignature on initialValues; including the object ref\n // here would re-fire the effect every render.\n }, [initialValues, initialView]);\n\n const visibleSections = React.useMemo(() => {\n if (!filteredSchema) return [];\n return getVisibleSettingsSections(\n filteredSchema,\n values,\n view,\n excludeKeys,\n );\n }, [filteredSchema, values, view, excludeKeys]);\n\n const handleFieldChange = React.useCallback(\n (fieldKey: string, nextValue: string | boolean) => {\n setValues((prev) => ({ ...prev, [fieldKey]: nextValue }));\n setDirty((prev) => ({ ...prev, [fieldKey]: true }));\n },\n [],\n );\n\n const handleError = React.useCallback(\n (error: AxiosError) => {\n const msg = retrieveAxiosErrorMessage(error);\n displayErrorToast(msg || t(I18nKey.ERROR$GENERIC));\n },\n [t],\n );\n\n // Stable save callback so `onSaveControlChange` can hand a single\n // function reference to the parent across renders. The latest\n // closure is kept up to date via `handleSaveRef`.\n const handleSaveRef = React.useRef<() => void>(() => {});\n const stableSave = React.useCallback(() => {\n handleSaveRef.current();\n }, []);\n\n // Stable accessor for the coerced, dirty-only payload. Mirrors the\n // `handleSaveRef` pattern so the exposed function reference stays stable\n // across renders while always reading the latest closure at call time.\n const buildDirtyPayloadRef = React.useRef<() => Record<string, unknown>>(\n () => ({}),\n );\n const stableGetDirtyPayload = React.useCallback(\n () => buildDirtyPayloadRef.current(),\n [],\n );\n\n const handleSave = () => {\n if (!filteredSchema || isReadOnly) return;\n\n let payload: Record<string, unknown>;\n try {\n const basePayload = buildSdkSettingsPayloadForView(\n filteredSchema,\n values,\n dirty,\n view,\n );\n let defaultPayload: Record<string, unknown>;\n if (settingsSource === \"conversation_settings\") {\n defaultPayload = { conversation_settings_diff: basePayload };\n } else {\n defaultPayload = { agent_settings_diff: basePayload };\n }\n payload = buildPayload\n ? buildPayload(basePayload, { values, dirty, view })\n : defaultPayload;\n } catch (error) {\n displayErrorToast(\n error instanceof Error ? error.message : t(I18nKey.ERROR$GENERIC),\n );\n return;\n }\n\n if (Object.keys(payload).length === 0) return;\n\n saveSettings(payload, {\n onError: handleError,\n onSuccess: () => {\n displaySuccessToast(t(I18nKey.SETTINGS$SAVED_WARNING));\n setDirty({});\n onSaveSuccess?.();\n },\n });\n };\n\n handleSaveRef.current = handleSave;\n // Dirty-only (NOT view-filtered): we must never inject defaults for\n // non-visible fields here, or a custom save flow would reset fields the\n // user never touched. `buildSdkSettingsPayloadForView` is reserved for the\n // built-in full-replace save above.\n buildDirtyPayloadRef.current = () =>\n filteredSchema\n ? buildSdkSettingsPayload(filteredSchema, values, dirty)\n : {};\n\n // Surface save state to the parent. Hooks must run before any\n // conditional early-returns below, so this lives here rather than\n // alongside the JSX. The dependency list deliberately excludes\n // `stableSave` (it never changes) and `onSaveControlChange` (we\n // tolerate ref-instability of the callback to avoid spamming the\n // parent on every render).\n const saveControlIsDirty = Object.keys(dirty).length > 0 || extraDirty;\n React.useEffect(() => {\n if (!onSaveControlChange) return;\n onSaveControlChange({\n save: stableSave,\n isSaving: isPending,\n isDirty: saveControlIsDirty,\n values,\n view,\n getDirtyPayload: stableGetDirtyPayload,\n });\n }, [isPending, saveControlIsDirty, values, view]);\n\n if (isLoading || isFetching || isSchemaLoading) {\n return <LlmSettingsInputsSkeleton />;\n }\n\n if (!filteredSchema || filteredSchema.sections.length === 0) {\n return (\n <Typography.Paragraph className=\"text-tertiary-alt\">\n {schemaUnavailableMessage}\n </Typography.Paragraph>\n );\n }\n\n if (Object.keys(values).length === 0) return <LlmSettingsInputsSkeleton />;\n\n // Scrolling is owned by the settings shell (or onboarding wrapper), not a\n // nested scroll region. Save actions are inline after the last field.\n const bodyClassName = \"flex flex-col gap-8\";\n\n return (\n <div\n data-testid={testId}\n className={\n embedded\n ? \"relative flex min-h-0 w-full flex-1 flex-col\"\n : \"relative w-full min-h-0\"\n }\n >\n <ViewToggle\n view={view}\n setView={setView}\n showAdvanced={showAdvanced}\n showAll={showAll}\n isDisabled={isReadOnly}\n />\n\n <div className={bodyClassName}>\n {header?.({\n values,\n isDisabled: isReadOnly,\n view,\n onChange: handleFieldChange,\n })}\n\n {visibleSections.map((section, sectionIndex) => (\n <section\n key={`${section.key}-${sectionIndex}`}\n className=\"flex flex-col gap-4\"\n >\n <div className=\"flex flex-col gap-4\">\n {section.fields.map((field) => (\n <SchemaField\n key={field.key}\n field={field}\n value={values[field.key]}\n isDisabled={isReadOnly}\n onChange={(nextValue) =>\n handleFieldChange(field.key, nextValue)\n }\n />\n ))}\n </div>\n </section>\n ))}\n\n {!isReadOnly && !hideSaveButton ? (\n <div className=\"flex justify-start pt-2\">\n <BrandButton\n testId=\"save-button\"\n type=\"button\"\n variant=\"primary\"\n isDisabled={\n isPending || (Object.keys(dirty).length === 0 && !extraDirty)\n }\n onClick={handleSave}\n >\n {isPending\n ? t(I18nKey.SETTINGS$SAVING)\n : t(I18nKey.SETTINGS$SAVE_CHANGES)}\n </BrandButton>\n </div>\n ) : null}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"sdk-section-page.cjs","names":[],"sources":["../../../../../src/components/features/settings/sdk-settings/sdk-section-page.tsx"],"sourcesContent":["import React from \"react\";\nimport { AxiosError } from \"axios\";\nimport { useTranslation } from \"react-i18next\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { LlmSettingsInputsSkeleton } from \"#/components/features/settings/llm-settings/llm-settings-inputs-skeleton\";\nimport { useSaveSettings } from \"#/hooks/mutation/use-save-settings\";\nimport {\n useAgentSettingsSchema,\n useConversationSettingsSchema,\n} from \"#/hooks/query/use-agent-settings-schema\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { Typography } from \"#/ui/typography\";\nimport { Settings, SettingsSchema, SettingsScope } from \"#/types/settings\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport {\n buildInitialSettingsFormValues,\n buildSdkSettingsPayload,\n buildSdkSettingsPayloadForView,\n getVisibleSettingsSections,\n hasAdvancedSettings,\n hasMinorSettings,\n inferInitialView,\n isValidSettingsSchema,\n SettingsDirtyState,\n SettingsFormValues,\n type SettingsValueSource,\n type SettingsView,\n} from \"#/utils/sdk-settings-schema\";\nimport { SchemaField } from \"./schema-field\";\nimport { ViewToggle } from \"./view-toggle\";\n\nconst EMPTY_EXCLUDE_KEYS = new Set<string>();\n\nconst VIEW_ORDER: Record<SettingsView, number> = {\n basic: 0,\n advanced: 1,\n all: 2,\n};\n\nconst getLessDetailedView = (\n currentView: SettingsView,\n nextView: SettingsView,\n): SettingsView =>\n VIEW_ORDER[nextView] < VIEW_ORDER[currentView] ? nextView : currentView;\n\nconst normalizeView = (\n view: SettingsView,\n {\n showAdvanced,\n showAll,\n }: {\n showAdvanced: boolean;\n showAll: boolean;\n },\n): SettingsView => {\n if (view === \"all\") {\n if (showAll) {\n return \"all\";\n }\n\n return showAdvanced ? \"advanced\" : \"basic\";\n }\n\n if (view === \"advanced\") {\n if (showAdvanced) {\n return \"advanced\";\n }\n\n return showAll ? \"all\" : \"basic\";\n }\n\n return \"basic\";\n};\n\nconst getSchemaUnavailableMessage = (\n error: unknown,\n fallbackMessage: string,\n): string => {\n if (!(error instanceof AxiosError)) {\n return fallbackMessage;\n }\n\n if (error.response?.status === 401) {\n return `${fallbackMessage} This agent server requires X-Session-API-Key. Set VITE_SESSION_API_KEY in the frontend to the same value used by the backend SESSION_API_KEY or OH_SESSION_API_KEYS_0.`;\n }\n\n if (error.response?.status === 404) {\n return `${fallbackMessage} This backend does not expose /api/settings/* schema endpoints. Upgrade to a recent openhands-agent-server release.`;\n }\n\n return fallbackMessage;\n};\n\nexport interface SdkSectionHeaderProps {\n values: SettingsFormValues;\n isDisabled: boolean;\n view: SettingsView;\n onChange: (key: string, value: string | boolean) => void;\n}\n\n/**\n * Snapshot of the page's save state, surfaced to the parent so it can\n * render its own Save/Next button (e.g. in onboarding) when\n * {@link SdkSectionPage}'s built-in button is hidden via\n * `hideSaveButton`.\n */\nexport interface SdkSectionSaveControl {\n /** Trigger a save of the currently-dirty fields. No-op while `isSaving` or `!isDirty`. */\n save: () => void;\n /** A save mutation is in flight. */\n isSaving: boolean;\n /** At least one field is dirty (or `extraDirty` was passed in). */\n isDirty: boolean;\n /** Current form values (for custom save flows). */\n values: SettingsFormValues;\n /** The active view tier (basic/advanced/all) the form is rendering. */\n view: SettingsView;\n /**\n * Returns the coerced, dirty-only payload as a nested object\n * (e.g. `{ llm: { temperature: 0.7 } }`). Lets a custom save flow persist\n * exactly the fields the user changed, with proper types, without\n * re-implementing schema-driven coercion. Throws if a field fails coercion.\n */\n getDirtyPayload: () => Record<string, unknown>;\n}\n\n/**\n * A generic SDK-schema–driven settings page that renders fields\n * from one or more schema sections.\n *\n * @param sectionKeys - which schema section(s) this page owns (e.g. [\"condenser\"])\n * @param excludeKeys - field keys to skip (rendered elsewhere by the caller)\n * @param header - optional render prop receiving shared state to render above fields\n * @param testId - data-testid for the page wrapper\n */\nexport function SdkSectionPage({\n sectionKeys,\n excludeKeys = EMPTY_EXCLUDE_KEYS,\n scope = \"personal\",\n settingsSource = \"agent_settings\",\n header,\n extraDirty = false,\n buildPayload,\n onSaveSuccess,\n getInitialView,\n forceShowAdvancedView = false,\n allowAllView = true,\n initialValueOverrides,\n embedded = false,\n hideSaveButton = false,\n suppressSuccessToast = false,\n onSaveControlChange,\n testId = \"sdk-section-settings-screen\",\n}: {\n sectionKeys: string[];\n excludeKeys?: Set<string>;\n scope?: SettingsScope;\n settingsSource?: SettingsValueSource;\n\n header?: (props: SdkSectionHeaderProps) => React.ReactNode;\n extraDirty?: boolean;\n buildPayload?: (\n payload: ReturnType<typeof buildSdkSettingsPayloadForView>,\n context: {\n values: SettingsFormValues;\n dirty: SettingsDirtyState;\n view: SettingsView;\n },\n ) => Record<string, unknown>;\n onSaveSuccess?: () => void;\n getInitialView?: (\n settings: Settings,\n filteredSchema: SettingsSchema,\n ) => SettingsView;\n forceShowAdvancedView?: boolean;\n allowAllView?: boolean;\n /**\n * Per-field initial value overrides that win over the values\n * derived from `useSettings`. The keys of each override are also\n * marked dirty on hydration so the user can save the form without\n * having to touch the prefilled fields. Useful when the page is\n * embedded in a flow that wants to nudge brand-new users toward a\n * particular default (e.g. onboarding pre-filling OpenHands/Opus).\n */\n initialValueOverrides?: SettingsFormValues;\n /**\n * When true, the Save button container is rendered inline (no\n * sticky positioning, no contrasting `bg-base` band) so the page\n * can be dropped into a modal/card without a hard footer break.\n */\n embedded?: boolean;\n /**\n * Suppress the built-in Save Changes button entirely. Pair with\n * {@link onSaveControlChange} to drive saving from a parent-rendered\n * action (e.g. an onboarding \"Next\" button).\n */\n hideSaveButton?: boolean;\n /** Suppress the default success toast after save completes. */\n suppressSuccessToast?: boolean;\n /**\n * Fires whenever the save state changes (a mutation starts/finishes,\n * dirty status flips). Provides a stable `save()` callback the\n * parent can wire to its own button. Useful when the form is\n * embedded in a custom flow and the built-in Save button is hidden.\n */\n onSaveControlChange?: (control: SdkSectionSaveControl) => void;\n testId?: string;\n}) {\n const { t } = useTranslation(\"openhands\");\n const { mutate: saveSettings, isPending } = useSaveSettings(scope);\n const { data: settings, isLoading, isFetching } = useSettings(scope);\n const agentSchemaQuery = useAgentSettingsSchema(\n settings?.agent_settings_schema,\n );\n const conversationSchemaQuery = useConversationSettingsSchema(\n settings?.conversation_settings_schema,\n );\n const activeSchemaQuery =\n settingsSource === \"conversation_settings\"\n ? conversationSchemaQuery\n : agentSchemaQuery;\n const schema = activeSchemaQuery.data;\n const isSchemaLoading = activeSchemaQuery.isLoading;\n const isReadOnly = false;\n\n const [view, setView] = React.useState<SettingsView>(\"basic\");\n const [values, setValues] = React.useState<SettingsFormValues>({});\n const [dirty, setDirty] = React.useState<SettingsDirtyState>({});\n const hasHydratedViewRef = React.useRef(false);\n\n const sectionKeysSignature = React.useMemo(\n () => JSON.stringify(sectionKeys),\n [sectionKeys],\n );\n const stableSectionKeys = React.useMemo(\n () => JSON.parse(sectionKeysSignature) as string[],\n [sectionKeysSignature],\n );\n\n // Build a filtered schema containing only the requested sections.\n // `isValidSettingsSchema` guards against truthy-but-malformed schema\n // responses (e.g. when the deployment is pointed at a host that does\n // not serve `/api/settings/agent-schema` and returns an SPA shell\n // that parses into an object without a `sections` array). Without\n // the guard, `schema.sections.filter(...)` would throw and React\n // Router would escalate the crash to a full-screen error.\n const filteredSchema = React.useMemo(() => {\n if (!isValidSettingsSchema(schema)) return null;\n const sectionSet = new Set(stableSectionKeys);\n return {\n ...schema,\n sections: schema.sections.filter((s) => sectionSet.has(s.key)),\n };\n }, [schema, stableSectionKeys]);\n\n const showAdvanced =\n forceShowAdvancedView || hasAdvancedSettings(filteredSchema);\n const showAll = allowAllView && hasMinorSettings(filteredSchema);\n const schemaUnavailableMessage = React.useMemo(\n () =>\n getSchemaUnavailableMessage(\n activeSchemaQuery.error,\n t(I18nKey.SETTINGS$SDK_SCHEMA_UNAVAILABLE),\n ),\n [activeSchemaQuery.error, t],\n );\n\n const overridesSignature = React.useMemo(\n () => (initialValueOverrides ? JSON.stringify(initialValueOverrides) : \"\"),\n [initialValueOverrides],\n );\n\n const initialValues = React.useMemo(() => {\n if (!settings || !filteredSchema) return null;\n const base = buildInitialSettingsFormValues(\n settings,\n filteredSchema,\n settingsSource,\n );\n if (!initialValueOverrides) return base;\n return { ...base, ...initialValueOverrides };\n // overridesSignature keeps the memo reactive without depending on\n // a (potentially recreated) object reference each render.\n }, [settings, filteredSchema, settingsSource, overridesSignature]);\n\n const initialView = React.useMemo(() => {\n if (!settings || !filteredSchema) return null;\n\n const resolvedInitialView = getInitialView\n ? getInitialView(settings, filteredSchema)\n : inferInitialView(settings, filteredSchema, settingsSource);\n\n return normalizeView(resolvedInitialView, { showAdvanced, showAll });\n }, [\n settings,\n filteredSchema,\n getInitialView,\n settingsSource,\n showAdvanced,\n showAll,\n ]);\n\n React.useEffect(() => {\n hasHydratedViewRef.current = false;\n setView(\"basic\");\n setValues({});\n setDirty({});\n }, [scope, settingsSource, sectionKeysSignature]);\n\n React.useEffect(() => {\n if (!initialValues || !initialView) return;\n\n setValues(initialValues);\n // Override-supplied keys are pre-populated for the user, so mark\n // them dirty up-front; otherwise the Save button stays disabled\n // until the user touches a field, defeating the point of the\n // override.\n const overrideDirty: SettingsDirtyState = initialValueOverrides\n ? Object.fromEntries(\n Object.keys(initialValueOverrides).map((key) => [key, true]),\n )\n : {};\n setDirty(overrideDirty);\n setView((currentView) => {\n if (!hasHydratedViewRef.current) {\n hasHydratedViewRef.current = true;\n return initialView;\n }\n\n return getLessDetailedView(currentView, initialView);\n });\n // initialValueOverrides is intentionally tracked via\n // overridesSignature on initialValues; including the object ref\n // here would re-fire the effect every render.\n }, [initialValues, initialView]);\n\n const visibleSections = React.useMemo(() => {\n if (!filteredSchema) return [];\n return getVisibleSettingsSections(\n filteredSchema,\n values,\n view,\n excludeKeys,\n );\n }, [filteredSchema, values, view, excludeKeys]);\n\n const handleFieldChange = React.useCallback(\n (fieldKey: string, nextValue: string | boolean) => {\n setValues((prev) => ({ ...prev, [fieldKey]: nextValue }));\n setDirty((prev) => ({ ...prev, [fieldKey]: true }));\n },\n [],\n );\n\n const handleError = React.useCallback(\n (error: AxiosError) => {\n const msg = retrieveAxiosErrorMessage(error);\n displayErrorToast(msg || t(I18nKey.ERROR$GENERIC));\n },\n [t],\n );\n\n // Stable save callback so `onSaveControlChange` can hand a single\n // function reference to the parent across renders. The latest\n // closure is kept up to date via `handleSaveRef`.\n const handleSaveRef = React.useRef<() => void>(() => {});\n const stableSave = React.useCallback(() => {\n handleSaveRef.current();\n }, []);\n\n // Stable accessor for the coerced, dirty-only payload. Mirrors the\n // `handleSaveRef` pattern so the exposed function reference stays stable\n // across renders while always reading the latest closure at call time.\n const buildDirtyPayloadRef = React.useRef<() => Record<string, unknown>>(\n () => ({}),\n );\n const stableGetDirtyPayload = React.useCallback(\n () => buildDirtyPayloadRef.current(),\n [],\n );\n\n const handleSave = () => {\n if (!filteredSchema || isReadOnly) return;\n\n let payload: Record<string, unknown>;\n try {\n const basePayload = buildSdkSettingsPayloadForView(\n filteredSchema,\n values,\n dirty,\n view,\n );\n let defaultPayload: Record<string, unknown>;\n if (settingsSource === \"conversation_settings\") {\n defaultPayload = { conversation_settings_diff: basePayload };\n } else {\n defaultPayload = { agent_settings_diff: basePayload };\n }\n payload = buildPayload\n ? buildPayload(basePayload, { values, dirty, view })\n : defaultPayload;\n } catch (error) {\n displayErrorToast(\n error instanceof Error ? error.message : t(I18nKey.ERROR$GENERIC),\n );\n return;\n }\n\n if (Object.keys(payload).length === 0) return;\n\n saveSettings(payload, {\n onError: handleError,\n onSuccess: () => {\n if (!suppressSuccessToast) {\n displaySuccessToast(t(I18nKey.SETTINGS$SAVED_WARNING));\n }\n setDirty({});\n onSaveSuccess?.();\n },\n });\n };\n\n handleSaveRef.current = handleSave;\n // Dirty-only (NOT view-filtered): we must never inject defaults for\n // non-visible fields here, or a custom save flow would reset fields the\n // user never touched. `buildSdkSettingsPayloadForView` is reserved for the\n // built-in full-replace save above.\n buildDirtyPayloadRef.current = () =>\n filteredSchema\n ? buildSdkSettingsPayload(filteredSchema, values, dirty)\n : {};\n\n // Surface save state to the parent. Hooks must run before any\n // conditional early-returns below, so this lives here rather than\n // alongside the JSX. The dependency list deliberately excludes\n // `stableSave` (it never changes) and `onSaveControlChange` (we\n // tolerate ref-instability of the callback to avoid spamming the\n // parent on every render).\n const saveControlIsDirty = Object.keys(dirty).length > 0 || extraDirty;\n React.useEffect(() => {\n if (!onSaveControlChange) return;\n onSaveControlChange({\n save: stableSave,\n isSaving: isPending,\n isDirty: saveControlIsDirty,\n values,\n view,\n getDirtyPayload: stableGetDirtyPayload,\n });\n }, [isPending, saveControlIsDirty, values, view]);\n\n // Keep existing form content visible during background refetches to avoid\n // flashing the full skeleton (notably during onboarding Next transitions).\n const isInitialSettingsLoad = (isLoading || isFetching) && !settings;\n if (isInitialSettingsLoad || isSchemaLoading) {\n return <LlmSettingsInputsSkeleton />;\n }\n\n if (!filteredSchema || filteredSchema.sections.length === 0) {\n return (\n <Typography.Paragraph className=\"text-tertiary-alt\">\n {schemaUnavailableMessage}\n </Typography.Paragraph>\n );\n }\n\n if (Object.keys(values).length === 0) return <LlmSettingsInputsSkeleton />;\n\n // Scrolling is owned by the settings shell (or onboarding wrapper), not a\n // nested scroll region. Save actions are inline after the last field.\n const bodyClassName = \"flex flex-col gap-8\";\n\n return (\n <div\n data-testid={testId}\n className={\n embedded\n ? \"relative flex min-h-0 w-full flex-1 flex-col\"\n : \"relative w-full min-h-0\"\n }\n >\n <ViewToggle\n view={view}\n setView={setView}\n showAdvanced={showAdvanced}\n showAll={showAll}\n isDisabled={isReadOnly}\n />\n\n <div className={bodyClassName}>\n {header?.({\n values,\n isDisabled: isReadOnly,\n view,\n onChange: handleFieldChange,\n })}\n\n {visibleSections.map((section, sectionIndex) => (\n <section\n key={`${section.key}-${sectionIndex}`}\n className=\"flex flex-col gap-4\"\n >\n <div className=\"flex flex-col gap-4\">\n {section.fields.map((field) => (\n <SchemaField\n key={field.key}\n field={field}\n value={values[field.key]}\n isDisabled={isReadOnly}\n onChange={(nextValue) =>\n handleFieldChange(field.key, nextValue)\n }\n />\n ))}\n </div>\n </section>\n ))}\n\n {!isReadOnly && !hideSaveButton ? (\n <div className=\"flex justify-start pt-2\">\n <BrandButton\n testId=\"save-button\"\n type=\"button\"\n variant=\"primary\"\n isDisabled={\n isPending || (Object.keys(dirty).length === 0 && !extraDirty)\n }\n onClick={handleSave}\n >\n {isPending\n ? t(I18nKey.SETTINGS$SAVING)\n : t(I18nKey.SETTINGS$SAVE_CHANGES)}\n </BrandButton>\n </div>\n ) : null}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -41,7 +41,7 @@ export interface SdkSectionSaveControl {
41
41
  * @param header - optional render prop receiving shared state to render above fields
42
42
  * @param testId - data-testid for the page wrapper
43
43
  */
44
- export declare function SdkSectionPage({ sectionKeys, excludeKeys, scope, settingsSource, header, extraDirty, buildPayload, onSaveSuccess, getInitialView, forceShowAdvancedView, allowAllView, initialValueOverrides, embedded, hideSaveButton, onSaveControlChange, testId, }: {
44
+ export declare function SdkSectionPage({ sectionKeys, excludeKeys, scope, settingsSource, header, extraDirty, buildPayload, onSaveSuccess, getInitialView, forceShowAdvancedView, allowAllView, initialValueOverrides, embedded, hideSaveButton, suppressSuccessToast, onSaveControlChange, testId, }: {
45
45
  sectionKeys: string[];
46
46
  excludeKeys?: Set<string>;
47
47
  scope?: SettingsScope;
@@ -78,6 +78,8 @@ export declare function SdkSectionPage({ sectionKeys, excludeKeys, scope, settin
78
78
  * action (e.g. an onboarding "Next" button).
79
79
  */
80
80
  hideSaveButton?: boolean;
81
+ /** Suppress the default success toast after save completes. */
82
+ suppressSuccessToast?: boolean;
81
83
  /**
82
84
  * Fires whenever the save state changes (a mutation starts/finishes,
83
85
  * dirty status flips). Provides a stable `save()` callback the
@@ -3,69 +3,69 @@ import { I18nKey as t } from "../../../../i18n/declaration.js";
3
3
  import { displayErrorToast as n, displaySuccessToast as ee } from "../../../../utils/custom-toast-handlers.js";
4
4
  import { AxiosError as r } from "../../../../node_modules/axios/index.js";
5
5
  import { useSettings as te } from "../../../../hooks/query/use-settings.js";
6
- import { Typography as i } from "../../../../ui/typography.js";
7
- import { BrandButton as ne } from "../brand-button.js";
8
- import { useSaveSettings as re } from "../../../../hooks/mutation/use-save-settings.js";
6
+ import { Typography as ne } from "../../../../ui/typography.js";
7
+ import { BrandButton as re } from "../brand-button.js";
8
+ import { useSaveSettings as i } from "../../../../hooks/mutation/use-save-settings.js";
9
9
  import { retrieveAxiosErrorMessage as ie } from "../../../../utils/retrieve-axios-error-message.js";
10
- import { useAgentSettingsSchema as a, useConversationSettingsSchema as o } from "../../../../hooks/query/use-agent-settings-schema.js";
11
- import { LlmSettingsInputsSkeleton as s } from "../llm-settings/llm-settings-inputs-skeleton.js";
12
- import { buildInitialSettingsFormValues as c, buildSdkSettingsPayload as l, buildSdkSettingsPayloadForView as ae, getVisibleSettingsSections as oe, hasAdvancedSettings as se, hasMinorSettings as ce, inferInitialView as le, isValidSettingsSchema as ue } from "../../../../utils/sdk-settings-schema.js";
13
- import { SchemaField as u } from "./schema-field.js";
14
- import { ViewToggle as de } from "./view-toggle.js";
15
- import d from "react";
16
- import { jsx as f, jsxs as p } from "react/jsx-runtime";
10
+ import { useAgentSettingsSchema as ae, useConversationSettingsSchema as a } from "../../../../hooks/query/use-agent-settings-schema.js";
11
+ import { LlmSettingsInputsSkeleton as o } from "../llm-settings/llm-settings-inputs-skeleton.js";
12
+ import { buildInitialSettingsFormValues as s, buildSdkSettingsPayload as c, buildSdkSettingsPayloadForView as l, getVisibleSettingsSections as oe, hasAdvancedSettings as se, hasMinorSettings as ce, inferInitialView as le, isValidSettingsSchema as ue } from "../../../../utils/sdk-settings-schema.js";
13
+ import { SchemaField as de } from "./schema-field.js";
14
+ import { ViewToggle as fe } from "./view-toggle.js";
15
+ import u from "react";
16
+ import { jsx as d, jsxs as f } from "react/jsx-runtime";
17
17
  //#region src/components/features/settings/sdk-settings/sdk-section-page.tsx
18
- var fe = /* @__PURE__ */ new Set(), m = {
18
+ var pe = /* @__PURE__ */ new Set(), p = {
19
19
  basic: 0,
20
20
  advanced: 1,
21
21
  all: 2
22
- }, h = (e, t) => m[t] < m[e] ? t : e, pe = (e, { showAdvanced: t, showAll: n }) => e === "all" ? n ? "all" : t ? "advanced" : "basic" : e === "advanced" ? t ? "advanced" : n ? "all" : "basic" : "basic", me = (e, t) => e instanceof r ? e.response?.status === 401 ? `${t} This agent server requires X-Session-API-Key. Set VITE_SESSION_API_KEY in the frontend to the same value used by the backend SESSION_API_KEY or OH_SESSION_API_KEYS_0.` : e.response?.status === 404 ? `${t} This backend does not expose /api/settings/* schema endpoints. Upgrade to a recent openhands-agent-server release.` : t : t;
23
- function g({ sectionKeys: r, excludeKeys: m = fe, scope: g = "personal", settingsSource: _ = "agent_settings", header: he, extraDirty: v = !1, buildPayload: y, onSaveSuccess: ge, getInitialView: b, forceShowAdvancedView: _e = !1, allowAllView: ve = !0, initialValueOverrides: x, embedded: ye = !1, hideSaveButton: S = !1, onSaveControlChange: C, testId: w = "sdk-section-settings-screen" }) {
24
- let { t: T } = e("openhands"), { mutate: E, isPending: D } = re(g), { data: O, isLoading: k, isFetching: A } = te(g), j = a(O?.agent_settings_schema), M = o(O?.conversation_settings_schema), N = _ === "conversation_settings" ? M : j, P = N.data, be = N.isLoading, [F, I] = d.useState("basic"), [L, R] = d.useState({}), [z, B] = d.useState({}), V = d.useRef(!1), H = d.useMemo(() => JSON.stringify(r), [r]), U = d.useMemo(() => JSON.parse(H), [H]), W = d.useMemo(() => {
22
+ }, me = (e, t) => p[t] < p[e] ? t : e, he = (e, { showAdvanced: t, showAll: n }) => e === "all" ? n ? "all" : t ? "advanced" : "basic" : e === "advanced" ? t ? "advanced" : n ? "all" : "basic" : "basic", m = (e, t) => e instanceof r ? e.response?.status === 401 ? `${t} This agent server requires X-Session-API-Key. Set VITE_SESSION_API_KEY in the frontend to the same value used by the backend SESSION_API_KEY or OH_SESSION_API_KEYS_0.` : e.response?.status === 404 ? `${t} This backend does not expose /api/settings/* schema endpoints. Upgrade to a recent openhands-agent-server release.` : t : t;
23
+ function h({ sectionKeys: r, excludeKeys: p = pe, scope: h = "personal", settingsSource: g = "agent_settings", header: ge, extraDirty: _ = !1, buildPayload: v, onSaveSuccess: _e, getInitialView: y, forceShowAdvancedView: ve = !1, allowAllView: ye = !0, initialValueOverrides: b, embedded: be = !1, hideSaveButton: x = !1, suppressSuccessToast: S = !1, onSaveControlChange: C, testId: w = "sdk-section-settings-screen" }) {
24
+ let { t: T } = e("openhands"), { mutate: E, isPending: D } = i(h), { data: O, isLoading: k, isFetching: A } = te(h), j = ae(O?.agent_settings_schema), M = a(O?.conversation_settings_schema), N = g === "conversation_settings" ? M : j, P = N.data, xe = N.isLoading, [F, I] = u.useState("basic"), [L, R] = u.useState({}), [z, B] = u.useState({}), V = u.useRef(!1), H = u.useMemo(() => JSON.stringify(r), [r]), U = u.useMemo(() => JSON.parse(H), [H]), W = u.useMemo(() => {
25
25
  if (!ue(P)) return null;
26
26
  let e = new Set(U);
27
27
  return {
28
28
  ...P,
29
29
  sections: P.sections.filter((t) => e.has(t.key))
30
30
  };
31
- }, [P, U]), G = _e || se(W), K = ve && ce(W), xe = d.useMemo(() => me(N.error, T(t.SETTINGS$SDK_SCHEMA_UNAVAILABLE)), [N.error, T]), Se = d.useMemo(() => x ? JSON.stringify(x) : "", [x]), q = d.useMemo(() => {
31
+ }, [P, U]), G = ve || se(W), K = ye && ce(W), Se = u.useMemo(() => m(N.error, T(t.SETTINGS$SDK_SCHEMA_UNAVAILABLE)), [N.error, T]), Ce = u.useMemo(() => b ? JSON.stringify(b) : "", [b]), q = u.useMemo(() => {
32
32
  if (!O || !W) return null;
33
- let e = c(O, W, _);
34
- return x ? {
33
+ let e = s(O, W, g);
34
+ return b ? {
35
35
  ...e,
36
- ...x
36
+ ...b
37
37
  } : e;
38
38
  }, [
39
39
  O,
40
40
  W,
41
- _,
42
- Se
43
- ]), J = d.useMemo(() => !O || !W ? null : pe(b ? b(O, W) : le(O, W, _), {
41
+ g,
42
+ Ce
43
+ ]), J = u.useMemo(() => !O || !W ? null : he(y ? y(O, W) : le(O, W, g), {
44
44
  showAdvanced: G,
45
45
  showAll: K
46
46
  }), [
47
47
  O,
48
48
  W,
49
- b,
50
- _,
49
+ y,
50
+ g,
51
51
  G,
52
52
  K
53
53
  ]);
54
- d.useEffect(() => {
54
+ u.useEffect(() => {
55
55
  V.current = !1, I("basic"), R({}), B({});
56
56
  }, [
57
+ h,
57
58
  g,
58
- _,
59
59
  H
60
- ]), d.useEffect(() => {
61
- !q || !J || (R(q), B(x ? Object.fromEntries(Object.keys(x).map((e) => [e, !0])) : {}), I((e) => V.current ? h(e, J) : (V.current = !0, J)));
60
+ ]), u.useEffect(() => {
61
+ !q || !J || (R(q), B(b ? Object.fromEntries(Object.keys(b).map((e) => [e, !0])) : {}), I((e) => V.current ? me(e, J) : (V.current = !0, J)));
62
62
  }, [q, J]);
63
- let Ce = d.useMemo(() => W ? oe(W, L, F, m) : [], [
63
+ let we = u.useMemo(() => W ? oe(W, L, F, p) : [], [
64
64
  W,
65
65
  L,
66
66
  F,
67
- m
68
- ]), Y = d.useCallback((e, t) => {
67
+ p
68
+ ]), Y = u.useCallback((e, t) => {
69
69
  R((n) => ({
70
70
  ...n,
71
71
  [e]: t
@@ -73,16 +73,16 @@ function g({ sectionKeys: r, excludeKeys: m = fe, scope: g = "personal", setting
73
73
  ...t,
74
74
  [e]: !0
75
75
  }));
76
- }, []), we = d.useCallback((e) => {
76
+ }, []), Te = u.useCallback((e) => {
77
77
  n(ie(e) || T(t.ERROR$GENERIC));
78
- }, [T]), X = d.useRef(() => {}), Te = d.useCallback(() => {
78
+ }, [T]), X = u.useRef(() => {}), Ee = u.useCallback(() => {
79
79
  X.current();
80
- }, []), Z = d.useRef(() => ({})), Ee = d.useCallback(() => Z.current(), []), Q = () => {
80
+ }, []), Z = u.useRef(() => ({})), De = u.useCallback(() => Z.current(), []), Q = () => {
81
81
  if (!W) return;
82
82
  let e;
83
83
  try {
84
- let t = ae(W, L, z, F), n;
85
- n = _ === "conversation_settings" ? { conversation_settings_diff: t } : { agent_settings_diff: t }, e = y ? y(t, {
84
+ let t = l(W, L, z, F), n;
85
+ n = g === "conversation_settings" ? { conversation_settings_diff: t } : { agent_settings_diff: t }, e = v ? v(t, {
86
86
  values: L,
87
87
  dirty: z,
88
88
  view: F
@@ -92,54 +92,54 @@ function g({ sectionKeys: r, excludeKeys: m = fe, scope: g = "personal", setting
92
92
  return;
93
93
  }
94
94
  Object.keys(e).length !== 0 && E(e, {
95
- onError: we,
95
+ onError: Te,
96
96
  onSuccess: () => {
97
- ee(T(t.SETTINGS$SAVED_WARNING)), B({}), ge?.();
97
+ S || ee(T(t.SETTINGS$SAVED_WARNING)), B({}), _e?.();
98
98
  }
99
99
  });
100
100
  };
101
- X.current = Q, Z.current = () => W ? l(W, L, z) : {};
102
- let $ = Object.keys(z).length > 0 || v;
103
- return d.useEffect(() => {
101
+ X.current = Q, Z.current = () => W ? c(W, L, z) : {};
102
+ let $ = Object.keys(z).length > 0 || _;
103
+ return u.useEffect(() => {
104
104
  C && C({
105
- save: Te,
105
+ save: Ee,
106
106
  isSaving: D,
107
107
  isDirty: $,
108
108
  values: L,
109
109
  view: F,
110
- getDirtyPayload: Ee
110
+ getDirtyPayload: De
111
111
  });
112
112
  }, [
113
113
  D,
114
114
  $,
115
115
  L,
116
116
  F
117
- ]), k || A || be ? /* @__PURE__ */ f(s, {}) : !W || W.sections.length === 0 ? /* @__PURE__ */ f(i.Paragraph, {
117
+ ]), (k || A) && !O || xe ? /* @__PURE__ */ d(o, {}) : !W || W.sections.length === 0 ? /* @__PURE__ */ d(ne.Paragraph, {
118
118
  className: "text-tertiary-alt",
119
- children: xe
120
- }) : Object.keys(L).length === 0 ? /* @__PURE__ */ f(s, {}) : /* @__PURE__ */ p("div", {
119
+ children: Se
120
+ }) : Object.keys(L).length === 0 ? /* @__PURE__ */ d(o, {}) : /* @__PURE__ */ f("div", {
121
121
  "data-testid": w,
122
- className: ye ? "relative flex min-h-0 w-full flex-1 flex-col" : "relative w-full min-h-0",
123
- children: [/* @__PURE__ */ f(de, {
122
+ className: be ? "relative flex min-h-0 w-full flex-1 flex-col" : "relative w-full min-h-0",
123
+ children: [/* @__PURE__ */ d(fe, {
124
124
  view: F,
125
125
  setView: I,
126
126
  showAdvanced: G,
127
127
  showAll: K,
128
128
  isDisabled: !1
129
- }), /* @__PURE__ */ p("div", {
129
+ }), /* @__PURE__ */ f("div", {
130
130
  className: "flex flex-col gap-8",
131
131
  children: [
132
- he?.({
132
+ ge?.({
133
133
  values: L,
134
134
  isDisabled: !1,
135
135
  view: F,
136
136
  onChange: Y
137
137
  }),
138
- Ce.map((e, t) => /* @__PURE__ */ f("section", {
138
+ we.map((e, t) => /* @__PURE__ */ d("section", {
139
139
  className: "flex flex-col gap-4",
140
- children: /* @__PURE__ */ f("div", {
140
+ children: /* @__PURE__ */ d("div", {
141
141
  className: "flex flex-col gap-4",
142
- children: e.fields.map((e) => /* @__PURE__ */ f(u, {
142
+ children: e.fields.map((e) => /* @__PURE__ */ d(de, {
143
143
  field: e,
144
144
  value: L[e.key],
145
145
  isDisabled: !1,
@@ -147,13 +147,13 @@ function g({ sectionKeys: r, excludeKeys: m = fe, scope: g = "personal", setting
147
147
  }, e.key))
148
148
  })
149
149
  }, `${e.key}-${t}`)),
150
- S ? null : /* @__PURE__ */ f("div", {
150
+ x ? null : /* @__PURE__ */ d("div", {
151
151
  className: "flex justify-start pt-2",
152
- children: /* @__PURE__ */ f(ne, {
152
+ children: /* @__PURE__ */ d(re, {
153
153
  testId: "save-button",
154
154
  type: "button",
155
155
  variant: "primary",
156
- isDisabled: D || Object.keys(z).length === 0 && !v,
156
+ isDisabled: D || Object.keys(z).length === 0 && !_,
157
157
  onClick: Q,
158
158
  children: T(D ? t.SETTINGS$SAVING : t.SETTINGS$SAVE_CHANGES)
159
159
  })
@@ -163,6 +163,6 @@ function g({ sectionKeys: r, excludeKeys: m = fe, scope: g = "personal", setting
163
163
  });
164
164
  }
165
165
  //#endregion
166
- export { g as SdkSectionPage };
166
+ export { h as SdkSectionPage };
167
167
 
168
168
  //# sourceMappingURL=sdk-section-page.js.map